diff --git a/chibicc.h b/chibicc.h index 7320300..9405ffb 100644 --- a/chibicc.h +++ b/chibicc.h @@ -98,6 +98,7 @@ typedef enum { ND_BLOCK, // { ... } ND_FUNCALL, // Function call ND_EXPR_STMT, // Expression statement + ND_STMT_EXPR, // Statement expression ND_VAR, // Variable ND_NUM, // Integer } NodeKind; @@ -119,7 +120,7 @@ struct Node { Node *init; Node *inc; - // Block + // Block or statement expression Node *body; // Function call diff --git a/codegen.c b/codegen.c index 7450d53..afcaabd 100644 --- a/codegen.c +++ b/codegen.c @@ -6,6 +6,7 @@ static char *argreg64[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; static Obj *current_fn; static void gen_expr(Node *node); +static void gen_stmt(Node *node); static int count(void) { static int i = 1; @@ -104,6 +105,10 @@ static void gen_expr(Node *node) { gen_expr(node->rhs); store(node->ty); return; + case ND_STMT_EXPR: + for (Node *n = node->body; n; n = n->next) + gen_stmt(n); + return; case ND_FUNCALL: { int nargs = 0; for (Node *arg = node->args; arg; arg = arg->next) { diff --git a/parse.c b/parse.c index 5b3a187..d7ee3fe 100644 --- a/parse.c +++ b/parse.c @@ -545,8 +545,21 @@ static Node *funcall(Token **rest, Token *tok) { return node; } -// primary = "(" expr ")" | "sizeof" unary | ident func-args? | str | num +// primary = "(" "{" stmt+ "}" ")" +// | "(" expr ")" +// | "sizeof" unary +// | ident func-args? +// | str +// | num static Node *primary(Token **rest, Token *tok) { + if (equal(tok, "(") && equal(tok->next, "{")) { + // This is a GNU statement expresssion. + Node *node = new_node(ND_STMT_EXPR, tok); + node->body = compound_stmt(&tok, tok->next->next)->body; + *rest = skip(tok, ")"); + return node; + } + if (equal(tok, "(")) { Node *node = expr(&tok, tok->next); *rest = skip(tok, ")"); diff --git a/test.sh b/test.sh index e070ef9..f24792c 100755 --- a/test.sh +++ b/test.sh @@ -207,4 +207,10 @@ assert 119 'int main() { return "\x77"[0]; }' assert 165 'int main() { return "\xA5"[0]; }' assert 255 'int main() { return "\x00ff"[0]; }' +assert 0 'int main() { return ({ 0; }); }' +assert 2 'int main() { return ({ 0; 1; 2; }); }' +assert 1 'int main() { ({ 0; return 1; 2; }); return 3; }' +assert 6 'int main() { return ({ 1; }) + ({ 2; }) + ({ 3; }); }' +assert 3 'int main() { return ({ int x=3; x; }); }' + echo OK diff --git a/type.c b/type.c index 9603faf..bff3fed 100644 --- a/type.c +++ b/type.c @@ -89,5 +89,17 @@ void add_type(Node *node) { error_tok(node->tok, "invalid pointer dereference"); node->ty = node->lhs->ty->base; return; + case ND_STMT_EXPR: + if (node->body) { + Node *stmt = node->body; + while (stmt->next) + stmt = stmt->next; + if (stmt->kind == ND_EXPR_STMT) { + node->ty = stmt->lhs->ty; + return; + } + } + error_tok(node->tok, "statement expression returning void is not supported"); + return; } }