Implement a statement walker.
authorChristoph Mallon <christoph.mallon@gmx.de>
Tue, 21 Oct 2008 06:07:12 +0000 (06:07 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Tue, 21 Oct 2008 06:07:12 +0000 (06:07 +0000)
[r23056]

Makefile
ast2firm.c
parser.c
walk_statements.c [new file with mode: 0644]
walk_statements.h [new file with mode: 0644]

index 6bac107..f7be9fb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,7 @@ SOURCES := \
        lexer.c \
        main.c \
        parser.c \
+       walk_statements.c \
        symbol_table.c \
        token.c \
        type.c \
index 72a56d4..bd59f51 100644 (file)
@@ -39,6 +39,7 @@
 #include "diagnostic.h"
 #include "lang_features.h"
 #include "types.h"
+#include "walk_statements.h"
 #include "warning.h"
 #include "entitymap_t.h"
 #include "driver/firm_opt.h"
@@ -94,7 +95,6 @@ typedef enum declaration_kind_t {
 
 static ir_type *get_ir_type(type_t *type);
 static ir_type *get_ir_type_incomplete(type_t *type);
-static int count_decls_in_stmts(const statement_t *stmt);
 
 static void enqueue_inner_function(declaration_t *declaration) {
        if (inner_functions == NULL) {
@@ -5059,8 +5059,6 @@ static void statement_to_firm(statement_t *statement)
        panic("Statement not implemented\n");
 }
 
-static int count_decls_in_expression(const expression_t *expression);
-
 static int count_local_declarations(const declaration_t *      decl,
                                     const declaration_t *const end)
 {
@@ -5072,218 +5070,29 @@ static int count_local_declarations(const declaration_t *      decl,
 
                if (!decl->address_taken && is_type_scalar(type))
                        ++count;
-               const initializer_t *initializer = decl->init.initializer;
-               /* FIXME: should walk initializer hierarchies... */
-               if (initializer != NULL && initializer->kind == INITIALIZER_VALUE) {
-                       count += count_decls_in_expression(initializer->value.value);
-               }
        }
        return count;
 }
 
-static int count_decls_in_expression(const expression_t *expression) {
-       int count = 0;
-
-       if (expression == NULL)
-               return 0;
-
-       switch((expression_kind_t) expression->base.kind) {
-       case EXPR_STATEMENT:
-               return count_decls_in_stmts(expression->statement.statement);
-       EXPR_BINARY_CASES {
-               int count_left  = count_decls_in_expression(expression->binary.left);
-               int count_right = count_decls_in_expression(expression->binary.right);
-               return count_left + count_right;
-       }
-       EXPR_UNARY_CASES
-               return count_decls_in_expression(expression->unary.value);
-       case EXPR_CALL: {
-               call_argument_t *argument = expression->call.arguments;
-               for( ; argument != NULL; argument = argument->next) {
-                       count += count_decls_in_expression(argument->expression);
-               }
-               return count;
-       }
-
-       case EXPR_UNKNOWN:
-       case EXPR_INVALID:
-               panic("unexpected expression kind");
-
-       case EXPR_COMPOUND_LITERAL:
-               /* TODO... */
-               break;
-
-       case EXPR_CONDITIONAL:
-               count += count_decls_in_expression(expression->conditional.condition);
-               count += count_decls_in_expression(expression->conditional.true_expression);
-               count += count_decls_in_expression(expression->conditional.false_expression);
-               return count;
-
-       case EXPR_BUILTIN_PREFETCH:
-               count += count_decls_in_expression(expression->builtin_prefetch.adr);
-               count += count_decls_in_expression(expression->builtin_prefetch.rw);
-               count += count_decls_in_expression(expression->builtin_prefetch.locality);
-               return count;
-
-       case EXPR_BUILTIN_CONSTANT_P:
-               count += count_decls_in_expression(expression->builtin_constant.value);
-               return count;
-
-       case EXPR_SELECT:
-               count += count_decls_in_expression(expression->select.compound);
-               return count;
-
-       case EXPR_ARRAY_ACCESS:
-               count += count_decls_in_expression(expression->array_access.array_ref);
-               count += count_decls_in_expression(expression->array_access.index);
-               return count;
-
-       case EXPR_CLASSIFY_TYPE:
-               count += count_decls_in_expression(expression->classify_type.type_expression);
-               return count;
-
-       case EXPR_SIZEOF:
-       case EXPR_ALIGNOF: {
-               expression_t *tp_expression = expression->typeprop.tp_expression;
-               if (tp_expression != NULL) {
-                       count += count_decls_in_expression(tp_expression);
-               }
-               return count;
-       }
-
-       case EXPR_OFFSETOF:
-       case EXPR_REFERENCE:
-       case EXPR_CONST:
-       case EXPR_CHARACTER_CONSTANT:
-       case EXPR_WIDE_CHARACTER_CONSTANT:
-       case EXPR_STRING_LITERAL:
-       case EXPR_WIDE_STRING_LITERAL:
-       case EXPR_FUNCNAME:
-       case EXPR_BUILTIN_SYMBOL:
-       case EXPR_VA_START:
-       case EXPR_VA_ARG:
-       case EXPR_LABEL_ADDRESS:
-               break;
-       }
-
-       /* TODO FIXME: finish/fix that firm patch that allows dynamic value numbers
-        * (or implement all the missing expressions here/implement a walker)
-        */
-
-       return 0;
-}
-
-static int count_decls_in_stmts(const statement_t *stmt)
+static void count_decls_in_stmt(statement_t *stmt, void *const env)
 {
-       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,
-                                                                 decl_stmt->declarations_end->next);
-                               break;
-                       }
-
-                       case STATEMENT_COMPOUND: {
-                               const compound_statement_t *const comp =
-                                       &stmt->compound;
-                               count += count_decls_in_stmts(comp->statements);
-                               break;
-                       }
-
-                       case STATEMENT_IF: {
-                               const if_statement_t *const if_stmt = &stmt->ifs;
-                               count += count_decls_in_expression(if_stmt->condition);
-                               count += count_decls_in_stmts(if_stmt->true_statement);
-                               count += count_decls_in_stmts(if_stmt->false_statement);
-                               break;
-                       }
-
-                       case STATEMENT_SWITCH: {
-                               const switch_statement_t *const switch_stmt = &stmt->switchs;
-                               count += count_decls_in_expression(switch_stmt->expression);
-                               count += count_decls_in_stmts(switch_stmt->body);
-                               break;
-                       }
-
-                       case STATEMENT_LABEL: {
-                               const label_statement_t *const label_stmt = &stmt->label;
-                               if (label_stmt->statement != NULL) {
-                                       count += count_decls_in_stmts(label_stmt->statement);
-                               }
-                               break;
-                       }
-
-                       case STATEMENT_WHILE: {
-                               const while_statement_t *const while_stmt = &stmt->whiles;
-                               count += count_decls_in_expression(while_stmt->condition);
-                               count += count_decls_in_stmts(while_stmt->body);
-                               break;
-                       }
-
-                       case STATEMENT_DO_WHILE: {
-                               const do_while_statement_t *const do_while_stmt = &stmt->do_while;
-                               count += count_decls_in_expression(do_while_stmt->condition);
-                               count += count_decls_in_stmts(do_while_stmt->body);
-                               break;
-                       }
+       int *const count = env;
 
-                       case STATEMENT_FOR: {
-                               const for_statement_t *const for_stmt = &stmt->fors;
-                               count += count_local_declarations(for_stmt->scope.declarations, NULL);
-                               count += count_decls_in_expression(for_stmt->initialisation);
-                               count += count_decls_in_expression(for_stmt->condition);
-                               count += count_decls_in_expression(for_stmt->step);
-                               count += count_decls_in_stmts(for_stmt->body);
-                               break;
-                       }
-
-                       case STATEMENT_CASE_LABEL: {
-                               const case_label_statement_t *label = &stmt->case_label;
-                               count += count_decls_in_expression(label->expression);
-                               if (label->statement != NULL) {
-                                       count += count_decls_in_stmts(label->statement);
-                               }
-                               break;
-                       }
-
-                       case STATEMENT_ASM:
-                       case STATEMENT_BREAK:
-                       case STATEMENT_CONTINUE:
-                               break;
-
-                       case STATEMENT_EXPRESSION: {
-                               const expression_statement_t *expr_stmt = &stmt->expression;
-                               count += count_decls_in_expression(expr_stmt->expression);
-                               break;
-                       }
-
-                       case STATEMENT_GOTO:
-                       case STATEMENT_LEAVE:
-                       case STATEMENT_INVALID:
-                               break;
+       switch (stmt->kind) {
+               case STATEMENT_DECLARATION: {
+                       const declaration_statement_t *const decl_stmt = &stmt->declaration;
+                       *count += count_local_declarations(decl_stmt->declarations_begin,
+                                                                                                                                                                decl_stmt->declarations_end->next);
+                       break;
+               }
 
-                       case STATEMENT_RETURN: {
-                               const return_statement_t *ret_stmt = &stmt->returns;
-                               count += count_decls_in_expression(ret_stmt->value);
-                               break;
-                       }
+               case STATEMENT_FOR:
+                       *count += count_local_declarations(stmt->fors.scope.declarations, NULL);
+                       break;
 
-                       case STATEMENT_MS_TRY: {
-                               const ms_try_statement_t *const try_stmt = &stmt->ms_try;
-                               count += count_decls_in_stmts(try_stmt->try_statement);
-                               if (try_stmt->except_expression != NULL)
-                                       count += count_decls_in_expression(try_stmt->except_expression);
-                               count += count_decls_in_stmts(try_stmt->final_statement);
-                               break;
-                       }
-               }
+               default:
+                       break;
        }
-       return count;
 }
 
 static int get_function_n_local_vars(declaration_t *declaration)
@@ -5294,8 +5103,7 @@ static int get_function_n_local_vars(declaration_t *declaration)
        count += count_local_declarations(declaration->scope.declarations, NULL);
 
        /* count local variables declared in body */
-       count += count_decls_in_stmts(declaration->init.statement);
-
+       walk_statements(declaration->init.statement, count_decls_in_stmt, &count);
        return count;
 }
 
index ba33164..7f2bf55 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -34,6 +34,7 @@
 #include "type_hash.h"
 #include "ast_t.h"
 #include "lang_features.h"
+#include "walk_statements.h"
 #include "warning.h"
 #include "adt/bitfiddle.h"
 #include "adt/error.h"
@@ -5136,77 +5137,24 @@ static void warn_unused_decl(declaration_t *decl, declaration_t *end, char const
        }
 }
 
-static void check_unused_variables(statement_t const *const stmt)
+static void check_unused_variables(statement_t *const stmt, void *const env)
 {
-       // TODO statement expressions
-       switch (stmt->kind) {
-               case STATEMENT_COMPOUND:
-                       for (statement_t const *s = stmt->compound.statements; s != NULL; s = s->base.next) {
-                               check_unused_variables(s);
-                       }
-                       return;
-
-               case STATEMENT_FOR: {
-                       warn_unused_decl(stmt->fors.scope.declarations, NULL, "variable");
-                       check_unused_variables(stmt->fors.body);
-                       return;
-               }
-
-               case STATEMENT_IF:
-                       check_unused_variables(stmt->ifs.true_statement);
-                       if (stmt->ifs.false_statement != NULL)
-                               check_unused_variables(stmt->ifs.false_statement);
-                       return;
-
-               case STATEMENT_SWITCH:
-                       check_unused_variables(stmt->switchs.body);
-                       return;
-
-               case STATEMENT_LABEL:
-                       check_unused_variables(stmt->label.statement);
-                       return;
-
-               case STATEMENT_CASE_LABEL:
-                       check_unused_variables(stmt->case_label.statement);
-                       return;
-
-               case STATEMENT_WHILE:
-                       check_unused_variables(stmt->whiles.body);
-                       return;
-
-               case STATEMENT_DO_WHILE:
-                       check_unused_variables(stmt->do_while.body);
-                       return;
+       (void)env;
 
+       switch (stmt->kind) {
                case STATEMENT_DECLARATION: {
                        declaration_statement_t const *const decls = &stmt->declaration;
                        warn_unused_decl(decls->declarations_begin, decls->declarations_end, "variable");
                        return;
                }
 
-               case STATEMENT_EXPRESSION:
-                       // TODO statement expressions
-                       return;
-
-               case STATEMENT_INVALID:
-               case STATEMENT_EMPTY:
-               case STATEMENT_RETURN:
-               case STATEMENT_CONTINUE:
-               case STATEMENT_BREAK:
-               case STATEMENT_GOTO:
-               case STATEMENT_ASM:
-               case STATEMENT_LEAVE:
+               case STATEMENT_FOR:
+                       warn_unused_decl(stmt->fors.scope.declarations, NULL, "variable");
                        return;
 
-               case STATEMENT_MS_TRY: {
-                       ms_try_statement_t const *const ms_try = &stmt->ms_try;
-                       check_unused_variables(ms_try->try_statement);
-                       check_unused_variables(ms_try->final_statement);
+               default:
                        return;
-               }
        }
-
-       panic("unhandled statement");
 }
 
 /**
@@ -5223,7 +5171,7 @@ static void check_declarations(void)
                }
        }
        if (warning.unused_variable) {
-               check_unused_variables(current_function->init.statement);
+               walk_statements(current_function->init.statement, check_unused_variables, NULL);
        }
 }
 
@@ -5586,58 +5534,12 @@ continue_for:;
        check_reachable(next);
 }
 
-static void check_unreachable(statement_t const* const stmt)
+static void check_unreachable(statement_t* const stmt, void *const env)
 {
-       if (!stmt->base.reachable            &&
-           stmt->kind != STATEMENT_DO_WHILE &&
-           stmt->kind != STATEMENT_FOR      &&
-           (stmt->kind != STATEMENT_COMPOUND || stmt->compound.statements == NULL)) {
-               warningf(&stmt->base.source_position, "statement is unreachable");
-       }
+       (void)env;
 
        switch (stmt->kind) {
-               case STATEMENT_INVALID:
-               case STATEMENT_EMPTY:
-               case STATEMENT_RETURN:
-               case STATEMENT_DECLARATION:
-               case STATEMENT_EXPRESSION:
-               case STATEMENT_CONTINUE:
-               case STATEMENT_BREAK:
-               case STATEMENT_GOTO:
-               case STATEMENT_ASM:
-               case STATEMENT_LEAVE:
-                       return;
-
-               case STATEMENT_COMPOUND:
-                       for (statement_t const *s = stmt->compound.statements; s != NULL; s = s->base.next) {
-                               check_unreachable(s);
-                       }
-                       return;
-
-               case STATEMENT_IF:
-                       check_unreachable(stmt->ifs.true_statement);
-                       if (stmt->ifs.false_statement != NULL)
-                               check_unreachable(stmt->ifs.false_statement);
-                       return;
-
-               case STATEMENT_SWITCH:
-                       check_unreachable(stmt->switchs.body);
-                       return;
-
-               case STATEMENT_LABEL:
-                       check_unreachable(stmt->label.statement);
-                       return;
-
-               case STATEMENT_CASE_LABEL:
-                       check_unreachable(stmt->case_label.statement);
-                       return;
-
-               case STATEMENT_WHILE:
-                       check_unreachable(stmt->whiles.body);
-                       return;
-
                case STATEMENT_DO_WHILE:
-                       check_unreachable(stmt->do_while.body);
                        if (!stmt->base.reachable) {
                                expression_t const *const cond = stmt->do_while.condition;
                                if (determine_truth(cond) >= 0) {
@@ -5669,20 +5571,19 @@ static void check_unreachable(statement_t const* const stmt)
                                                 "step of for-statement is unreachable");
                                }
                        }
-
-                       check_unreachable(fors->body);
                        return;
                }
 
-               case STATEMENT_MS_TRY: {
-                       ms_try_statement_t const *const ms_try = &stmt->ms_try;
-                       check_unreachable(ms_try->try_statement);
-                       check_unreachable(ms_try->final_statement);
+               case STATEMENT_COMPOUND:
+                       if (stmt->compound.statements != NULL)
+                               return;
+                       /* FALLTHROUGH*/
+
+               default:
+                       if (!stmt->base.reachable)
+                               warningf(&stmt->base.source_position, "statement is unreachable");
                        return;
-               }
        }
-
-       panic("unhandled statement");
 }
 
 static void parse_external_declaration(void)
@@ -5821,7 +5722,7 @@ static void parse_external_declaration(void)
                        noreturn_candidate = true;
                        check_reachable(body);
                        if (warning.unreachable_code)
-                               check_unreachable(body);
+                               walk_statements(body, check_unreachable, NULL);
                        if (warning.missing_noreturn &&
                            noreturn_candidate       &&
                            !(declaration->modifiers & DM_NORETURN)) {
diff --git a/walk_statements.c b/walk_statements.c
new file mode 100644 (file)
index 0000000..385b93c
--- /dev/null
@@ -0,0 +1,194 @@
+#include "adt/error.h"
+#include "ast_t.h"
+#include "walk_statements.h"
+
+
+static void walk_expression(expression_t const *const expr, statement_callback const callback, void *const env)
+{
+       switch (expr->base.kind) {
+               case EXPR_STATEMENT:
+                       walk_statements(expr->statement.statement, callback, env);
+                       return;
+
+               EXPR_BINARY_CASES
+                       walk_expression(expr->binary.left,  callback, env);
+                       walk_expression(expr->binary.right, callback, env);
+                       return;
+
+               EXPR_UNARY_CASES
+                       walk_expression(expr->unary.value, callback, env);
+                       return;
+
+               case EXPR_CALL:
+                       for (call_argument_t *arg = expr->call.arguments; arg != NULL; arg = arg->next) {
+                               walk_expression(arg->expression, callback, env);
+                       }
+                       return;
+
+               case EXPR_UNKNOWN:
+               case EXPR_INVALID:
+                       panic("unexpected expr kind");
+
+               case EXPR_COMPOUND_LITERAL:
+                       /* TODO... */
+                       break;
+
+               case EXPR_CONDITIONAL:
+                       walk_expression(expr->conditional.condition,        callback, env);
+                       walk_expression(expr->conditional.true_expression,  callback, env);
+                       walk_expression(expr->conditional.false_expression, callback, env);
+                       return;
+
+               case EXPR_BUILTIN_PREFETCH:
+                       walk_expression(expr->builtin_prefetch.adr,      callback, env);
+                       walk_expression(expr->builtin_prefetch.rw,       callback, env);
+                       walk_expression(expr->builtin_prefetch.locality, callback, env);
+                       return;
+
+               case EXPR_BUILTIN_CONSTANT_P:
+                       walk_expression(expr->builtin_constant.value, callback, env);
+                       return;
+
+               case EXPR_SELECT:
+                       walk_expression(expr->select.compound, callback, env);
+                       return;
+
+               case EXPR_ARRAY_ACCESS:
+                       walk_expression(expr->array_access.array_ref, callback, env);
+                       walk_expression(expr->array_access.index,     callback, env);
+                       return;
+
+               case EXPR_CLASSIFY_TYPE:
+                       walk_expression(expr->classify_type.type_expression, callback, env);
+                       return;
+
+               case EXPR_SIZEOF:
+               case EXPR_ALIGNOF: {
+                       expression_t *tp_expression = expr->typeprop.tp_expression;
+                       if (tp_expression != NULL) {
+                               walk_expression(tp_expression, callback, env);
+                       }
+                       return;
+               }
+
+               case EXPR_OFFSETOF:
+               case EXPR_REFERENCE:
+               case EXPR_CONST:
+               case EXPR_CHARACTER_CONSTANT:
+               case EXPR_WIDE_CHARACTER_CONSTANT:
+               case EXPR_STRING_LITERAL:
+               case EXPR_WIDE_STRING_LITERAL:
+               case EXPR_FUNCNAME:
+               case EXPR_BUILTIN_SYMBOL:
+               case EXPR_VA_START:
+               case EXPR_VA_ARG:
+               case EXPR_LABEL_ADDRESS:
+                       break;
+       }
+
+       /* TODO FIXME: implement all the missing expressions here */
+}
+
+
+static void walk_declarations(const declaration_t *      decl,
+                              const declaration_t *const end,
+                              statement_callback   const callback,
+                              void                *const env)
+{
+       for (; decl != end; decl = decl->next) {
+               if (decl->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               const initializer_t *initializer = decl->init.initializer;
+               /* FIXME: should walk initializer hierarchies... */
+               if (initializer != NULL && initializer->kind == INITIALIZER_VALUE) {
+                       walk_expression(initializer->value.value, callback, env);
+               }
+       }
+}
+
+
+void walk_statements(statement_t *const stmt, statement_callback const callback, void *const env)
+{
+       callback(stmt, env);
+
+       switch (stmt->kind) {
+               case STATEMENT_COMPOUND:
+                       for (statement_t *s = stmt->compound.statements; s != NULL; s = s->base.next) {
+                               walk_statements(s, callback, env);
+                       }
+                       return;
+
+               case STATEMENT_FOR:
+                       walk_declarations(stmt->fors.scope.declarations, NULL, callback, env);
+                       if (stmt->fors.initialisation != NULL)
+                               walk_expression(stmt->fors.initialisation, callback, env);
+                       if (stmt->fors.condition != NULL)
+                               walk_expression(stmt->fors.condition, callback, env);
+                       if (stmt->fors.step != NULL)
+                               walk_expression(stmt->fors.step, callback, env);
+                       walk_statements(stmt->fors.body,           callback, env);
+                       return;
+
+               case STATEMENT_IF:
+                       walk_expression(stmt->ifs.condition,      callback, env);
+                       walk_statements(stmt->ifs.true_statement, callback, env);
+                       if (stmt->ifs.false_statement != NULL)
+                               walk_statements(stmt->ifs.false_statement, callback, env);
+                       return;
+
+               case STATEMENT_SWITCH:
+                       walk_expression(stmt->switchs.expression, callback, env);
+                       walk_statements(stmt->switchs.body,       callback, env);
+                       return;
+
+               case STATEMENT_LABEL:
+                       walk_statements(stmt->label.statement, callback, env);
+                       return;
+
+               case STATEMENT_CASE_LABEL:
+                       walk_statements(stmt->case_label.statement, callback, env);
+                       return;
+
+               case STATEMENT_WHILE:
+                       walk_expression(stmt->whiles.condition, callback, env);
+                       walk_statements(stmt->whiles.body,      callback, env);
+                       return;
+
+               case STATEMENT_DO_WHILE:
+                       walk_statements(stmt->do_while.body,      callback, env);
+                       walk_expression(stmt->do_while.condition, callback, env);
+                       return;
+
+               case STATEMENT_EXPRESSION:
+                       walk_expression(stmt->expression.expression, callback, env);
+                       return;
+
+               case STATEMENT_RETURN:
+                       if (stmt->returns.value != NULL)
+                               walk_expression(stmt->returns.value, callback, env);
+                       return;
+
+               case STATEMENT_DECLARATION:
+                       walk_declarations(stmt->declaration.declarations_begin,
+                                         stmt->declaration.declarations_end->next,
+                                         callback, env);
+                       return;
+
+               case STATEMENT_MS_TRY:
+                       walk_statements(stmt->ms_try.try_statement,   callback, env);
+                       walk_statements(stmt->ms_try.final_statement, callback, env);
+                       return;
+
+               case STATEMENT_INVALID:
+               case STATEMENT_EMPTY:
+               case STATEMENT_CONTINUE:
+               case STATEMENT_BREAK:
+               case STATEMENT_GOTO:
+               case STATEMENT_ASM:
+               case STATEMENT_LEAVE:
+                       return;
+       }
+
+       panic("unhandled statement");
+}
diff --git a/walk_statements.h b/walk_statements.h
new file mode 100644 (file)
index 0000000..9f7f3e2
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef WALK_STATEMENTS_H
+#define WALK_STATEMENTS_H
+
+#include "ast.h"
+
+typedef void (*statement_callback)(statement_t*, void *env);
+
+void walk_statements(statement_t*, statement_callback, void *env);
+
+#endif