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:
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;