diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/badlib.h | 4 | ||||
-rw-r--r-- | src/main.c | 192 |
2 files changed, 191 insertions, 5 deletions
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 | ||
812 | static inline void * | 813 | static 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); |
@@ -21,28 +21,202 @@ init(void) { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | void | 23 | void |
24 | print_token(Token tok) { | ||
25 | println("%d:%d\t%s %s", tok.line, tok.col, token_str[tok.type], tok.val); | ||
26 | } | ||
27 | |||
28 | void | ||
29 | print_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 | |||
37 | typedef struct Parser { | ||
38 | Token current; | ||
39 | Token previous; | ||
40 | Token *tokens; | ||
41 | sz idx; | ||
42 | bool err; | ||
43 | bool panic; | ||
44 | } Parser; | ||
45 | |||
46 | typedef 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 | |||
60 | typedef void (*ParseFn)(Parser *); | ||
61 | |||
62 | typedef struct { | ||
63 | ParseFn prefix; | ||
64 | ParseFn infix; | ||
65 | ParsePrecedence precedence; | ||
66 | } ParseRule; | ||
67 | |||
68 | void parse_expr(Parser *parser); | ||
69 | void parse_advance(Parser *parser); | ||
70 | |||
71 | void parse_grouping(Parser *parser); | ||
72 | void parse_unary(Parser *parser); | ||
73 | void parse_binary(Parser *parser); | ||
74 | void parse_number(Parser *parser); | ||
75 | |||
76 | ParseRule 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 | |||
85 | void | ||
86 | parse_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 | |||
101 | void | ||
102 | parse_advance(Parser *parser) { | ||
103 | assert(parser); | ||
104 | parser->previous = parser->current; | ||
105 | parser->current = parser->tokens[parser->idx++]; | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | parse_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 | |||
117 | static void | ||
118 | parse_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 | |||
139 | void | ||
140 | parse_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 | |||
154 | void | ||
155 | parse_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 | |||
172 | void | ||
173 | parse_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 | |||
181 | void | ||
182 | parse_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 | |||
189 | void | ||
190 | parse_expr(Parser *parser) { | ||
191 | // TODO: ... | ||
192 | // Can this be prec_none instead? | ||
193 | parse_prec(parser, PREC_ASSIGNMENT); | ||
194 | } | ||
195 | |||
196 | void | ||
24 | process_file(Str path) { | 197 | process_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 | |||
53 | stop: | 235 | stop: |
54 | // Free up resources. | 236 | // Free up resources. |
55 | arena_destroy(&lexer_arena, os_allocator); | 237 | arena_destroy(&lexer_arena, os_allocator); |