]> git.xonotic.org Git - xonotic/gmqcc.git/blob - parser.c
Keep track of blocklocal in parser_parse_block
[xonotic/gmqcc.git] / parser.c
1 #include <stdio.h>
2 #include <stdarg.h>
3
4 #include "gmqcc.h"
5 #include "lexer.h"
6
7 typedef struct {
8     lex_file *lex;
9     int      tok;
10
11     MEM_VECTOR_MAKE(ast_value*, globals);
12     MEM_VECTOR_MAKE(ast_function*, functions);
13
14     ast_function *function;
15     MEM_VECTOR_MAKE(ast_value*, locals);
16     size_t blocklocal;
17 } parser_t;
18
19 MEM_VEC_FUNCTIONS(parser_t, ast_value*, globals)
20 MEM_VEC_FUNCTIONS(parser_t, ast_value*, locals)
21 MEM_VEC_FUNCTIONS(parser_t, ast_function*, functions)
22
23 void parseerror(parser_t *parser, const char *fmt, ...)
24 {
25         va_list ap;
26
27     if (parser)
28             printf("error %s:%lu: ", parser->lex->tok->ctx.file, (unsigned long)parser->lex->tok->ctx.line);
29         else
30             printf("error: ");
31
32         va_start(ap, fmt);
33         vprintf(fmt, ap);
34         va_end(ap);
35
36         printf("\n");
37 }
38
39 bool parser_next(parser_t *parser)
40 {
41     /* lex_do kills the previous token */
42     parser->tok = lex_do(parser->lex);
43     if (parser->tok == TOKEN_EOF || parser->tok >= TOKEN_ERROR)
44         return false;
45     return true;
46 }
47
48 /* lift a token out of the parser so it's not destroyed by parser_next */
49 token *parser_lift(parser_t *parser)
50 {
51     token *tok = parser->lex->tok;
52     parser->lex->tok = NULL;
53     return tok;
54 }
55
56 #define parser_tokval(p) (p->lex->tok->value)
57 #define parser_token(p)  (p->lex->tok)
58 #define parser_ctx(p)    (p->lex->tok->ctx)
59
60 ast_value* parser_find_global(parser_t *parser, const char *name)
61 {
62     size_t i;
63     for (i = 0; i < parser->globals_count; ++i) {
64         if (!strcmp(parser->globals[i]->name, name))
65             return parser->globals[i];
66     }
67     return NULL;
68 }
69
70 ast_value* parser_find_local(parser_t *parser, const char *name, size_t upto)
71 {
72     size_t i;
73     for (i = parser->locals_count; i > upto;) {
74         --i;
75         if (!strcmp(parser->locals[i]->name, name))
76             return parser->locals[i];
77     }
78     return NULL;
79 }
80
81 ast_value* parser_find_var(parser_t *parser, const char *name)
82 {
83     ast_value *v;
84     v         = parser_find_local(parser, name, 0);
85     if (!v) v = parser_find_global(parser, name);
86     return v;
87 }
88
89 typedef struct {
90     MEM_VECTOR_MAKE(ast_value*, p);
91 } paramlist_t;
92 MEM_VEC_FUNCTIONS(paramlist_t, ast_value*, p)
93
94 ast_value *parser_parse_type(parser_t *parser, bool *isfunc)
95 {
96     paramlist_t params;
97     ast_value *var;
98     lex_ctx   ctx = parser_ctx(parser);
99     int vtype = parser_token(parser)->constval.t;
100
101     MEM_VECTOR_INIT(&params, p);
102
103     *isfunc = false;
104
105     if (!parser_next(parser))
106         return NULL;
107
108     if (parser->tok == '(') {
109         *isfunc = true;
110         while (true) {
111             ast_value *param;
112             bool dummy;
113
114             if (!parser_next(parser)) {
115                 MEM_VECTOR_CLEAR(&params, p);
116                 return NULL;
117             }
118
119             if (parser->tok == ')')
120                 break;
121
122             param = parser_parse_type(parser, &dummy);
123             (void)dummy;
124
125             if (!param) {
126                 MEM_VECTOR_CLEAR(&params, p);
127                 return NULL;
128             }
129
130             if (!paramlist_t_p_add(&params, param)) {
131                 MEM_VECTOR_CLEAR(&params, p);
132                 parseerror(parser, "Out of memory while parsing typename");
133                 return NULL;
134             }
135
136             if (parser->tok == ',')
137                 continue;
138             if (parser->tok == ')')
139                 break;
140             MEM_VECTOR_CLEAR(&params, p);
141             parseerror(parser, "Unexpected token");
142             return NULL;
143         }
144         if (!parser_next(parser)) {
145             MEM_VECTOR_CLEAR(&params, p);
146             return NULL;
147         }
148     }
149
150     var = ast_value_new(ctx, "<unnamed>", vtype);
151     if (!var) {
152         MEM_VECTOR_CLEAR(&params, p);
153         return NULL;
154     }
155     MEM_VECTOR_MOVE(&params, p, var, params);
156     return var;
157 }
158
159 bool parser_body_do(parser_t *parser, ast_block *block)
160 {
161     if (parser->tok == TOKEN_TYPENAME)
162     {
163         /* local variable */
164     }
165     else if (parser->tok == '{')
166     {
167         /* a block */
168     }
169
170     parseerror(parser, "expected statement");
171     return false;
172 }
173
174 ast_block* parser_parse_block(parser_t *parser)
175 {
176     size_t oldblocklocal;
177     ast_block *block = NULL;
178
179     oldblocklocal = parser->blocklocal;
180     parser->blocklocal = parser->locals_count;
181
182     if (!parser_next(parser)) { /* skip the '{' */
183         parseerror(parser, "expected function body");
184         goto cleanup;
185     }
186
187     block = ast_block_new(parser_ctx(parser));
188
189     while (parser->tok != TOKEN_EOF && parser->tok < TOKEN_ERROR)
190     {
191         if (parser->tok == '}')
192             break;
193
194         if (!parser_body_do(parser, block)) {
195             ast_block_delete(block);
196             block = NULL;
197             goto cleanup;
198         }
199     }
200
201 cleanup:
202     parser->blocklocal = oldblocklocal;
203     return block;
204 }
205
206 bool parser_variable(parser_t *parser, bool global)
207 {
208     bool isfunc = false;
209     ast_function *func = NULL;
210     lex_ctx ctx = parser_ctx(parser);
211     ast_value *var = parser_parse_type(parser, &isfunc);
212     if (!var)
213         return false;
214
215     if (parser->tok != TOKEN_IDENT) {
216         parseerror(parser, "expected variable name\n");
217         return false;
218     }
219
220     if (global && parser_find_global(parser, parser_tokval(parser))) {
221         ast_value_delete(var);
222         parseerror(parser, "global already exists: %s\n", parser_tokval(parser));
223         return false;
224     }
225
226     if (!global && parser_find_local(parser, parser_tokval(parser), parser->blocklocal)) {
227         ast_value_delete(var);
228         parseerror(parser, "local variable already exists: %s\n", parser_tokval(parser));
229         return false;
230     }
231
232     if (!ast_value_set_name(var, parser_tokval(parser))) {
233         parseerror(parser, "failed to set variable name\n");
234         ast_value_delete(var);
235         return false;
236     }
237
238     if (isfunc) {
239         /* a function was defined */
240         ast_value *fval;
241
242         /* turn var into a value of TYPE_FUNCTION, with the old var
243          * as return type
244          */
245         fval = ast_value_new(ctx, var->name, TYPE_FUNCTION);
246         func = ast_function_new(ctx, var->name, fval);
247         if (!fval || !func) {
248             ast_value_delete(var);
249             if (fval) ast_value_delete(fval);
250             if (func) ast_function_delete(func);
251             return false;
252         }
253
254         fval->expression.next = (ast_expression*)var;
255         MEM_VECTOR_MOVE(var, params, fval, params);
256
257         if (!parser_t_functions_add(parser, func)) {
258             ast_value_delete(var);
259             if (fval) ast_value_delete(fval);
260             if (func) ast_function_delete(func);
261             return false;
262         }
263
264         var = fval;
265     }
266
267     if ( ( global && !parser_t_globals_add(parser, var)) ||
268          (!global && !parser_t_locals_add(parser, var)) )
269     {
270         ast_value_delete(var);
271         return false;
272     }
273
274     if (!parser_next(parser)) {
275         ast_value_delete(var);
276         return false;
277     }
278
279     if (parser->tok == ';') {
280         if (!parser_next(parser))
281             return parser->tok == TOKEN_EOF;
282         return true;
283     }
284
285     if (parser->tok != '=') {
286         parseerror(parser, "expected '=' or ';'");
287         return false;
288     }
289
290     if (!parser_next(parser))
291         return false;
292
293     if (parser->tok == '#') {
294         if (!global) {
295             parseerror(parser, "cannot declare builtins within functions");
296             return false;
297         }
298         if (!isfunc || !func) {
299             parseerror(parser, "unexpected builtin number, '%s' is not a function", var->name);
300             return false;
301         }
302         if (!parser_next(parser)) {
303             parseerror(parser, "expected builtin number");
304             return false;
305         }
306         if (parser->tok != TOKEN_INTCONST) {
307             parseerror(parser, "builtin number must be an integer constant");
308             return false;
309         }
310         if (parser_token(parser)->constval.i <= 0) {
311             parseerror(parser, "builtin number must be positive integer greater than zero");
312             return false;
313         }
314
315         func->builtin = -parser_token(parser)->constval.i;
316     } else if (parser->tok == '{') {
317         /* function body */
318         ast_block *block;
319         ast_function *old = parser->function;
320
321         if (!global) {
322             parseerror(parser, "cannot declare functions within functions");
323             return false;
324         }
325
326         parser->function = func;
327         block = parser_parse_block(parser);
328         parser->function = old;
329
330         if (!block)
331             return false;
332
333         if (!ast_function_blocks_add(func, block)) {
334             ast_block_delete(block);
335             return false;
336         }
337         return true;
338     } else {
339         parseerror(parser, "TODO, const assignment");
340     }
341
342     if (!parser_next(parser))
343         return false;
344
345     if (parser->tok != ';') {
346         parseerror(parser, "expected semicolon");
347         return false;
348     }
349
350     (void)parser_next(parser);
351
352     return true;
353 }
354
355 bool parser_do(parser_t *parser)
356 {
357     if (parser->tok == TOKEN_TYPENAME)
358     {
359         return parser_variable(parser, true);
360     }
361     else if (parser->tok == TOKEN_KEYWORD)
362     {
363         /* handle 'var' and 'const' */
364         return false;
365     }
366     else if (parser->tok == '.')
367     {
368         /* entity-member declaration */
369         return false;
370     }
371     else
372     {
373         parseerror(parser, "unexpected token: %s", parser->lex->tok->value);
374         return false;
375     }
376     return true;
377 }
378
379 bool parser_compile(const char *filename)
380 {
381     size_t i;
382     parser_t *parser;
383     ir_builder *ir;
384
385     parser = (parser_t*)mem_a(sizeof(parser_t));
386     if (!parser)
387         return false;
388
389     memset(parser, 0, sizeof(parser));
390
391     MEM_VECTOR_INIT(parser, globals);
392     MEM_VECTOR_INIT(parser, locals);
393     parser->lex = lex_open(filename);
394
395     if (!parser->lex) {
396         printf("failed to open file \"%s\"\n", filename);
397         return false;
398     }
399
400     /* initial lexer/parser state */
401     parser->lex->flags.noops = true;
402
403     if (parser_next(parser))
404     {
405         while (parser->tok != TOKEN_EOF && parser->tok < TOKEN_ERROR)
406         {
407             if (!parser_do(parser)) {
408                 if (parser->tok == TOKEN_EOF)
409                     parseerror(parser, "unexpected eof");
410                 else
411                     parseerror(parser, "parse error\n");
412                 lex_close(parser->lex);
413                 mem_d(parser);
414                 return false;
415             }
416         }
417     }
418
419     lex_close(parser->lex);
420
421     ir = ir_builder_new("gmqcc_out");
422     if (!ir) {
423         printf("failed to allocate builder\n");
424         goto cleanup;
425     }
426
427     for (i = 0; i < parser->globals_count; ++i) {
428         if (!ast_global_codegen(parser->globals[i], ir)) {
429             printf("failed to generate global %s\n", parser->globals[i]->name);
430         }
431     }
432     for (i = 0; i < parser->functions_count; ++i) {
433         if (!ast_function_codegen(parser->functions[i], ir)) {
434             printf("failed to generate function %s\n", parser->functions[i]->name);
435         }
436         if (!ir_function_finalize(parser->functions[i]->ir_func)) {
437             printf("failed to finalize function %s\n", parser->functions[i]->name);
438         }
439     }
440
441     ir_builder_dump(ir, printf);
442
443 cleanup:
444     for (i = 0; i < parser->globals_count; ++i) {
445         ast_value_delete(parser->globals[i]);
446     }
447     MEM_VECTOR_CLEAR(parser, globals);
448
449     mem_d(parser);
450     return true;
451 }