From addd1bfd522d570469218936bf0a03a7ce5251cc Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Wed, 7 Aug 2019 08:05:18 +0900 Subject: [PATCH] [GNU] Add statement expression This is a GNU C extension but will be useful for writing tests. --- chibicc.h | 3 ++- codegen.c | 5 +++++ parse.c | 15 ++++++++++++++- test.sh | 6 ++++++ type.c | 12 ++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/chibicc.h b/chibicc.h index 6d7f8d9..7b8d56b 100644 --- a/chibicc.h +++ b/chibicc.h @@ -90,6 +90,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; @@ -111,7 +112,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 fc40d09..0c5bbb9 100644 --- a/codegen.c +++ b/codegen.c @@ -6,6 +6,7 @@ static char *argreg64[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; static Var *current_fn; static void gen_expr(Node *node); +static void gen_stmt(Node *node); static int count(void) { static int i = 1; @@ -100,6 +101,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 14583ac..5ff6d15 100644 --- a/parse.c +++ b/parse.c @@ -547,8 +547,21 @@ static Node *funcall(Token **rest, Token *tok) { return node; } -// primary = "(" expr ")" | "sizeof" unary | ident func-args? | str | num +// primary = "(" "{" stmt 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 f6d6211..7cf1625 100755 --- a/test.sh +++ b/test.sh @@ -206,4 +206,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 5526cef..5794a3d 100644 --- a/type.c +++ b/type.c @@ -88,5 +88,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; } } -- GitLab