]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
parsing goto
authorWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 25 Nov 2012 20:53:14 +0000 (21:53 +0100)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 25 Nov 2012 20:53:14 +0000 (21:53 +0100)
ast.c
ast.h
parser.c

diff --git a/ast.c b/ast.c
index a73c586bfbd5458d4c3a2d91032c674f3fdf73e4..9a1fbe3f3960ecbff3dc1505e3579938445368e9 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -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)
 {
diff --git a/ast.h b/ast.h
index 3a133ac1ef8524840960ac0eef5c6962f5df64de..29c3192df4acd1c1ecfbbeb18870481c0d36e66c 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -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**);
 
index 1d752c409688c4f1270aa7a7cc1c3cd0b6832254..67cf0fd2b01d6b40dbdbaf82f012e24b81a1932b 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -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);
 }