Add support for the structure of function-like macros.
[mesa.git] / glcpp-parse.y
1 %{
2 /*
3 * Copyright © 2010 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <talloc.h>
29
30 #include "glcpp.h"
31
32 #define YYLEX_PARAM parser->scanner
33
34 typedef struct {
35 int is_function;
36 list_t *parameter_list;
37 list_t *replacement_list;
38 } macro_t;
39
40 struct glcpp_parser {
41 yyscan_t scanner;
42 struct hash_table *defines;
43 };
44
45 void
46 yyerror (void *scanner, const char *error);
47
48 void
49 _define_object_macro (glcpp_parser_t *parser,
50 const char *macro,
51 list_t *replacement_list);
52
53 void
54 _define_function_macro (glcpp_parser_t *parser,
55 const char *macro,
56 list_t *parameter_list,
57 list_t *replacement_list);
58
59 void
60 _print_expanded_object_macro (glcpp_parser_t *parser, const char *macro);
61
62 void
63 _print_expanded_function_macro (glcpp_parser_t *parser,
64 const char *macro,
65 list_t *arguments);
66
67 list_t *
68 _list_create (void *ctx);
69
70 void
71 _list_append_item (list_t *list, const char *str);
72
73 void
74 _list_append_list (list_t *list, list_t *tail);
75
76 %}
77
78 %union {
79 char *str;
80 list_t *list;
81 }
82
83 %parse-param {glcpp_parser_t *parser}
84 %lex-param {void *scanner}
85
86 %token DEFINE FUNC_MACRO IDENTIFIER NEWLINE OBJ_MACRO TOKEN UNDEF
87 %type <str> FUNC_MACRO IDENTIFIER OBJ_MACRO TOKEN string
88 %type <list> argument argument_list parameter_list replacement_list
89
90 %%
91
92 input:
93 /* empty */
94 | input content
95 ;
96
97 content:
98 IDENTIFIER {
99 printf ("%s", $1);
100 talloc_free ($1);
101 }
102 | TOKEN {
103 printf ("%s", $1);
104 talloc_free ($1);
105 }
106 | macro
107 | directive_with_newline
108 | NEWLINE {
109 printf ("\n");
110 }
111 ;
112
113 macro:
114 FUNC_MACRO '(' argument_list ')' {
115 _print_expanded_function_macro (parser, $1, $3);
116 }
117 | OBJ_MACRO {
118 _print_expanded_object_macro (parser, $1);
119 talloc_free ($1);
120 }
121 ;
122
123 argument_list:
124 /* empty */ {
125 $$ = _list_create (parser);
126 }
127 | argument {
128 $$ = _list_create (parser);
129 _list_append_list ($$, $1);
130 }
131 | argument_list ',' argument {
132 _list_append_list ($1, $3);
133 $$ = $1;
134 }
135 ;
136
137 argument:
138 /* empty */ {
139 $$ = _list_create (parser);
140 }
141 | argument string {
142 _list_append_item ($1, $2);
143 talloc_free ($2);
144 }
145 | argument '(' argument ')'
146 ;
147
148 directive_with_newline:
149 directive NEWLINE {
150 printf ("\n");
151 }
152 ;
153
154 directive:
155 DEFINE IDENTIFIER replacement_list {
156 _define_object_macro (parser, $2, $3);
157 }
158 | DEFINE IDENTIFIER '(' parameter_list ')' replacement_list {
159 _define_function_macro (parser, $2, $4, $6);
160 }
161 | UNDEF FUNC_MACRO {
162 list_t *replacement = hash_table_find (parser->defines, $2);
163 if (replacement) {
164 /* XXX: Need hash table to support a real way
165 * to remove an element rather than prefixing
166 * a new node with data of NULL like this. */
167 hash_table_insert (parser->defines, NULL, $2);
168 talloc_free (replacement);
169 }
170 talloc_free ($2);
171 }
172 | UNDEF OBJ_MACRO {
173 list_t *replacement = hash_table_find (parser->defines, $2);
174 if (replacement) {
175 /* XXX: Need hash table to support a real way
176 * to remove an element rather than prefixing
177 * a new node with data of NULL like this. */
178 hash_table_insert (parser->defines, NULL, $2);
179 talloc_free (replacement);
180 }
181 talloc_free ($2);
182 }
183 ;
184
185 replacement_list:
186 /* empty */ {
187 $$ = _list_create (parser);
188 }
189 | replacement_list string {
190 _list_append_item ($1, $2);
191 talloc_free ($2);
192 $$ = $1;
193 }
194 ;
195
196 parameter_list:
197 /* empty */ {
198 $$ = _list_create (parser);
199 }
200 | IDENTIFIER {
201 $$ = _list_create (parser);
202 _list_append_item ($$, $1);
203 talloc_free ($1);
204 }
205 | parameter_list ',' IDENTIFIER {
206 _list_append_item ($1, $3);
207 talloc_free ($3);
208 $$ = $1;
209 }
210 ;
211
212 string:
213 IDENTIFIER { $$ = $1; }
214 | FUNC_MACRO { $$ = $1; }
215 | OBJ_MACRO { $$ = $1; }
216 | TOKEN { $$ = $1; }
217 ;
218
219 %%
220
221 list_t *
222 _list_create (void *ctx)
223 {
224 list_t *list;
225
226 list = xtalloc (ctx, list_t);
227 list->head = NULL;
228 list->tail = NULL;
229
230 return list;
231 }
232
233 void
234 _list_append_list (list_t *list, list_t *tail)
235 {
236 if (list->head == NULL) {
237 list->head = tail->head;
238 } else {
239 list->tail->next = tail->head;
240 }
241
242 list->tail = tail->tail;
243 }
244
245 void
246 _list_append_item (list_t *list, const char *str)
247 {
248 node_t *node;
249
250 node = xtalloc (list, node_t);
251 node->str = xtalloc_strdup (node, str);
252
253 node->next = NULL;
254
255 if (list->head == NULL) {
256 list->head = node;
257 } else {
258 list->tail->next = node;
259 }
260
261 list->tail = node;
262 }
263
264 void
265 yyerror (void *scanner, const char *error)
266 {
267 fprintf (stderr, "Parse error: %s\n", error);
268 }
269
270 glcpp_parser_t *
271 glcpp_parser_create (void)
272 {
273 glcpp_parser_t *parser;
274
275 parser = xtalloc (NULL, glcpp_parser_t);
276
277 yylex_init_extra (parser, &parser->scanner);
278 parser->defines = hash_table_ctor (32, hash_table_string_hash,
279 hash_table_string_compare);
280
281 return parser;
282 }
283
284 int
285 glcpp_parser_parse (glcpp_parser_t *parser)
286 {
287 return yyparse (parser);
288 }
289
290 void
291 glcpp_parser_destroy (glcpp_parser_t *parser)
292 {
293 yylex_destroy (parser->scanner);
294 hash_table_dtor (parser->defines);
295 talloc_free (parser);
296 }
297
298 macro_type_t
299 glcpp_parser_macro_type (glcpp_parser_t *parser, const char *identifier)
300 {
301 macro_t *macro;
302
303 macro = hash_table_find (parser->defines, identifier);
304
305 if (macro == NULL)
306 return MACRO_TYPE_UNDEFINED;
307
308 if (macro->is_function)
309 return MACRO_TYPE_FUNCTION;
310 else
311 return MACRO_TYPE_OBJECT;
312 }
313
314 static void
315 _print_expanded_macro_recursive (glcpp_parser_t *parser,
316 const char *token,
317 const char *orig,
318 int *first)
319 {
320 macro_t *macro;
321 node_t *node;
322
323 macro = hash_table_find (parser->defines, token);
324 if (macro == NULL) {
325 printf ("%s%s", *first ? "" : " ", token);
326 *first = 0;
327 } else {
328 list_t *replacement_list = macro->replacement_list;
329
330 for (node = replacement_list->head ; node ; node = node->next) {
331 token = node->str;
332 if (strcmp (token, orig) == 0) {
333 printf ("%s%s", *first ? "" : " ", token);
334 *first = 0;
335 } else {
336 _print_expanded_macro_recursive (parser,
337 token, orig,
338 first);
339 }
340 }
341 }
342 }
343
344 void
345 _define_object_macro (glcpp_parser_t *parser,
346 const char *identifier,
347 list_t *replacement_list)
348 {
349 macro_t *macro;
350
351 macro = xtalloc (parser, macro_t);
352
353 macro->is_function = 0;
354 macro->parameter_list = NULL;
355 macro->replacement_list = talloc_steal (macro, replacement_list);
356
357 hash_table_insert (parser->defines, macro, identifier);
358 }
359
360 void
361 _define_function_macro (glcpp_parser_t *parser,
362 const char *identifier,
363 list_t *parameter_list,
364 list_t *replacement_list)
365 {
366 macro_t *macro;
367
368 macro = xtalloc (parser, macro_t);
369
370 macro->is_function = 1;
371 macro->parameter_list = talloc_steal (macro, parameter_list);
372 macro->replacement_list = talloc_steal (macro, replacement_list);
373
374 hash_table_insert (parser->defines, macro, identifier);
375 }
376
377 void
378 _print_expanded_object_macro (glcpp_parser_t *parser, const char *identifier)
379 {
380 int first = 1;
381 macro_t *macro;
382
383 macro = hash_table_find (parser->defines, identifier);
384 assert (! macro->is_function);
385
386 _print_expanded_macro_recursive (parser, identifier, identifier, &first);
387 }
388
389 void
390 _print_expanded_function_macro (glcpp_parser_t *parser,
391 const char *identifier,
392 list_t *arguments)
393 {
394 int first = 1;
395 macro_t *macro;
396
397 macro = hash_table_find (parser->defines, identifier);
398 assert (macro->is_function);
399
400 /* XXX: Need to use argument list here in the expansion. */
401
402 _print_expanded_macro_recursive (parser, identifier, identifier, &first);
403 }