A statement_base_t is enough space for break and continue statements.
[cparser] / parser.c
index 7fd54f4..7d9b334 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -50,7 +50,8 @@ static declaration_t      *last_declaration  = NULL;
 static declaration_t      *current_function  = NULL;
 static switch_statement_t *current_switch    = NULL;
 static statement_t        *current_loop      = NULL;
-static goto_statement_t   *goto_list         = NULL;
+static goto_statement_t   *goto_first        = NULL;
+static goto_statement_t   *goto_last         = NULL;
 static struct obstack  temp_obst;
 
 /** The current source position. */
@@ -462,14 +463,6 @@ static void eat_paren(void)
     }                                              \
     next_token();
 
-#define expect_fail(expected)                      \
-    if(UNLIKELY(token.type != (expected))) {       \
-        parse_error_expected(NULL, (expected), 0); \
-        eat_statement();                           \
-        goto fail;                                 \
-    }                                              \
-    next_token();
-
 #define expect_block(expected)                     \
     if(UNLIKELY(token.type != (expected))) {       \
         parse_error_expected(NULL, (expected), 0); \
@@ -2700,19 +2693,24 @@ static void parse_kr_declaration_list(declaration_t *declaration)
  */
 static void check_for_missing_labels(void)
 {
-       const goto_statement_t *goto_statement, *next;
-
-       for (goto_statement = goto_list;
+       bool first_err = true;
+       for (const goto_statement_t *goto_statement = goto_first;
             goto_statement != NULL;
-            goto_statement = next) {
+            goto_statement = goto_statement->next) {
                 const declaration_t *label = goto_statement->label;
 
                 if (label->source_position.input_name == NULL) {
+                        if (first_err) {
+                                first_err = false;
+                                diagnosticf("%s: In function '%Y':\n",
+                                        current_function->source_position.input_name,
+                                        current_function->symbol);
+                        }
                         errorf(goto_statement->statement.source_position,
                                 "label '%Y' used but not defined", label->symbol);
                 }
        }
-       goto_list = NULL;
+       goto_first = goto_last = NULL;
 }
 
 static void parse_external_declaration(void)
@@ -5067,6 +5065,15 @@ static statement_t *parse_switch(void)
        return (statement_t*) statement;
 }
 
+static statement_t *parse_loop_body(statement_t *const loop)
+{
+       statement_t *const rem = current_loop;
+       current_loop = loop;
+       statement_t *const body = parse_statement();
+       current_loop = rem;
+       return body;
+}
+
 /**
  * Parse a while statement.
  */
@@ -5078,18 +5085,13 @@ static statement_t *parse_while(void)
        statement->statement.kind            = STATEMENT_WHILE;
        statement->statement.source_position = token.source_position;
 
-       statement_t *rem = current_loop;
-       expect_fail('(');
+       expect('(');
        statement->condition = parse_expression();
-       expect_fail(')');
+       expect(')');
 
-       statement->body = parse_statement();
-       current_loop = rem;
+       statement->body = parse_loop_body((statement_t*)statement);
 
        return (statement_t*) statement;
-fail:
-       current_loop = rem;
-       return NULL;
 }
 
 /**
@@ -5103,19 +5105,14 @@ static statement_t *parse_do(void)
        statement->statement.kind            = STATEMENT_DO_WHILE;
        statement->statement.source_position = token.source_position;
 
-       statement_t *rem = current_loop;
-       statement->body = parse_statement();
-       expect_fail(T_while);
-       expect_fail('(');
+       statement->body = parse_loop_body((statement_t*)statement);
+       expect(T_while);
+       expect('(');
        statement->condition = parse_expression();
-       expect_fail(')');
-       current_loop = rem;
+       expect(')');
        expect(';');
 
        return (statement_t*) statement;
-fail:
-       current_loop = rem;
-       return NULL;
 }
 
 /**
@@ -5131,7 +5128,6 @@ static statement_t *parse_for(void)
 
        expect('(');
 
-       statement_t *rem = current_loop;
        int         top          = environment_top();
        context_t  *last_context = context;
        set_context(&statement->context);
@@ -5141,31 +5137,27 @@ static statement_t *parse_for(void)
                        parse_declaration(record_declaration);
                } else {
                        statement->initialisation = parse_expression();
-                       expect_fail(';');
+                       expect(';');
                }
        } else {
-               expect_fail(';');
+               expect(';');
        }
 
        if(token.type != ';') {
                statement->condition = parse_expression();
        }
-       expect_fail(';');
+       expect(';');
        if(token.type != ')') {
                statement->step = parse_expression();
        }
-       expect_fail(')');
-       statement->body = parse_statement();
+       expect(')');
+       statement->body = parse_loop_body((statement_t*)statement);
 
        assert(context == &statement->context);
        set_context(last_context);
        environment_pop_to(top);
-       current_loop = rem;
 
        return (statement_t*) statement;
-fail:
-       current_loop = rem;
-       return NULL;
 }
 
 /**
@@ -5193,8 +5185,11 @@ static statement_t *parse_goto(void)
        statement->label = label;
 
        /* remember the goto's in a list for later checking */
-       statement->next = goto_list;
-       goto_list       = statement;
+       if (goto_last == NULL) {
+               goto_first = goto_last = statement;
+       } else {
+               goto_last->next = statement;
+       }
 
        expect(';');
 
@@ -5206,19 +5201,20 @@ static statement_t *parse_goto(void)
  */
 static statement_t *parse_continue(void)
 {
-       eat(T_continue);
-       expect(';');
-
-       statement_t *statement          = allocate_ast_zero(sizeof(statement[0]));
-       statement->kind                 = STATEMENT_CONTINUE;
-       statement->base.source_position = token.source_position;
-
+       statement_base_t *statement;
        if (current_loop == NULL) {
                errorf(HERE, "continue statement not within loop");
-               return NULL;
+               statement = NULL;
+       } else {
+               statement                  = allocate_ast_zero(sizeof(statement[0]));
+               statement->kind            = STATEMENT_CONTINUE;
+               statement->source_position = token.source_position;
        }
 
-       return statement;
+       eat(T_continue);
+       expect(';');
+
+       return (statement_t*)statement;
 }
 
 /**
@@ -5226,18 +5222,20 @@ static statement_t *parse_continue(void)
  */
 static statement_t *parse_break(void)
 {
-       eat(T_break);
-       expect(';');
-
-       statement_t *statement          = allocate_ast_zero(sizeof(statement[0]));
-       statement->kind                 = STATEMENT_BREAK;
-       statement->base.source_position = token.source_position;
-
+       statement_base_t *statement;
        if (current_switch == NULL && current_loop == NULL) {
                errorf(HERE, "break statement not within loop or switch");
-               return NULL;
+               statement = NULL;
+       } else {
+               statement                  = allocate_ast_zero(sizeof(statement[0]));
+               statement->kind            = STATEMENT_BREAK;
+               statement->source_position = token.source_position;
        }
-       return statement;
+
+       eat(T_break);
+       expect(';');
+
+       return (statement_t*)statement;
 }
 
 /**