aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-12-23 12:07:42 +0100
committerBad Diode <bd@badd10de.dev>2021-12-23 12:07:42 +0100
commit64d282b77633338ac3ff9fe924fe86bfab1012e6 (patch)
tree9a903531f378fa1c736166c38664f42dfc235256
parent7146084c7730274c7739db5e1ede7e5ee910b237 (diff)
downloadbdl-64d282b77633338ac3ff9fe924fe86bfab1012e6.tar.gz
bdl-64d282b77633338ac3ff9fe924fe86bfab1012e6.zip
Add `not` and `and` builtins for ir compilation
-rw-r--r--src/ir.h87
-rw-r--r--src/parser.c15
2 files changed, 89 insertions, 13 deletions
diff --git a/src/ir.h b/src/ir.h
index 845bf63..bb15596 100644
--- a/src/ir.h
+++ b/src/ir.h
@@ -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
55typedef struct Instruction { 62typedef 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
76typedef struct ProgramIr { 93typedef 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
81void 110void
82print_instruction(Instruction *instruction) { 111print_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
130void 163void
131compile_print(ProgramIr *program, Procedure *proc, 164compile_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
141void 173void
174compile_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
180void
181compile_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
198void
199compile_or(ProgramIr *program, Procedure *proc,
200 size_t line, size_t col, Object *args) {
201}
202
203void
142compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { 204compile_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
200compile(Program program) { 270compile(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;
5static Root *roots = NULL; 5static Root *roots = NULL;
6static Environment **environments = NULL; 6static Environment **environments = NULL;
7 7
8// Builtin procedures.
8static Object builtins[] = { 9static 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.
34static Object obj_nil = { .type = OBJ_TYPE_NIL };
35static Object obj_true = { .type = OBJ_TYPE_TRUE };
36static Object obj_false = { .type = OBJ_TYPE_FALSE };
37
32Token 38Token
33peek_token(const Parser *parser) { 39peek_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
81Object * 87Object *
82parse_bool(Token tok) { 88parse_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
88Object * 95Object *
@@ -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;