aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-28 16:11:22 +0200
committerBad Diode <bd@badd10de.dev>2024-06-28 16:11:22 +0200
commit74d361639148feceb67f8a3db22856c80b048b63 (patch)
tree13b844702a071e88075ee15311610c8274d799f8
parenta723c431f7674de916997df5ed4ce4026a244e07 (diff)
downloadbdl-74d361639148feceb67f8a3db22856c80b048b63.tar.gz
bdl-74d361639148feceb67f8a3db22856c80b048b63.zip
Add compilation of binary logic expressions
-rw-r--r--src/compiler.c55
-rw-r--r--src/main.c13
-rw-r--r--src/vm.c47
-rw-r--r--tests/compilation.bad7
4 files changed, 106 insertions, 16 deletions
diff --git a/src/compiler.c b/src/compiler.c
index bc875fd..51d7cd6 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -20,6 +20,7 @@ typedef union Constant {
20} Constant; 20} Constant;
21 21
22typedef struct Chunk { 22typedef struct Chunk {
23 sz id;
23 Instruction *code; 24 Instruction *code;
24 25
25 // Constant values that fit in 64 bits. 26 // Constant values that fit in 64 bits.
@@ -94,6 +95,23 @@ typedef enum OpCode {
94 OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF 95 OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF
95 OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF 96 OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF
96 OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF 97 OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF
98 // Logic operations (only 64 bits for now).
99 OP_EQI, // eqk rx, ra, cb
100 OP_NEQI, // neqk rx, ra, cb
101 OP_LTI, // ltk rx, ra, cb
102 OP_GTI, // gtk rx, ra, cb
103 OP_LEI, // lek rx, ra, cb
104 OP_GEI, // gek rx, ra, cb
105 OP_ANDI, // andk rx, ra, cb
106 OP_ORI, // ork rx, ra, cb
107 OP_EQ, // eq rx, ra, rb
108 OP_NEQ, // neq rx, ra, rb
109 OP_LT, // lt rx, ra, rb
110 OP_GT, // gt rx, ra, rb
111 OP_LE, // le rx, ra, rb
112 OP_GE, // ge rx, ra, rb
113 OP_AND, // and rx, ra, rb
114 OP_OR, // or rx, ra, rb
97} OpCode; 115} OpCode;
98 116
99Str op_str[] = { 117Str op_str[] = {
@@ -146,6 +164,19 @@ Str op_str[] = {
146 [OP_MOV16] = cstr("MOV16 "), 164 [OP_MOV16] = cstr("MOV16 "),
147 [OP_MOV32] = cstr("MOV32 "), 165 [OP_MOV32] = cstr("MOV32 "),
148 [OP_MOV64] = cstr("MOV64 "), 166 [OP_MOV64] = cstr("MOV64 "),
167 // Logic operations.
168 [OP_EQI] = cstr("EQI "),
169 [OP_NEQI] = cstr("NEQI "),
170 [OP_LTI] = cstr("LTI "),
171 [OP_GTI] = cstr("GTI "),
172 [OP_LEI] = cstr("LEI "),
173 [OP_GEI] = cstr("GEI "),
174 [OP_EQ] = cstr("EQ "),
175 [OP_NEQ] = cstr("NEQ "),
176 [OP_LT] = cstr("LT "),
177 [OP_GT] = cstr("GT "),
178 [OP_LE] = cstr("LE "),
179 [OP_GE] = cstr("GE "),
149}; 180};
150 181
151typedef enum { 182typedef enum {
@@ -213,6 +244,14 @@ compile_binary(Chunk *chunk, Node *node) {
213 op = OP_MODF; 244 op = OP_MODF;
214 } 245 }
215 } break; 246 } break;
247 case NODE_EQ: op = OP_EQ; break;
248 case NODE_NEQ: op = OP_NEQ; break;
249 case NODE_LT: op = OP_LT; break;
250 case NODE_GT: op = OP_GT; break;
251 case NODE_LE: op = OP_LE; break;
252 case NODE_GE: op = OP_GE; break;
253 case NODE_AND: op = OP_EQ; break;
254 case NODE_OR: op = OP_NEQ; break;
216 default: break; 255 default: break;
217 } 256 }
218 CompResult comp_a = compile_expr(chunk, node->left); 257 CompResult comp_a = compile_expr(chunk, node->left);
@@ -243,8 +282,8 @@ compile_binary(Chunk *chunk, Node *node) {
243 return (CompResult){.type = COMP_ERR}; 282 return (CompResult){.type = COMP_ERR};
244 } break; 283 } break;
245 } 284 }
246 sz reg_dst = comp_a.idx; // Less registers 285 // sz reg_dst = comp_a.idx; // Less registers
247 // sz reg_dst = chunk->reg_idx++; // Better for optimization 286 sz reg_dst = chunk->reg_idx++; // Better for optimization
248 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); 287 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk);
249 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 288 return (CompResult){.type = COMP_REG, .idx = reg_dst};
250} 289}
@@ -252,6 +291,18 @@ compile_binary(Chunk *chunk, Node *node) {
252CompResult 291CompResult
253compile_expr(Chunk *chunk, Node *node) { 292compile_expr(Chunk *chunk, Node *node) {
254 switch (node->kind) { 293 switch (node->kind) {
294 // Logic.
295 // case NODE_NOT:
296 // case NODE_XOR:
297 case NODE_AND:
298 case NODE_OR:
299 case NODE_EQ:
300 case NODE_NEQ:
301 case NODE_LT:
302 case NODE_GT:
303 case NODE_LE:
304 // Arithmetic.
305 case NODE_GE:
255 case NODE_ADD: 306 case NODE_ADD:
256 case NODE_SUB: 307 case NODE_SUB:
257 case NODE_MUL: 308 case NODE_MUL:
diff --git a/src/main.c b/src/main.c
index c52ec74..60122b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -194,6 +194,19 @@ process_file(Str path) {
194 Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg}; 194 Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg};
195 array_push(chunk.code, halt, &bytecode_arena); 195 array_push(chunk.code, halt, &bytecode_arena);
196 196
197 if (chunk.const_idx >= 256) {
198 eprintln("too many constants on chunk %s", chunk.id);
199 exit(EXIT_FAILURE);
200 }
201 if (chunk.str_idx >= 256) {
202 eprintln("too many strings on chunk %s", chunk.id);
203 exit(EXIT_FAILURE);
204 }
205 if (chunk.reg_idx >= 256) {
206 eprintln("too many registers used on chunk %s", chunk.id);
207 exit(EXIT_FAILURE);
208 }
209
197 disassemble_chunk(chunk); 210 disassemble_chunk(chunk);
198 211
199 // Run bytecode on VM. 212 // Run bytecode on VM.
diff --git a/src/vm.c b/src/vm.c
index 3400d7a..08a9ec3 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -39,6 +39,14 @@ disassemble_instruction(Instruction instruction) {
39 case OP_MULFI: 39 case OP_MULFI:
40 case OP_DIVFI: 40 case OP_DIVFI:
41 case OP_MODFI: 41 case OP_MODFI:
42 case OP_EQI:
43 case OP_NEQI:
44 case OP_LTI:
45 case OP_GTI:
46 case OP_LEI:
47 case OP_GEI:
48 case OP_ANDI:
49 case OP_ORI:
42 println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, 50 println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst,
43 instruction.a, instruction.b); 51 instruction.a, instruction.b);
44 break; 52 break;
@@ -60,6 +68,14 @@ disassemble_instruction(Instruction instruction) {
60 case OP_MULF: 68 case OP_MULF:
61 case OP_DIVF: 69 case OP_DIVF:
62 case OP_MODF: 70 case OP_MODF:
71 case OP_EQ:
72 case OP_NEQ:
73 case OP_LT:
74 case OP_GT:
75 case OP_LE:
76 case OP_GE:
77 case OP_AND:
78 case OP_OR:
63 println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, 79 println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst,
64 instruction.a, instruction.b); 80 instruction.a, instruction.b);
65 break; 81 break;
@@ -106,7 +122,7 @@ vm_init(VM *vm, Chunk *chunk) {
106 vm->ip = vm->chunk->code; 122 vm->ip = vm->chunk->code;
107} 123}
108 124
109#define OP_ARITHMETIC(OP, TYPE) \ 125#define OP_BINARY(OP, TYPE) \
110 do { \ 126 do { \
111 u8 dst = instruction.dst; \ 127 u8 dst = instruction.dst; \
112 u8 src_a = instruction.a; \ 128 u8 src_a = instruction.a; \
@@ -114,7 +130,7 @@ vm_init(VM *vm, Chunk *chunk) {
114 vm->regs[dst].TYPE = vm->regs[src_a].TYPE OP vm->regs[src_b].TYPE; \ 130 vm->regs[dst].TYPE = vm->regs[src_a].TYPE OP vm->regs[src_b].TYPE; \
115 } while (0); 131 } while (0);
116 132
117#define OP_ARITHMETIC_CONST(OP, TYPE) \ 133#define OP_BINARY_CONST(OP, TYPE) \
118 do { \ 134 do { \
119 u8 dst = instruction.dst; \ 135 u8 dst = instruction.dst; \
120 u8 src_a = instruction.a; \ 136 u8 src_a = instruction.a; \
@@ -144,15 +160,23 @@ vm_run(VM *vm) {
144 u8 src_a = instruction.a; 160 u8 src_a = instruction.a;
145 vm->regs[dst].i = vm->chunk->constants[src_a].i; 161 vm->regs[dst].i = vm->chunk->constants[src_a].i;
146 } break; 162 } break;
147 case OP_ADD: OP_ARITHMETIC(+, i) break; 163 case OP_EQ: OP_BINARY(==, i) break;
148 case OP_SUB: OP_ARITHMETIC(-, i) break; 164 case OP_NEQ: OP_BINARY(!=, i) break;
149 case OP_MUL: OP_ARITHMETIC(*, i) break; 165 case OP_LT: OP_BINARY(<, i) break;
150 case OP_DIV: OP_ARITHMETIC(/, i) break; 166 case OP_GT: OP_BINARY(>, i) break;
151 case OP_MOD: OP_ARITHMETIC(%, i) break; 167 case OP_LE: OP_BINARY(<=, i) break;
152 case OP_ADDF: OP_ARITHMETIC(+, f) break; 168 case OP_GE: OP_BINARY(>=, i) break;
153 case OP_SUBF: OP_ARITHMETIC(-, f) break; 169 case OP_AND: OP_BINARY(&&, i) break;
154 case OP_MULF: OP_ARITHMETIC(*, f) break; 170 case OP_OR: OP_BINARY(||, i) break;
155 case OP_DIVF: OP_ARITHMETIC(/, f) break; 171 case OP_ADD: OP_BINARY(+, i) break;
172 case OP_SUB: OP_BINARY(-, i) break;
173 case OP_MUL: OP_BINARY(*, i) break;
174 case OP_DIV: OP_BINARY(/, i) break;
175 case OP_MOD: OP_BINARY(%, i) break;
176 case OP_ADDF: OP_BINARY(+, f) break;
177 case OP_SUBF: OP_BINARY(-, f) break;
178 case OP_MULF: OP_BINARY(*, f) break;
179 case OP_DIVF: OP_BINARY(/, f) break;
156 case OP_MODF: { 180 case OP_MODF: {
157 u8 dst = instruction.dst; 181 u8 dst = instruction.dst;
158 u8 src_a = instruction.a; 182 u8 src_a = instruction.a;
@@ -165,7 +189,6 @@ vm_run(VM *vm) {
165 println("VM HALT (float) -> %f", vm->regs[instruction.dst]); 189 println("VM HALT (float) -> %f", vm->regs[instruction.dst]);
166 return; 190 return;
167 } 191 }
168
169 default: { 192 default: {
170 eprintln("unimplemented OP code: %d", instruction.op); 193 eprintln("unimplemented OP code: %d", instruction.op);
171 return; 194 return;
diff --git a/tests/compilation.bad b/tests/compilation.bad
index 6fc5662..da6a6e3 100644
--- a/tests/compilation.bad
+++ b/tests/compilation.bad
@@ -1,5 +1,8 @@
11 + 2 * 3 1; 1 < 2
21.0 + 2.0 * 3.0 2; 1 == 1 && 1 <= 1
31 * 3 >= 3 && 4 != 3 + 2
4; 1 + 2 * 3
5; 1.0 + 2.0 * 3.0
3; true 6; true
4; false 7; false
5; 0 1 8; 0 1