Add GNU expression statement

This commit is contained in:
Rui Ueyama 2019-08-07 08:05:18 +09:00
parent e648f9fba5
commit ca52c2c7fd
5 changed files with 45 additions and 4 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
ND_NULL, // Empty statement
@ -121,7 +122,7 @@ struct Node {
Node *init;
Node *inc;
// Block
// Block or statement expression
Node *body;
// Function call

View File

@ -139,6 +139,7 @@ static void gen(Node *node) {
return;
}
case ND_BLOCK:
case ND_STMT_EXPR:
for (Node *n = node->body; n; n = n->next)
gen(n);
return;

33
parse.c
View File

@ -463,6 +463,26 @@ static Node *postfix(void) {
return node;
}
// stmt-expr = "(" "{" stmt stmt* "}" ")"
//
// Statement expression is a GNU C extension.
static Node *stmt_expr(Token *tok) {
Node *node = new_node(ND_STMT_EXPR, tok);
node->body = stmt();
Node *cur = node->body;
while (!consume("}")) {
cur->next = stmt();
cur = cur->next;
}
expect(")");
if (cur->kind != ND_EXPR_STMT)
error_tok(cur->tok, "stmt expr returning void is not supported");
memcpy(cur, cur->lhs, sizeof(Node));
return node;
}
// func-args = "(" (assign ("," assign)*)? ")"
static Node *func_args(void) {
if (consume(")"))
@ -478,12 +498,19 @@ static Node *func_args(void) {
return head;
}
// primary = "(" expr ")" | "sizeof" unary | ident func-args? | str | num
// args = "(" ident ("," ident)* ")"
// primary = "(" "{" stmt-expr-tail
// | "(" expr ")"
// | "sizeof" unary
// | ident func-args?
// | str
// | num
static Node *primary(void) {
Token *tok;
if (consume("(")) {
if (tok = consume("(")) {
if (consume("{"))
return stmt_expr(tok);
Node *node = expr();
expect(")");
return node;

View File

@ -183,4 +183,9 @@ assert 106 'int main() { return "\j"[0]; }'
assert 107 'int main() { return "\k"[0]; }'
assert 108 'int main() { return "\l"[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 3 'int main() { return ({ int x=3; x; }); }'
echo OK

7
type.c
View File

@ -74,5 +74,12 @@ void add_type(Node *node) {
error_tok(node->tok, "invalid pointer dereference");
node->ty = node->lhs->ty->base;
return;
case ND_STMT_EXPR: {
Node *last = node->body;
while (last->next)
last = last->next;
node->ty = last->ty;
return;
}
}
}