From cb813c68cc21991d461d930fe1ee60364ca1d172 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 27 Aug 2020 21:59:19 +0900 Subject: [PATCH] Add continue statement --- chibicc.h | 3 ++- codegen.c | 1 + parse.c | 21 ++++++++++++++++++++- test/control.c | 7 +++++++ tokenize.c | 2 +- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/chibicc.h b/chibicc.h index 350243c..c8194db 100644 --- a/chibicc.h +++ b/chibicc.h @@ -137,8 +137,9 @@ struct Node { Node *init; Node *inc; - // "break" label + // "break" and "continue" labels char *brk_label; + char *cont_label; // Block or statement expression Node *body; diff --git a/codegen.c b/codegen.c index 0d1f0ab..8b2fd7e 100644 --- a/codegen.c +++ b/codegen.c @@ -357,6 +357,7 @@ static void gen_stmt(Node *node) { println(" je %s", node->brk_label); } gen_stmt(node->then); + println("%s:", node->cont_label); if (node->inc) gen_expr(node->inc); println(" jmp .L.begin.%d", c); diff --git a/parse.c b/parse.c index 23286e6..1a37e78 100644 --- a/parse.c +++ b/parse.c @@ -77,8 +77,9 @@ static Var *current_fn; static Node *gotos; static Node *labels; -// Current "goto" jump target. +// Current "goto" and "continue" jump targets. static char *brk_label; +static char *cont_label; static bool is_typename(Token *tok); static Type *typespec(Token **rest, Token *tok, VarAttr *attr); @@ -592,6 +593,7 @@ static bool is_typename(Token *tok) { // | "while" "(" expr ")" stmt // | "goto" ident ";" // | "break" ";" +// | "continue" ";" // | ident ":" stmt // | "{" compound-stmt // | expr-stmt @@ -625,7 +627,9 @@ static Node *stmt(Token **rest, Token *tok) { enter_scope(); char *brk = brk_label; + char *cont = cont_label; brk_label = node->brk_label = new_unique_name(); + cont_label = node->cont_label = new_unique_name(); if (is_typename(tok)) { Type *basety = typespec(&tok, tok, NULL); @@ -646,6 +650,7 @@ static Node *stmt(Token **rest, Token *tok) { leave_scope(); brk_label = brk; + cont_label = cont; return node; } @@ -656,9 +661,14 @@ static Node *stmt(Token **rest, Token *tok) { tok = skip(tok, ")"); char *brk = brk_label; + char *cont = cont_label; brk_label = node->brk_label = new_unique_name(); + cont_label = node->cont_label = new_unique_name(); + node->then = stmt(rest, tok); + brk_label = brk; + cont_label = cont; return node; } @@ -680,6 +690,15 @@ static Node *stmt(Token **rest, Token *tok) { return node; } + if (equal(tok, "continue")) { + if (!cont_label) + error_tok(tok, "stray continue"); + Node *node = new_node(ND_GOTO, tok); + node->unique_label = cont_label; + *rest = skip(tok->next, ";"); + return node; + } + if (tok->kind == TK_IDENT && equal(tok->next, ":")) { Node *node = new_node(ND_LABEL, tok); node->label = strndup(tok->loc, tok->len); diff --git a/test/control.c b/test/control.c index 24a8eff..a38734c 100644 --- a/test/control.c +++ b/test/control.c @@ -47,6 +47,13 @@ int main() { ASSERT(3, ({ int i=0; for(;i<10;i++) { for (;;) break; if (i == 3) break; } i; })); ASSERT(4, ({ int i=0; while (1) { while(1) break; if (i++ == 3) break; } i; })); + ASSERT(10, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } i; })); + ASSERT(6, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } j; })); + ASSERT(10, ({ int i=0; int j=0; for(;!i;) { for (;j!=10;j++) continue; break; } j; })); + ASSERT(11, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } i; })); + ASSERT(5, ({ 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; })); + printf("OK\n"); return 0; } diff --git a/tokenize.c b/tokenize.c index 6729fe3..4546b40 100644 --- a/tokenize.c +++ b/tokenize.c @@ -125,7 +125,7 @@ static bool is_keyword(Token *tok) { static char *kw[] = { "return", "if", "else", "for", "while", "int", "sizeof", "char", "struct", "union", "short", "long", "void", "typedef", "_Bool", - "enum", "static", "goto", "break", + "enum", "static", "goto", "break", "continue", }; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) -- GitLab