nooc

nooc programming language compiler
git clone git://git.nihaljere.xyz/nooc
Log | Files | Refs | LICENSE

commit 63c4bc319435bc2fd1653008bdde41c318dedda9
parent 3dc2455e1bc046b6520629e50ba2df5c9b7ec8a2
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Mon, 31 Jan 2022 16:54:21 -0600

add break statement to get out of loops

also fix the jmp instruction range

Diffstat:
Mir.c | 11++++++++++-
Mlex.c | 3+++
Mnooc.h | 4+++-
Mparse.c | 9+++++++++
Atest/break.pass.nooc | 14++++++++++++++
Atest/break_outside_loop.fail.nooc | 4++++
Mx64.c | 15+++++++++------
7 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/ir.c b/ir.c @@ -20,7 +20,7 @@ #define PTRSIZE 8 static uint64_t tmpi, labeli, curi, reali, rblocki, out_index; -static struct stack *blocks; +static struct stack *blocks, loops; static void genblock(struct iproc *const out, const struct block *const block); @@ -319,10 +319,12 @@ genexpr(struct iproc *const out, const size_t expri, uint64_t *const val) case EXPR_LOOP: { size_t startlabel = bumplabel(out), endlabel = bumplabel(out); NEWBLOCK(startlabel, endlabel); + stackpush(&loops, &out->blocks.data[out->blocks.len - 1]); LABEL(startlabel); genblock(out, &expr->d.loop.block); STARTINS(IR_JUMP, startlabel, VT_LABEL); LABEL(endlabel); + stackpop(&loops); return VT_EMPTY; } default: @@ -393,6 +395,9 @@ genblock(struct iproc *const out, const struct block *const block) case STMT_RETURN: STARTINS(IR_RETURN, 0, VT_EMPTY); break; + case STMT_BREAK: + STARTINS(IR_JUMP, ((struct iblock *)loops.data[loops.idx - 1])->end, VT_LABEL); + break; default: die("ir_genproc: unreachable"); } @@ -450,6 +455,7 @@ genproc(struct stack *blockstack, struct decl *const decl, const struct proc *co tmpi = labeli = curi = 1; rblocki = reali = 0; blocks = blockstack; + loops = (struct stack){ 0 }; struct type *type; struct iproc iproc = { .s = decl->s, @@ -501,6 +507,9 @@ genproc(struct stack *blockstack, struct decl *const decl, const struct proc *co genblock(out, &proc->block); stackpop(blocks); + if (loops.data) + free(loops.data); + LABEL(endlabel); chooseregs(&iproc); array_add((&toplevel.code), iproc); diff --git a/lex.c b/lex.c @@ -52,6 +52,9 @@ lex(struct slice start) } else if (slice_cmplit(&start, "return") == 0) { cur->type = TOK_RETURN; ADVANCE(6); + } else if (slice_cmplit(&start, "break") == 0) { + cur->type = TOK_BREAK; + ADVANCE(5); } else if (*start.data == '>') { cur->type = TOK_GREATER; ADVANCE(1); diff --git a/nooc.h b/nooc.h @@ -31,7 +31,8 @@ enum tokentype { TOK_IF, TOK_ELSE, TOK_LOOP, - TOK_RETURN + TOK_RETURN, + TOK_BREAK }; struct slice { @@ -151,6 +152,7 @@ struct statement { STMT_ASSGN, STMT_EXPR, STMT_RETURN, + STMT_BREAK, } kind; size_t idx; const struct token *start; diff --git a/parse.c b/parse.c @@ -13,6 +13,7 @@ static const struct token *tok; static struct stack blocks; +static int loopcount; static void parsenametypes(struct nametypes *const nametypes); static size_t parsetype(); @@ -116,7 +117,9 @@ parseexpr(struct block *const block) expr.start = tok; expr.kind = EXPR_LOOP; tok = tok->next; + loopcount += 1; parseblock(&expr.d.loop.block); + loopcount -= 1; break; case TOK_IF: expr.start = tok; @@ -405,6 +408,12 @@ parseblock(struct block *const block) statement.kind = STMT_RETURN; tok = tok->next; array_add((block), statement); + } else if (tok->type == TOK_BREAK) { + if (!loopcount) + error(tok->line, tok->col, "break statement outside of loop"); + statement.kind = STMT_BREAK; + tok = tok->next; + array_add((block), statement); } else if (tok->type == TOK_NAME && tok->next && tok->next->type == TOK_EQUAL) { struct assgn assgn = { 0 }; assgn.start = tok; diff --git a/test/break.pass.nooc b/test/break.pass.nooc @@ -0,0 +1,13 @@ +let str [9]i8 = "arstarst\n" + +let main proc() = proc() { + let i i64 = 0 + + loop { + if = i 10 { break } + syscall4(1, 0, $str, 9) + i = + i 1 + } + + syscall2(60, 0) +}+ \ No newline at end of file diff --git a/test/break_outside_loop.fail.nooc b/test/break_outside_loop.fail.nooc @@ -0,0 +1,3 @@ +let main proc() = proc() { + break +}+ \ No newline at end of file diff --git a/x64.c b/x64.c @@ -708,13 +708,16 @@ static size_t jmp(struct data *const text, const int64_t offset) { uint8_t temp; - if (-256 <= offset && offset <= 255) { - int8_t i = offset; + if (-2147483648 <= offset && offset <= 2147483647) { + int32_t i = offset; if (text) { - array_addlit(text, 0xEB); - array_addlit(text, i); + array_addlit(text, 0xE9); + array_addlit(text, ((uint32_t) i) & 0xFF); + array_addlit(text, (((uint32_t) i) >> 8) & 0xFF); + array_addlit(text, (((uint32_t) i) >> 16) & 0xFF); + array_addlit(text, (((uint32_t) i) >> 24) & 0xFF); } - return 2; + return 5; } else { die("unimplemented jmp offet!"); } @@ -850,7 +853,7 @@ emitblock(struct data *const text, const struct iproc *const proc, const struct if (ins < &proc->data[proc->labels.data[label]]) { total += jmp(text, emitblock(NULL, proc, ins + 1, &proc->data[proc->labels.data[label]], active, curi)); } else { - total += jmp(text, emitblock(NULL, proc, start, &proc->data[proc->labels.data[label]], 0, 0) - total - 2); // FIXME: 2 = size of short jump + total += jmp(text, emitblock(NULL, proc, start, &proc->data[proc->labels.data[label]], 0, 0) - total - 5); } NEXT; break;