diff --git a/chibi.h b/chibi.h index 8743925ba3e52f4b4ac26ce77eb92cae01db35c6..c234a68800d5152aa3add601f70885b0c087d4b6 100644 --- a/chibi.h +++ b/chibi.h @@ -123,6 +123,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 @@ -160,6 +162,9 @@ struct Node { 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 }; diff --git a/codegen.c b/codegen.c index a06b58834f2957e7404ecd28bd5ee37f8a8f01db..f89ce29580527aa9854a1909738fab6f5a16cd4f 100644 --- a/codegen.c +++ b/codegen.c @@ -401,6 +401,13 @@ static void gen(Node *node) { error_tok(node->tok, "stray continue"); printf(" jmp .L.continue.%d\n", contseq); 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_FUNCALL: { int nargs = 0; for (Node *arg = node->args; arg; arg = arg->next) { diff --git a/parse.c b/parse.c index 7279929a8556e90eb462eae27d09053a68791b9a..986c623411a31dc62abf99eaab9a15a6337f5b96 100644 --- a/parse.c +++ b/parse.c @@ -719,6 +719,8 @@ static Node *stmt(void) { // | "{" stmt* "}" // | "break" ";" // | "continue" ";" +// | "goto" ident ";" +// | ident ":" stmt // | declaration // | expr ";" static Node *stmt2(void) { @@ -802,6 +804,22 @@ static Node *stmt2(void) { 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(); diff --git a/tests b/tests index 3deacdc494d93def87c2176f7953d49c6e2f4191..8d5481ec327679f3db48a813c830a5cdb9033fe9 100644 --- a/tests +++ b/tests @@ -438,6 +438,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; } diff --git a/tokenize.c b/tokenize.c index 4931b288b953243e24b381aac56bc2f3e3cdd486..845d575d050e2e08af30de6dc6c33e2f7f882e46 100644 --- a/tokenize.c +++ b/tokenize.c @@ -150,7 +150,7 @@ static char *starts_with_reserved(char *p) { static char *kw[] = {"return", "if", "else", "while", "for", "int", "char", "sizeof", "struct", "typedef", "short", "long", "void", "_Bool", "enum", "static", "break", - "continue"}; + "continue", "goto"}; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { int len = strlen(kw[i]);