finish parsing of labeled loops; ast support added

This commit is contained in:
Wolfgang Bumiller 2012-12-28 00:04:09 +01:00
parent c702970a0e
commit a60d0182db
3 changed files with 69 additions and 32 deletions

34
ast.c
View file

@ -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
View file

@ -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

View file

@ -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");