aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-16 21:36:49 +0200
committerBad Diode <bd@badd10de.dev>2024-06-16 21:36:49 +0200
commitbf4aa41a445986658f4ee931305d9caf496e9072 (patch)
tree3fbc53824ac50e24050420ef6aa541cc7ea84af3
parentb86d262b9fe27131d8163a6ba49957736691b1d0 (diff)
downloadbdl-bf4aa41a445986658f4ee931305d9caf496e9072.tar.gz
bdl-bf4aa41a445986658f4ee931305d9caf496e9072.zip
Add parsing for logical operators
-rw-r--r--Makefile2
-rw-r--r--src/main.c99
-rw-r--r--tests/comparisons.bad13
3 files changed, 101 insertions, 13 deletions
diff --git a/Makefile b/Makefile
index 7fed16b..082ab87 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
5SRC_DIR := src 5SRC_DIR := src
6BUILD_DIR := build 6BUILD_DIR := build
7SRC_MAIN := $(SRC_DIR)/main.c 7SRC_MAIN := $(SRC_DIR)/main.c
8SRC_BAD := tests/expressions.bad 8SRC_BAD := tests/comparisons.bad
9WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h") 9WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h")
10INC_DIRS := $(shell find $(SRC_DIR) -type d) 10INC_DIRS := $(shell find $(SRC_DIR) -type d)
11INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 11INC_FLAGS := $(addprefix -I,$(INC_DIRS))
diff --git a/src/main.c b/src/main.c
index f15afed..1c71a6e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -39,14 +39,28 @@ print_tokens(Str path, Token *tokens) {
39// 39//
40 40
41typedef enum NodeKind { 41typedef enum NodeKind {
42 NODE_NUM_INT, 42 // Arithmetic.
43 NODE_NUM_FLOAT,
44 // TODO: probably want to handle ints/unsigneds/floats separately.
45 NODE_ADD, 43 NODE_ADD,
46 NODE_SUB, 44 NODE_SUB,
47 NODE_DIV, 45 NODE_DIV,
48 NODE_MUL, 46 NODE_MUL,
49 NODE_MOD, 47 NODE_MOD,
48 // Logical.
49 NODE_NOT,
50 NODE_AND,
51 NODE_OR,
52 NODE_EQ,
53 NODE_NOTEQ,
54 NODE_LT,
55 NODE_GT,
56 NODE_LE,
57 NODE_GE,
58 // Literals.
59 NODE_NUM_INT,
60 NODE_NUM_FLOAT,
61 NODE_TRUE,
62 NODE_FALSE,
63 NODE_NIL,
50} NodeKind; 64} NodeKind;
51 65
52Str node_str[] = { 66Str node_str[] = {
@@ -56,10 +70,22 @@ Str node_str[] = {
56 [NODE_DIV] = cstr("DIV"), 70 [NODE_DIV] = cstr("DIV"),
57 [NODE_MUL] = cstr("MUL"), 71 [NODE_MUL] = cstr("MUL"),
58 [NODE_MOD] = cstr("MOD"), 72 [NODE_MOD] = cstr("MOD"),
59 73 // Logical.
74 [NODE_NOT] = cstr("NOT"),
75 [NODE_AND] = cstr("AND"),
76 [NODE_OR] = cstr("OR"),
77 [NODE_EQ] = cstr("EQ"),
78 [NODE_NOTEQ] = cstr("NOTEQ"),
79 [NODE_LT] = cstr("LT"),
80 [NODE_GT] = cstr("GT"),
81 [NODE_LE] = cstr("LE"),
82 [NODE_GE] = cstr("GE"),
60 // Literals. 83 // Literals.
61 [NODE_NUM_INT] = cstr("INT"), 84 [NODE_NUM_INT] = cstr("INT"),
62 [NODE_NUM_FLOAT] = cstr("FLOAT"), 85 [NODE_NUM_FLOAT] = cstr("FLOAT"),
86 [NODE_TRUE] = cstr("TRUE"),
87 [NODE_FALSE] = cstr("FALSE"),
88 [NODE_NIL] = cstr("NIL"),
63}; 89};
64 90
65typedef struct Node { 91typedef struct Node {
@@ -135,16 +161,32 @@ void parse_grouping(Parser *parser);
135void parse_unary(Parser *parser); 161void parse_unary(Parser *parser);
136void parse_binary(Parser *parser); 162void parse_binary(Parser *parser);
137void parse_number(Parser *parser); 163void parse_number(Parser *parser);
164void parse_literal(Parser *parser);
138 165
139ParseRule parse_rules[] = { 166ParseRule parse_rules[] = {
140 [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE}, 167 [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE},
168 // Arithmetic.
141 [TOK_SUB] = {parse_unary, parse_binary, PREC_TERM}, 169 [TOK_SUB] = {parse_unary, parse_binary, PREC_TERM},
142 [TOK_ADD] = {NULL, parse_binary, PREC_TERM}, 170 [TOK_ADD] = {NULL, parse_binary, PREC_TERM},
143 [TOK_DIV] = {NULL, parse_binary, PREC_FACTOR}, 171 [TOK_DIV] = {NULL, parse_binary, PREC_FACTOR},
144 [TOK_MUL] = {NULL, parse_binary, PREC_FACTOR}, 172 [TOK_MUL] = {NULL, parse_binary, PREC_FACTOR},
145 [TOK_MOD] = {NULL, parse_binary, PREC_FACTOR}, 173 [TOK_MOD] = {NULL, parse_binary, PREC_FACTOR},
174 // Logical.
175 [TOK_NOT] = {parse_unary, NULL, PREC_NONE},
176 [TOK_AND] = {NULL, parse_binary, PREC_AND},
177 [TOK_OR] = {NULL, parse_binary, PREC_OR},
178 [TOK_EQ] = {NULL, parse_binary, PREC_EQUALITY},
179 [TOK_NOTEQ] = {NULL, parse_binary, PREC_EQUALITY},
180 [TOK_LT] = {NULL, parse_binary, PREC_COMPARISON},
181 [TOK_GT] = {NULL, parse_binary, PREC_COMPARISON},
182 [TOK_LE] = {NULL, parse_binary, PREC_COMPARISON},
183 [TOK_GE] = {NULL, parse_binary, PREC_COMPARISON},
184 // Literals.
146 [TOK_NUM_INT] = {parse_number, NULL, PREC_NONE}, 185 [TOK_NUM_INT] = {parse_number, NULL, PREC_NONE},
147 [TOK_NUM_FLOAT] = {parse_number, NULL, PREC_NONE}, 186 [TOK_NUM_FLOAT] = {parse_number, NULL, PREC_NONE},
187 [TOK_TRUE] = {parse_literal, NULL, PREC_NONE},
188 [TOK_FALSE] = {parse_literal, NULL, PREC_NONE},
189 [TOK_NIL] = {parse_literal, NULL, PREC_NONE},
148 [TOK_EOF] = {NULL, NULL, PREC_NONE}, 190 [TOK_EOF] = {NULL, NULL, PREC_NONE},
149}; 191};
150 192
@@ -209,13 +251,37 @@ parse_unary(Parser *parser) {
209 print("parsing unary "); 251 print("parsing unary ");
210 print_token(prev); 252 print_token(prev);
211#endif 253#endif
212 TokenKind kind = prev.kind; 254 parse_expr(parser, PREC_UNARY);
213 parse_expr(parser, PREC_LOW); 255 Node *node = NULL;
214 // TODO: ... 256 switch (prev.kind) {
215 switch (kind) { 257 case TOK_NOT: node = node_alloc(NODE_NOT, prev, parser->storage); break;
216 // case TOKEN_MINUS: emitByte(OP_NEGATE); break; 258 default: break; // Unreachable.
259 }
260 node->left = array_pop(parser->nodes);
261 array_push(parser->nodes, node, parser->storage);
262}
263
264void
265parse_literal(Parser *parser) {
266 Token prev = parser->previous;
267#if DEBUG == 1
268 print("parsing literal ");
269 print_token(prev);
270#endif
271 Node *node = NULL;
272 switch (prev.kind) {
273 case TOK_TRUE: {
274 node = node_alloc(NODE_TRUE, prev, parser->storage);
275 } break;
276 case TOK_FALSE: {
277 node = node_alloc(NODE_FALSE, prev, parser->storage);
278 } break;
279 case TOK_NIL: {
280 node = node_alloc(NODE_NIL, prev, parser->storage);
281 } break;
217 default: return; // Unreachable. 282 default: return; // Unreachable.
218 } 283 }
284 array_push(parser->nodes, node, parser->storage);
219} 285}
220 286
221void 287void
@@ -225,17 +291,26 @@ parse_binary(Parser *parser) {
225 print("parsing binary "); 291 print("parsing binary ");
226 print_token(prev); 292 print_token(prev);
227#endif 293#endif
228 TokenKind kind = prev.kind; 294 ParseRule rule = parse_rules[prev.kind];
229 ParseRule rule = parse_rules[kind];
230 parse_expr(parser, rule.precedence + 1); 295 parse_expr(parser, rule.precedence + 1);
231 296
232 Node *node; 297 Node *node;
233 switch (kind) { 298 switch (prev.kind) {
234 case TOK_ADD: node = node_alloc(NODE_ADD, prev, parser->storage); break; 299 case TOK_ADD: node = node_alloc(NODE_ADD, prev, parser->storage); break;
235 case TOK_SUB: node = node_alloc(NODE_SUB, prev, parser->storage); break; 300 case TOK_SUB: node = node_alloc(NODE_SUB, prev, parser->storage); break;
236 case TOK_MUL: node = node_alloc(NODE_MUL, prev, parser->storage); break; 301 case TOK_MUL: node = node_alloc(NODE_MUL, prev, parser->storage); break;
237 case TOK_DIV: node = node_alloc(NODE_DIV, prev, parser->storage); break; 302 case TOK_DIV: node = node_alloc(NODE_DIV, prev, parser->storage); break;
238 case TOK_MOD: node = node_alloc(NODE_MOD, prev, parser->storage); break; 303 case TOK_MOD: node = node_alloc(NODE_MOD, prev, parser->storage); break;
304 case TOK_AND: node = node_alloc(NODE_AND, prev, parser->storage); break;
305 case TOK_OR: node = node_alloc(NODE_OR, prev, parser->storage); break;
306 case TOK_EQ: node = node_alloc(NODE_EQ, prev, parser->storage); break;
307 case TOK_NOTEQ:
308 node = node_alloc(NODE_NOTEQ, prev, parser->storage);
309 break;
310 case TOK_LT: node = node_alloc(NODE_LT, prev, parser->storage); break;
311 case TOK_GT: node = node_alloc(NODE_GT, prev, parser->storage); break;
312 case TOK_LE: node = node_alloc(NODE_LE, prev, parser->storage); break;
313 case TOK_GE: node = node_alloc(NODE_GE, prev, parser->storage); break;
239 default: { 314 default: {
240 parse_emit_err(parser, prev, cstr("unreachable")); 315 parse_emit_err(parser, prev, cstr("unreachable"));
241 return; 316 return;
diff --git a/tests/comparisons.bad b/tests/comparisons.bad
new file mode 100644
index 0000000..7bc5d33
--- /dev/null
+++ b/tests/comparisons.bad
@@ -0,0 +1,13 @@
1true != false
2!true == false
3!(true == !false) != true
4(true == true) != true != false
5!(true || false)
6
72 >= 1 && 2 > 1
83 >= 3 || 4 <= 5
94 < (5 + 6) == true
10
11nil != false
12nil != true
13nil != 1