static struct block *cast_expression(struct block *block) { struct typetree *type; struct token tok; struct symbol *sym; /* This rule needs two lookahead; to see beyond the initial parenthesis if * it is actually a cast or an expression. */ if (peek().token == '(') { tok = peekn(2); switch (tok.token) { case IDENTIFIER: sym = sym_lookup(&ns_ident, tok.strval); if (!sym || sym->symtype != SYM_TYPEDEF) break; case FIRST(type_name): consume('('); type = declaration_specifiers(NULL); if (peek().token != ')') { type = declarator(type, NULL); } consume(')'); block = cast_expression(block); block->expr = eval_cast(block, block->expr, type); return block; default: break; } } return unary_expression(block); }
/* * Consumes all forms of whitespace, * including comments. If we are in a * state where we should ignore newlines, * we also consume '\n'. ';' is still * accepted as a line ending. */ static void eatspace(void) { int c; int ignorenl; ignorenl = 0; while (1) { c = peek(); if (!ignorenl && c == '\n') { break; } else if (c == '\\') { ignorenl = 1; next(); } else if (ignorenl && c == '\n') { next(); curloc.line++; ignorenl = 0; } else if (isspace(c)) { next(); } else if (c == '/' && peekn(1) == '*') { eatcomment(); } else { break; } } }
static int peek(void) { return peekn(0); }
static struct block *unary_expression(struct block *block) { struct var value; switch (peek().token) { case '&': consume('&'); block = cast_expression(block); block->expr = eval_addr(block, block->expr); break; case '*': consume('*'); block = cast_expression(block); block->expr = eval_deref(block, block->expr); break; case '!': consume('!'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_EQ, var_int(0), block->expr); break; case '~': consume('~'); block = cast_expression(block); block->expr = eval_expr(block, IR_NOT, block->expr); break; case '+': consume('+'); block = cast_expression(block); block->expr.lvalue = 0; break; case '-': consume('-'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_SUB, var_int(0), block->expr); break; case SIZEOF: { struct typetree *type; struct block *head = cfg_block_init(), *tail; consume(SIZEOF); if (peek().token == '(') { switch (peekn(2).token) { case FIRST(type_name): consume('('); type = declaration_specifiers(NULL); if (peek().token != ')') { type = declarator(type, NULL); } consume(')'); break; default: tail = unary_expression(head); type = (struct typetree *) tail->expr.type; break; } } else { tail = unary_expression(head); type = (struct typetree *) tail->expr.type; } if (is_function(type)) { error("Cannot apply 'sizeof' to function type."); } if (!size_of(type)) { error("Cannot apply 'sizeof' to incomplete type."); } block->expr = var_int(size_of(type)); break; } case INCREMENT: consume(INCREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_ADD, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; case DECREMENT: consume(DECREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_SUB, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; default: block = postfix_expression(block); break; } return block; }