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