[GNU] Support labels-as-values

This commit is contained in:
Rui Ueyama 2020-09-04 12:26:27 +09:00
parent 3d5550e29a
commit 4f165ec60b
5 changed files with 38 additions and 3 deletions

View File

@ -209,7 +209,9 @@ typedef enum {
ND_CASE, // "case"
ND_BLOCK, // { ... }
ND_GOTO, // "goto"
ND_GOTO_EXPR, // "goto" labels-as-values
ND_LABEL, // Labeled statement
ND_LABEL_VAL, // [GNU] Labels-as-values
ND_FUNCALL, // Function call
ND_EXPR_STMT, // Expression statement
ND_STMT_EXPR, // Statement expression
@ -254,7 +256,7 @@ struct Node {
bool pass_by_stack;
Obj *ret_buffer;
// Goto or labeled statement
// Goto or labeled statement, or labels-as-values
char *label;
char *unique_label;
Node *goto_next;

View File

@ -925,6 +925,9 @@ static void gen_expr(Node *node) {
return;
}
case ND_LABEL_VAL:
println(" lea %s(%%rip), %%rax", node->unique_label);
return;
}
switch (node->lhs->ty->kind) {
@ -1194,6 +1197,10 @@ static void gen_stmt(Node *node) {
case ND_GOTO:
println(" jmp %s", node->unique_label);
return;
case ND_GOTO_EXPR:
gen_expr(node->lhs);
println(" jmp *%%rax");
return;
case ND_LABEL:
println("%s:", node->unique_label);
gen_stmt(node->lhs);

23
parse.c
View File

@ -1533,7 +1533,7 @@ static Node *asm_stmt(Token **rest, Token *tok) {
// | "while" "(" expr ")" stmt
// | "do" stmt "while" "(" expr ")" ";"
// | "asm" asm-stmt
// | "goto" ident ";"
// | "goto" (ident | "*" expr) ";"
// | "break" ";"
// | "continue" ";"
// | ident ":" stmt
@ -1704,6 +1704,14 @@ static Node *stmt(Token **rest, Token *tok) {
return asm_stmt(rest, tok);
if (equal(tok, "goto")) {
if (equal(tok->next, "*")) {
// [GNU] `goto *ptr` jumps to the address specified by `ptr`.
Node *node = new_node(ND_GOTO_EXPR, tok);
node->lhs = expr(&tok, tok->next->next);
*rest = skip(tok, ";");
return node;
}
Node *node = new_node(ND_GOTO, tok);
node->label = get_ident(tok->next);
node->goto_next = gotos;
@ -2406,6 +2414,7 @@ static Node *cast(Token **rest, Token *tok) {
// unary = ("+" | "-" | "*" | "&" | "!" | "~") cast
// | ("++" | "--") unary
// | "&&" ident
// | postfix
static Node *unary(Token **rest, Token *tok) {
if (equal(tok, "+"))
@ -2448,6 +2457,16 @@ static Node *unary(Token **rest, Token *tok) {
if (equal(tok, "--"))
return to_assign(new_sub(unary(rest, tok->next), new_num(1, tok), tok));
// [GNU] labels-as-values
if (equal(tok, "&&")) {
Node *node = new_node(ND_LABEL_VAL, tok);
node->label = get_ident(tok->next);
node->goto_next = gotos;
gotos = node;
*rest = tok->next->next;
return node;
}
return postfix(rest, tok);
}
@ -3005,7 +3024,7 @@ static void create_param_lvars(Type *param) {
}
}
// This function matches gotos with labels.
// This function matches gotos or labels-as-values with labels.
//
// We cannot resolve gotos as we parse a function because gotos
// can refer a label that appears later in the function.

View File

@ -87,6 +87,10 @@ int main() {
ASSERT(1, ({ int i=0; switch(7) { case 0 ... 7: i=1; break; case 8 ... 10: i=2; break; } i; }));
ASSERT(1, ({ int i=0; switch(7) { case 0: i=1; break; case 7 ... 7: i=1; break; } i; }));
ASSERT(3, ({ void *p = &&v11; int i=0; goto *p; v11:i++; v12:i++; v13:i++; i; }));
ASSERT(2, ({ void *p = &&v22; int i=0; goto *p; v21:i++; v22:i++; v23:i++; i; }));
ASSERT(1, ({ void *p = &&v33; int i=0; goto *p; v31:i++; v32:i++; v33:i++; i; }));
printf("OK\n");
return 0;
}

3
type.c
View File

@ -284,5 +284,8 @@ void add_type(Node *node) {
}
error_tok(node->tok, "statement expression returning void is not supported");
return;
case ND_LABEL_VAL:
node->ty = pointer_to(ty_void);
return;
}
}