From a03973653262fbbfed7ce42dfa39646d16bdc98f Mon Sep 17 00:00:00 2001 From: ubq323 Date: Fri, 21 Jun 2024 00:25:55 +0100 Subject: while loops, comparisons, modulo, fizzbuzz --- Makefile | 4 ++-- com.c | 40 ++++++++++++++++++++++++++++++++++------ dis.c | 17 ++++++++++++++++- "fizzbuzz.b\303\276" | 10 ++++++++++ g.peg | 2 +- vm.c | 24 +++++++++++++++++++++--- vm.h | 5 +++++ 7 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 "fizzbuzz.b\303\276" 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 #include +#include 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\303\276" "b/fizzbuzz.b\303\276" new file mode 100644 index 0000000..e70c2c1 --- /dev/null +++ "b/fizzbuzz.b\303\276" @@ -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 #include #include +#include #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, -- cgit v1.2.3