improve ast-walk infrastructure
authorMatthias Braun <matze@braunis.de>
Thu, 11 Aug 2011 21:02:49 +0000 (23:02 +0200)
committerMatthias Braun <matze@braunis.de>
Thu, 11 Aug 2011 23:32:45 +0000 (01:32 +0200)
ast2firm.c
parser.c
walk.c [new file with mode: 0644]
walk.h [new file with mode: 0644]
walk_statements.c [deleted file]
walk_statements.h [deleted file]

index c114ae1..2c7e1bb 100644 (file)
@@ -44,7 +44,7 @@
 #include "types.h"
 #include "type_hash.h"
 #include "mangle.h"
-#include "walk_statements.h"
+#include "walk.h"
 #include "warning.h"
 #include "printer.h"
 #include "entitymap_t.h"
index 102334d..6803e98 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -36,7 +36,7 @@
 #include "entity_t.h"
 #include "attribute_t.h"
 #include "lang_features.h"
-#include "walk_statements.h"
+#include "walk.h"
 #include "warning.h"
 #include "printer.h"
 #include "adt/bitfiddle.h"
diff --git a/walk.c b/walk.c
new file mode 100644 (file)
index 0000000..e213f2b
--- /dev/null
+++ b/walk.c
@@ -0,0 +1,419 @@
+/*
+ * This file is part of cparser.
+ * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <config.h>
+
+#include "adt/error.h"
+#include "ast_t.h"
+#include "entity_t.h"
+#include "type_t.h"
+#include "walk.h"
+#include <libfirm/adt/pset.h>
+
+typedef struct walk_env_t {
+       pset *visited_types;
+       declaration_callback declaration_func;
+       statement_callback   statement_func;
+       expression_callback  expression_func;
+       void *env;
+} walk_env_t;
+
+static void walk_expression(expression_t *expr, const walk_env_t *const env);
+static void walk_statement(statement_t *stmt, const walk_env_t *env);
+static void walk_entity(entity_t *entity, const walk_env_t *env);
+static void walk_designator(const designator_t *, const walk_env_t *);
+static void walk_initializer(const initializer_t  *, const walk_env_t *);
+static void walk_scope(const scope_t *const scope, const walk_env_t *const env);
+
+static void walk_type(type_t *const type, const walk_env_t *const env)
+{
+       if (pset_find_ptr(env->visited_types, type) != NULL)
+               return;
+       pset_insert_ptr(env->visited_types, type);
+
+       switch (type->kind) {
+       case TYPE_ATOMIC:
+       case TYPE_COMPLEX:
+       case TYPE_IMAGINARY:
+       case TYPE_REFERENCE:
+       case TYPE_ERROR:
+               return;
+       case TYPE_POINTER:
+               walk_type(type->pointer.points_to, env);
+               return;
+       case TYPE_ARRAY:
+               walk_type(type->array.element_type, env);
+               if (type->array.size_expression != NULL)
+                       walk_expression(type->array.size_expression, env);
+               return;
+       case TYPE_FUNCTION:
+               for (function_parameter_t *parameter = type->function.parameters;
+                    parameter != NULL; parameter = parameter->next) {
+                       walk_type(parameter->type, env);
+               }
+               walk_type(type->function.return_type, env);
+               return;
+       case TYPE_TYPEOF:
+               walk_expression(type->typeoft.expression, env);
+               return;
+       case TYPE_TYPEDEF:
+               walk_entity((entity_t*)type->typedeft.typedefe, env);
+               return;
+       case TYPE_COMPOUND_STRUCT:
+       case TYPE_COMPOUND_UNION:
+               walk_entity((entity_t*)type->compound.compound, env);
+               return;
+       case TYPE_ENUM:
+               walk_entity((entity_t*)type->enumt.enume, env);
+               return;
+       case TYPE_INVALID:
+               break;
+       }
+       panic("invalid type found");
+}
+
+static void walk_expression(expression_t *const expr,
+                            const walk_env_t *const env)
+{
+       env->expression_func(expr, env->env);
+
+       switch (expr->base.kind) {
+       case EXPR_STATEMENT:
+               walk_statement(expr->statement.statement, env);
+               return;
+
+       EXPR_BINARY_CASES
+               walk_expression(expr->binary.left, env);
+               walk_expression(expr->binary.right, env);
+               return;
+
+       EXPR_UNARY_CASES_OPTIONAL
+               if (expr->unary.value == NULL)
+                       return;
+               /* FALLTHROUGH */
+       EXPR_UNARY_CASES_MANDATORY
+               walk_expression(expr->unary.value, env);
+               return;
+
+       case EXPR_CALL:
+               for (call_argument_t *arg = expr->call.arguments; arg != NULL;
+                    arg = arg->next) {
+                       walk_expression(arg->expression, env);
+               }
+               return;
+
+       case EXPR_COMPOUND_LITERAL:
+               walk_initializer(expr->compound_literal.initializer, env);
+               return;
+
+       case EXPR_CONDITIONAL:
+               walk_expression(expr->conditional.condition, env);
+               /* may be NULL because of gnu extension */
+               if (expr->conditional.true_expression != NULL)
+                       walk_expression(expr->conditional.true_expression, env);
+               walk_expression(expr->conditional.false_expression, env);
+               return;
+
+       case EXPR_BUILTIN_CONSTANT_P:
+               walk_expression(expr->builtin_constant.value, env);
+               return;
+
+       case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
+               walk_type(expr->builtin_types_compatible.left, env);
+               walk_type(expr->builtin_types_compatible.right, env);
+               return;
+
+       case EXPR_SELECT:
+               walk_expression(expr->select.compound, env);
+               return;
+
+       case EXPR_ARRAY_ACCESS:
+               walk_expression(expr->array_access.array_ref, env);
+               walk_expression(expr->array_access.index, env);
+               return;
+
+       case EXPR_CLASSIFY_TYPE:
+               walk_expression(expr->classify_type.type_expression, env);
+               return;
+
+       case EXPR_SIZEOF:
+       case EXPR_ALIGNOF: {
+               expression_t *tp_expression = expr->typeprop.tp_expression;
+               if (tp_expression != NULL) {
+                       walk_expression(tp_expression, env);
+               }
+               return;
+       }
+
+       case EXPR_VA_START:
+               walk_expression(expr->va_starte.ap, env);
+               return;
+
+       case EXPR_VA_ARG:
+               walk_expression(expr->va_arge.ap, env);
+               return;
+
+       case EXPR_VA_COPY:
+               walk_expression(expr->va_copye.src, env);
+               walk_expression(expr->va_copye.dst, env);
+               return;
+
+       case EXPR_OFFSETOF:
+               walk_designator(expr->offsetofe.designator, env);
+               return;
+
+       EXPR_LITERAL_CASES
+       case EXPR_REFERENCE:
+       case EXPR_REFERENCE_ENUM_VALUE:
+       case EXPR_STRING_LITERAL:
+       case EXPR_WIDE_STRING_LITERAL:
+       case EXPR_FUNCNAME:
+       case EXPR_LABEL_ADDRESS:
+               return;
+       case EXPR_INVALID:
+               break;
+       }
+       panic("invalid expr kind");
+}
+
+static void walk_designator(const designator_t *designator,
+                            const walk_env_t *const env)
+{
+       for ( ; designator != NULL; designator = designator->next) {
+               walk_expression(designator->array_index, env);
+       }
+}
+
+static void walk_initializer(const initializer_t  *initializer,
+                             const walk_env_t *const env)
+{
+       switch(initializer->kind) {
+       case INITIALIZER_VALUE:
+               walk_expression(initializer->value.value, env);
+               return;
+       case INITIALIZER_LIST: {
+               for (size_t i = 0; i < initializer->list.len; ++i) {
+                       walk_initializer(initializer->list.initializers[i], env);
+               }
+               return;
+       }
+       case INITIALIZER_DESIGNATOR:
+               walk_designator(initializer->designator.designator, env);
+               return;
+       case INITIALIZER_STRING:
+       case INITIALIZER_WIDE_STRING:
+               return;
+       }
+}
+
+static void walk_entity(entity_t *entity, const walk_env_t *const env)
+{
+       env->declaration_func(entity, env->env);
+
+       switch (entity->kind) {
+       case ENTITY_VARIABLE: {
+               const variable_t    *variable    = &entity->variable;
+               const initializer_t *initializer = variable->initializer;
+               walk_type(entity->declaration.type, env);
+               if (initializer != NULL) {
+                       walk_initializer(initializer, env);
+               }
+               return;
+       }
+       case ENTITY_ENUM_VALUE:
+               walk_expression(entity->enum_value.value, env);
+               return;
+       case ENTITY_TYPEDEF:
+               walk_type(entity->typedefe.type, env);
+               return;
+       case ENTITY_FUNCTION:
+               walk_type(entity->declaration.type, env);
+               if (entity->function.statement != NULL)
+                       walk_statement(entity->function.statement, env);
+               return;
+       case ENTITY_COMPOUND_MEMBER:
+       case ENTITY_PARAMETER:
+               walk_type(entity->declaration.type, env);
+               return;
+       case ENTITY_CLASS:
+       case ENTITY_STRUCT:
+       case ENTITY_UNION:
+               walk_scope(&entity->compound.members, env);
+               return;
+       case ENTITY_NAMESPACE:
+               walk_scope(&entity->namespacee.members, env);
+               return;
+       case ENTITY_ENUM:
+               for (entity = entity->base.next;
+                    entity != NULL && entity->kind == ENTITY_ENUM_VALUE;
+                        entity = entity->base.next) {
+                       walk_entity(entity, env);
+               }
+               return;
+       case ENTITY_LABEL:
+       case ENTITY_LOCAL_LABEL:
+               return;
+       case ENTITY_INVALID:
+               break;
+       }
+       panic("invalid entity found");
+}
+
+static void walk_declarations(entity_t*            entity,
+                              entity_t*      const last,
+                                                         const walk_env_t    *const env)
+{
+       entity_t const *const end = last != NULL ? last->base.next : NULL;
+       for (; entity != end; entity = entity->base.next) {
+               walk_entity(entity, env);
+       }
+}
+
+static void walk_scope(const scope_t *const scope, const walk_env_t *const env)
+{
+       walk_declarations(scope->entities, NULL, env);
+}
+
+static void walk_statement(statement_t *const stmt, const walk_env_t *const env)
+{
+       env->statement_func(stmt, env->env);
+
+       switch (stmt->kind) {
+       case STATEMENT_COMPOUND:
+               for (statement_t *s = stmt->compound.statements; s != NULL;
+                    s = s->base.next) {
+                       walk_statement(s, env);
+               }
+               return;
+
+       case STATEMENT_FOR:
+               walk_declarations(stmt->fors.scope.entities, NULL, env);
+               if (stmt->fors.initialisation != NULL)
+                       walk_expression(stmt->fors.initialisation, env);
+               if (stmt->fors.condition != NULL)
+                       walk_expression(stmt->fors.condition, env);
+               if (stmt->fors.step != NULL)
+                       walk_expression(stmt->fors.step, env);
+               walk_statement(stmt->fors.body, env);
+               return;
+
+       case STATEMENT_IF:
+               walk_expression(stmt->ifs.condition, env);
+               walk_statement(stmt->ifs.true_statement, env);
+               if (stmt->ifs.false_statement != NULL)
+                       walk_statement(stmt->ifs.false_statement, env);
+               return;
+
+       case STATEMENT_SWITCH:
+               walk_expression(stmt->switchs.expression, env);
+               walk_statement(stmt->switchs.body, env);
+               return;
+
+       case STATEMENT_LABEL:
+               walk_statement(stmt->label.statement, env);
+               return;
+
+       case STATEMENT_CASE_LABEL:
+               walk_statement(stmt->case_label.statement, env);
+               return;
+
+       case STATEMENT_WHILE:
+               walk_expression(stmt->whiles.condition, env);
+               walk_statement(stmt->whiles.body, env);
+               return;
+
+       case STATEMENT_DO_WHILE:
+               walk_statement(stmt->do_while.body, env);
+               walk_expression(stmt->do_while.condition, env);
+               return;
+
+       case STATEMENT_EXPRESSION:
+               walk_expression(stmt->expression.expression, env);
+               return;
+
+       case STATEMENT_RETURN:
+               if (stmt->returns.value != NULL)
+                       walk_expression(stmt->returns.value, env);
+               return;
+
+       case STATEMENT_DECLARATION:
+               walk_declarations(stmt->declaration.declarations_begin,
+                               stmt->declaration.declarations_end, env);
+               return;
+
+       case STATEMENT_MS_TRY:
+               walk_statement(stmt->ms_try.try_statement, env);
+               walk_statement(stmt->ms_try.final_statement, 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");
+}
+
+static void null_declaration_func(entity_t *entity, void *env)
+{
+       (void) entity;
+       (void) env;
+}
+
+static void null_statement_func(statement_t *statement, void *env)
+{
+       (void) statement;
+       (void) env;
+}
+
+static void null_expression_func(expression_t *expression, void *env)
+{
+       (void) expression;
+       (void) env;
+}
+
+void walk_translation_unit(translation_unit_t *unit,
+                           declaration_callback declaration_func,
+                                                  statement_callback statement_func,
+                                                  expression_callback expression_func, void *env)
+{
+       walk_env_t walk_env = {
+               pset_new_ptr_default(),
+               declaration_func != NULL ? declaration_func : null_declaration_func,
+               statement_func != NULL ? statement_func : null_statement_func,
+               expression_func != NULL ? expression_func : null_expression_func,
+               env
+       };
+       walk_scope(&unit->scope, &walk_env);
+       del_pset(walk_env.visited_types);
+}
+
+void walk_statements(statement_t *statement, statement_callback func, void *env)
+{
+       walk_env_t walk_env
+               = { pset_new_ptr_default(),
+                   null_declaration_func, func, null_expression_func, env };
+       walk_statement(statement, &walk_env);
+       del_pset(walk_env.visited_types);
+}
diff --git a/walk.h b/walk.h
new file mode 100644 (file)
index 0000000..bf64617
--- /dev/null
+++ b/walk.h
@@ -0,0 +1,18 @@
+#ifndef WALK_STATEMENTS_H
+#define WALK_STATEMENTS_H
+
+#include "ast.h"
+
+typedef void (*statement_callback)(statement_t*, void *env);
+typedef void (*expression_callback)(expression_t*, void *env);
+typedef void (*declaration_callback)(entity_t*, void *env);
+
+void walk_translation_unit(translation_unit_t *unit,
+                           declaration_callback,
+                                                  statement_callback,
+                                                  expression_callback,
+                                                  void *env);
+
+void walk_statements(statement_t*, statement_callback, void *env);
+
+#endif
diff --git a/walk_statements.c b/walk_statements.c
deleted file mode 100644 (file)
index fe61cf5..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * This file is part of cparser.
- * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-#include <config.h>
-
-#include "adt/error.h"
-#include "ast_t.h"
-#include "entity_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_OPTIONAL
-               if (expr->unary.value == NULL)
-                       return;
-               /* FALLTHROUGH */
-       EXPR_UNARY_CASES_MANDATORY
-               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_COMPOUND_LITERAL:
-               /* TODO... */
-               break;
-
-       case EXPR_CONDITIONAL:
-               walk_expression(expr->conditional.condition,        callback, env);
-               /* may be NULL because of gnu extension */
-               if (expr->conditional.true_expression != NULL)
-                       walk_expression(expr->conditional.true_expression,  callback, env);
-               walk_expression(expr->conditional.false_expression, 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_VA_START:
-               walk_expression(expr->va_starte.ap, callback, env);
-               return;
-
-       case EXPR_VA_ARG:
-               walk_expression(expr->va_arge.ap, callback, env);
-               return;
-
-       case EXPR_VA_COPY:
-               walk_expression(expr->va_copye.src, callback, env);
-               walk_expression(expr->va_copye.dst, callback, env);
-               return;
-
-       EXPR_LITERAL_CASES
-       case EXPR_INVALID:
-       case EXPR_OFFSETOF:
-       case EXPR_REFERENCE:
-       case EXPR_REFERENCE_ENUM_VALUE:
-       case EXPR_STRING_LITERAL:
-       case EXPR_WIDE_STRING_LITERAL:
-       case EXPR_FUNCNAME:
-       case EXPR_LABEL_ADDRESS:
-       case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
-               break;
-       }
-
-       /* TODO FIXME: implement all the missing expressions here */
-}
-
-static void walk_initializer(const initializer_t  *initializer,
-                             statement_callback    callback,
-                                                        void                 *env)
-{
-       switch(initializer->kind) {
-       case INITIALIZER_VALUE:
-               walk_expression(initializer->value.value, callback, env);
-               return;
-       default:
-               /* FIXME: should walk initializer hierarchies... */
-               break;
-       }
-}
-
-static void walk_declarations(const entity_t*            entity,
-                              const entity_t*      const last,
-                              statement_callback   const callback,
-                              void                *const env)
-{
-       entity_t const *const end = last != NULL ? last->base.next : NULL;
-       for (; entity != end; entity = entity->base.next) {
-               /* we only look at variables */
-               if (entity->kind != ENTITY_VARIABLE)
-                       continue;
-
-               const variable_t    *variable    = &entity->variable;
-               const initializer_t *initializer = variable->initializer;
-               if (initializer != NULL) {
-                       walk_initializer(initializer, 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.entities, 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, 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
deleted file mode 100644 (file)
index 9f7f3e2..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#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