diff --git a/ccc.h b/ccc.h index cb7f735..5c20cae 100644 --- a/ccc.h +++ b/ccc.h @@ -85,6 +85,7 @@ typedef enum { ND_WHILE, // "while" ND_FOR, // "for" ND_BLOCK, // { ... } + ND_BREAK, // "break" ND_FUNCALL, // Function call ND_EXPR_STMT, // Expression statement ND_STMT_EXPR, // statement expression diff --git a/codegen.c b/codegen.c index 921e9e1..3b4559b 100644 --- a/codegen.c +++ b/codegen.c @@ -5,7 +5,8 @@ char *argreg2[] = {"di", "si", "dx", "cx", "r8w", "r9w"}; char *argreg4[] = {"edi", "esi", "edx", "ecx", "r8d", "r9d"}; char *argreg8[] = {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}; -int labelseq = 0; +int labelseq; +int brkseq; char *funcname; void truncate(Type *ty) { @@ -216,36 +217,52 @@ void gen(Node *node) { } case ND_WHILE: { int seq = labelseq++; + int brk = brkseq; + brkseq = seq; + printf(".Lbegin%d:\n", seq); gen(node->cond); printf(" pop rax\n"); printf(" cmp rax, 0\n"); - printf(" je .Lend%d\n", seq); + printf(" je .L.break.%d\n", seq); gen(node->then); printf(" jmp .Lbegin%d\n", seq); - printf(".Lend%d:\n", seq); + printf(".L.break.%d:\n", seq); + + brkseq = brk; return; } case ND_FOR: { int seq = labelseq++; + int brk = brkseq; + brkseq = seq; + if (node->init) gen(node->init); printf(".Lbegin%d:\n", seq); if (node->cond) { gen(node->cond); printf(" pop rax\n"); printf(" cmp rax, 0\n"); - printf(" je .Lend%d\n", seq); + printf(" je .L.break.%d\n", seq); } gen(node->then); if (node->inc) gen(node->inc); printf(" jmp .Lbegin%d\n", seq); - printf(".Lend%d:\n", seq); + printf(".L.break.%d:\n", seq); + + brkseq = brk; return; } case ND_BLOCK: case ND_STMT_EXPR: for (Node *n = node->body; n; n = n->next) gen(n); return; + case ND_BREAK: + if (brkseq == 0) { + error_tok(node->tok, "stray break"); + } + printf(" jmp .L.break.%d\n", brkseq); + 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 7f04635..8729b77 100644 --- a/parse.c +++ b/parse.c @@ -641,6 +641,7 @@ bool is_typename() { // | "while" "(" expr ")" stmt // | "for" "(" (expr? ";" | declaration) expr? ";" expr? ")" stmt // | "{" stmt* "}" +// | "break" ";" // | declaration // | expr ";" Node *stmt() { @@ -709,6 +710,10 @@ Node *stmt() { node->body = head.next; return node; } + if (tok = consume("break")) { + expect(";"); + return new_node(ND_BREAK, tok); + } if (is_typename()) { return declaration(); } diff --git a/tests b/tests index 3fc492b..0bd4dc3 100644 --- a/tests +++ b/tests @@ -781,6 +781,11 @@ int main() { assert(3, ({ int x[2]; x[0]=3; param_decay(x); }), "int x[2]; x[0]=3; param_decay(x);"); + assert(3, ({ int i=0; for(;i<10;i++) { if (i == 3) break; } i; }), "int i=0; for(;i<10;i++) { if (i == 3) break; } i;"); + assert(4, ({ int i=0; while (1) { if (i++ == 3) break; } i; }), "int i=0; while { if (i == 3) break; } i;"); + assert(3, ({ int i=0; for(;i<10;i++) { for (;;) break; if (i == 3) break; } i; }), "int i=0; for(;i<10;i++) { if (i == 3) break; } i;"); + assert(4, ({ int i=0; while (1) { while(1) break; if (i++ == 3) break; } i; }), "int i=0; while { if (i == 3) break; } i;"); + printf("OK\n"); return 0; } diff --git a/tokenize.c b/tokenize.c index 43887f7..839ded1 100644 --- a/tokenize.c +++ b/tokenize.c @@ -151,7 +151,7 @@ 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"}; + "void", "_Bool", "enum", "static", "break"}; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { int len = strlen(kw[i]); if (startswith(p, kw[i]) && !is_alnum(p[len])) {