diff options
| author | Mistivia <i@mistivia.com> | 2025-03-26 19:10:25 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2025-03-26 19:10:25 +0800 |
| commit | 312716a295626f2b60b41777728c7f220fee843d (patch) | |
| tree | 5747882b5a662c29a734dc66486035f93fe42990 /src/as_codegen.c | |
| parent | b2be728e0cf6f024ecc524b28806012c53ca5206 (diff) | |
finish fvm-as
Diffstat (limited to 'src/as_codegen.c')
| -rw-r--r-- | src/as_codegen.c | 112 |
1 files changed, 94 insertions, 18 deletions
diff --git a/src/as_codegen.c b/src/as_codegen.c index 5c1d60e..678733f 100644 --- a/src/as_codegen.c +++ b/src/as_codegen.c @@ -1,12 +1,38 @@ #include "as_codegen.h" + +#include <string.h> + #include "as_analyzer.h" #include "as_op.h" #include "fvm.h" #include "utils.h" -bytearray *new_bytearray(allocator *alct); -void bytearray_emit8(bytearray *self, int8_t data); -void bytearray_emit64(bytearray *self, int64_t data); +bytearray *new_bytearray(allocator *alct) { + bytearray* arr = allocate(alct, sizeof(bytearray)); + arr->len = 0; + arr->cap = 16; + arr->buf = allocate(alct, 16); + arr->alct = alct; + return arr; +} + +void bytearray_emit8(bytearray *arr, int8_t data) { + if (arr->len == arr->cap) { + void* oldbuf = arr->buf; + arr->buf = allocate(arr->alct, 2 * arr->cap); + memcpy(arr->buf, oldbuf, arr->cap); + arr->cap = arr->cap * 2; + } + arr->buf[arr->len] = data; + arr->len++; +} + +void bytearray_emit64(bytearray *self, int64_t data) { + int8_t* ptr = (int8_t*)&data; + for (int i = 0; i < 8; i++) { + bytearray_emit8(self, ptr[i]); + } +} int8_t op_bytecode(op op) { @@ -43,6 +69,12 @@ int8_t op_bytecode(op op) { if (op == OP_XOR) return (int8_t)FVM_OP_XOR; if (op == OP_INVERT) return (int8_t)FVM_OP_INVERT; + if (op == OP_JNZ) return (int8_t)FVM_OP_JNZ; + if (op == OP_JZ) return (int8_t)FVM_OP_JZ; + if (op == OP_JMP) return (int8_t)FVM_OP_JMP; + if (op == OP_CALL) return (int8_t)FVM_OP_CALL; + if (op == OP_SYSCALL) return (int8_t)FVM_OP_SYSCALL; + if (op == OP_GT) return (int8_t)FVM_OP_GT; if (op == OP_LT) return (int8_t)FVM_OP_LT; if (op == OP_GE) return (int8_t)FVM_OP_GE; @@ -86,22 +118,66 @@ result codegen(allocator* alct, prog* prog, sym_table tbl) { int8_t code = op_bytecode(op); bytearray_emit8(output, code); offset += 1; - } else if (op_size(op) == 9) { - if (op == OP_IMM) { - if (instr->tag_name != NULL || instr->arg == NULL) { - return err(safe_sprintf(alct, "line %d: invalid instruction format. (imm)\n", instr->lineno)); - } - bytearray_emit8(output, FVM_OP_IMM); - bytearray_emit64(output, instr->arg->ival); - offset += 9; - } else if (op == OP_REL) { - if (instr->tag_name == NULL || instr->arg != NULL) { - return err(safe_sprintf(alct, "line %d: invalid instruction format. (rel)\n", instr->lineno)); - } - bytearray_emit8(output, FVM_OP_IMM); + } else if (op == OP_IMM) { + if (instr->tag_name != NULL || instr->arg == NULL) { + return err(safe_sprintf(alct, "line %d: invalid instruction format. (imm)\n", instr->lineno)); } - } else if (op_size(op) == 10) { - + bytearray_emit8(output, FVM_OP_IMM); + bytearray_emit64(output, instr->arg->ival); + offset += 9; + } else if (op == OP_REL) { + if (instr->tag_name == NULL || instr->arg != NULL) { + return err(safe_sprintf(alct, "line %d: invalid instruction format. (rel)\n", instr->lineno)); + } + bytearray_emit8(output, FVM_OP_IMM); + int target_offset = sym_table_lookup(&tbl, instr->tag_name); + if (target_offset == -1) { + return err(safe_sprintf(alct, "line %d: unknown tag: %s", instr->lineno, instr->tag_name)); + } + bytearray_emit64(output, target_offset - (offset + 9)); + bytearray_emit8(output, FVM_OP_PC); + bytearray_emit8(output, FVM_OP_ADD); + offset += 11; + } else if (op == OP_LDARG) { + if (instr->tag_name != NULL || instr->arg == NULL) { + return err(safe_sprintf(alct, "line %d: invalid instruction format. (ldarg)\n", instr->lineno)); + } + bytearray_emit8(output, FVM_OP_IMM); + bytearray_emit64(output, 8 * (instr->arg->ival + 2)); + bytearray_emit8(output, FVM_OP_BP); + bytearray_emit8(output, FVM_OP_ADD); + bytearray_emit8(output, FVM_OP_LD); + offset += 12; + } else if (op == OP_STARG) { + if (instr->tag_name != NULL || instr->arg == NULL) { + return err(safe_sprintf(alct, "line %d: invalid instruction format. (starg)\n", instr->lineno)); + } + bytearray_emit8(output, FVM_OP_IMM); + bytearray_emit64(output, 8 * (instr->arg->ival + 2)); + bytearray_emit8(output, FVM_OP_BP); + bytearray_emit8(output, FVM_OP_ADD); + bytearray_emit8(output, FVM_OP_ST); + offset += 12; + } else if (op == OP_LDVAR) { + if (instr->tag_name != NULL || instr->arg == NULL) { + return err(safe_sprintf(alct, "line %d: invalid instruction format. (ldvar)\n", instr->lineno)); + } + bytearray_emit8(output, FVM_OP_IMM); + bytearray_emit64(output, 8 * (-instr->arg->ival - 1)); + bytearray_emit8(output, FVM_OP_BP); + bytearray_emit8(output, FVM_OP_ADD); + bytearray_emit8(output, FVM_OP_LD); + offset += 12; + } else if (op == OP_STVAR) { + if (instr->tag_name != NULL || instr->arg == NULL) { + return err(safe_sprintf(alct, "line %d: invalid instruction format. (stvar)\n", instr->lineno)); + } + bytearray_emit8(output, FVM_OP_IMM); + bytearray_emit64(output, 8 * (-instr->arg->ival - 2)); + bytearray_emit8(output, FVM_OP_BP); + bytearray_emit8(output, FVM_OP_ADD); + bytearray_emit8(output, FVM_OP_ST); + offset += 12; } } return ok(output); |
