]> git.xonotic.org Git - xonotic/gmqcc.git/blob - parser.c
ac499674ae5d79ae91b499f8bdc81fe8d93d82cb
[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 } parser_t;
14
15 MEM_VEC_FUNCTIONS(parser_t, ast_value*, globals)
16 MEM_VEC_FUNCTIONS(parser_t, ast_function*, functions)
17
18 void parseerror(parser_t *parser, const char *fmt, ...)
19 {
20         va_list ap;
21
22     if (parser)
23             printf("error %s:%lu: ", parser->lex->tok->ctx.file, (unsigned long)parser->lex->tok->ctx.line);
24         else
25             printf("error: ");
26
27         va_start(ap, fmt);
28         vprintf(fmt, ap);
29         va_end(ap);
30
31         printf("\n");
32 }
33
34 bool parser_next(parser_t *parser)
35 {
36     /* lex_do kills the previous token */
37     parser->tok = lex_do(parser->lex);
38     if (parser->tok == TOKEN_EOF || parser->tok >= TOKEN_ERROR)
39         return false;
40     return true;
41 }
42
43 /* lift a token out of the parser so it's not destroyed by parser_next */
44 token *parser_lift(parser_t *parser)
45 {
46     token *tok = parser->lex->tok;
47     parser->lex->tok = NULL;
48     return tok;
49 }
50
51 #define parser_tokval(p) (p->lex->tok->value)
52 #define parser_token(p)  (p->lex->tok)
53 #define parser_ctx(p)    (p->lex->tok->ctx)
54
55 ast_value* parser_find_global(parser_t *parser, const char *name)
56 {
57     size_t i;
58     for (i = 0; i < parser->globals_count; ++i) {
59         if (!strcmp(parser->globals[i]->name, name))
60             return parser->globals[i];
61     }
62     return NULL;
63 }
64
65 typedef struct {
66     MEM_VECTOR_MAKE(ast_value*, p);
67 } paramlist_t;
68 MEM_VEC_FUNCTIONS(paramlist_t, ast_value*, p)
69
70 ast_value *parser_parse_type(parser_t *parser, bool *isfunc)
71 {
72     paramlist_t params;
73     ast_value *var;
74     lex_ctx   ctx = parser_ctx(parser);
75     int vtype = parser_token(parser)->constval.t;
76
77     MEM_VECTOR_INIT(&params, p);
78
79     *isfunc = false;
80
81     if (!parser_next(parser))
82         return NULL;
83
84     if (parser->tok == '(') {
85         *isfunc = true;
86         while (true) {
87             ast_value *param;
88             bool dummy;
89
90             if (!parser_next(parser)) {
91                 MEM_VECTOR_CLEAR(&params, p);
92                 return NULL;
93             }
94
95             param = parser_parse_type(parser, &dummy);
96             (void)dummy;
97
98             if (!param) {
99                 MEM_VECTOR_CLEAR(&params, p);
100                 return NULL;
101             }
102
103             if (!paramlist_t_p_add(&params, param)) {
104                 MEM_VECTOR_CLEAR(&params, p);
105                 parseerror(parser, "Out of memory while parsing typename");
106                 return NULL;
107             }
108
109             if (parser->tok == ',')
110                 continue;
111             if (parser->tok == ')')
112                 break;
113             MEM_VECTOR_CLEAR(&params, p);
114             parseerror(parser, "Unexpected token");
115             return NULL;
116         }
117         if (!parser_next(parser)) {
118             MEM_VECTOR_CLEAR(&params, p);
119             return NULL;
120         }
121     }
122
123     var = ast_value_new(ctx, "<unnamed>", vtype);
124     if (!var) {
125         MEM_VECTOR_CLEAR(&params, p);
126         return NULL;
127     }
128     MEM_VECTOR_MOVE(&params, p, var, params);
129     return var;
130 }
131
132 bool parser_do(parser_t *parser)
133 {
134     if (parser->tok == TOKEN_TYPENAME)
135     {
136         bool isfunc = false;
137         ast_function *func = NULL;
138         lex_ctx ctx = parser_ctx(parser);
139         ast_value *var = parser_parse_type(parser, &isfunc);
140         if (!var)
141             return false;
142
143         if (parser->tok != TOKEN_IDENT) {
144             parseerror(parser, "expected variable name\n");
145             return false;
146         }
147
148         if (parser_find_global(parser, parser_tokval(parser))) {
149             ast_value_delete(var);
150             parseerror(parser, "global already exists: %s\n", parser_tokval(parser));
151             return false;
152         }
153
154         if (!ast_value_set_name(var, parser_tokval(parser))) {
155             parseerror(parser, "failed to set variable name\n");
156             ast_value_delete(var);
157             return false;
158         }
159
160         if (isfunc) {
161             /* a function was defined */
162             ast_value *fval;
163
164             /* turn var into a value of TYPE_FUNCTION, with the old var
165              * as return type
166              */
167             fval = ast_value_new(ctx, var->name, TYPE_FUNCTION);
168             func = ast_function_new(ctx, var->name, fval);
169             if (!fval || !func) {
170                 ast_value_delete(var);
171                 if (fval) ast_value_delete(fval);
172                 if (func) ast_function_delete(func);
173                 return false;
174             }
175
176             fval->expression.next = (ast_expression*)var;
177             MEM_VECTOR_MOVE(var, params, func, params);
178
179             if (!parser_t_functions_add(parser, func)) {
180                 ast_value_delete(var);
181                 if (fval) ast_value_delete(fval);
182                 if (func) ast_function_delete(func);
183                 return false;
184             }
185
186             var = fval;
187         }
188
189         if (!parser_t_globals_add(parser, var) ||
190             !parser_next(parser))
191         {
192             ast_value_delete(var);
193             return false;
194         }
195
196         if (parser->tok == ';') {
197             if (!parser_next(parser))
198                 return parser->tok == TOKEN_EOF;
199             return true;
200         }
201
202         if (parser->tok != '=') {
203             parseerror(parser, "expected '=' or ';'");
204             return false;
205         }
206
207         if (!parser_next(parser))
208             return false;
209
210         if (parser->tok == '#') {
211             if (!func) {
212                 parseerror(parser, "unexpected builtin number, '%s' is not a function", var->name);
213                 return false;
214             }
215             if (!parser_next(parser)) {
216                 parseerror(parser, "expected builtin number");
217                 return false;
218             }
219             if (parser->tok != TOKEN_INTCONST) {
220                 parseerror(parser, "builtin number must be an integer constant");
221                 return false;
222             }
223             if (parser_token(parser)->constval.i <= 0) {
224                 parseerror(parser, "builtin number must be positive integer greater than zero");
225                 return false;
226             }
227
228             if (func)
229                 func->builtin = -parser_token(parser)->constval.i;
230         } else if (parser->tok == '{') {
231             /* function body */
232         } else {
233             parseerror(parser, "TODO, const assignment");
234         }
235
236         if (!parser_next(parser))
237             return false;
238
239         if (parser->tok != ';') {
240             parseerror(parser, "expected semicolon");
241             return false;
242         }
243
244         return true;
245     }
246     else if (parser->tok == TOKEN_KEYWORD)
247     {
248         /* handle 'var' and 'const' */
249         return false;
250     }
251     else if (parser->tok == '.')
252     {
253         /* entity-member declaration */
254         return false;
255     }
256     else
257     {
258         parseerror(parser, "unexpected token: %s", parser->lex->tok->value);
259         return false;
260     }
261     return true;
262 }
263
264 bool parser_compile(const char *filename)
265 {
266     size_t i;
267     parser_t *parser;
268     ir_builder *ir;
269
270     parser = (parser_t*)mem_a(sizeof(parser_t));
271     if (!parser)
272         return false;
273
274     MEM_VECTOR_INIT(parser, globals);
275     parser->lex = lex_open(filename);
276
277     if (!parser->lex) {
278         printf("failed to open file \"%s\"\n", filename);
279         return false;
280     }
281
282     /* initial lexer/parser state */
283     parser->lex->flags.noops = true;
284
285     if (parser_next(parser))
286     {
287         while (parser->tok != TOKEN_EOF && parser->tok < TOKEN_ERROR)
288         {
289             if (!parser_do(parser)) {
290                 if (parser->tok == TOKEN_EOF)
291                     parseerror(parser, "unexpected eof");
292                 else
293                     parseerror(parser, "parse error\n");
294                 lex_close(parser->lex);
295                 mem_d(parser);
296                 return false;
297             }
298         }
299     }
300
301     lex_close(parser->lex);
302
303     ir = ir_builder_new("gmqcc_out");
304     if (!ir) {
305         printf("failed to allocate builder\n");
306         goto cleanup;
307     }
308
309     for (i = 0; i < parser->globals_count; ++i) {
310         if (!ast_global_codegen(parser->globals[i], ir)) {
311             printf("failed to generate global %s\n", parser->globals[i]->name);
312         }
313     }
314     for (i = 0; i < parser->functions_count; ++i) {
315         if (!ast_function_codegen(parser->functions[i], ir)) {
316             printf("failed to generate function %s\n", parser->functions[i]->name);
317         }
318         if (!ir_function_finalize(parser->functions[i]->ir_func)) {
319             printf("failed to finalize function %s\n", parser->functions[i]->name);
320         }
321     }
322
323     ir_builder_dump(ir, printf);
324
325 cleanup:
326     for (i = 0; i < parser->globals_count; ++i) {
327         ast_value_delete(parser->globals[i]);
328     }
329     MEM_VECTOR_CLEAR(parser, globals);
330
331     mem_d(parser);
332     return true;
333 }