Skip to content

Commit

Permalink
feat: goto statement
Browse files Browse the repository at this point in the history
  • Loading branch information
diohabara committed Jul 25, 2023
1 parent d5aa742 commit 58b00d5
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 5 deletions.
4 changes: 4 additions & 0 deletions ccc.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ typedef enum {
ND_BLOCK, // { ... }
ND_BREAK, // "break"
ND_CONTINUE, // "continue"
ND_GOTO, // "goto"
ND_LABEL, // Labeled statement
ND_FUNCALL, // Function call
ND_EXPR_STMT, // Expression statement
ND_STMT_EXPR, // statement expression
Expand Down Expand Up @@ -135,6 +137,8 @@ struct Node {
// Function call
char *funcname;
Node *args;
// Goto or labeled statement
char *label_name;
Var *var; // Used if kind == ND_VAR
long val; // Used if kind == ND_NUM
// Struct member access
Expand Down
7 changes: 7 additions & 0 deletions codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,13 @@ void gen(Node *node) {
contseq = cont;
return;
}
case ND_GOTO:
printf(" jmp .L.label.%s.%s\n", funcname, node->label_name);
return;
case ND_LABEL:
printf(".L.label.%s.%s:\n", funcname, node->label_name);
gen(node->lhs);
return;
case ND_BLOCK:
case ND_STMT_EXPR:
for (Node *n = node->body; n; n = n->next) gen(n);
Expand Down
16 changes: 16 additions & 0 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,8 @@ bool is_typename() {
// | "{" stmt* "}"
// | "break" ";"
// | "continue" ";"
// | "goto" ident ";"
// | ident ":" stmt
// | declaration
// | expr ";"
Node *stmt() {
Expand Down Expand Up @@ -719,6 +721,20 @@ Node *stmt() {
expect(";");
return new_node(ND_CONTINUE, tok);
}
if (tok = consume("goto")) {
Node *node = new_node(ND_GOTO, tok);
node->label_name = expect_ident();
expect(";");
return node;
}
if (tok = consume_ident()) {
if (consume(":")) {
Node *node = new_unary(ND_LABEL, stmt(), tok);
node->label_name = strndup(tok->str, tok->len);
return node;
}
token = tok;
}
if (is_typename()) {
return declaration();
}
Expand Down
4 changes: 4 additions & 0 deletions tests
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,10 @@ int main() {
assert(5, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } j; }), "int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } j;");
assert(11, ({ int i=0; int j=0; while(!i) { while (j++!=10) continue; break; } j; }), "int i=0; int j=0; while(!i) { while (j++!=10) continue; break; } j;");

assert(3, ({ int i=0; goto a; a: i++; b: i++; c: i++; i; }), "int i=0; goto a; a: i++; b: i++; c: i++; i;");
assert(2, ({ int i=0; goto e; d: i++; e: i++; f: i++; i; }), "int i=0; goto d; d: i++; e: i++; f: i++; i;");
assert(1, ({ int i=0; goto i; g: i++; h: i++; i: i++; i; }), "int i=0; goto g; h: i++; i: i++; j: i++; i;");

printf("OK\n");
return 0;
}
10 changes: 5 additions & 5 deletions tokenize.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ bool is_alnum(char c) { return is_alpha(c) || ('0' <= c && c <= '9'); }

char *starts_with_reserved(char *p) {
// Keyword
static char *kw[] = {"return", "if", "else", "while", "for",
"char", "int", "sizeof", "struct", "typedef",
"short", "long", "void", "_Bool", "enum",
"static", "break", "continue"};
static char *kw[] = {"return", "if", "else", "while", "for",
"char", "int", "sizeof", "struct", "typedef",
"short", "long", "void", "_Bool", "enum",
"static", "break", "continue", "goto"};
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) {
int len = strlen(kw[i]);
if (startswith(p, kw[i]) && !is_alnum(p[len])) {
Expand Down Expand Up @@ -284,7 +284,7 @@ Token *tokenize() {
continue;
}
// Single-letter punctuator
if (strchr("+-*/()<>;={},&[].,!~|^", *p)) {
if (strchr("+-*/()<>;={},&[].,!~|^:", *p)) {
cur = new_token(TK_RESERVED, cur, p++, 1);
continue;
}
Expand Down

0 comments on commit 58b00d5

Please sign in to comment.