lexer.c \
main.c \
parser.c \
+ walk_statements.c \
symbol_table.c \
token.c \
type.c \
#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"
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) {
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)
{
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)
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;
}
#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"
}
}
-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");
}
/**
}
}
if (warning.unused_variable) {
- check_unused_variables(current_function->init.statement);
+ walk_statements(current_function->init.statement, check_unused_variables, NULL);
}
}
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) {
"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)
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)) {
--- /dev/null
+#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");
+}
--- /dev/null
+#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