typedef enum Operator { // Arithmetic ops. OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, // Load/store/copy operations. OP_LD8, OP_LD16, OP_LD32, OP_LD64, OP_ST8, OP_ST16, OP_ST32, OP_ST64, OP_CP8, OP_CP16, OP_CP32, OP_CP64, // Bit fiddling operations. OP_NOT, OP_AND, OP_OR, OP_XOR, OP_LSHIFT, OP_RSHIFT, OP_LROT, OP_RROT, // (Un)conditional jump operations. OP_LABEL, OP_JMP, OP_JMP_EQ, OP_JMP_NEQ, OP_JMP_GT, OP_JMP_LT, OP_JMP_GE, OP_JMP_LE, } Operator; typedef enum OperandType { OP_TYPE_REG, OP_TYPE_CONST, OP_TYPE_LABEL, } OperandType; static size_t reg_gen_id = 0; #define NEW_REG() (Operand){ .type = OP_TYPE_REG, .id = reg_gen_id++ } #define NEW_S64(C) (Operand){ .type = OP_TYPE_CONST, .constant.sval = (C) } typedef struct Operand { OperandType type; union { // REG/LABEL size_t id; // s64 constant; struct { union { u64 uval; s64 sval; }; } constant; }; } Operand; typedef struct Instruction { Operator op; Operand dst; Operand src_a; Operand src_b; } Instruction; typedef struct LineInfo { size_t line; size_t col; } LineInfo; typedef struct ProgramBASM { Instruction *inst; LineInfo *lines; } ProgramBASM; Operand emit_basm(ProgramBASM *program, Node *node) { switch (node->type) { case NODE_NUMBER: { // TODO: ldX depending on type of number. Instruction inst = (Instruction){ .op = OP_LD64, .dst = NEW_REG(), .src_a = NEW_S64(node->number.integral), }; LineInfo line = (LineInfo){.line = node->line, .col = node->col}; array_push(program->inst, inst); array_push(program->lines, line); return inst.dst; } break; case NODE_BUILTIN: { Operator op; switch (node->builtin.type) { case TOKEN_ADD: { op = OP_ADD; } break; case TOKEN_SUB: { op = OP_SUB; } break; case TOKEN_MUL: { op = OP_MUL; } break; case TOKEN_DIV: { op = OP_DIV; } break; case TOKEN_MOD: { op = OP_MOD; } break; default: break; } Operand reg_a = emit_basm(program, node->builtin.args[0]); Operand reg_b; for (size_t i = 1; i < array_size(node->builtin.args); ++i) { Node *arg = node->builtin.args[i]; reg_b = emit_basm(program, arg); Instruction inst = (Instruction){ .op = op, .dst = NEW_REG(), .src_a = reg_a, .src_b = reg_b, }; reg_a = inst.dst; LineInfo line = (LineInfo){ .line = node->line, .col = node->col, }; array_push(program->inst, inst); array_push(program->lines, line); } return reg_a; } break; default: { printf("UNIMPLEMENTED\n"); return (Operand){0}; } break; } } ProgramBASM * generate_basm(ParseTree *parse_tree) { ProgramBASM *program = malloc(sizeof(ProgramBASM)); array_init(program->inst, 0); array_init(program->lines, 0); for (size_t i = 0; i < array_size(parse_tree->roots); ++i) { Node *root = parse_tree->roots[i]; emit_basm(program, root); } return program; }