[GNU] Add statement expression

This is a GNU C extension but will be useful for writing tests.
This commit is contained in:
Rui Ueyama 2019-08-07 08:05:18 +09:00
parent c2cc1d3c45
commit 9dae23461e
5 changed files with 39 additions and 2 deletions

View File

@ -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

View File

@ -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) {

15
parse.c
View File

@ -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, ")");

View File

@ -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

12
type.c
View File

@ -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;
}
}