summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2024-06-21 00:25:55 +0100
committerubq323 <ubq323@ubq323.website>2024-06-21 00:25:55 +0100
commita03973653262fbbfed7ce42dfa39646d16bdc98f (patch)
treefcf222d1e67b715af8173fda8edcab3b6c0793cd
parentf331192861d8ba02af7fd47f2e0c6d6db7515007 (diff)
while loops, comparisons, modulo, fizzbuzz
-rw-r--r--Makefile4
-rw-r--r--com.c40
-rw-r--r--dis.c17
-rw-r--r--fizzbuzz.bþ10
-rw-r--r--g.peg2
-rw-r--r--vm.c24
-rw-r--r--vm.h5
7 files changed, 89 insertions, 13 deletions
diff --git a/Makefile b/Makefile
index 1993b3f..596f2a3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
CS=ast.c com.c dis.c ht.c mem.c prs.c read.c state.c val.c vm.c
HS=ast.h dis.h ht.h mem.h prs.h read.h state.h val.h vm.h
-CFLAGS=-O3 -Wall -Wpedantic -Werror=implicit-function-declaration
+CFLAGS=-O3 -lm -Wall -Wpedantic -Werror=implicit-function-declaration
-bþ: $(CS) $(HS)
+bþ: $(CS) $(HS) Makefile
$(CC) $(CFLAGS) -o bþ $(CS)
prs.c: g.peg
diff --git a/com.c b/com.c
index fef2dab..cfe4df5 100644
--- a/com.c
+++ b/com.c
@@ -83,17 +83,42 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
// B:
compile_node(S, ch, l.vals[1]);
chunk_wbc(S, ch, OP_0BRANCH);
- size_t ph1 = placeholder(S, ch);
+ size_t ph_a = placeholder(S, ch);
compile_node(S, ch, l.vals[2]);
chunk_wbc(S, ch, OP_SKIP);
- size_t ph2 = placeholder(S, ch);
- size_t dest1 = ch->bc.len;
+ size_t ph_b = placeholder(S, ch);
+ size_t dest_a = ch->bc.len;
compile_node(S, ch, l.vals[3]);
- size_t dest2 = ch->bc.len;
+ size_t dest_b = ch->bc.len;
- patch(S, ch, ph1, dest1 - ph1 - 2);
- patch(S, ch, ph2, dest2 - ph2 - 2);
+ patch(S, ch, ph_a, dest_a - ph_a - 2);
+ patch(S, ch, ph_b, dest_b - ph_b - 2);
+ } else if (0 == strcmp(name, "while")) {
+ CK(l.len >= 3, "while requires at least 2 arguments");
+ // (while cond body ...)
+ // A:
+ // cond
+ // 0branch ->B
+ // body ....
+ // redo ->A
+ // B:
+ // nil (while loop always returns nil)
+ size_t dest_a = ch->bc.len;
+ compile_node(S, ch, l.vals[1]);
+ chunk_wbc(S, ch, OP_0BRANCH);
+ size_t ph_b = placeholder(S, ch);
+ for (int i = 2; i < l.len; i++) {
+ compile_node(S, ch, l.vals[i]);
+ chunk_wbc(S, ch, OP_DROP);
+ }
+ chunk_wbc(S, ch, OP_REDO);
+ size_t ph_a = placeholder(S, ch);
+ size_t dest_b = ch->bc.len;
+ chunk_wbc(S, ch, OP_NIL);
+
+ patch(S, ch, ph_a, ph_a - dest_a + 2);
+ patch(S, ch, ph_b, dest_b - ph_b - 2);
} else {
@@ -106,6 +131,9 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
OP('-', OP_SUB)
OP('*', OP_MUL)
OP('/', OP_DIV)
+ OP('=', OP_EQU)
+ OP('<', OP_CMP)
+ OP('%', OP_MOD)
#undef OP
default:
printf("unkown op %s\n",l.vals[0].as.str);
diff --git a/dis.c b/dis.c
index 9033bff..5c22cc2 100644
--- a/dis.c
+++ b/dis.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdint.h>
+#include <stdlib.h>
static void print_const(Chunk *ch, uint8_t ix) {
Val k = ch->consts.d[ix];
@@ -10,6 +11,13 @@ static void print_const(Chunk *ch, uint8_t ix) {
}
void disasm_chunk(Chunk *ch) {
+ puts("constants:");
+ for (uint8_t cix = 0; cix < ch->consts.len; cix++) {
+ printf("%hd\t",cix);
+ print_const(ch, cix);
+ }
+
+ puts("bytecode:");
for (size_t ip = 0; ip < ch->bc.len; ) {
uint8_t instr = ch->bc.d[ip];
printf("%04zd\t",ip);
@@ -49,7 +57,7 @@ void disasm_chunk(Chunk *ch) {
case OP_REDO: {
ip += 2;
uint16_t offset = RSHORT();
- printf("0branch -%5hu\t; -> %04zd\n", offset, ip - offset);
+ printf("redo -%5hu\t; -> %04zd\n", offset, ip - offset);
break;
}
#undef RSHORT
@@ -64,11 +72,18 @@ void disasm_chunk(Chunk *ch) {
SIMPLE_INSTR(OP_SUB, "sub")
SIMPLE_INSTR(OP_MUL, "mul")
SIMPLE_INSTR(OP_DIV, "div")
+ SIMPLE_INSTR(OP_MOD, "mod")
SIMPLE_INSTR(OP_NIL, "nil")
SIMPLE_INSTR(OP_TRUE, "true")
SIMPLE_INSTR(OP_FALSE, "false")
+ SIMPLE_INSTR(OP_CMP, "cmp")
+ SIMPLE_INSTR(OP_EQU, "equ")
#undef SIMPLE_INSTR
+ default:
+ printf("unknown opcode %d\n", instr);
+ exit(2);
+
}
}
}
diff --git a/fizzbuzz.bþ b/fizzbuzz.bþ
new file mode 100644
index 0000000..e70c2c1
--- /dev/null
+++ b/fizzbuzz.bþ
@@ -0,0 +1,10 @@
+(do
+ (set n 1)
+ (while (< n 30)
+ (print
+ (if (= 0 (% n 5))
+ (if (= 0 (% n 3)) "fizzbuzz" "buzz")
+ (if (= 0 (% n 3)) "fizz" n)))
+ (set n (+ n 1))))
+
+
diff --git a/g.peg b/g.peg
index c026e62..d6bca5c 100644
--- a/g.peg
+++ b/g.peg
@@ -39,7 +39,7 @@ number <- < [0-9]+ > (! ident_char) _ { $$ = astnode_new_num(atoi($1)); }
ident <- < ident_char+ > _ { $$ = astnode_new_ident(strdup($1)); }
string <- '"' < [^"]+ > '"' _ { $$ = astnode_new_string(strdup($1)); }
-ident_char <- [-_a-zA-Z'+*0-9]
+ident_char <- [-_a-zA-Z'+*/\\%=0-9<>]
_ <- [ \t\n]*
diff --git a/vm.c b/vm.c
index 70aca3d..e969692 100644
--- a/vm.c
+++ b/vm.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
+#include <math.h>
#include "val.h"
#include "vm.h"
@@ -130,7 +131,7 @@ int runvm(State *S) {
break;
}
-#define ARITH_OP(opcode, OP) \
+#define BINARY_OP(opcode, OP, RET_TYPE) \
case opcode: { \
Val b = POP(); \
Val a = POP(); \
@@ -139,15 +140,32 @@ int runvm(State *S) {
typename_str(a), typename_str(b)); \
goto done; \
} \
- PUSH(VAL_NUM(AS_NUM(a) OP AS_NUM(b))); \
+ PUSH(RET_TYPE(AS_NUM(a) OP AS_NUM(b))); \
} \
break;
-
+#define ARITH_OP(opcode, OP) BINARY_OP(opcode, OP, VAL_NUM)
+#define BOOL_OP(opcode, OP) BINARY_OP(opcode, OP, VAL_BOOL)
ARITH_OP(OP_ADD, +)
ARITH_OP(OP_SUB, -)
ARITH_OP(OP_MUL, *)
ARITH_OP(OP_DIV, /)
+ BOOL_OP(OP_EQU, ==)
+ BOOL_OP(OP_CMP, <)
+#undef BINARY_OP
#undef ARITH_OP
+#undef BOOL_OP
+ case OP_MOD: {
+ Val b = POP();
+ Val a = POP();
+ if (!IS_NUM(a) || !IS_NUM(b)) {
+ printf("can't do arithmetic on %s and %s",
+ typename_str(a), typename_str(b));
+ goto done;
+ }
+ PUSH(VAL_NUM(fmod(AS_NUM(a), AS_NUM(b))));
+ }
+ break;
+
case OP_NIL: PUSH(VAL_NIL); break;
case OP_TRUE: PUSH(VAL_TRUE); break;
diff --git a/vm.h b/vm.h
index 81abea3..609ed2c 100644
--- a/vm.h
+++ b/vm.h
@@ -44,6 +44,11 @@ typedef enum {
OP_SUB,
OP_MUL,
OP_DIV,
+ OP_MOD,
+
+ OP_EQU,
+ OP_CMP,
+
OP_DROP,