parsing goto

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-11-25 21:53:14 +01:00
parent 4b71b74c6a
commit 24f9b63475
3 changed files with 61 additions and 1 deletions

5
ast.c
View file

@ -844,6 +844,11 @@ void ast_goto_delete(ast_goto *self)
mem_d(self);
}
void ast_goto_set_label(ast_goto *self, ast_label *label)
{
self->target = label;
}
ast_call* ast_call_new(lex_ctx ctx,
ast_expression *funcexpr)
{

2
ast.h
View file

@ -525,7 +525,7 @@ struct ast_goto_s
ast_goto* ast_goto_new(lex_ctx ctx, const char *name);
void ast_goto_delete(ast_goto*);
void ast_goto_setlabel(ast_goto*, ast_label*);
void ast_goto_set_label(ast_goto*, ast_label*);
bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**);

View file

@ -58,6 +58,12 @@ typedef struct {
ast_function *function;
/* All the labels the function defined...
* Should they be in ast_function instead?
*/
ast_label **labels;
ast_goto **gotos;
/* A list of hashtables for each scope */
ht *variables;
ht htfields;
@ -2227,6 +2233,40 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou
return true;
}
static bool parse_goto(parser_t *parser, ast_expression **out)
{
size_t i;
ast_goto *gt;
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
parseerror(parser, "expected label name after `goto`");
return false;
}
gt = ast_goto_new(parser_ctx(parser), parser_tokval(parser));
for (i = 0; i < vec_size(parser->labels); ++i) {
if (!strcmp(parser->labels[i]->name, parser_tokval(parser))) {
ast_goto_set_label(gt, parser->labels[i]);
break;
}
}
if (i == vec_size(parser->labels))
vec_push(parser->gotos, gt);
if (!parser_next(parser) || parser->tok != ';') {
parseerror(parser, "semicolon expected after goto label");
return false;
}
if (!parser_next(parser)) {
parseerror(parser, "parse error after goto");
return false;
}
*out = (ast_expression*)gt;
return true;
}
static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases)
{
ast_value *typevar = NULL;
@ -2316,6 +2356,10 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
}
return true;
}
else if (!strcmp(parser_tokval(parser), "goto"))
{
return parse_goto(parser, out);
}
else if (!strcmp(parser_tokval(parser), "typedef"))
{
if (!parser_next(parser)) {
@ -2350,6 +2394,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
label = ast_label_new(parser_ctx(parser), parser_tokval(parser));
if (!label)
return false;
vec_push(parser->labels, label);
*out = (ast_expression*)label;
if (!parser_next(parser)) {
parseerror(parser, "parse error after label");
@ -2495,6 +2540,11 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
has_frame_think = false;
old = parser->function;
if (vec_size(parser->gotos) || vec_size(parser->labels)) {
parseerror(parser, "gotos/labels leaking");
return false;
}
if (var->expression.variadic) {
if (parsewarning(parser, WARN_VARIADIC_FUNCTION,
"variadic function with implementation will not be able to access additional parameters"))
@ -3871,6 +3921,8 @@ skipvar:
if (!parse_function_body(parser, var))
break;
ast_delete(basetype);
vec_free(parser->gotos);
vec_free(parser->labels);
return true;
} else {
ast_expression *cexp;
@ -4248,6 +4300,9 @@ void parser_cleanup()
vec_free(parser->typedefs);
vec_free(parser->_blocktypedefs);
vec_free(parser->labels);
vec_free(parser->gotos);
mem_d(parser);
}