mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-23 20:33:05 +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->ir_func = NULL;
|
||||||
self->curblock = NULL;
|
self->curblock = NULL;
|
||||||
|
|
||||||
self->breakblock = NULL;
|
self->breakblocks = NULL;
|
||||||
self->continueblock = NULL;
|
self->continueblocks = NULL;
|
||||||
|
|
||||||
vtype->hasvalue = true;
|
vtype->hasvalue = true;
|
||||||
vtype->constval.vfunc = self;
|
vtype->constval.vfunc = self;
|
||||||
|
@ -1052,6 +1052,8 @@ void ast_function_delete(ast_function *self)
|
||||||
for (i = 0; i < vec_size(self->blocks); ++i)
|
for (i = 0; i < vec_size(self->blocks); ++i)
|
||||||
ast_delete(self->blocks[i]);
|
ast_delete(self->blocks[i]);
|
||||||
vec_free(self->blocks);
|
vec_free(self->blocks);
|
||||||
|
vec_free(self->breakblocks);
|
||||||
|
vec_free(self->continueblocks);
|
||||||
mem_d(self);
|
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 *bcontinue = NULL;
|
||||||
ir_block *bbreak = NULL;
|
ir_block *bbreak = NULL;
|
||||||
|
|
||||||
ir_block *old_bcontinue = NULL;
|
|
||||||
ir_block *old_bbreak = NULL;
|
|
||||||
|
|
||||||
ir_block *tmpblock = NULL;
|
ir_block *tmpblock = NULL;
|
||||||
|
|
||||||
(void)lvalue;
|
(void)lvalue;
|
||||||
|
@ -2502,12 +2501,11 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
|
||||||
/* enter */
|
/* enter */
|
||||||
func->curblock = bbody;
|
func->curblock = bbody;
|
||||||
|
|
||||||
old_bbreak = func->breakblock;
|
vec_push(func->breakblocks, bbreak);
|
||||||
old_bcontinue = func->continueblock;
|
if (bcontinue)
|
||||||
func->breakblock = bbreak;
|
vec_push(func->continueblocks, bcontinue);
|
||||||
func->continueblock = bcontinue;
|
else
|
||||||
if (!func->continueblock)
|
vec_push(func->continueblocks, bbody);
|
||||||
func->continueblock = bbody;
|
|
||||||
|
|
||||||
/* generate */
|
/* generate */
|
||||||
if (self->body) {
|
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;
|
end_bbody = func->curblock;
|
||||||
func->breakblock = old_bbreak;
|
vec_pop(func->breakblocks);
|
||||||
func->continueblock = old_bcontinue;
|
vec_pop(func->continueblocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* post-loop-condition */
|
/* 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;
|
self->expression.outr = (ir_value*)1;
|
||||||
|
|
||||||
if (self->is_continue)
|
if (self->is_continue)
|
||||||
target = func->continueblock;
|
target = func->continueblocks[vec_size(func->continueblocks)-1-self->levels];
|
||||||
else
|
else
|
||||||
target = func->breakblock;
|
target = func->breakblocks[vec_size(func->breakblocks)-1-self->levels];
|
||||||
|
|
||||||
if (!target) {
|
if (!target) {
|
||||||
compile_error(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break"));
|
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 *dummy = NULL;
|
||||||
ir_value *irop = NULL;
|
ir_value *irop = NULL;
|
||||||
ir_block *old_break = NULL;
|
|
||||||
ir_block *bout = NULL;
|
ir_block *bout = NULL;
|
||||||
ir_block *bfall = NULL;
|
ir_block *bfall = NULL;
|
||||||
size_t bout_id;
|
size_t bout_id;
|
||||||
|
@ -2712,8 +2709,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* setup the break block */
|
/* setup the break block */
|
||||||
old_break = func->breakblock;
|
vec_push(func->breakblocks, bout);
|
||||||
func->breakblock = bout;
|
|
||||||
|
|
||||||
/* Now create all cases */
|
/* Now create all cases */
|
||||||
for (c = 0; c < vec_size(self->cases); ++c) {
|
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;
|
func->curblock = bout;
|
||||||
|
|
||||||
/* restore the break block */
|
/* restore the break block */
|
||||||
func->breakblock = old_break;
|
vec_pop(func->breakblocks);
|
||||||
|
|
||||||
/* Move 'bout' to the end, it's nicer */
|
/* Move 'bout' to the end, it's nicer */
|
||||||
vec_remove(func->ir_func->blocks, bout_id, 1);
|
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_function *ir_func;
|
||||||
ir_block *curblock;
|
ir_block *curblock;
|
||||||
ir_block *breakblock;
|
ir_block **breakblocks;
|
||||||
ir_block *continueblock;
|
ir_block **continueblocks;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* In order for early-out logic not to go over
|
/* 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 */
|
(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 */
|
/* parse into the expression */
|
||||||
if (!parser_next(parser)) {
|
if (!parser_next(parser)) {
|
||||||
parseerror(parser, "expected 'while' condition after opening paren");
|
parseerror(parser, "expected 'while' condition after opening paren");
|
||||||
|
@ -2588,7 +2583,59 @@ onerr:
|
||||||
return true;
|
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)
|
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_expression *operand;
|
||||||
ast_value *opval;
|
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)block; /* not touching */
|
||||||
(void)opval;
|
(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 */
|
/* parse into the expression */
|
||||||
if (!parser_next(parser)) {
|
if (!parser_next(parser)) {
|
||||||
parseerror(parser, "expected switch operand");
|
parseerror(parser, "expected switch operand");
|
||||||
|
|
Loading…
Reference in a new issue