]> de.git.xonotic.org Git - xonotic/gmqcc.git/blob - parser.c
f17e9dda73e4b8b452ba082f9f635cab7c8781b7
[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         ast_value *var = parser_parse_type(parser);
129         if (!var)
130             return false;
131
132         if (parser->tok != TOKEN_IDENT) {
133             parseerror(parser, "expected variable name\n");
134             return false;
135         }
136
137         if (parser_find_global(parser, parser_tokval(parser))) {
138             ast_value_delete(var);
139             parseerror(parser, "global already exists: %s\n", parser_tokval(parser));
140             return false;
141         }
142
143         if (!ast_value_set_name(var, parser_tokval(parser))) {
144             parseerror(parser, "failed to set variable name\n");
145             ast_value_delete(var);
146             return false;
147         }
148
149         if (!parser_t_globals_add(parser, var))
150             return false;
151
152         /* Constant assignment */
153         if (!parser_next(parser))
154             return false;
155
156         if (parser->tok == ';')
157             return parser_next(parser);
158
159         if (parser->tok != '=') {
160             parseerror(parser, "expected '=' or ';'");
161             return false;
162         }
163
164         /* '=' found, assign... */
165         parseerror(parser, "TODO, const assignment");
166         return false;
167     }
168     else if (parser->tok == TOKEN_KEYWORD)
169     {
170         /* handle 'var' and 'const' */
171         return false;
172     }
173     else if (parser->tok == '.')
174     {
175         /* entity-member declaration */
176         return false;
177     }
178     else
179     {
180         parseerror(parser, "unexpected token: %s", parser->lex->tok->value);
181         return false;
182     }
183     return true;
184 }
185
186 bool parser_compile(const char *filename)
187 {
188     size_t i;
189     parser_t *parser;
190     ir_builder *ir;
191
192     parser = (parser_t*)mem_a(sizeof(parser_t));
193     if (!parser)
194         return false;
195
196     MEM_VECTOR_INIT(parser, globals);
197     parser->lex = lex_open(filename);
198
199     if (!parser->lex) {
200         printf("failed to open file \"%s\"\n", filename);
201         return false;
202     }
203
204     /* initial lexer/parser state */
205     parser->lex->flags.noops = true;
206
207     if (parser_next(parser))
208     {
209         while (parser->tok != TOKEN_EOF && parser->tok < TOKEN_ERROR)
210         {
211             if (!parser_do(parser)) {
212                 if (parser->tok == TOKEN_EOF)
213                     break;
214                 printf("parse error\n");
215                 lex_close(parser->lex);
216                 mem_d(parser);
217                 return false;
218             }
219         }
220     }
221
222     lex_close(parser->lex);
223
224     ir = ir_builder_new("gmqcc_out");
225     if (!ir) {
226         printf("failed to allocate builder\n");
227         goto cleanup;
228     }
229
230     for (i = 0; i < parser->globals_count; ++i) {
231         if (!ast_global_codegen(parser->globals[i], ir)) {
232             printf("failed to generate global %s\n", parser->globals[i]->name);
233         }
234     }
235
236     ir_builder_dump(ir, printf);
237
238 cleanup:
239     for (i = 0; i < parser->globals_count; ++i) {
240         ast_value_delete(parser->globals[i]);
241     }
242     MEM_VECTOR_CLEAR(parser, globals);
243
244     mem_d(parser);
245     return true;
246 }