- add empty and invalid statements
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 14 Mar 2008 14:16:09 +0000 (14:16 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 14 Mar 2008 14:16:09 +0000 (14:16 +0000)
- AST can be printed even with invalid entities in it

[r18940]

TODO
ast.c
ast.h
ast2firm.c
ast_t.h
main.c
parser.c
parsetest/empty.c [new file with mode: 0644]

diff --git a/TODO b/TODO
index dc334d8..2e086bb 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,4 @@
 Refactoring:
-- create an empty_statement_t and use that instead of a NULL pointer in places
-  like if, loop bodys, statements after labels
 - eliminate target_architecture.h and replace with stuff in lang_features.h
 - redo storage classes: so we can separate real from declared storage class
 
diff --git a/ast.c b/ast.c
index 9e90ee3..d15ece7 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -705,7 +705,7 @@ static void print_expression_prec(const expression_t *expression, unsigned top_p
        switch(expression->kind) {
        case EXPR_UNKNOWN:
        case EXPR_INVALID:
-               fprintf(out, "*invalid expression*");
+               fprintf(out, "$invalid expression$");
                break;
        case EXPR_CHARACTER_CONSTANT:
                print_character_constant(&expression->conste);
@@ -856,9 +856,7 @@ static void print_label_statement(const label_statement_t *statement)
 {
        fprintf(stderr, "(%p)", (void*) statement->label);
        fprintf(out, "%s:\n", statement->label->symbol->string);
-       if(statement->statement != NULL) {
-               print_statement(statement->statement);
-       }
+       print_statement(statement->statement);
 }
 
 /**
@@ -868,7 +866,7 @@ static void print_label_statement(const label_statement_t *statement)
  */
 static void print_if_statement(const if_statement_t *statement)
 {
-       fputs("if(", out);
+       fputs("if (", out);
        print_expression(statement->condition);
        fputs(") ", out);
        if(statement->true_statement != NULL) {
@@ -889,7 +887,7 @@ static void print_if_statement(const if_statement_t *statement)
  */
 static void print_switch_statement(const switch_statement_t *statement)
 {
-       fputs("switch(", out);
+       fputs("switch (", out);
        print_expression(statement->expression);
        fputs(") ", out);
        print_statement(statement->body);
@@ -952,7 +950,7 @@ static void print_declaration_statement(
  */
 static void print_while_statement(const while_statement_t *statement)
 {
-       fputs("while(", out);
+       fputs("while (", out);
        print_expression(statement->condition);
        fputs(") ", out);
        print_statement(statement->body);
@@ -968,7 +966,7 @@ static void print_do_while_statement(const do_while_statement_t *statement)
        fputs("do ", out);
        print_statement(statement->body);
        print_indent();
-       fputs("while(", out);
+       fputs("while (", out);
        print_expression(statement->condition);
        fputs(");\n", out);
 }
@@ -980,7 +978,7 @@ static void print_do_while_statement(const do_while_statement_t *statement)
  */
 static void print_for_statement(const for_statement_t *statement)
 {
-       fputs("for(", out);
+       fputs("for (", out);
        if(statement->scope.declarations != NULL) {
                assert(statement->initialisation == NULL);
                print_declaration(statement->scope.declarations);
@@ -1085,6 +1083,9 @@ end_of_print_asm_statement:
 void print_statement(const statement_t *statement)
 {
        switch(statement->kind) {
+       case STATEMENT_EMPTY:
+               fputs(";\n", out);
+               break;
        case STATEMENT_COMPOUND:
                print_compound_statement(&statement->compound);
                break;
@@ -1131,7 +1132,7 @@ void print_statement(const statement_t *statement)
                print_asm_statement(&statement->asms);
                break;
        case STATEMENT_INVALID:
-               fprintf(out, "*invalid statement*");
+               fprintf(out, "$invalid statement$");
                break;
        }
 }
diff --git a/ast.h b/ast.h
index 1df31e4..320eafa 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -66,6 +66,8 @@ typedef union  initializer_t                initializer_t;
 typedef struct declaration_t                declaration_t;
 
 typedef struct statement_base_t             statement_base_t;
+typedef struct invalid_statement_t          invalid_statement_t;
+typedef struct empty_statement_t            empty_statement_t;
 typedef struct compound_statement_t         compound_statement_t;
 typedef struct return_statement_t           return_statement_t;
 typedef struct if_statement_t               if_statement_t;
index fe08af7..53e55c8 100644 (file)
@@ -4291,6 +4291,10 @@ static void statement_to_firm(statement_t *statement)
        switch(statement->kind) {
        case STATEMENT_INVALID:
                panic("invalid statement found");
+               return;
+       case STATEMENT_EMPTY:
+               /* nothing */
+               return;
        case STATEMENT_COMPOUND:
                compound_statement_to_firm(&statement->compound);
                return;
@@ -4458,6 +4462,9 @@ static int count_decls_in_stmts(const statement_t *stmt)
        int count = 0;
        for (; stmt != NULL; stmt = stmt->base.next) {
                switch (stmt->kind) {
+                       case STATEMENT_EMPTY:
+                               break;
+
                        case STATEMENT_DECLARATION: {
                                const declaration_statement_t *const decl_stmt = &stmt->declaration;
                                count += count_local_declarations(decl_stmt->declarations_begin,
diff --git a/ast_t.h b/ast_t.h
index 59ebc2a..4d32e54 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -478,6 +478,7 @@ struct declaration_t {
 
 typedef enum {
        STATEMENT_INVALID,
+       STATEMENT_EMPTY,
        STATEMENT_COMPOUND,
        STATEMENT_RETURN,
        STATEMENT_DECLARATION,
@@ -501,6 +502,14 @@ struct statement_base_t {
        source_position_t  source_position;
 };
 
+struct invalid_statement_t {
+       statement_base_t  base;
+};
+
+struct empty_statement_t {
+       statement_base_t  base;
+};
+
 struct return_statement_t {
        statement_base_t  base;
        expression_t     *value;
@@ -628,6 +637,19 @@ void *_allocate_ast(size_t size)
        return obstack_alloc(&ast_obstack, size);
 }
 
+static inline
+bool is_invalid_expression(expression_t *expression)
+{
+       return expression->base.kind == EXPR_INVALID;
+}
+
+static inline
+bool is_invalid_statement(statement_t *statement)
+{
+       return statement->base.kind == STATEMENT_INVALID;
+}
+
+
 #define allocate_ast(size)                 _allocate_ast(size)
 
 #endif
diff --git a/main.c b/main.c
index c2e0bf0..624592f 100644 (file)
--- a/main.c
+++ b/main.c
@@ -362,6 +362,7 @@ int main(int argc, char **argv)
        const char     *dumpfunction = NULL;
        compile_mode_t  mode         = CompileAssembleLink;
        int             opt_level    = 1;
+       int             result = EXIT_SUCCESS;
 
        obstack_init(&cppflags_obst);
        obstack_init(&ldflags_obst);
@@ -686,29 +687,35 @@ int main(int argc, char **argv)
 
        FILE *preprocessed_in = preprocess(in, input);
        translation_unit_t *const unit = do_parsing(preprocessed_in, input);
-       int result = pclose(preprocessed_in);
-       if(result != 0) {
-               return result;
+       int res = pclose(preprocessed_in);
+       if(res != 0) {
+               return res;
        }
-       if(unit == NULL) {
+
+       if(error_count > 0) {
                /* parsing failed because of errors */
                fprintf(stderr, "%u error(s), %u warning(s)\n", error_count, warning_count);
-               return EXIT_FAILURE;
-       }
-       if (warning_count > 0) {
+               result = EXIT_FAILURE;
+       } else if(warning_count > 0) {
                fprintf(stderr, "%u warning(s)\n", warning_count);
        }
 
        if(mode == BenchmarkParser) {
-               return 0;
+               return result;
        }
 
+       /* prints the AST even if errors occurred */
        if(mode == PrintAst) {
                type_set_output(out);
                ast_set_output(out);
                print_ast(unit);
-               return 0;
+               return result;
        }
+
+       /* cannot handle other modes with errors */
+       if(result != EXIT_SUCCESS)
+               return result;
+
        if(mode == PrintFluffy) {
                type_set_output(out);
                ast_set_output(out);
index 6de13dd..ab73613 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -210,6 +210,8 @@ static declaration_t *allocate_declaration_zero(void)
 static size_t get_statement_struct_size(statement_kind_t kind)
 {
        static const size_t sizes[] = {
+               [STATEMENT_INVALID]     = sizeof(invalid_statement_t),
+               [STATEMENT_EMPTY]       = sizeof(empty_statement_t),
                [STATEMENT_COMPOUND]    = sizeof(compound_statement_t),
                [STATEMENT_RETURN]      = sizeof(return_statement_t),
                [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
@@ -244,6 +246,26 @@ static statement_t *allocate_statement_zero(statement_kind_t kind)
        return res;
 }
 
+/**
+ * Creates a new invalid statement.
+ */
+static statement_t *create_invalid_statement(void)
+{
+       statement_t *statement          = allocate_statement_zero(STATEMENT_INVALID);
+       statement->base.source_position = token.source_position;
+       return statement;
+}
+
+/**
+ * Allocate a new empty statement.
+ */
+static statement_t *create_empty_statement(void)
+{
+       statement_t *statement          = allocate_statement_zero(STATEMENT_EMPTY);
+       statement->base.source_position = token.source_position;
+       return statement;
+}
+
 /**
  * Returns the size of an expression node.
  *
@@ -513,6 +535,10 @@ static void eat_block(void) {
                next_token();
 }
 
+/**
+ * eat all token until a ';' is reached
+ * or a stop token is found.
+ */
 static void eat_statement(void) {
        eat_until_matching_token(';');
        if(token.type == ';')
@@ -6100,7 +6126,7 @@ end_of_asm:
        expect(';');
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6146,7 +6172,7 @@ static statement_t *parse_case_statement(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6198,7 +6224,7 @@ static statement_t *parse_default_statement(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6255,13 +6281,20 @@ static statement_t *parse_label_statement(void)
 
        if(token.type == '}') {
                /* TODO only warn? */
-               errorf(HERE, "label at end of compound statement");
+               if(false) {
+                       warningf(HERE, "label at end of compound statement");
+                       statement->label.statement = create_empty_statement();
+               } else {
+                       errorf(HERE, "label at end of compound statement");
+                       statement->label.statement = create_invalid_statement();
+               }
                return statement;
        } else {
                if (token.type == ';') {
                        /* eat an empty statement here, to avoid the warning about an empty
                         * after a label.  label:; is commonly used to have a label before
                         * a }. */
+                       statement->label.statement = create_empty_statement();
                        next_token();
                } else {
                        statement->label.statement = parse_statement();
@@ -6306,7 +6339,7 @@ static statement_t *parse_if(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6344,7 +6377,7 @@ static statement_t *parse_switch(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 static statement_t *parse_loop_body(statement_t *const loop)
@@ -6378,7 +6411,7 @@ static statement_t *parse_while(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6406,7 +6439,7 @@ static statement_t *parse_do(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6470,7 +6503,7 @@ end_error:
        set_scope(last_scope);
        environment_pop_to(top);
 
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6507,7 +6540,7 @@ static statement_t *parse_goto(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6530,7 +6563,7 @@ static statement_t *parse_continue(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6553,7 +6586,7 @@ static statement_t *parse_break(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6670,7 +6703,7 @@ static statement_t *parse_return(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6714,7 +6747,7 @@ static statement_t *parse_expression_statement(void)
 
        return statement;
 end_error:
-       return NULL;
+       return create_invalid_statement();
 }
 
 /**
@@ -6780,11 +6813,11 @@ static statement_t *parse_statement(void)
                break;
 
        case ';':
-               if (warning.empty_statement) {
+               if(warning.empty_statement) {
                        warningf(HERE, "statement is empty");
                }
+               statement = create_empty_statement();
                next_token();
-               statement = NULL;
                break;
 
        case T_IDENTIFIER:
@@ -6820,8 +6853,8 @@ static statement_t *parse_statement(void)
        }
        rem_anchor_token(';');
 
-       assert(statement == NULL
-                       || statement->base.source_position.input_name != NULL);
+       assert(statement != NULL
+                       && statement->base.source_position.input_name != NULL);
 
        return statement;
 }
@@ -6846,7 +6879,7 @@ static statement_t *parse_compound_statement(void)
 
        while(token.type != '}' && token.type != T_EOF) {
                statement_t *sub_statement = parse_statement();
-               if(sub_statement == NULL) {
+               if(is_invalid_statement(sub_statement)) {
                        /* an error occurred. if we are at an anchor, return */
                        if(at_anchor())
                                goto end_error;
@@ -6993,9 +7026,6 @@ translation_unit_t *parse(void)
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);
 
-       if(error_count > 0)
-               return NULL;
-
        return unit;
 }
 
diff --git a/parsetest/empty.c b/parsetest/empty.c
new file mode 100644 (file)
index 0000000..a8c9023
--- /dev/null
@@ -0,0 +1,4 @@
+int main() {
+       ;
+       return 0;
+}