From 74d361639148feceb67f8a3db22856c80b048b63 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Fri, 28 Jun 2024 16:11:22 +0200 Subject: Add compilation of binary logic expressions --- src/compiler.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/main.c | 13 ++++++++++++ src/vm.c | 47 ++++++++++++++++++++++++++++++++----------- tests/compilation.bad | 7 +++++-- 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 { } Constant; typedef struct Chunk { + sz id; Instruction *code; // Constant values that fit in 64 bits. @@ -94,6 +95,23 @@ typedef enum OpCode { OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF + // Logic operations (only 64 bits for now). + OP_EQI, // eqk rx, ra, cb + OP_NEQI, // neqk rx, ra, cb + OP_LTI, // ltk rx, ra, cb + OP_GTI, // gtk rx, ra, cb + OP_LEI, // lek rx, ra, cb + OP_GEI, // gek rx, ra, cb + OP_ANDI, // andk rx, ra, cb + OP_ORI, // ork rx, ra, cb + OP_EQ, // eq rx, ra, rb + OP_NEQ, // neq rx, ra, rb + OP_LT, // lt rx, ra, rb + OP_GT, // gt rx, ra, rb + OP_LE, // le rx, ra, rb + OP_GE, // ge rx, ra, rb + OP_AND, // and rx, ra, rb + OP_OR, // or rx, ra, rb } OpCode; Str op_str[] = { @@ -146,6 +164,19 @@ Str op_str[] = { [OP_MOV16] = cstr("MOV16 "), [OP_MOV32] = cstr("MOV32 "), [OP_MOV64] = cstr("MOV64 "), + // Logic operations. + [OP_EQI] = cstr("EQI "), + [OP_NEQI] = cstr("NEQI "), + [OP_LTI] = cstr("LTI "), + [OP_GTI] = cstr("GTI "), + [OP_LEI] = cstr("LEI "), + [OP_GEI] = cstr("GEI "), + [OP_EQ] = cstr("EQ "), + [OP_NEQ] = cstr("NEQ "), + [OP_LT] = cstr("LT "), + [OP_GT] = cstr("GT "), + [OP_LE] = cstr("LE "), + [OP_GE] = cstr("GE "), }; typedef enum { @@ -213,6 +244,14 @@ compile_binary(Chunk *chunk, Node *node) { op = OP_MODF; } } break; + case NODE_EQ: op = OP_EQ; break; + case NODE_NEQ: op = OP_NEQ; break; + case NODE_LT: op = OP_LT; break; + case NODE_GT: op = OP_GT; break; + case NODE_LE: op = OP_LE; break; + case NODE_GE: op = OP_GE; break; + case NODE_AND: op = OP_EQ; break; + case NODE_OR: op = OP_NEQ; break; default: break; } CompResult comp_a = compile_expr(chunk, node->left); @@ -243,8 +282,8 @@ compile_binary(Chunk *chunk, Node *node) { return (CompResult){.type = COMP_ERR}; } break; } - sz reg_dst = comp_a.idx; // Less registers - // sz reg_dst = chunk->reg_idx++; // Better for optimization + // sz reg_dst = comp_a.idx; // Less registers + sz reg_dst = chunk->reg_idx++; // Better for optimization EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); return (CompResult){.type = COMP_REG, .idx = reg_dst}; } @@ -252,6 +291,18 @@ compile_binary(Chunk *chunk, Node *node) { CompResult compile_expr(Chunk *chunk, Node *node) { switch (node->kind) { + // Logic. + // case NODE_NOT: + // case NODE_XOR: + case NODE_AND: + case NODE_OR: + case NODE_EQ: + case NODE_NEQ: + case NODE_LT: + case NODE_GT: + case NODE_LE: + // Arithmetic. + case NODE_GE: case NODE_ADD: case NODE_SUB: 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) { Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg}; array_push(chunk.code, halt, &bytecode_arena); + if (chunk.const_idx >= 256) { + eprintln("too many constants on chunk %s", chunk.id); + exit(EXIT_FAILURE); + } + if (chunk.str_idx >= 256) { + eprintln("too many strings on chunk %s", chunk.id); + exit(EXIT_FAILURE); + } + if (chunk.reg_idx >= 256) { + eprintln("too many registers used on chunk %s", chunk.id); + exit(EXIT_FAILURE); + } + disassemble_chunk(chunk); // 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) { case OP_MULFI: case OP_DIVFI: case OP_MODFI: + case OP_EQI: + case OP_NEQI: + case OP_LTI: + case OP_GTI: + case OP_LEI: + case OP_GEI: + case OP_ANDI: + case OP_ORI: println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, instruction.a, instruction.b); break; @@ -60,6 +68,14 @@ disassemble_instruction(Instruction instruction) { case OP_MULF: case OP_DIVF: case OP_MODF: + case OP_EQ: + case OP_NEQ: + case OP_LT: + case OP_GT: + case OP_LE: + case OP_GE: + case OP_AND: + case OP_OR: println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, instruction.a, instruction.b); break; @@ -106,7 +122,7 @@ vm_init(VM *vm, Chunk *chunk) { vm->ip = vm->chunk->code; } -#define OP_ARITHMETIC(OP, TYPE) \ +#define OP_BINARY(OP, TYPE) \ do { \ u8 dst = instruction.dst; \ u8 src_a = instruction.a; \ @@ -114,7 +130,7 @@ vm_init(VM *vm, Chunk *chunk) { vm->regs[dst].TYPE = vm->regs[src_a].TYPE OP vm->regs[src_b].TYPE; \ } while (0); -#define OP_ARITHMETIC_CONST(OP, TYPE) \ +#define OP_BINARY_CONST(OP, TYPE) \ do { \ u8 dst = instruction.dst; \ u8 src_a = instruction.a; \ @@ -144,15 +160,23 @@ vm_run(VM *vm) { u8 src_a = instruction.a; vm->regs[dst].i = vm->chunk->constants[src_a].i; } break; - case OP_ADD: OP_ARITHMETIC(+, i) break; - case OP_SUB: OP_ARITHMETIC(-, i) break; - case OP_MUL: OP_ARITHMETIC(*, i) break; - case OP_DIV: OP_ARITHMETIC(/, i) break; - case OP_MOD: OP_ARITHMETIC(%, i) break; - case OP_ADDF: OP_ARITHMETIC(+, f) break; - case OP_SUBF: OP_ARITHMETIC(-, f) break; - case OP_MULF: OP_ARITHMETIC(*, f) break; - case OP_DIVF: OP_ARITHMETIC(/, f) break; + case OP_EQ: OP_BINARY(==, i) break; + case OP_NEQ: OP_BINARY(!=, i) break; + case OP_LT: OP_BINARY(<, i) break; + case OP_GT: OP_BINARY(>, i) break; + case OP_LE: OP_BINARY(<=, i) break; + case OP_GE: OP_BINARY(>=, i) break; + case OP_AND: OP_BINARY(&&, i) break; + case OP_OR: OP_BINARY(||, i) break; + case OP_ADD: OP_BINARY(+, i) break; + case OP_SUB: OP_BINARY(-, i) break; + case OP_MUL: OP_BINARY(*, i) break; + case OP_DIV: OP_BINARY(/, i) break; + case OP_MOD: OP_BINARY(%, i) break; + case OP_ADDF: OP_BINARY(+, f) break; + case OP_SUBF: OP_BINARY(-, f) break; + case OP_MULF: OP_BINARY(*, f) break; + case OP_DIVF: OP_BINARY(/, f) break; case OP_MODF: { u8 dst = instruction.dst; u8 src_a = instruction.a; @@ -165,7 +189,6 @@ vm_run(VM *vm) { println("VM HALT (float) -> %f", vm->regs[instruction.dst]); return; } - default: { eprintln("unimplemented OP code: %d", instruction.op); 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 @@ -1 + 2 * 3 -1.0 + 2.0 * 3.0 +; 1 < 2 +; 1 == 1 && 1 <= 1 +1 * 3 >= 3 && 4 != 3 + 2 +; 1 + 2 * 3 +; 1.0 + 2.0 * 3.0 ; true ; false ; 0 1 -- cgit v1.2.1