mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-23 12:22:26 +00:00
finish parsing of labeled loops; ast support added
This commit is contained in:
parent
c702970a0e
commit
a60d0182db
3 changed files with 69 additions and 32 deletions
34
ast.c
34
ast.c
|
@ -1026,8 +1026,8 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
|
|||
self->ir_func = NULL;
|
||||
self->curblock = NULL;
|
||||
|
||||
self->breakblock = NULL;
|
||||
self->continueblock = NULL;
|
||||
self->breakblocks = NULL;
|
||||
self->continueblocks = NULL;
|
||||
|
||||
vtype->hasvalue = true;
|
||||
vtype->constval.vfunc = self;
|
||||
|
@ -1052,6 +1052,8 @@ void ast_function_delete(ast_function *self)
|
|||
for (i = 0; i < vec_size(self->blocks); ++i)
|
||||
ast_delete(self->blocks[i]);
|
||||
vec_free(self->blocks);
|
||||
vec_free(self->breakblocks);
|
||||
vec_free(self->continueblocks);
|
||||
mem_d(self);
|
||||
}
|
||||
|
||||
|
@ -2407,9 +2409,6 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
|
|||
ir_block *bcontinue = NULL;
|
||||
ir_block *bbreak = NULL;
|
||||
|
||||
ir_block *old_bcontinue = NULL;
|
||||
ir_block *old_bbreak = NULL;
|
||||
|
||||
ir_block *tmpblock = NULL;
|
||||
|
||||
(void)lvalue;
|
||||
|
@ -2502,12 +2501,11 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
|
|||
/* enter */
|
||||
func->curblock = bbody;
|
||||
|
||||
old_bbreak = func->breakblock;
|
||||
old_bcontinue = func->continueblock;
|
||||
func->breakblock = bbreak;
|
||||
func->continueblock = bcontinue;
|
||||
if (!func->continueblock)
|
||||
func->continueblock = bbody;
|
||||
vec_push(func->breakblocks, bbreak);
|
||||
if (bcontinue)
|
||||
vec_push(func->continueblocks, bcontinue);
|
||||
else
|
||||
vec_push(func->continueblocks, bbody);
|
||||
|
||||
/* generate */
|
||||
if (self->body) {
|
||||
|
@ -2517,8 +2515,8 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
|
|||
}
|
||||
|
||||
end_bbody = func->curblock;
|
||||
func->breakblock = old_bbreak;
|
||||
func->continueblock = old_bcontinue;
|
||||
vec_pop(func->breakblocks);
|
||||
vec_pop(func->continueblocks);
|
||||
}
|
||||
|
||||
/* post-loop-condition */
|
||||
|
@ -2644,9 +2642,9 @@ bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue,
|
|||
self->expression.outr = (ir_value*)1;
|
||||
|
||||
if (self->is_continue)
|
||||
target = func->continueblock;
|
||||
target = func->continueblocks[vec_size(func->continueblocks)-1-self->levels];
|
||||
else
|
||||
target = func->breakblock;
|
||||
target = func->breakblocks[vec_size(func->breakblocks)-1-self->levels];
|
||||
|
||||
if (!target) {
|
||||
compile_error(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break"));
|
||||
|
@ -2669,7 +2667,6 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
|
|||
|
||||
ir_value *dummy = NULL;
|
||||
ir_value *irop = NULL;
|
||||
ir_block *old_break = NULL;
|
||||
ir_block *bout = NULL;
|
||||
ir_block *bfall = NULL;
|
||||
size_t bout_id;
|
||||
|
@ -2712,8 +2709,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
|
|||
return false;
|
||||
|
||||
/* setup the break block */
|
||||
old_break = func->breakblock;
|
||||
func->breakblock = bout;
|
||||
vec_push(func->breakblocks, bout);
|
||||
|
||||
/* Now create all cases */
|
||||
for (c = 0; c < vec_size(self->cases); ++c) {
|
||||
|
@ -2818,7 +2814,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
|
|||
func->curblock = bout;
|
||||
|
||||
/* restore the break block */
|
||||
func->breakblock = old_break;
|
||||
vec_pop(func->breakblocks);
|
||||
|
||||
/* Move 'bout' to the end, it's nicer */
|
||||
vec_remove(func->ir_func->blocks, bout_id, 1);
|
||||
|
|
4
ast.h
4
ast.h
|
@ -608,8 +608,8 @@ struct ast_function_s
|
|||
|
||||
ir_function *ir_func;
|
||||
ir_block *curblock;
|
||||
ir_block *breakblock;
|
||||
ir_block *continueblock;
|
||||
ir_block **breakblocks;
|
||||
ir_block **continueblocks;
|
||||
|
||||
#if 0
|
||||
/* In order for early-out logic not to go over
|
||||
|
|
63
parser.c
63
parser.c
|
@ -2085,11 +2085,6 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression **
|
|||
|
||||
(void)block; /* not touching */
|
||||
|
||||
/* skip the 'while' and check for opening paren */
|
||||
if (!parser_next(parser) || parser->tok != '(') {
|
||||
parseerror(parser, "expected 'while' condition in parenthesis");
|
||||
return false;
|
||||
}
|
||||
/* parse into the expression */
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected 'while' condition after opening paren");
|
||||
|
@ -2588,7 +2583,59 @@ onerr:
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out);
|
||||
static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out)
|
||||
{
|
||||
bool rv;
|
||||
char *label = NULL;
|
||||
|
||||
/* skip the 'while' and get the body */
|
||||
if (!parser_next(parser)) {
|
||||
if (OPTS_FLAG(LOOP_LABELS))
|
||||
parseerror(parser, "expected loop label or 'switch' operand in parenthesis");
|
||||
else
|
||||
parseerror(parser, "expected 'switch' operand in parenthesis");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parser->tok == ':') {
|
||||
if (!OPTS_FLAG(LOOP_LABELS))
|
||||
parseerror(parser, "labeled loops not activated, try using -floop-labels");
|
||||
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
|
||||
parseerror(parser, "expected loop label");
|
||||
return false;
|
||||
}
|
||||
label = util_strdup(parser_tokval(parser));
|
||||
if (!parser_next(parser)) {
|
||||
mem_d(label);
|
||||
parseerror(parser, "expected 'switch' operand in parenthesis");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parser->tok != '(') {
|
||||
parseerror(parser, "expected 'switch' operand in parenthesis");
|
||||
return false;
|
||||
}
|
||||
|
||||
vec_push(parser->breaks, label);
|
||||
|
||||
rv = parse_switch_go(parser, block, out);
|
||||
if (label)
|
||||
mem_d(label);
|
||||
if (vec_last(parser->breaks) != label) {
|
||||
parseerror(parser, "internal error: label stack corrupted");
|
||||
rv = false;
|
||||
ast_delete(*out);
|
||||
*out = NULL;
|
||||
}
|
||||
else {
|
||||
vec_pop(parser->breaks);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out)
|
||||
{
|
||||
ast_expression *operand;
|
||||
ast_value *opval;
|
||||
|
@ -2604,12 +2651,6 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou
|
|||
(void)block; /* not touching */
|
||||
(void)opval;
|
||||
|
||||
/* parse over the opening paren */
|
||||
if (!parser_next(parser) || parser->tok != '(') {
|
||||
parseerror(parser, "expected switch operand in parenthesis");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* parse into the expression */
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected switch operand");
|
||||
|
|
Loading…
Reference in a new issue