mirror of
https://github.com/rui314/chibicc
synced 2024-11-25 23:59:36 +03:00
[GNU] Add statement expression
This is a GNU C extension but will be useful for writing tests.
This commit is contained in:
parent
c2cc1d3c45
commit
9dae23461e
@ -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
|
||||
|
@ -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
15
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, ")");
|
||||
|
6
test.sh
6
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
|
||||
|
12
type.c
12
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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user