diff options
author | ubq323 <ubq323@ubq323.website> | 2024-06-21 00:25:55 +0100 |
---|---|---|
committer | ubq323 <ubq323@ubq323.website> | 2024-06-21 00:25:55 +0100 |
commit | a03973653262fbbfed7ce42dfa39646d16bdc98f (patch) | |
tree | fcf222d1e67b715af8173fda8edcab3b6c0793cd | |
parent | f331192861d8ba02af7fd47f2e0c6d6db7515007 (diff) |
while loops, comparisons, modulo, fizzbuzz
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | com.c | 40 | ||||
-rw-r--r-- | dis.c | 17 | ||||
-rw-r--r-- | fizzbuzz.bþ | 10 | ||||
-rw-r--r-- | g.peg | 2 | ||||
-rw-r--r-- | vm.c | 24 | ||||
-rw-r--r-- | vm.h | 5 |
7 files changed, 89 insertions, 13 deletions
@@ -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 @@ -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); @@ -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)))) + + @@ -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]* @@ -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; @@ -44,6 +44,11 @@ typedef enum { OP_SUB, OP_MUL, OP_DIV, + OP_MOD, + + OP_EQU, + OP_CMP, + OP_DROP, |