diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir.h | 87 | ||||
-rw-r--r-- | src/parser.c | 15 |
2 files changed, 89 insertions, 13 deletions
@@ -15,11 +15,16 @@ typedef enum Op { | |||
15 | OP_MUL, | 15 | OP_MUL, |
16 | OP_DIV, | 16 | OP_DIV, |
17 | OP_MOD, | 17 | OP_MOD, |
18 | // Logic ops. | ||
19 | OP_NOT, | ||
18 | // Stack ops. | 20 | // Stack ops. |
19 | // - Requires an Object to push into the stack. | 21 | // - Requires an Object to push into the stack. |
20 | OP_PUSH, | 22 | OP_PUSH, |
21 | // - Discards the last value in the stack. | 23 | // - Discards the last value in the stack. |
22 | OP_DROP, | 24 | OP_DROP, |
25 | // A label for memory access. | ||
26 | // - The argument should be a unique value. | ||
27 | OP_LABEL, | ||
23 | // Jump/conditional ops. | 28 | // Jump/conditional ops. |
24 | // - Take a label as argument. | 29 | // - Take a label as argument. |
25 | // - For conditional jumps, the last value in the stack is used. | 30 | // - For conditional jumps, the last value in the stack is used. |
@@ -43,8 +48,10 @@ static const char* ops_str[] = { | |||
43 | [OP_MUL] = "OP_MUL", | 48 | [OP_MUL] = "OP_MUL", |
44 | [OP_DIV] = "OP_DIV", | 49 | [OP_DIV] = "OP_DIV", |
45 | [OP_MOD] = "OP_MOD", | 50 | [OP_MOD] = "OP_MOD", |
51 | [OP_NOT] = "OP_NOT", | ||
46 | [OP_PUSH] = "OP_PUSH", | 52 | [OP_PUSH] = "OP_PUSH", |
47 | [OP_DROP] = "OP_DROP", | 53 | [OP_DROP] = "OP_DROP", |
54 | [OP_LABEL] = "OP_LABEL", | ||
48 | [OP_JUMP] = "OP_JUMP", | 55 | [OP_JUMP] = "OP_JUMP", |
49 | [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", | 56 | [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", |
50 | [OP_PRINT] = "OP_PRINT", | 57 | [OP_PRINT] = "OP_PRINT", |
@@ -54,7 +61,17 @@ static const char* ops_str[] = { | |||
54 | 61 | ||
55 | typedef struct Instruction { | 62 | typedef struct Instruction { |
56 | Op op; | 63 | Op op; |
57 | Object *argument; | 64 | |
65 | // Op arguments. | ||
66 | union { | ||
67 | // OP_PUSH | ||
68 | Object *argument; | ||
69 | |||
70 | // OP_LABEL | ||
71 | // OP_JUMP | ||
72 | // OP_JUMP_IF_FALSE | ||
73 | size_t label_id; | ||
74 | }; | ||
58 | 75 | ||
59 | // Original line/column for debugging purposes. | 76 | // Original line/column for debugging purposes. |
60 | size_t line; | 77 | size_t line; |
@@ -75,9 +92,21 @@ typedef struct Procedure { | |||
75 | 92 | ||
76 | typedef struct ProgramIr { | 93 | typedef struct ProgramIr { |
77 | Procedure **procedures; | 94 | Procedure **procedures; |
78 | Object **constants; | 95 | size_t labels; |
79 | } ProgramIr; | 96 | } ProgramIr; |
80 | 97 | ||
98 | #define INST_SIMPLE(PROC, OP, LINE, COL) \ | ||
99 | do { \ | ||
100 | Instruction inst = (Instruction){(OP), NULL, (LINE), (COL)}; \ | ||
101 | array_push((PROC)->instructions, inst); \ | ||
102 | } while(false); | ||
103 | |||
104 | #define INST_ARG(PROC, OP, ARG, LINE, COL) \ | ||
105 | do { \ | ||
106 | Instruction inst = (Instruction){(OP), (ARG), (LINE), (COL)}; \ | ||
107 | array_push((PROC)->instructions, inst); \ | ||
108 | } while(false); | ||
109 | |||
81 | void | 110 | void |
82 | print_instruction(Instruction *instruction) { | 111 | print_instruction(Instruction *instruction) { |
83 | printf("%4ld:%-4ld ", instruction->line, instruction->col); | 112 | printf("%4ld:%-4ld ", instruction->line, instruction->col); |
@@ -87,6 +116,11 @@ print_instruction(Instruction *instruction) { | |||
87 | printf("%-16s -> ", ops_str[op]); | 116 | printf("%-16s -> ", ops_str[op]); |
88 | OBJ_PRINT(instruction->argument); | 117 | OBJ_PRINT(instruction->argument); |
89 | } break; | 118 | } break; |
119 | case OP_JUMP: | ||
120 | case OP_JUMP_IF_FALSE: | ||
121 | case OP_LABEL: { | ||
122 | printf("%-16s -> %zu\n", ops_str[op], instruction->label_id); | ||
123 | } break; | ||
90 | default: { | 124 | default: { |
91 | printf("%s\n", ops_str[op]); | 125 | printf("%s\n", ops_str[op]); |
92 | } break; | 126 | } break; |
@@ -122,23 +156,51 @@ compile_arithmetic(ProgramIr *program, Procedure *proc, Op op, | |||
122 | while (args != NULL) { | 156 | while (args != NULL) { |
123 | compile_object(program, proc, args->head); | 157 | compile_object(program, proc, args->head); |
124 | args = args->tail; | 158 | args = args->tail; |
125 | Instruction inst = (Instruction){op, NULL, line, col}; | 159 | INST_SIMPLE(proc, op, line, col); |
126 | array_push(proc->instructions, inst); | ||
127 | } | 160 | } |
128 | } | 161 | } |
129 | 162 | ||
130 | void | 163 | void |
131 | compile_print(ProgramIr *program, Procedure *proc, | 164 | compile_print(ProgramIr *program, Procedure *proc, |
132 | size_t line, size_t col, Object *args) { | 165 | size_t line, size_t col, Object *args) { |
133 | Instruction inst = (Instruction){OP_PRINT, NULL, line, col}; | ||
134 | while (args != NULL) { | 166 | while (args != NULL) { |
135 | compile_object(program, proc, args->head); | 167 | compile_object(program, proc, args->head); |
136 | args = args->tail; | 168 | args = args->tail; |
137 | array_push(proc->instructions, inst); | 169 | INST_SIMPLE(proc, OP_PRINT, line, col); |
138 | } | 170 | } |
139 | } | 171 | } |
140 | 172 | ||
141 | void | 173 | void |
174 | compile_not(ProgramIr *program, Procedure *proc, | ||
175 | size_t line, size_t col, Object *args) { | ||
176 | compile_object(program, proc, args->head); | ||
177 | INST_SIMPLE(proc, OP_NOT, line, col); | ||
178 | } | ||
179 | |||
180 | void | ||
181 | compile_and(ProgramIr *program, Procedure *proc, | ||
182 | size_t line, size_t col, Object *args) { | ||
183 | // Generate labels. | ||
184 | size_t label_false = program->labels++; | ||
185 | size_t label_exit = program->labels++; | ||
186 | while (args != NULL) { | ||
187 | compile_object(program, proc, args->head); | ||
188 | args = args->tail; | ||
189 | INST_ARG(proc, OP_JUMP_IF_FALSE, label_false, line, col); | ||
190 | } | ||
191 | INST_ARG(proc, OP_PUSH, &obj_true, line, col); | ||
192 | INST_ARG(proc, OP_JUMP, label_exit, line, col); | ||
193 | INST_ARG(proc, OP_LABEL, label_false, line, col); | ||
194 | INST_ARG(proc, OP_PUSH, &obj_false, line, col); | ||
195 | INST_ARG(proc, OP_LABEL, label_exit, line, col); | ||
196 | } | ||
197 | |||
198 | void | ||
199 | compile_or(ProgramIr *program, Procedure *proc, | ||
200 | size_t line, size_t col, Object *args) { | ||
201 | } | ||
202 | |||
203 | void | ||
142 | compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { | 204 | compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { |
143 | size_t line = obj->line; | 205 | size_t line = obj->line; |
144 | size_t col = obj->col; | 206 | size_t col = obj->col; |
@@ -162,6 +224,15 @@ compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { | |||
162 | case BUILTIN_PRINT: { | 224 | case BUILTIN_PRINT: { |
163 | compile_print(program, proc, line, col, obj->tail); | 225 | compile_print(program, proc, line, col, obj->tail); |
164 | } break; | 226 | } break; |
227 | case BUILTIN_NOT: { | ||
228 | compile_not(program, proc, line, col, obj->tail); | ||
229 | } break; | ||
230 | case BUILTIN_AND: { | ||
231 | compile_and(program, proc, line, col, obj->tail); | ||
232 | } break; | ||
233 | case BUILTIN_OR: { | ||
234 | compile_or(program, proc, line, col, obj->tail); | ||
235 | } break; | ||
165 | default: { | 236 | default: { |
166 | assert(false && "builtin not implemented"); | 237 | assert(false && "builtin not implemented"); |
167 | } break; | 238 | } break; |
@@ -179,8 +250,7 @@ compile_object(ProgramIr *program, Procedure *proc, Object *obj) { | |||
179 | case OBJ_TYPE_FALSE: | 250 | case OBJ_TYPE_FALSE: |
180 | case OBJ_TYPE_STRING: | 251 | case OBJ_TYPE_STRING: |
181 | case OBJ_TYPE_FIXNUM: { | 252 | case OBJ_TYPE_FIXNUM: { |
182 | Instruction inst = (Instruction){OP_PUSH, obj, obj->line, obj->col}; | 253 | INST_ARG(proc, OP_PUSH, obj, obj->line, obj->col); |
183 | array_push(proc->instructions, inst); | ||
184 | } break; | 254 | } break; |
185 | case OBJ_TYPE_PAIR: { compile_proc_call(program, proc, obj); } break; | 255 | case OBJ_TYPE_PAIR: { compile_proc_call(program, proc, obj); } break; |
186 | // case OBJ_TYPE_IF: { compile_if(obj); } break; | 256 | // case OBJ_TYPE_IF: { compile_if(obj); } break; |
@@ -200,7 +270,6 @@ ProgramIr | |||
200 | compile(Program program) { | 270 | compile(Program program) { |
201 | ProgramIr program_ir = {0}; | 271 | ProgramIr program_ir = {0}; |
202 | array_init(program_ir.procedures, 0); | 272 | array_init(program_ir.procedures, 0); |
203 | array_init(program_ir.constants, 0); | ||
204 | Procedure *main = proc_alloc(&program_ir, STRING("main")); | 273 | Procedure *main = proc_alloc(&program_ir, STRING("main")); |
205 | 274 | ||
206 | for (size_t i = 0; i < array_size(program.roots); i++) { | 275 | for (size_t i = 0; i < array_size(program.roots); i++) { |
diff --git a/src/parser.c b/src/parser.c index ce0c395..29a0444 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -5,6 +5,7 @@ static Object **objects = NULL; | |||
5 | static Root *roots = NULL; | 5 | static Root *roots = NULL; |
6 | static Environment **environments = NULL; | 6 | static Environment **environments = NULL; |
7 | 7 | ||
8 | // Builtin procedures. | ||
8 | static Object builtins[] = { | 9 | static Object builtins[] = { |
9 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_ADD, .builtin_text = STRING("+") }, | 10 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_ADD, .builtin_text = STRING("+") }, |
10 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_SUB, .builtin_text = STRING("-") }, | 11 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_SUB, .builtin_text = STRING("-") }, |
@@ -29,6 +30,11 @@ static Object builtins[] = { | |||
29 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_CDR, .builtin_text = STRING("cdr") }, | 30 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_CDR, .builtin_text = STRING("cdr") }, |
30 | }; | 31 | }; |
31 | 32 | ||
33 | // Static singleton objects. | ||
34 | static Object obj_nil = { .type = OBJ_TYPE_NIL }; | ||
35 | static Object obj_true = { .type = OBJ_TYPE_TRUE }; | ||
36 | static Object obj_false = { .type = OBJ_TYPE_FALSE }; | ||
37 | |||
32 | Token | 38 | Token |
33 | peek_token(const Parser *parser) { | 39 | peek_token(const Parser *parser) { |
34 | if (parser->current >= array_size(parser->tokens)) { | 40 | if (parser->current >= array_size(parser->tokens)) { |
@@ -80,9 +86,10 @@ parse_fixnum(Token tok) { | |||
80 | 86 | ||
81 | Object * | 87 | Object * |
82 | parse_bool(Token tok) { | 88 | parse_bool(Token tok) { |
83 | ObjectType type = tok.type == TOKEN_TRUE ? OBJ_TYPE_TRUE : OBJ_TYPE_FALSE; | 89 | if (tok.type == TOKEN_TRUE) { |
84 | Object *ret = object_alloc(tok, type); | 90 | return &obj_true; |
85 | return ret; | 91 | } |
92 | return &obj_false; | ||
86 | } | 93 | } |
87 | 94 | ||
88 | Object * | 95 | Object * |
@@ -444,7 +451,7 @@ parse_tree(Parser *parser, Errors *errors) { | |||
444 | return parse_symbol(tok); | 451 | return parse_symbol(tok); |
445 | } break; | 452 | } break; |
446 | case TOKEN_NIL: { | 453 | case TOKEN_NIL: { |
447 | return object_alloc(tok, OBJ_TYPE_NIL); | 454 | return &obj_nil; |
448 | } break; | 455 | } break; |
449 | default: { | 456 | default: { |
450 | break; | 457 | break; |