diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | check.c | 1 | ||||
| -rw-r--r-- | evaluate.c | 238 | ||||
| -rw-r--r-- | expand.c | 609 | ||||
| -rw-r--r-- | expression.h | 2 | ||||
| -rw-r--r-- | symbol.c | 19 | ||||
| -rw-r--r-- | symbol.h | 8 | ||||
| -rw-r--r-- | test-parsing.c | 3 |
8 files changed, 649 insertions, 233 deletions
@@ -8,7 +8,7 @@ PROGRAMS=test-lexing test-parsing obfuscate check LIB_H= token.h parse.h lib.h symbol.h scope.h expression.h target.h LIB_OBJS= parse.o tokenize.o pre-process.o symbol.o lib.o scope.o \ - expression.o show-parse.o evaluate.o inline.o + expression.o show-parse.o evaluate.o expand.o inline.o LIB_FILE= sparse.a LIBS=$(LIB_FILE) @@ -94,6 +94,7 @@ static void clean_up_symbol(struct symbol *sym, void *_parent, int flags) { check_duplicates(sym); evaluate_symbol(sym); + expand_symbol(sym); } int main(int argc, char **argv) @@ -34,9 +34,6 @@ static struct symbol *evaluate_symbol_expression(struct expression *expr) if (!sym) { if (preprocessing) { - warn(expr->pos, "undefined preprocessor identifier '%s'", show_ident(expr->symbol_name)); - expr->type = EXPR_VALUE; - expr->value = 0; expr->ctype = &int_ctype; return &int_ctype; } @@ -57,16 +54,6 @@ static struct symbol *evaluate_symbol_expression(struct expression *expr) /* The type of a symbol is the symbol itself! */ expr->ctype = sym; - /* Const symbol with a constant initializer? */ - if (sym->ctype.modifiers & MOD_CONST) { - struct expression *value = sym->initializer; - if (value && value->type == EXPR_VALUE) { - expr->type = EXPR_VALUE; - expr->value = value->value; - return sym; - } - } - /* enum's can be turned into plain values */ if (sym->type != SYM_ENUM) { struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL); @@ -137,54 +124,12 @@ static struct symbol *bigger_int_type(struct symbol *left, struct symbol *right) return ctype_integer(mod); } -static struct symbol * cast_value(struct expression *expr, struct symbol *newtype, - struct expression *old, struct symbol *oldtype) -{ - int old_size = oldtype->bit_size; - int new_size = newtype->bit_size; - long long value, mask, ormask, andmask; - int is_signed; - - // FIXME! We don't handle FP casts of constant values yet - if (newtype->ctype.base_type == &fp_type) - return NULL; - if (oldtype->ctype.base_type == &fp_type) - return NULL; - - // For pointers and integers, we can just move the value around - expr->type = EXPR_VALUE; - if (old_size == new_size) { - expr->value = old->value; - return newtype; - } - - // expand it to the full "long long" value - is_signed = !(oldtype->ctype.modifiers & MOD_UNSIGNED); - mask = 1ULL << (old_size-1); - value = old->value; - if (!(value & mask)) - is_signed = 0; - andmask = mask | (mask-1); - ormask = ~andmask; - if (!is_signed) - ormask = 0; - value = (value & andmask) | ormask; - - // Truncate it to the new size - mask = 1ULL << (new_size-1); - mask = mask | (mask-1); - expr->value = value & mask; - return newtype; -} - static struct expression * cast_to(struct expression *old, struct symbol *type) { struct expression *expr = alloc_expression(old->pos, EXPR_CAST); expr->ctype = type; expr->cast_type = type; expr->cast_expression = old; - if (old->type == EXPR_VALUE) - cast_value(expr, type, old, old->ctype); return expr; } @@ -235,69 +180,11 @@ static struct symbol * compatible_integer_binop(struct expression *expr, struct return NULL; } -static int check_shift_count(struct expression *expr, struct symbol *ctype, unsigned int count) -{ - if (count >= ctype->bit_size) { - warn(expr->pos, "shift too big for type"); - count &= ctype->bit_size-1; - } - return count; -} - -/* - * CAREFUL! We need to get the size and sign of the - * result right! - */ -static void simplify_int_binop(struct expression *expr, struct symbol *ctype) -{ - struct expression *left = expr->left, *right = expr->right; - unsigned long long v, l, r, mask; - signed long long s, sl, sr; - int is_signed, shift; - - if (left->type != EXPR_VALUE || right->type != EXPR_VALUE) - return; - l = left->value; r = right->value; - is_signed = !(ctype->ctype.modifiers & MOD_UNSIGNED); - mask = 1ULL << (ctype->bit_size-1); - sl = l; sr = r; - if (is_signed && (sl & mask)) - sl |= ~(mask-1); - if (is_signed && (sr & mask)) - sr |= ~(mask-1); - - switch (expr->op) { - case '+': v = l + r; s = v; break; - case '-': v = l - r; s = v; break; - case '&': v = l & r; s = v; break; - case '|': v = l | r; s = v; break; - case '^': v = l ^ r; s = v; break; - case '*': v = l * r; s = sl * sr; break; - case '/': if (!r) return; v = l / r; s = sl / sr; break; - case '%': if (!r) return; v = l % r; s = sl % sr; break; - case SPECIAL_LEFTSHIFT: shift = check_shift_count(expr, ctype, r); v = l << shift; s = v; break; - case SPECIAL_RIGHTSHIFT:shift = check_shift_count(expr, ctype, r); v = l >> shift; s = sl >> shift; break; - case '<': v = l < r; s = sl < sr; break; - case '>': v = l > r; s = sl > sr; break; - case SPECIAL_LTE: v = l <= r; s = sl <= sr; break; - case SPECIAL_GTE: v = l >= r; s = sl >= sr; break; - case SPECIAL_EQUAL: v = l == r; s = v; break; - case SPECIAL_NOTEQUAL: v = l != r; s = v; break; - default: return; - } - if (is_signed) - v = s; - mask = mask | (mask-1); - expr->value = v & mask; - expr->type = EXPR_VALUE; -} - static struct symbol *evaluate_int_binop(struct expression *expr) { struct symbol *ctype = compatible_integer_binop(expr, &expr->left, &expr->right); if (ctype) { expr->ctype = ctype; - simplify_int_binop(expr, ctype); return ctype; } return bad_expr_type(expr); @@ -382,12 +269,10 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct expressio mul->ctype = size_t_ctype; mul->left = i; mul->right = val; - simplify_int_binop(mul, size_t_ctype); /* Leave 'add->op' as 'expr->op' - either '+' or '-' */ add->left = ptr; add->right = mul; - simplify_int_binop(add, ctype); } expr->ctype = ctype; @@ -410,7 +295,7 @@ static struct symbol *evaluate_add(struct expression *expr) } #define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG | MOD_LONGLONG) -#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE | MOD_SIGNED | MOD_UNSIGNED) +#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE | MOD_SIGNED | MOD_UNSIGNED | MOD_ASSIGNED) static const char * type_difference(struct symbol *target, struct symbol *source, unsigned long target_mod_ignore, unsigned long source_mod_ignore) @@ -591,44 +476,11 @@ static struct symbol *evaluate_sub(struct expression *expr) static struct symbol *evaluate_logical(struct expression *expr) { - struct expression *left = expr->left; - struct expression *right; - - if (!evaluate_expression(left)) + if (!evaluate_expression(expr->left)) return NULL; - - /* Do immediate short-circuiting ... */ - if (left->type == EXPR_VALUE) { - if (expr->op == SPECIAL_LOGICAL_AND) { - if (!left->value) { - expr->type = EXPR_VALUE; - expr->value = 0; - expr->ctype = &bool_ctype; - return &bool_ctype; - } - } else { - if (left->value) { - expr->type = EXPR_VALUE; - expr->value = 1; - expr->ctype = &bool_ctype; - return &bool_ctype; - } - } - } - - right = expr->right; - if (!evaluate_expression(right)) + if (!evaluate_expression(expr->right)) return NULL; expr->ctype = &bool_ctype; - if (left->type == EXPR_VALUE && right->type == EXPR_VALUE) { - /* - * We know the left value doesn't matter, since - * otherwise we would have short-circuited it.. - */ - expr->type = EXPR_VALUE; - expr->value = right->value; - } - return &bool_ctype; } @@ -682,7 +534,6 @@ static struct symbol *evaluate_compare(struct expression *expr) ctype = compatible_integer_binop(expr, &expr->left, &expr->right); if (ctype) { - simplify_int_binop(expr, ctype); expr->ctype = &bool_ctype; return &bool_ctype; } @@ -711,7 +562,7 @@ static int is_null_ptr(struct expression *expr) } /* - * FIXME!! This shoul ddo casts, array degeneration etc.. + * FIXME!! This should do casts, array degeneration etc.. */ static struct symbol *compatible_ptr_type(struct expression *left, struct expression *right) { @@ -767,12 +618,6 @@ static struct symbol * evaluate_conditional(struct expression *expr) } } - /* Simplify conditional expression.. */ - if (cond->type == EXPR_VALUE) { - if (!cond->value) - true = false; - *expr = *true; - } expr->ctype = ctype; return ctype; } @@ -886,6 +731,9 @@ static struct symbol *evaluate_assignment(struct expression *expr) if (!compatible_assignment_types(expr, ltype, &expr->right, rtype, "assignment")) return 0; + if (ltype->type == SYM_NODE) + ltype->ctype.modifiers |= MOD_ASSIGNED; + expr->ctype = ltype; return ltype; } @@ -960,27 +808,6 @@ static struct symbol *evaluate_dereference(struct expression *expr) return sym; } -static void simplify_preop(struct expression *expr) -{ - struct expression *op = expr->unop; - unsigned long long v, mask; - - if (op->type != EXPR_VALUE) - return; - v = op->value; - switch (expr->op) { - case '+': break; - case '-': v = -v; break; - case '!': v = !v; break; - case '~': v = ~v; break; - default: return; - } - mask = 1ULL << (expr->ctype->bit_size-1); - mask = mask | (mask-1); - expr->value = v & mask; - expr->type = EXPR_VALUE; -} - /* * Unary post-ops: x++ and x-- */ @@ -1029,7 +856,6 @@ static struct symbol *evaluate_preop(struct expression *expr) break; } expr->ctype = ctype; - simplify_preop(expr); return &bool_ctype; } @@ -1083,7 +909,6 @@ static struct expression *evaluate_offset(struct expression *expr, unsigned long add->right->ctype = &int_ctype; add->right->value = offset; - simplify_int_binop(add, &ptr_ctype); return add; } @@ -1384,10 +1209,6 @@ static struct symbol *evaluate_cast(struct expression *expr) } evaluate_expression(target); - - /* Simplify normal integer casts.. */ - if (target->type == EXPR_VALUE) - cast_value(expr, ctype, target, target->ctype); return ctype; } @@ -1404,8 +1225,8 @@ static int evaluate_symbol_call(struct expression *expr) if (fn->type != EXPR_PREOP) return 0; - if (ctype->evaluate) - return ctype->evaluate(expr); + if (ctype->op && ctype->op->evaluate) + return ctype->op->evaluate(expr); /* * FIXME!! We should really expand the inline functions. @@ -1444,6 +1265,10 @@ static struct symbol *evaluate_call(struct expression *expr) if (evaluate_symbol_call(expr)) return expr->ctype; } + if (sym->type == SYM_NODE) { + if (evaluate_symbol_call(expr)) + return expr->ctype; + } if (ctype->type != SYM_FN) { warn(expr->pos, "not a function"); return NULL; @@ -1654,20 +1479,6 @@ static void evaluate_if_statement(struct statement *stmt) if (!ctype) return; - /* Simplify constant conditionals without even evaluating the false side */ - if (expr->type == EXPR_VALUE) { - struct statement *simple; - simple = expr->value ? stmt->if_true : stmt->if_false; - - /* Nothing? */ - if (!simple) { - stmt->type = STMT_NONE; - return; - } - evaluate_statement(simple); - *stmt = *simple; - return; - } evaluate_statement(stmt->if_true); evaluate_statement(stmt->if_false); } @@ -1724,26 +1535,3 @@ struct symbol *evaluate_statement(struct statement *stmt) } return NULL; } - -long long get_expression_value(struct expression *expr) -{ - long long value, mask; - struct symbol *ctype; - - ctype = evaluate_expression(expr); - if (!ctype || expr->type != EXPR_VALUE) { - warn(expr->pos, "bad constant expression"); - return 0; - } - - value = expr->value; - mask = 1ULL << (ctype->bit_size-1); - - if (value & mask) { - while (ctype->type != SYM_BASETYPE) - ctype = ctype->ctype.base_type; - if (!(ctype->ctype.modifiers & MOD_UNSIGNED)) - value = value | mask | ~(mask-1); - } - return value; -} diff --git a/expand.c b/expand.c new file mode 100644 index 00000000..7842c026 --- /dev/null +++ b/expand.c @@ -0,0 +1,609 @@ +/* + * sparse/expand.c + * + * Copyright (C) 2003 Transmeta Corp. + * + * Licensed under the Open Software License version 1.1 + * + * expand constant expressions. + */ +#include <stdlib.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> + +#include "lib.h" +#include "parse.h" +#include "token.h" +#include "symbol.h" +#include "target.h" +#include "expression.h" + +static void expand_expression(struct expression *); +static void expand_statement(struct statement *); + +static void expand_symbol_expression(struct expression *expr) +{ + struct symbol *sym = expr->symbol; + + /* + * The preprocessor can cause unknown symbols to be generated + */ + if (!sym) { + warn(expr->pos, "undefined preprocessor identifier '%s'", show_ident(expr->symbol_name)); + expr->type = EXPR_VALUE; + expr->value = 0; + return; + } +} + +static void cast_value(struct expression *expr, struct symbol *newtype, + struct expression *old, struct symbol *oldtype) +{ + int old_size = oldtype->bit_size; + int new_size = newtype->bit_size; + long long value, mask, ormask, andmask; + int is_signed; + + // FIXME! We don't handle FP casts of constant values yet + if (newtype->ctype.base_type == &fp_type) + return; + if (oldtype->ctype.base_type == &fp_type) + return; + + // For pointers and integers, we can just move the value around + expr->type = EXPR_VALUE; + if (old_size == new_size) { + expr->value = old->value; + return; + } + + // expand it to the full "long long" value + is_signed = !(oldtype->ctype.modifiers & MOD_UNSIGNED); + mask = 1ULL << (old_size-1); + value = old->value; + if (!(value & mask)) + is_signed = 0; + andmask = mask | (mask-1); + ormask = ~andmask; + if (!is_signed) + ormask = 0; + value = (value & andmask) | ormask; + + // Truncate it to the new size + mask = 1ULL << (new_size-1); + mask = mask | (mask-1); + expr->value = value & mask; +} + +static int check_shift_count(struct expression *expr, struct symbol *ctype, unsigned int count) +{ + if (count >= ctype->bit_size) { + warn(expr->pos, "shift too big for type"); + count &= ctype->bit_size-1; + } + return count; +} + +/* + * CAREFUL! We need to get the size and sign of the + * result right! + */ +static void simplify_int_binop(struct expression *expr, struct symbol *ctype) +{ + struct expression *left = expr->left, *right = expr->right; + unsigned long long v, l, r, mask; + signed long long s, sl, sr; + int is_signed, shift; + + if (left->type != EXPR_VALUE || right->type != EXPR_VALUE) + return; + l = left->value; r = right->value; + is_signed = !(ctype->ctype.modifiers & MOD_UNSIGNED); + mask = 1ULL << (ctype->bit_size-1); + sl = l; sr = r; + if (is_signed && (sl & mask)) + sl |= ~(mask-1); + if (is_signed && (sr & mask)) + sr |= ~(mask-1); + + switch (expr->op) { + case '+': v = l + r; s = v; break; + case '-': v = l - r; s = v; break; + case '&': v = l & r; s = v; break; + case '|': v = l | r; s = v; break; + case '^': v = l ^ r; s = v; break; + case '*': v = l * r; s = sl * sr; break; + case '/': if (!r) return; v = l / r; s = sl / sr; break; + case '%': if (!r) return; v = l % r; s = sl % sr; break; + case SPECIAL_LEFTSHIFT: shift = check_shift_count(expr, ctype, r); v = l << shift; s = v; break; + case SPECIAL_RIGHTSHIFT:shift = check_shift_count(expr, ctype, r); v = l >> shift; s = sl >> shift; break; + case '<': v = l < r; s = sl < sr; break; + case '>': v = l > r; s = sl > sr; break; + case SPECIAL_LTE: v = l <= r; s = sl <= sr; break; + case SPECIAL_GTE: v = l >= r; s = sl >= sr; break; + case SPECIAL_EQUAL: v = l == r; s = v; break; + case SPECIAL_NOTEQUAL: v = l != r; s = v; break; + default: return; + } + if (is_signed) + v = s; + mask = mask | (mask-1); + expr->value = v & mask; + expr->type = EXPR_VALUE; +} + +static void expand_int_binop(struct expression *expr) +{ + simplify_int_binop(expr, expr->ctype); +} + +static void expand_logical(struct expression *expr) +{ + struct expression *left = expr->left; + struct expression *right; + + /* Do immediate short-circuiting ... */ + expand_expression(left); + if (left->type == EXPR_VALUE) { + if (expr->op == SPECIAL_LOGICAL_AND) { + if (!left->value) { + expr->type = EXPR_VALUE; + expr->value = 0; + return; + } + } else { + if (left->value) { + expr->type = EXPR_VALUE; + expr->value = 1; + return; + } + } + } + + right = expr->right; + expand_expression(right); + if (left->type == EXPR_VALUE && right->type == EXPR_VALUE) { + /* + * We know the left value doesn't matter, since + * otherwise we would have short-circuited it.. + */ + expr->type = EXPR_VALUE; + expr->value = right->value; + } +} + +static void expand_binop(struct expression *expr) +{ + expand_int_binop(expr); +} + +static void expand_comma(struct expression *expr) +{ + if (expr->left->type == EXPR_VALUE) + *expr = *expr->right; +} + +static void expand_compare(struct expression *expr) +{ + simplify_int_binop(expr, expr->ctype); +} + +static void expand_conditional(struct expression *expr) +{ + struct expression *cond = expr->conditional; + + if (cond->type == EXPR_VALUE) { + struct expression *true, *false; + + true = expr->cond_true ? : cond; + false = expr->cond_false; + + if (!cond->value) + true = false; + *expr = *true; + } +} + +static void expand_assignment(struct expression *expr) +{ +} + +static void expand_addressof(struct expression *expr) +{ +} + +static void expand_dereference(struct expression *expr) +{ + struct expression *unop = expr->unop; + if (unop->type == EXPR_SYMBOL) { + struct symbol *sym = unop->symbol; + + if (sym->ctype.modifiers & MOD_NODEREF) + warn(expr->pos, "dereference of '%s'", show_ident(sym->ident)); + + /* Const symbol with a constant initializer? */ + if (!(sym->ctype.modifiers & (MOD_ASSIGNED | MOD_ADDRESSABLE))) { + struct expression *value = sym->initializer; + if (value) { + if (value->type == EXPR_VALUE) { + expr->type = EXPR_VALUE; + expr->value = value->value; + } + } + } + } +} + +static void simplify_preop(struct expression *expr) +{ + struct expression *op = expr->unop; + unsigned long long v, mask; + + if (op->type != EXPR_VALUE) + return; + v = op->value; + switch (expr->op) { + case '+': break; + case '-': v = -v; break; + case '!': v = !v; break; + case '~': v = ~v; break; + default: return; + } + mask = 1ULL << (expr->ctype->bit_size-1); + mask = mask | (mask-1); + expr->value = v & mask; + expr->type = EXPR_VALUE; +} + +/* + * Unary post-ops: x++ and x-- + */ +static void expand_postop(struct expression *expr) +{ +} + +static void expand_preop(struct expression *expr) +{ + switch (expr->op) { + case '*': + expand_dereference(expr); + return; + + case '&': + expand_addressof(expr); + return; + + case SPECIAL_INCREMENT: + case SPECIAL_DECREMENT: + /* + * From a type evaluation standpoint the pre-ops are + * the same as the postops + */ + expand_postop(expr); + return; + + default: + break; + } + simplify_preop(expr); +} + +static void expand_arguments(struct expression_list *head) +{ + struct expression *expr; + + FOR_EACH_PTR (head, expr) { + expand_expression(expr); + } END_FOR_EACH_PTR; +} + +static void expand_cast(struct expression *expr) +{ + struct expression *target = expr->cast_expression; + + expand_expression(target); + + /* Simplify normal integer casts.. */ + if (target->type == EXPR_VALUE) + cast_value(expr, expr->ctype, target, target->ctype); +} + +/* + * expand a call expression with a symbol. This + * should expand inline functions, and expand + * builtins. + */ +static void expand_symbol_call(struct expression *expr) +{ + struct expression *fn = expr->fn; + struct symbol *ctype = fn->ctype; + + if (fn->type != EXPR_PREOP) + return; + + if (ctype->op && ctype->op->expand) { + ctype->op->expand(expr); + return; + } + + if (ctype->ctype.modifiers & MOD_INLINE) + inline_function(expr, ctype); +} + +static void expand_call(struct expression *expr) +{ + struct symbol *sym; + struct expression *fn = expr->fn; + + sym = fn->ctype; + expand_arguments(expr->args); + if (sym->type == SYM_NODE) + expand_symbol_call(expr); +} + +static void expand_expression_list(struct expression_list *list) +{ + struct expression *expr; + + FOR_EACH_PTR(list, expr) { + expand_expression(expr); + } END_FOR_EACH_PTR; +} + +static void expand_expression(struct expression *expr) +{ + if (!expr) + return; + if (!expr->ctype) + return; + + switch (expr->type) { + case EXPR_VALUE: + return; + case EXPR_STRING: + return; + case EXPR_SYMBOL: + expand_symbol_expression(expr); + return; + case EXPR_BINOP: + expand_expression(expr->left); + expand_expression(expr->right); + expand_binop(expr); + return; + + case EXPR_LOGICAL: + expand_logical(expr); + return; + + case EXPR_COMMA: + expand_expression(expr->left); + expand_expression(expr->right); + expand_comma(expr); + return; + + case EXPR_COMPARE: + expand_expression(expr->left); + expand_expression(expr->right); + expand_compare(expr); + return; + + case EXPR_ASSIGNMENT: + expand_expression(expr->left); + expand_expression(expr->right); + expand_assignment(expr); + return; + + case EXPR_PREOP: + expand_expression(expr->unop); + expand_preop(expr); + return; + + case EXPR_POSTOP: + expand_expression(expr->unop); + expand_postop(expr); + return; + + case EXPR_CAST: + expand_cast(expr); + return; + + case EXPR_CALL: + expand_call(expr); + return; + + case EXPR_DEREF: + return; + + case EXPR_BITFIELD: + expand_expression(expr->address); + return; + + case EXPR_CONDITIONAL: + expand_expression(expr->conditional); + expand_expression(expr->cond_false); + expand_expression(expr->cond_true); + expand_conditional(expr); + return; + + case EXPR_STATEMENT: + expand_statement(expr->statement); + return; + + case EXPR_LABEL: + return; + + case EXPR_INITIALIZER: + expand_expression_list(expr->expr_list); + return; + + case EXPR_IDENTIFIER: + return; + + case EXPR_INDEX: + return; + + case EXPR_POS: + expand_expression(expr->init_expr); + return; + + case EXPR_SIZEOF: + warn(expr->pos, "internal front-end error: sizeof in expansion?"); + return; + } + return; +} + + +static void expand_one_statement(struct statement *stmt, void *unused, int flags) +{ + expand_statement(stmt); +} + +void expand_symbol(struct symbol *sym) +{ + struct symbol *base_type; + + if (!sym) + return; + base_type = sym->ctype.base_type; + if (!base_type) + return; + + expand_expression(sym->initializer); + /* expand the body of the symbol */ + if (base_type->type == SYM_FN) { + if (base_type->stmt) + expand_statement(base_type->stmt); + } +} + +static void expand_one_symbol(struct symbol *sym, void *unused, int flags) +{ + expand_symbol(sym); +} + +static void expand_return_expression(struct statement *stmt) +{ + expand_expression(stmt->expression); +} + +static void expand_if_statement(struct statement *stmt) +{ + struct expression *expr = stmt->if_conditional; + + if (!expr || !expr->ctype) + return; + + expand_expression(expr); + + /* Simplify constant conditionals without even evaluating the false side */ + if (expr->type == EXPR_VALUE) { + struct statement *simple; + simple = expr->value ? stmt->if_true : stmt->if_false; + + /* Nothing? */ + if (!simple) { + stmt->type = STMT_NONE; + return; + } + expand_statement(simple); + *stmt = *simple; + return; + } + expand_statement(stmt->if_true); + expand_statement(stmt->if_false); +} + +static void expand_statement(struct statement *stmt) +{ + if (!stmt) + return; + + switch (stmt->type) { + case STMT_RETURN: + expand_return_expression(stmt); + return; + + case STMT_EXPRESSION: + expand_expression(stmt->expression); + return; + + case STMT_COMPOUND: { + symbol_iterate(stmt->syms, expand_one_symbol, NULL); + expand_symbol(stmt->ret); + statement_iterate(stmt->stmts, expand_one_statement, NULL); + return; + } + + case STMT_IF: + expand_if_statement(stmt); + return; + + case STMT_ITERATOR: + expand_expression(stmt->iterator_pre_condition); + expand_expression(stmt->iterator_post_condition); + expand_statement(stmt->iterator_pre_statement); + expand_statement(stmt->iterator_statement); + expand_statement(stmt->iterator_post_statement); + return; + + case STMT_SWITCH: + expand_expression(stmt->switch_expression); + expand_statement(stmt->switch_statement); + return; + + case STMT_CASE: + expand_expression(stmt->case_expression); + expand_expression(stmt->case_to); + expand_statement(stmt->case_statement); + return; + + case STMT_LABEL: + expand_statement(stmt->label_statement); + return; + + case STMT_GOTO: + expand_expression(stmt->goto_expression); + return; + + case STMT_NONE: + break; + case STMT_ASM: + /* FIXME! Do the asm parameter evaluation! */ + break; + } +} + +long long get_expression_value(struct expression *expr) +{ + long long value, mask; + struct symbol *ctype; + + ctype = evaluate_expression(expr); + if (!ctype) { + warn(expr->pos, "bad constant expression type"); + return 0; + } + expand_expression(expr); + if (expr->type != EXPR_VALUE) { + warn(expr->pos, "bad constant expression"); + return 0; + } + + value = expr->value; + mask = 1ULL << (ctype->bit_size-1); + + if (value & mask) { + while (ctype->type != SYM_BASETYPE) + ctype = ctype->ctype.base_type; + if (!(ctype->ctype.modifiers & MOD_UNSIGNED)) + value = value | mask | ~(mask-1); + } + return value; +} diff --git a/expression.h b/expression.h index 8a5ea3b5..a9245caf 100644 --- a/expression.h +++ b/expression.h @@ -125,6 +125,8 @@ extern struct symbol *evaluate_symbol(struct symbol *sym); extern struct symbol *evaluate_statement(struct statement *stmt); extern struct symbol *evaluate_expression(struct expression *); +extern void expand_symbol(struct symbol *); + static inline struct expression *alloc_expression(struct position pos, int type) { struct expression *expr = __alloc_expression(0); @@ -332,6 +332,12 @@ static struct symbol *create_symbol(int stream, const char *name, int type, int static int evaluate_constant_p(struct expression *expr) { + expr->ctype = &int_ctype; + return 1; +} + +static void expand_constant_p(struct expression *expr) +{ struct expression *arg; struct expression_list *arglist = expr->args; int value = 1; @@ -341,10 +347,8 @@ static int evaluate_constant_p(struct expression *expr) value = 0; } END_FOR_EACH_PTR; - expr->ctype = &int_ctype; expr->type = EXPR_VALUE; expr->value = value; - return 1; } /* @@ -358,7 +362,7 @@ struct sym_init { const char *name; struct symbol *base_type; unsigned int modifiers; - int (*evaluate)(struct expression *); + struct symbol_op *op; } symbol_init_table[] = { /* Storage class */ { "auto", NULL, MOD_AUTO }, @@ -420,11 +424,16 @@ struct sym_init { { NULL, NULL, 0 } }; +struct symbol_op constant_p_op = { + .evaluate = evaluate_constant_p, + .expand = expand_constant_p +}; + /* * Builtin functions */ struct sym_init eval_init_table[] = { - { "__builtin_constant_p", &int_type, MOD_TOPLEVEL, evaluate_constant_p }, + { "__builtin_constant_p", &int_type, MOD_TOPLEVEL, &constant_p_op }, { NULL, NULL, 0 } }; @@ -545,7 +554,7 @@ void init_symbols(void) sym = create_symbol(stream, ptr->name, SYM_NODE, NS_SYMBOL); sym->ctype.base_type = ptr->base_type; sym->ctype.modifiers = ptr->modifiers; - sym->evaluate = ptr->evaluate; + sym->op = ptr->op; } ptr_ctype.type = SYM_PTR; @@ -56,6 +56,11 @@ struct ctype { struct symbol *base_type; }; +struct symbol_op { + int (*evaluate)(struct expression *); + void (*expand)(struct expression *); +}; + struct symbol { enum namespace namespace:8; enum type type:8; @@ -66,7 +71,7 @@ struct symbol { struct symbol *replace; /* What is this symbol shadowed by in copy-expression */ struct scope *scope; struct symbol *same_symbol; - int (*evaluate)(struct expression *); + struct symbol_op *op; struct /* preprocessor_sym */ { struct token *expansion; @@ -127,6 +132,7 @@ struct symbol { #define MOD_TOPLEVEL 0x800000 // scoping.. #define MOD_LABEL 0x1000000 +#define MOD_ASSIGNED 0x2000000 /* Basic types */ extern struct symbol void_type, diff --git a/test-parsing.c b/test-parsing.c index c9ee16d3..f63be073 100644 --- a/test-parsing.c +++ b/test-parsing.c @@ -70,6 +70,7 @@ static void handle_switch(char *arg) static void clean_up_symbol(struct symbol *sym, void *_parent, int flags) { evaluate_symbol(sym); + expand_symbol(sym); } int main(int argc, char **argv) @@ -112,7 +113,7 @@ int main(int argc, char **argv) // Parse the resulting C code translation_unit(token, &used_list); - // Do type evaluation and simplify + // Do type evaluation and simplification symbol_iterate(used_list, clean_up_symbol, NULL); #if 1 |
