aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-16 11:20:28 +0200
committerBad Diode <bd@badd10de.dev>2024-06-16 11:20:28 +0200
commitc2c8796511c90930c41700f5fcd2043a5c4405c9 (patch)
treee121750568a77ad56e599660fd340494849a01fe
parente7cd0d47a603e4199b0ee7daa2434fc0db602bad (diff)
downloadbdl-c2c8796511c90930c41700f5fcd2043a5c4405c9.tar.gz
bdl-c2c8796511c90930c41700f5fcd2043a5c4405c9.zip
Setup initial Pratt parser
-rw-r--r--Makefile2
-rw-r--r--src/badlib.h4
-rw-r--r--src/main.c192
-rw-r--r--tests/expressions.bad4
4 files changed, 196 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index 4e66983..987ecd8 100644
--- a/Makefile
+++ b/Makefile
@@ -44,7 +44,7 @@ $(BUILD_DIR):
44 mkdir -p $(BUILD_DIR) 44 mkdir -p $(BUILD_DIR)
45 45
46run: $(BIN) 46run: $(BIN)
47 $(BIN) tests/literals.bad 47 $(BIN) tests/expressions.bad
48 48
49viz_lex: $(BIN) 49viz_lex: $(BIN)
50 $(BIN) -pl example.bdl 50 $(BIN) -pl example.bdl
diff --git a/src/badlib.h b/src/badlib.h
index a91fcf8..71f4bee 100644
--- a/src/badlib.h
+++ b/src/badlib.h
@@ -11,6 +11,7 @@
11// - Implement binary search for searching into an array: 11// - Implement binary search for searching into an array:
12// SearchResult find_array(Array haystack, Array needle). 12// SearchResult find_array(Array haystack, Array needle).
13// - Logger functions for hash map and queues. 13// - Logger functions for hash map and queues.
14// - Make assert/abort macros dump the file name/line?
14// 15//
15 16
16#include <stdarg.h> 17#include <stdarg.h>
@@ -811,6 +812,9 @@ _array_reserve(sz num_elem, sz type_size, Arena *a) {
811 812
812static inline void * 813static inline void *
813_array_maybe_grow(void *arr, sz type_size, Arena *a) { 814_array_maybe_grow(void *arr, sz type_size, Arena *a) {
815 if (!arr) {
816 arr = _array_reserve(0, 0, a);
817 }
814 ArrayHeader *head = array_head(arr); 818 ArrayHeader *head = array_head(arr);
815 if (head->cap == head->size) { 819 if (head->cap == head->size) {
816 sz prev_size = head->cap * type_size + sizeof(ArrayHeader); 820 sz prev_size = head->cap * type_size + sizeof(ArrayHeader);
diff --git a/src/main.c b/src/main.c
index 9848b8b..44a7bf1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -21,28 +21,202 @@ init(void) {
21} 21}
22 22
23void 23void
24print_token(Token tok) {
25 println("%d:%d\t%s %s", tok.line, tok.col, token_str[tok.type], tok.val);
26}
27
28void
29print_tokens(Str path, Token *tokens) {
30 for (sz i = 0; i < array_size(tokens); i++) {
31 Token tok = tokens[i];
32 print("%s:", path);
33 print_token(tok);
34 }
35}
36
37typedef struct Parser {
38 Token current;
39 Token previous;
40 Token *tokens;
41 sz idx;
42 bool err;
43 bool panic;
44} Parser;
45
46typedef enum {
47 PREC_NONE = 0,
48 PREC_ASSIGNMENT, // = FIXME: this may not happen in our lang?
49 PREC_OR, // ||
50 PREC_AND, // &&
51 PREC_EQUALITY, // == !=
52 PREC_COMPARISON, // < > <= >=
53 PREC_TERM, // + -
54 PREC_FACTOR, // * /
55 PREC_UNARY, // ! -
56 PREC_CALL, // . ()
57 PREC_PRIMARY
58} ParsePrecedence;
59
60typedef void (*ParseFn)(Parser *);
61
62typedef struct {
63 ParseFn prefix;
64 ParseFn infix;
65 ParsePrecedence precedence;
66} ParseRule;
67
68void parse_expr(Parser *parser);
69void parse_advance(Parser *parser);
70
71void parse_grouping(Parser *parser);
72void parse_unary(Parser *parser);
73void parse_binary(Parser *parser);
74void parse_number(Parser *parser);
75
76ParseRule parse_rules[] = {
77 [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE},
78 [TOK_SUB] = {parse_unary, parse_binary, PREC_TERM},
79 [TOK_ADD] = {NULL, parse_binary, PREC_TERM},
80 [TOK_DIV] = {NULL, parse_binary, PREC_FACTOR},
81 [TOK_MUL] = {NULL, parse_binary, PREC_FACTOR},
82 [TOK_NUMBER] = {parse_number, NULL, PREC_NONE},
83};
84
85void
86parse_emit_err(Parser *parser, Token token, Str msg) {
87 if (parser->panic) {
88 return;
89 }
90 parser->panic = true;
91 parser->err = true;
92 eprint("%d:%d: error: %s", token.line, token.col, msg);
93
94 if (token.type == TOK_EOF) {
95 eprintln(" -> at end of the file");
96 } else if (token.type != TOK_UNKNOWN) {
97 eprintln(" -> at %s", token.val);
98 }
99}
100
101void
102parse_advance(Parser *parser) {
103 assert(parser);
104 parser->previous = parser->current;
105 parser->current = parser->tokens[parser->idx++];
106}
107
108static void
109parse_consume(Parser *parser, TokenType type, Str msg) {
110 if (parser->current.type == type) {
111 parse_advance(parser);
112 return;
113 }
114 parse_emit_err(parser, parser->current, msg);
115}
116
117static void
118parse_prec(Parser *parser, ParsePrecedence precedence) {
119 parse_advance(parser);
120 ParseFn prefix = parse_rules[parser->previous.type].prefix;
121 if (prefix == NULL) {
122 parse_emit_err(parser, parser->previous, cstr("expected expression"));
123 return;
124 }
125 prefix(parser);
126
127 while (precedence <= parse_rules[parser->current.type].precedence) {
128 parse_advance(parser);
129 ParseFn infix = parse_rules[parser->previous.type].infix;
130 if (infix == NULL) {
131 parse_emit_err(parser, parser->previous,
132 cstr("expected expression"));
133 return;
134 }
135 infix(parser);
136 }
137}
138
139void
140parse_unary(Parser *parser) {
141 print("parsing unary ");
142 print_token(parser->previous);
143 parse_prec(parser, PREC_ASSIGNMENT);
144 TokenType type = parser->previous.type;
145 parse_expr(parser);
146 // TODO: ...
147 switch (type) {
148 // case TOKEN_MINUS: emitByte(OP_NEGATE); break;
149 default:
150 return; // Unreachable.
151 }
152}
153
154void
155parse_binary(Parser *parser) {
156 print("parsing binary ");
157 print_token(parser->previous);
158 TokenType operatorType = parser->previous.type;
159 ParseRule rule = parse_rules[operatorType];
160 parse_prec(parser, rule.precedence + 1);
161
162 // TODO: ...
163 // switch (operatorType) {
164 // case TOKEN_PLUS: emitByte(OP_ADD); break;
165 // case TOKEN_MINUS: emitByte(OP_SUBTRACT); break;
166 // case TOKEN_STAR: emitByte(OP_MULTIPLY); break;
167 // case TOKEN_SLASH: emitByte(OP_DIVIDE); break;
168 // default: return; // Unreachable.
169 // }
170}
171
172void
173parse_number(Parser *parser) {
174 print("parsing number ");
175 print_token(parser->previous);
176 // TODO: ...
177 // double value = strtod(parser.previous.start, NULL);
178 // emitConstant(value);
179}
180
181void
182parse_grouping(Parser *parser) {
183 print("parsing group ");
184 print_token(parser->previous);
185 parse_expr(parser);
186 parse_consume(parser, TOK_RPAREN, cstr("expected ')' after expression"));
187}
188
189void
190parse_expr(Parser *parser) {
191 // TODO: ...
192 // Can this be prec_none instead?
193 parse_prec(parser, PREC_ASSIGNMENT);
194}
195
196void
24process_file(Str path) { 197process_file(Str path) {
25 Arena lexer_arena = arena_create(LEXER_MEM, os_allocator); 198 Arena lexer_arena = arena_create(LEXER_MEM, os_allocator);
26 199
27 FileContents file = platform_read_file(path, &lexer_arena); 200 FileContents file = platform_read_file(path, &lexer_arena);
28 if (file.err) { 201 if (file.err) {
29 printf("file.err: %d\n", file.err);
30 eprintln("%s: error: %s", path, cstr("WOT")); 202 eprintln("%s: error: %s", path, cstr("WOT"));
31 return; 203 return;
32 } 204 }
205 sz errors = 0;
33 206
34 Scanner scanner = { 207 // Lexer.
35 .str = file.data, 208 Scanner scanner = {.str = file.data};
36 }; 209 Token *tokens = NULL;
37 Token tok = {0}; 210 Token tok = {0};
38 sz errors = 0;
39 while (tok.type != TOK_EOF) { 211 while (tok.type != TOK_EOF) {
40 tok = scan_token(&scanner); 212 tok = scan_token(&scanner);
41 if (tok.type == TOK_UNKNOWN) { 213 if (tok.type == TOK_UNKNOWN) {
42 eprintln("%s:%d:%d:%s %s", path, tok.line, tok.col, 214 eprintln("%s:%d:%d:%s %s", path, tok.line, tok.col,
43 token_str[tok.type], tok.val); 215 token_str[tok.type], tok.val);
44 errors++; 216 errors++;
217 continue;
45 } 218 }
219 array_push(tokens, tok, &lexer_arena);
46 } 220 }
47 221
48 // Only proceed if there are no errors. 222 // Only proceed if there are no errors.
@@ -50,6 +224,14 @@ process_file(Str path) {
50 goto stop; 224 goto stop;
51 } 225 }
52 226
227 // Parser.
228 Parser parser = {.tokens = tokens};
229 parse_advance(&parser);
230 parse_expr(&parser);
231 parse_consume(&parser, TOK_EOF, cstr("expected end of file"));
232
233 // print_tokens(path, tokens); // DEBUG
234
53stop: 235stop:
54 // Free up resources. 236 // Free up resources.
55 arena_destroy(&lexer_arena, os_allocator); 237 arena_destroy(&lexer_arena, os_allocator);
diff --git a/tests/expressions.bad b/tests/expressions.bad
new file mode 100644
index 0000000..c992a7a
--- /dev/null
+++ b/tests/expressions.bad
@@ -0,0 +1,4 @@
11 + 2 * 5 - 2
2; 1 + 2 * (5 - 2)
3; (1 + 2 * (5 - 2))
4; (1 + 2 * 5 - 2)