diff options
author | Søren Sandmann <sandmann@redhat.com> | 2007-09-06 02:43:36 -0400 |
---|---|---|
committer | Søren Sandmann <sandmann@redhat.com> | 2007-09-06 02:43:36 -0400 |
commit | a78f3c2495a5703dbf2b1021f7c3d55017f12e81 (patch) | |
tree | 94b1ed0140a810fe05d6c13fa3d96224198d107a /switch.c | |
parent | 559dd1585a01b74dfdd41dfb2c35eaf52b88a8aa (diff) |
Add switch.c ; Checking constant expressions
Diffstat (limited to 'switch.c')
-rw-r--r-- | switch.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/switch.c b/switch.c new file mode 100644 index 0000000..0bb4638 --- /dev/null +++ b/switch.c @@ -0,0 +1,167 @@ +#include "ast.h" +#include <stdlib.h> + +/* Check switch statements */ + +static int +compare_cases (const void *a, + const void *b) +{ + const ast_case_t *case_a = *(ast_case_t **)a; + const ast_case_t *case_b = *(ast_case_t **)b; + + if (case_a->common.type == AST_DEFAULT_CASE && + case_b->common.type == AST_DEFAULT_CASE) + { + return 0; + } + + if (case_a->common.type == AST_DEFAULT_CASE) + return 1; + + if (case_b->common.type == AST_DEFAULT_CASE) + return -1; + + g_assert (case_a->common.type == AST_EXPRESSION_CASE); + g_assert (case_b->common.type == AST_EXPRESSION_CASE); + + return case_a->int_.value - case_b->int_.value; +} + +static gboolean +constant_expression (ast_t *ast) +{ + GList *list; + + if (ast->common.type != AST_EXPRESSION) + return FALSE; + + switch (ast->expression.common.type) + { + case AST_INT_LITERAL_EXPRESSION: + case AST_BOOL_LITERAL_EXPRESSION: + case AST_NULL_EXPRESSION: + return TRUE; + + case AST_IDENTIFIER_EXPRESSION: + /* FIXME: should check if it's a constant */ + return FALSE; + + case AST_LAMBDA_EXPRESSION: + case AST_CALL_EXPRESSION: + case AST_STATEMENT_EXPRESSION: + case AST_NEW_EXPRESSION: + case AST_DOT_EXPRESSION: + case AST_THIS_EXPRESSION: + case AST_VOID_EXPRESSION: + return FALSE; + + case AST_UNARY_EXPRESSION: + case AST_BINARY_EXPRESSION: + case AST_TERNARY_EXPRESSION: + for (list = ast->common.children->head; list; list = list->next) + { + if (!constant_expression (list->data)) + return FALSE; + } + + return TRUE; + } + + return FALSE; +} + +static gboolean +check_constant_case_expressions (ast_t *ast) +{ + GList *list; + + for (list = ast->common.children->head; list; list = list->next) + { + if (!check_constant_case_expressions (list->data)) + return FALSE; + } + + if (ast_is (ast, AST_CASE, AST_EXPRESSION_CASE)) + { + /* FIXME: check that we are dealing with a constant expression, + * and store the value of that expression in the case clause + */ +#if 0 + if (!constant_expression (ast->case_.expression, &value)) + { + g_print ("Expression in case clause must be constant\n"); + + return FALSE; + } +#endif + + } + + return TRUE; +} + +static gboolean +check_unique_cases (ast_t *ast) +{ + GList *list; + + for (list = ast->common.children->head; list; list = list->next) + { + if (!check_unique_cases (list->data)) + return FALSE; + } + + if (ast_is (ast, AST_STATEMENT, AST_SWITCH_STATEMENT)) + { + int n_cases = array_length ((gpointer *)ast->statement.switch_.cases); + ast_case_t **cases = ast->statement.switch_.cases; + int i; + + if (n_cases <= 1) + { + /* Only one case; no need to check uniqueness */ + return TRUE; + } + + /* Sort cases according to value, with default(s) last */ + qsort (cases, n_cases, sizeof (ast_case_t *), compare_cases); + + for (i = 0; cases[i + 1] != NULL; ++i) + { + ast_case_t *case_a = cases[i]; + ast_case_t *case_b = cases[i + 1]; + + if (case_a->common.type == AST_DEFAULT_CASE && + case_b->common.type == AST_DEFAULT_CASE) + { + g_print ("More than default case in switch statement\n"); + return FALSE; + } + + if (case_a->common.type == AST_EXPRESSION_CASE && + case_b->common.type == AST_EXPRESSION_CASE && + case_a->int_.value == case_b->int_.value) + { + g_print ("More than one case with value %d\n", + case_a->int_.value); + return FALSE; + } + } + } + + return TRUE; +} + + +gboolean +switch_check (ast_program_t *program) +{ + if (!check_constant_case_expressions ((ast_t *)program)) + return FALSE; + + if (!check_unique_cases ((ast_t *)program)) + return FALSE; + + return TRUE; +} |