- 2009 patch
[cparser] / walk_statements.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <config.h>
21
22 #include "adt/error.h"
23 #include "ast_t.h"
24 #include "entity_t.h"
25 #include "walk_statements.h"
26
27
28 static void walk_expression(expression_t const *const expr,
29                             statement_callback const callback, void *const env)
30 {
31         switch (expr->base.kind) {
32         case EXPR_STATEMENT:
33                 walk_statements(expr->statement.statement, callback, env);
34                 return;
35
36         EXPR_BINARY_CASES
37                 walk_expression(expr->binary.left,  callback, env);
38                 walk_expression(expr->binary.right, callback, env);
39                 return;
40
41         EXPR_UNARY_CASES_OPTIONAL
42                 if (expr->unary.value == NULL)
43                         return;
44                 /* FALLTHROUGH */
45         EXPR_UNARY_CASES_MANDATORY
46                 walk_expression(expr->unary.value, callback, env);
47                 return;
48
49         case EXPR_CALL:
50                 for (call_argument_t *arg = expr->call.arguments; arg != NULL;
51                      arg = arg->next) {
52                         walk_expression(arg->expression, callback, env);
53                 }
54                 return;
55
56         case EXPR_UNKNOWN:
57                 panic("unexpected expr kind");
58
59         case EXPR_COMPOUND_LITERAL:
60                 /* TODO... */
61                 break;
62
63         case EXPR_CONDITIONAL:
64                 walk_expression(expr->conditional.condition,        callback, env);
65                 /* may be NULL because of gnu extension */
66                 if (expr->conditional.true_expression != NULL)
67                         walk_expression(expr->conditional.true_expression,  callback, env);
68                 walk_expression(expr->conditional.false_expression, callback, env);
69                 return;
70
71         case EXPR_BUILTIN_CONSTANT_P:
72                 walk_expression(expr->builtin_constant.value, callback, env);
73                 return;
74
75         case EXPR_SELECT:
76                 walk_expression(expr->select.compound, callback, env);
77                 return;
78
79         case EXPR_ARRAY_ACCESS:
80                 walk_expression(expr->array_access.array_ref, callback, env);
81                 walk_expression(expr->array_access.index,     callback, env);
82                 return;
83
84         case EXPR_CLASSIFY_TYPE:
85                 walk_expression(expr->classify_type.type_expression, callback, env);
86                 return;
87
88         case EXPR_SIZEOF:
89         case EXPR_ALIGNOF: {
90                 expression_t *tp_expression = expr->typeprop.tp_expression;
91                 if (tp_expression != NULL) {
92                         walk_expression(tp_expression, callback, env);
93                 }
94                 return;
95         }
96
97         case EXPR_VA_START:
98                 walk_expression(expr->va_starte.ap, callback, env);
99                 return;
100
101         case EXPR_VA_ARG:
102                 walk_expression(expr->va_arge.ap, callback, env);
103                 return;
104
105         case EXPR_VA_COPY:
106                 walk_expression(expr->va_copye.src, callback, env);
107                 walk_expression(expr->va_copye.dst, callback, env);
108                 return;
109
110         case EXPR_INVALID:
111         case EXPR_OFFSETOF:
112         case EXPR_REFERENCE:
113         case EXPR_REFERENCE_ENUM_VALUE:
114         case EXPR_CONST:
115         case EXPR_CHARACTER_CONSTANT:
116         case EXPR_WIDE_CHARACTER_CONSTANT:
117         case EXPR_STRING_LITERAL:
118         case EXPR_WIDE_STRING_LITERAL:
119         case EXPR_FUNCNAME:
120         case EXPR_LABEL_ADDRESS:
121         case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
122                 break;
123         }
124
125         /* TODO FIXME: implement all the missing expressions here */
126 }
127
128 static void walk_initializer(const initializer_t  *initializer,
129                              statement_callback    callback,
130                                                          void                 *env)
131 {
132         switch(initializer->kind) {
133         case INITIALIZER_VALUE:
134                 walk_expression(initializer->value.value, callback, env);
135                 return;
136         default:
137                 /* FIXME: should walk initializer hierarchies... */
138                 break;
139         }
140 }
141
142 static void walk_declarations(const entity_t*            entity,
143                               const entity_t*      const last,
144                               statement_callback   const callback,
145                               void                *const env)
146 {
147         entity_t const *const end = last != NULL ? last->base.next : NULL;
148         for (; entity != end; entity = entity->base.next) {
149                 /* we only look at variables */
150                 if (entity->kind != ENTITY_VARIABLE)
151                         continue;
152
153                 const variable_t    *variable    = &entity->variable;
154                 const initializer_t *initializer = variable->initializer;
155                 if (initializer != NULL) {
156                         walk_initializer(initializer, callback, env);
157                 }
158         }
159 }
160
161
162 void walk_statements(statement_t *const stmt, statement_callback const callback, void *const env)
163 {
164         callback(stmt, env);
165
166         switch (stmt->kind) {
167                 case STATEMENT_COMPOUND:
168                         for (statement_t *s = stmt->compound.statements; s != NULL; s = s->base.next) {
169                                 walk_statements(s, callback, env);
170                         }
171                         return;
172
173                 case STATEMENT_FOR:
174                         walk_declarations(stmt->fors.scope.entities, NULL, callback, env);
175                         if (stmt->fors.initialisation != NULL)
176                                 walk_expression(stmt->fors.initialisation, callback, env);
177                         if (stmt->fors.condition != NULL)
178                                 walk_expression(stmt->fors.condition, callback, env);
179                         if (stmt->fors.step != NULL)
180                                 walk_expression(stmt->fors.step, callback, env);
181                         walk_statements(stmt->fors.body,           callback, env);
182                         return;
183
184                 case STATEMENT_IF:
185                         walk_expression(stmt->ifs.condition,      callback, env);
186                         walk_statements(stmt->ifs.true_statement, callback, env);
187                         if (stmt->ifs.false_statement != NULL)
188                                 walk_statements(stmt->ifs.false_statement, callback, env);
189                         return;
190
191                 case STATEMENT_SWITCH:
192                         walk_expression(stmt->switchs.expression, callback, env);
193                         walk_statements(stmt->switchs.body,       callback, env);
194                         return;
195
196                 case STATEMENT_LABEL:
197                         walk_statements(stmt->label.statement, callback, env);
198                         return;
199
200                 case STATEMENT_CASE_LABEL:
201                         walk_statements(stmt->case_label.statement, callback, env);
202                         return;
203
204                 case STATEMENT_WHILE:
205                         walk_expression(stmt->whiles.condition, callback, env);
206                         walk_statements(stmt->whiles.body,      callback, env);
207                         return;
208
209                 case STATEMENT_DO_WHILE:
210                         walk_statements(stmt->do_while.body,      callback, env);
211                         walk_expression(stmt->do_while.condition, callback, env);
212                         return;
213
214                 case STATEMENT_EXPRESSION:
215                         walk_expression(stmt->expression.expression, callback, env);
216                         return;
217
218                 case STATEMENT_RETURN:
219                         if (stmt->returns.value != NULL)
220                                 walk_expression(stmt->returns.value, callback, env);
221                         return;
222
223                 case STATEMENT_DECLARATION:
224                         walk_declarations(stmt->declaration.declarations_begin,
225                                         stmt->declaration.declarations_end, callback, env);
226                         return;
227
228                 case STATEMENT_MS_TRY:
229                         walk_statements(stmt->ms_try.try_statement,   callback, env);
230                         walk_statements(stmt->ms_try.final_statement, callback, env);
231                         return;
232
233                 case STATEMENT_INVALID:
234                 case STATEMENT_EMPTY:
235                 case STATEMENT_CONTINUE:
236                 case STATEMENT_BREAK:
237                 case STATEMENT_GOTO:
238                 case STATEMENT_ASM:
239                 case STATEMENT_LEAVE:
240                         return;
241         }
242
243         panic("unhandled statement");
244 }