diff options
-rw-r--r-- | evaluate.c | 19 | ||||
-rw-r--r-- | expression.c | 23 | ||||
-rw-r--r-- | show-parse.c | 11 |
3 files changed, 45 insertions, 8 deletions
@@ -1225,9 +1225,26 @@ static struct symbol *evaluate_cast(struct expression *expr) * initializer, in which case we need to pass * the type value down to that initializer rather * than trying to evaluate it as an expression + * + * A more complex case is when the initializer is + * dereferenced as part of a post-fix expression. + * We need to produce an expression that can be dereferenced. */ if (target->type == EXPR_INITIALIZER) { - evaluate_initializer(ctype, &expr->cast_expression, 0); + struct symbol *sym = alloc_symbol(expr->pos, SYM_NODE); + struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL); + + sym->ctype.base_type = ctype; + sym->initializer = expr->cast_expression; + evaluate_symbol(sym); + + addr->ctype = &ptr_ctype; + addr->symbol = sym; + + expr->type = EXPR_PREOP; + expr->op = '*'; + expr->unop = addr; + expr->ctype = ctype; return ctype; } diff --git a/expression.c b/expression.c index 90a006a..48414c3 100644 --- a/expression.c +++ b/expression.c @@ -241,11 +241,17 @@ static struct token *expression_list(struct token *token, struct expression_list return token; } -static struct token *postfix_expression(struct token *token, struct expression **tree) +/* + * extend to deal with the ambiguous C grammar for parsing + * a cast expressions followed by an initializer. + */ +static struct token *postfix_expression(struct token *token, struct expression **tree, struct expression *cast_init_expr) { - struct expression *expr = NULL; + struct expression *expr = cast_init_expr; + + if (!expr) + token = primary_expression(token, &expr); - token = primary_expression(token, &expr); while (expr && token_type(token) == TOKEN_SPECIAL) { switch (token->special) { case '[': { /* Array dereference */ @@ -343,13 +349,16 @@ static struct token *unary_expression(struct token *token, struct expression **t } - return postfix_expression(token, tree); + return postfix_expression(token, tree, NULL); } /* * Ambiguity: a '(' can be either a cast-expression or * a primary-expression depending on whether it is followed * by a type or not. + * + * additional ambiguity: a "cast expression" followed by + * an initializer is really a postfix-expression. */ static struct token *cast_expression(struct token *token, struct expression **tree) { @@ -362,9 +371,11 @@ static struct token *cast_expression(struct token *token, struct expression **tr token = typename(next, &sym); cast->cast_type = sym->ctype.base_type; token = expect(token, ')', "at end of cast operator"); + if (match_op(token, '{')) { + token = initializer(&cast->cast_expression, token); + return postfix_expression(token, tree, cast); + } *tree = cast; - if (match_op(token, '{')) - return initializer(&cast->cast_expression, token); token = cast_expression(token, &cast->cast_expression); return token; } diff --git a/show-parse.c b/show-parse.c index 0d7084b..14b06bb 100644 --- a/show-parse.c +++ b/show-parse.c @@ -913,6 +913,15 @@ static int show_initializer_expr(struct expression *expr, struct symbol *ctype) return 0; } +int show_symbol_expr_init(struct symbol *sym) +{ + struct expression *expr = sym->initializer; + + if (expr) + show_initializer_expr(expr, expr->ctype); + return show_symbol_expr(sym); +} + /* * Print out an expression. Return the pseudo that contains the * variable. @@ -947,7 +956,7 @@ int show_expression(struct expression *expr) case EXPR_POSTOP: return show_postop(expr); case EXPR_SYMBOL: - return show_symbol_expr(expr->symbol); + return show_symbol_expr_init(expr->symbol); case EXPR_DEREF: case EXPR_SIZEOF: warn(expr->pos, "invalid expression after evaluation"); |