diff options
Diffstat (limited to 'src/ir.h')
-rw-r--r-- | src/ir.h | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/ir.h b/src/ir.h new file mode 100644 index 0000000..10f48fd --- /dev/null +++ b/src/ir.h | |||
@@ -0,0 +1,155 @@ | |||
1 | #ifndef BDL_IR_H | ||
2 | #define BDL_IR_H | ||
3 | |||
4 | typedef struct LineInfo { | ||
5 | size_t line; | ||
6 | size_t col; | ||
7 | } LineInfo; | ||
8 | |||
9 | typedef enum Op { | ||
10 | // Arithmetic ops. | ||
11 | // - Binary operations. | ||
12 | // - Arguments are passed via the stack. | ||
13 | OP_ADD, | ||
14 | OP_SUB, | ||
15 | OP_MUL, | ||
16 | OP_DIV, | ||
17 | OP_MOD, | ||
18 | // Stack ops. | ||
19 | // - Requires an Object to push into the stack. | ||
20 | OP_PUSH, | ||
21 | // - Discards the last value in the stack. | ||
22 | OP_DROP, | ||
23 | // Jump/conditional ops. | ||
24 | // - Take a label as argument. | ||
25 | // - For conditional jumps, the last value in the stack is used. | ||
26 | OP_JUMP, | ||
27 | OP_JUMP_IF_FALSE, | ||
28 | // Primitive complex commands. | ||
29 | // - Prints the last object in the stack. | ||
30 | OP_PRINT, | ||
31 | // Procedures. | ||
32 | // - Requires a function name as parameter. | ||
33 | OP_CALL, | ||
34 | // - Return position is on a know location of the stack based on the offset | ||
35 | // of locals, parameters, etc. | ||
36 | OP_RETURN, | ||
37 | // TODO: add remaining ops. | ||
38 | } Op; | ||
39 | |||
40 | static const char* ops_str[] = { | ||
41 | [OP_ADD] = "OP_ADD", | ||
42 | [OP_SUB] = "OP_SUB", | ||
43 | [OP_MUL] = "OP_MUL", | ||
44 | [OP_DIV] = "OP_DIV", | ||
45 | [OP_MOD] = "OP_MOD", | ||
46 | [OP_PUSH] = "OP_PUSH", | ||
47 | [OP_DROP] = "OP_DROP", | ||
48 | [OP_JUMP] = "OP_JUMP", | ||
49 | [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", | ||
50 | [OP_PRINT] = "OP_PRINT", | ||
51 | [OP_CALL] = "OP_CALL", | ||
52 | [OP_RETURN] = "OP_RETURN", | ||
53 | }; | ||
54 | |||
55 | typedef struct Instruction { | ||
56 | Op op; | ||
57 | Object *argument; | ||
58 | |||
59 | // Original line/column for debugging purposes. | ||
60 | size_t line; | ||
61 | size_t col; | ||
62 | } Instruction; | ||
63 | |||
64 | typedef struct Procedure { | ||
65 | // Procedure name. | ||
66 | char *name; | ||
67 | |||
68 | // Program code. | ||
69 | Instruction *instructions; | ||
70 | |||
71 | // Number of locals and parameters. | ||
72 | size_t n_params; | ||
73 | size_t n_locals; | ||
74 | } Procedure; | ||
75 | |||
76 | typedef struct ProgramIr { | ||
77 | Procedure **procedures; | ||
78 | Object **constants; | ||
79 | } ProgramIr; | ||
80 | |||
81 | void | ||
82 | print_instruction(Instruction *instruction) { | ||
83 | printf("%4ld:%-4ld ", instruction->line, instruction->col); | ||
84 | Op op = instruction->op; | ||
85 | switch (op) { | ||
86 | case OP_PUSH: { | ||
87 | printf("%-16s -> ", ops_str[op]); | ||
88 | OBJ_PRINT(instruction->argument); | ||
89 | } break; | ||
90 | default: { | ||
91 | printf("%s\n", ops_str[op]); | ||
92 | } break; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | void | ||
97 | print_procedure(Procedure *proc) { | ||
98 | printf("===== %.*s =====\n", (int)array_size(proc->name), proc->name); | ||
99 | printf("code:\n"); | ||
100 | for (size_t i = 0; i < array_size(proc->instructions); ++i) { | ||
101 | print_instruction(&proc->instructions[i]); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | Procedure * | ||
106 | proc_alloc(ProgramIr *program, StringView name) { | ||
107 | Procedure *proc = calloc(1, sizeof(Procedure)); | ||
108 | array_init(proc->name, name.n); | ||
109 | array_insert(proc->name, name.start, name.n); | ||
110 | array_init(proc->instructions, 0); | ||
111 | array_push(program->procedures, proc); | ||
112 | return proc; | ||
113 | } | ||
114 | |||
115 | void | ||
116 | compile_object(ProgramIr *program, Procedure *proc, Object *obj) { | ||
117 | switch (obj->type) { | ||
118 | case OBJ_TYPE_NIL: | ||
119 | case OBJ_TYPE_TRUE: | ||
120 | case OBJ_TYPE_FALSE: | ||
121 | case OBJ_TYPE_STRING: | ||
122 | case OBJ_TYPE_FIXNUM: { | ||
123 | Instruction inst = (Instruction){OP_PUSH, obj, obj->line, obj->col}; | ||
124 | array_push(proc->instructions, inst); | ||
125 | } break; | ||
126 | // case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; | ||
127 | // case OBJ_TYPE_IF: { compile_if(obj); } break; | ||
128 | // case OBJ_TYPE_LAMBDA: { compile_lambda(obj); } break; | ||
129 | // case OBJ_TYPE_DEF: { compile_def(obj); } break; | ||
130 | // case OBJ_TYPE_SYMBOL: { compile_symbol(obj); } break; | ||
131 | default: break; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | ProgramIr | ||
136 | compile(Program program) { | ||
137 | ProgramIr program_ir = {0}; | ||
138 | array_init(program_ir.procedures, 0); | ||
139 | array_init(program_ir.constants, 0); | ||
140 | Procedure *main = proc_alloc(&program_ir, STRING("main")); | ||
141 | |||
142 | for (size_t i = 0; i < array_size(program.roots); i++) { | ||
143 | Object *root = program.roots[i]; | ||
144 | compile_object(&program_ir, main, root); | ||
145 | } | ||
146 | |||
147 | // DEBUG:... | ||
148 | for (size_t i = 0; i < array_size(program_ir.procedures); ++i) { | ||
149 | print_procedure(program_ir.procedures[i]); | ||
150 | } | ||
151 | |||
152 | return program_ir; | ||
153 | } | ||
154 | |||
155 | #endif // BDL_IR_H | ||