mirror of https://github.com/rui314/chibicc
[GNU] Support case ranges
This commit is contained in:
parent
e0bf168041
commit
d90c73b605
|
@ -259,10 +259,14 @@ struct Node {
|
|||
char *unique_label;
|
||||
Node *goto_next;
|
||||
|
||||
// Switch-cases
|
||||
// Switch
|
||||
Node *case_next;
|
||||
Node *default_case;
|
||||
|
||||
// Case
|
||||
long begin;
|
||||
long end;
|
||||
|
||||
// "asm" string literal
|
||||
char *asm_str;
|
||||
|
||||
|
|
17
codegen.c
17
codegen.c
|
@ -1160,9 +1160,20 @@ static void gen_stmt(Node *node) {
|
|||
gen_expr(node->cond);
|
||||
|
||||
for (Node *n = node->case_next; n; n = n->case_next) {
|
||||
char *reg = (node->cond->ty->size == 8) ? "%rax" : "%eax";
|
||||
println(" cmp $%ld, %s", n->val, reg);
|
||||
println(" je %s", n->label);
|
||||
char *ax = (node->cond->ty->size == 8) ? "%rax" : "%eax";
|
||||
char *di = (node->cond->ty->size == 8) ? "%rdi" : "%edi";
|
||||
|
||||
if (n->begin == n->end) {
|
||||
println(" cmp $%ld, %s", n->begin, ax);
|
||||
println(" je %s", n->label);
|
||||
continue;
|
||||
}
|
||||
|
||||
// [GNU] Case ranges
|
||||
println(" mov %s, %s", ax, di);
|
||||
println(" sub $%ld, %s", n->begin, di);
|
||||
println(" cmp $%ld, %s", n->end - n->begin, di);
|
||||
println(" jbe %s", n->label);
|
||||
}
|
||||
|
||||
if (node->default_case)
|
||||
|
|
18
parse.c
18
parse.c
|
@ -1507,7 +1507,7 @@ static Node *asm_stmt(Token **rest, Token *tok) {
|
|||
// stmt = "return" expr? ";"
|
||||
// | "if" "(" expr ")" stmt ("else" stmt)?
|
||||
// | "switch" "(" expr ")" stmt
|
||||
// | "case" const-expr ":" stmt
|
||||
// | "case" const-expr ("..." const-expr)? ":" stmt
|
||||
// | "default" ":" stmt
|
||||
// | "for" "(" expr-stmt expr? ";" expr? ")" stmt
|
||||
// | "while" "(" expr ")" stmt
|
||||
|
@ -1573,11 +1573,23 @@ static Node *stmt(Token **rest, Token *tok) {
|
|||
error_tok(tok, "stray case");
|
||||
|
||||
Node *node = new_node(ND_CASE, tok);
|
||||
int val = const_expr(&tok, tok->next);
|
||||
int begin = const_expr(&tok, tok->next);
|
||||
int end;
|
||||
|
||||
if (equal(tok, "...")) {
|
||||
// [GNU] Case ranges, e.g. "case 1 ... 5:"
|
||||
end = const_expr(&tok, tok->next);
|
||||
if (end < begin)
|
||||
error_tok(tok, "empty case range specified");
|
||||
} else {
|
||||
end = begin;
|
||||
}
|
||||
|
||||
tok = skip(tok, ":");
|
||||
node->label = new_unique_name();
|
||||
node->lhs = stmt(rest, tok);
|
||||
node->val = val;
|
||||
node->begin = begin;
|
||||
node->end = end;
|
||||
node->case_next = current_switch->case_next;
|
||||
current_switch->case_next = node;
|
||||
return node;
|
||||
|
|
|
@ -83,6 +83,10 @@ int main() {
|
|||
ASSERT(10, ({ double i=10.0; int j=0; for (; i; i--, j++); j; }));
|
||||
ASSERT(10, ({ double i=10.0; int j=0; do j++; while(--i); j; }));
|
||||
|
||||
ASSERT(2, ({ int i=0; switch(7) { case 0 ... 5: i=1; break; case 6 ... 20: i=2; break; } i; }));
|
||||
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; }));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue