blob: 1b6c939a2696df0adf88f2d0bce497b6216ec22b [file] [log] [blame]
Carl Worth3a37b872010-05-10 11:44:09 -07001%{
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>
Carl Worthfcbbb462010-05-13 09:36:23 -070027#include <assert.h>
Carl Worth33cc4002010-05-12 12:17:10 -070028#include <talloc.h>
Carl Worth3a37b872010-05-10 11:44:09 -070029
Carl Wortha1e32bc2010-05-10 13:17:25 -070030#include "glcpp.h"
31
Carl Worth0b27b5f2010-05-10 16:16:06 -070032#define YYLEX_PARAM parser->scanner
Carl Worth3a37b872010-05-10 11:44:09 -070033
Carl Worthfcbbb462010-05-13 09:36:23 -070034typedef struct {
35 int is_function;
36 list_t *parameter_list;
37 list_t *replacement_list;
38} macro_t;
39
Carl Worth33cc4002010-05-12 12:17:10 -070040struct glcpp_parser {
41 yyscan_t scanner;
42 struct hash_table *defines;
43};
44
Carl Worth3a37b872010-05-10 11:44:09 -070045void
Carl Wortha1e32bc2010-05-10 13:17:25 -070046yyerror (void *scanner, const char *error);
Carl Worth3a37b872010-05-10 11:44:09 -070047
Carl Worth33cc4002010-05-12 12:17:10 -070048void
Carl Worthfcbbb462010-05-13 09:36:23 -070049_define_object_macro (glcpp_parser_t *parser,
50 const char *macro,
51 list_t *replacement_list);
52
53void
54_define_function_macro (glcpp_parser_t *parser,
55 const char *macro,
56 list_t *parameter_list,
57 list_t *replacement_list);
58
59void
60_print_expanded_object_macro (glcpp_parser_t *parser, const char *macro);
61
62void
63_print_expanded_function_macro (glcpp_parser_t *parser,
64 const char *macro,
65 list_t *arguments);
Carl Worth33cc4002010-05-12 12:17:10 -070066
67list_t *
68_list_create (void *ctx);
69
70void
Carl Worthfcbbb462010-05-13 09:36:23 -070071_list_append_item (list_t *list, const char *str);
72
73void
74_list_append_list (list_t *list, list_t *tail);
Carl Worthc6d5af32010-05-11 12:30:09 -070075
Carl Worthdcc2ecd2010-05-13 12:56:42 -070076int
77_list_contains (list_t *list, const char *member, int *index);
78
79const char *
80_list_member_at (list_t *list, int index);
81
82int
83_list_length (list_t *list);
84
Carl Worth3a37b872010-05-10 11:44:09 -070085%}
86
Carl Worth33cc4002010-05-12 12:17:10 -070087%union {
88 char *str;
89 list_t *list;
90}
91
Carl Worth0b27b5f2010-05-10 16:16:06 -070092%parse-param {glcpp_parser_t *parser}
Carl Worth38aa8352010-05-10 11:52:29 -070093%lex-param {void *scanner}
94
Carl Worth0a93cbb2010-05-13 10:29:07 -070095%token DEFINE FUNC_MACRO IDENTIFIER NEWLINE OBJ_MACRO SPACE TOKEN UNDEF
Carl Worth7f9aa362010-05-13 12:58:49 -070096%type <str> FUNC_MACRO IDENTIFIER identifier_perhaps_macro OBJ_MACRO TOKEN word word_or_symbol
Carl Worthfcbbb462010-05-13 09:36:23 -070097%type <list> argument argument_list parameter_list replacement_list
Carl Worth3a37b872010-05-10 11:44:09 -070098
99%%
100
Carl Worth33cc4002010-05-12 12:17:10 -0700101input:
102 /* empty */
Carl Worth8bcb6f12010-05-12 13:21:20 -0700103| input content
Carl Worth3a37b872010-05-10 11:44:09 -0700104;
105
Carl Worth33cc4002010-05-12 12:17:10 -0700106content:
Carl Worth9f62a7e2010-05-13 07:38:29 -0700107 IDENTIFIER {
108 printf ("%s", $1);
109 talloc_free ($1);
110 }
111| TOKEN {
112 printf ("%s", $1);
113 talloc_free ($1);
114 }
Carl Worthfcbbb462010-05-13 09:36:23 -0700115| macro
Carl Worthcd27e642010-05-12 13:11:50 -0700116| directive_with_newline
Carl Worth0a93cbb2010-05-13 10:29:07 -0700117| NEWLINE { printf ("\n"); }
118| '(' { printf ("("); }
119| ')' { printf (")"); }
120| ',' { printf (","); }
Carl Worth48b94da2010-05-13 10:46:29 -0700121| SPACE { printf (" "); }
Carl Worthcd27e642010-05-12 13:11:50 -0700122;
123
Carl Worthfcbbb462010-05-13 09:36:23 -0700124macro:
125 FUNC_MACRO '(' argument_list ')' {
126 _print_expanded_function_macro (parser, $1, $3);
127 }
128| OBJ_MACRO {
129 _print_expanded_object_macro (parser, $1);
130 talloc_free ($1);
131 }
132;
133
134argument_list:
Carl Worthdb35d552010-05-14 08:47:32 -0700135 argument {
Carl Worthfcbbb462010-05-13 09:36:23 -0700136 $$ = _list_create (parser);
137 _list_append_list ($$, $1);
138 }
139| argument_list ',' argument {
140 _list_append_list ($1, $3);
141 $$ = $1;
142 }
143;
144
145argument:
146 /* empty */ {
147 $$ = _list_create (parser);
148 }
Carl Worth0a93cbb2010-05-13 10:29:07 -0700149| argument word {
Carl Worthfcbbb462010-05-13 09:36:23 -0700150 _list_append_item ($1, $2);
151 talloc_free ($2);
152 }
153| argument '(' argument ')'
154;
155
Carl Worthcd27e642010-05-12 13:11:50 -0700156directive_with_newline:
157 directive NEWLINE {
158 printf ("\n");
159 }
Carl Worth3a37b872010-05-10 11:44:09 -0700160;
161
Carl Worth33cc4002010-05-12 12:17:10 -0700162directive:
Carl Worth0a93cbb2010-05-13 10:29:07 -0700163 DEFINE IDENTIFIER {
164 list_t *list = _list_create (parser);
165 _define_object_macro (parser, $2, list);
166 }
167| DEFINE IDENTIFIER SPACE replacement_list {
168 _define_object_macro (parser, $2, $4);
Carl Worthcd27e642010-05-12 13:11:50 -0700169 }
Carl Worth48b94da2010-05-13 10:46:29 -0700170| DEFINE IDENTIFIER '(' parameter_list ')' {
171 list_t *list = _list_create (parser);
172 _define_function_macro (parser, $2, $4, list);
173 }
174| DEFINE IDENTIFIER '(' parameter_list ')' SPACE replacement_list {
175 _define_function_macro (parser, $2, $4, $7);
Carl Worthfcbbb462010-05-13 09:36:23 -0700176 }
177| UNDEF FUNC_MACRO {
178 list_t *replacement = hash_table_find (parser->defines, $2);
179 if (replacement) {
180 /* XXX: Need hash table to support a real way
181 * to remove an element rather than prefixing
182 * a new node with data of NULL like this. */
183 hash_table_insert (parser->defines, NULL, $2);
184 talloc_free (replacement);
185 }
186 talloc_free ($2);
187 }
188| UNDEF OBJ_MACRO {
Carl Worthcd27e642010-05-12 13:11:50 -0700189 list_t *replacement = hash_table_find (parser->defines, $2);
190 if (replacement) {
191 /* XXX: Need hash table to support a real way
192 * to remove an element rather than prefixing
193 * a new node with data of NULL like this. */
194 hash_table_insert (parser->defines, NULL, $2);
195 talloc_free (replacement);
196 }
197 talloc_free ($2);
Carl Worth33cc4002010-05-12 12:17:10 -0700198 }
199;
200
201replacement_list:
Carl Worth48b94da2010-05-13 10:46:29 -0700202 word_or_symbol {
Carl Worth33cc4002010-05-12 12:17:10 -0700203 $$ = _list_create (parser);
Carl Worth48b94da2010-05-13 10:46:29 -0700204 _list_append_item ($$, $1);
205 talloc_free ($1);
Carl Worth33cc4002010-05-12 12:17:10 -0700206 }
Carl Worth0a93cbb2010-05-13 10:29:07 -0700207| replacement_list word_or_symbol {
Carl Worthfcbbb462010-05-13 09:36:23 -0700208 _list_append_item ($1, $2);
Carl Worth5070a202010-05-12 12:45:33 -0700209 talloc_free ($2);
Carl Worth33cc4002010-05-12 12:17:10 -0700210 $$ = $1;
211 }
212;
213
Carl Worthfcbbb462010-05-13 09:36:23 -0700214parameter_list:
215 /* empty */ {
216 $$ = _list_create (parser);
217 }
Carl Worth7f9aa362010-05-13 12:58:49 -0700218| identifier_perhaps_macro {
Carl Worthfcbbb462010-05-13 09:36:23 -0700219 $$ = _list_create (parser);
220 _list_append_item ($$, $1);
221 talloc_free ($1);
222 }
Carl Worth7f9aa362010-05-13 12:58:49 -0700223| parameter_list ',' identifier_perhaps_macro {
Carl Worthfcbbb462010-05-13 09:36:23 -0700224 _list_append_item ($1, $3);
225 talloc_free ($3);
226 $$ = $1;
227 }
228;
229
Carl Worth7f9aa362010-05-13 12:58:49 -0700230identifier_perhaps_macro:
231 IDENTIFIER { $$ = $1; }
232| FUNC_MACRO { $$ = $1; }
233| OBJ_MACRO { $$ = $1; }
234;
235
Carl Worth0a93cbb2010-05-13 10:29:07 -0700236word_or_symbol:
237 word { $$ = $1; }
238| '(' { $$ = xtalloc_strdup (parser, "("); }
239| ')' { $$ = xtalloc_strdup (parser, ")"); }
240| ',' { $$ = xtalloc_strdup (parser, ","); }
Carl Worth48b94da2010-05-13 10:46:29 -0700241| SPACE { $$ = xtalloc_strdup (parser, " "); }
Carl Worth0a93cbb2010-05-13 10:29:07 -0700242;
243
244word:
Carl Worth9f62a7e2010-05-13 07:38:29 -0700245 IDENTIFIER { $$ = $1; }
Carl Worthfcbbb462010-05-13 09:36:23 -0700246| FUNC_MACRO { $$ = $1; }
247| OBJ_MACRO { $$ = $1; }
Carl Worth9f62a7e2010-05-13 07:38:29 -0700248| TOKEN { $$ = $1; }
Carl Worth33cc4002010-05-12 12:17:10 -0700249;
250
251%%
252
253list_t *
254_list_create (void *ctx)
255{
256 list_t *list;
257
Carl Worth5070a202010-05-12 12:45:33 -0700258 list = xtalloc (ctx, list_t);
Carl Worth33cc4002010-05-12 12:17:10 -0700259 list->head = NULL;
260 list->tail = NULL;
261
262 return list;
Carl Worth0b27b5f2010-05-10 16:16:06 -0700263}
Carl Worth0b27b5f2010-05-10 16:16:06 -0700264
Carl Worth33cc4002010-05-12 12:17:10 -0700265void
Carl Worthfcbbb462010-05-13 09:36:23 -0700266_list_append_list (list_t *list, list_t *tail)
267{
268 if (list->head == NULL) {
269 list->head = tail->head;
270 } else {
271 list->tail->next = tail->head;
272 }
273
274 list->tail = tail->tail;
275}
276
277void
278_list_append_item (list_t *list, const char *str)
Carl Worth33cc4002010-05-12 12:17:10 -0700279{
280 node_t *node;
Carl Worth3a37b872010-05-10 11:44:09 -0700281
Carl Worth5070a202010-05-12 12:45:33 -0700282 node = xtalloc (list, node_t);
283 node->str = xtalloc_strdup (node, str);
Carl Worth33cc4002010-05-12 12:17:10 -0700284
285 node->next = NULL;
286
287 if (list->head == NULL) {
288 list->head = node;
289 } else {
290 list->tail->next = node;
291 }
292
293 list->tail = node;
294}
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700295
296int
297_list_contains (list_t *list, const char *member, int *index)
298{
299 node_t *node;
300 int i;
301
302 if (list == NULL)
303 return 0;
304
305 for (i = 0, node = list->head; node; i++, node = node->next) {
306 if (strcmp (node->str, member) == 0) {
307 *index = i;
308 return 1;
309 }
310 }
311
312 return 0;
313}
314
315int
316_list_length (list_t *list)
317{
318 int length = 0;
319 node_t *node;
320
321 if (list == NULL)
322 return 0;
323
324 for (node = list->head; node; node = node->next)
325 length++;
326
327 return length;
328}
329
330const char *
331_list_member_at (list_t *list, int index)
332{
333 node_t *node;
334 int i;
335
336 if (list == NULL)
337 return NULL;
338
339 node = list->head;
340 for (i = 0; i < index; i++) {
341 node = node->next;
342 if (node == NULL)
343 break;
344 }
345
346 if (node)
347 return node->str;
348
349 return NULL;
350}
Carl Worth33cc4002010-05-12 12:17:10 -0700351
Carl Worth3a37b872010-05-10 11:44:09 -0700352void
Carl Wortha1e32bc2010-05-10 13:17:25 -0700353yyerror (void *scanner, const char *error)
Carl Worth3a37b872010-05-10 11:44:09 -0700354{
355 fprintf (stderr, "Parse error: %s\n", error);
356}
Carl Worth0b27b5f2010-05-10 16:16:06 -0700357
Carl Worth33cc4002010-05-12 12:17:10 -0700358glcpp_parser_t *
359glcpp_parser_create (void)
Carl Worth0b27b5f2010-05-10 16:16:06 -0700360{
Carl Worth33cc4002010-05-12 12:17:10 -0700361 glcpp_parser_t *parser;
362
Carl Worth5070a202010-05-12 12:45:33 -0700363 parser = xtalloc (NULL, glcpp_parser_t);
Carl Worth33cc4002010-05-12 12:17:10 -0700364
Carl Worth5070a202010-05-12 12:45:33 -0700365 yylex_init_extra (parser, &parser->scanner);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700366 parser->defines = hash_table_ctor (32, hash_table_string_hash,
367 hash_table_string_compare);
Carl Worth33cc4002010-05-12 12:17:10 -0700368
369 return parser;
Carl Worth0b27b5f2010-05-10 16:16:06 -0700370}
371
372int
373glcpp_parser_parse (glcpp_parser_t *parser)
374{
375 return yyparse (parser);
376}
377
378void
Carl Worth33cc4002010-05-12 12:17:10 -0700379glcpp_parser_destroy (glcpp_parser_t *parser)
Carl Worth0b27b5f2010-05-10 16:16:06 -0700380{
381 yylex_destroy (parser->scanner);
382 hash_table_dtor (parser->defines);
Carl Worth33cc4002010-05-12 12:17:10 -0700383 talloc_free (parser);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700384}
Carl Worthc6d5af32010-05-11 12:30:09 -0700385
Carl Worthfcbbb462010-05-13 09:36:23 -0700386macro_type_t
387glcpp_parser_macro_type (glcpp_parser_t *parser, const char *identifier)
Carl Worth9f62a7e2010-05-13 07:38:29 -0700388{
Carl Worthfcbbb462010-05-13 09:36:23 -0700389 macro_t *macro;
390
391 macro = hash_table_find (parser->defines, identifier);
392
393 if (macro == NULL)
394 return MACRO_TYPE_UNDEFINED;
395
396 if (macro->is_function)
397 return MACRO_TYPE_FUNCTION;
398 else
399 return MACRO_TYPE_OBJECT;
Carl Worth9f62a7e2010-05-13 07:38:29 -0700400}
401
Carl Worth33cc4002010-05-12 12:17:10 -0700402void
Carl Worthfcbbb462010-05-13 09:36:23 -0700403_define_object_macro (glcpp_parser_t *parser,
404 const char *identifier,
405 list_t *replacement_list)
406{
407 macro_t *macro;
408
409 macro = xtalloc (parser, macro_t);
410
411 macro->is_function = 0;
412 macro->parameter_list = NULL;
413 macro->replacement_list = talloc_steal (macro, replacement_list);
414
415 hash_table_insert (parser->defines, macro, identifier);
416}
417
418void
419_define_function_macro (glcpp_parser_t *parser,
420 const char *identifier,
421 list_t *parameter_list,
422 list_t *replacement_list)
423{
424 macro_t *macro;
425
426 macro = xtalloc (parser, macro_t);
427
428 macro->is_function = 1;
429 macro->parameter_list = talloc_steal (macro, parameter_list);
430 macro->replacement_list = talloc_steal (macro, replacement_list);
431
432 hash_table_insert (parser->defines, macro, identifier);
433}
434
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700435static void
436_print_expanded_macro_recursive (glcpp_parser_t *parser,
437 const char *token,
438 const char *orig,
439 list_t *parameters,
440 list_t *arguments);
441
442static void
443_print_expanded_list_recursive (glcpp_parser_t *parser,
444 list_t *list,
445 const char *orig,
446 list_t *parameters,
447 list_t *arguments)
448{
449 const char *token;
450 node_t *node;
451 int index;
452
453 for (node = list->head ; node ; node = node->next) {
454 token = node->str;
455
456 if (strcmp (token, orig) == 0) {
457 printf ("%s", token);
458 continue;
459 }
460
461 if (_list_contains (parameters, token, &index)) {
462 const char *argument;
463
464 argument = _list_member_at (arguments, index);
465 _print_expanded_macro_recursive (parser, argument,
466 orig, parameters,
467 arguments);
468 } else {
469 _print_expanded_macro_recursive (parser, token,
470 orig, parameters,
471 arguments);
472 }
473 }
474}
475
476
477static void
478_print_expanded_macro_recursive (glcpp_parser_t *parser,
479 const char *token,
480 const char *orig,
481 list_t *parameters,
482 list_t *arguments)
483{
484 macro_t *macro;
485 list_t *replacement_list;
486
487 macro = hash_table_find (parser->defines, token);
488 if (macro == NULL) {
489 printf ("%s", token);
490 return;
491 }
492
493 replacement_list = macro->replacement_list;
494
495 _print_expanded_list_recursive (parser, replacement_list,
496 orig, parameters, arguments);
497}
498
Carl Worthfcbbb462010-05-13 09:36:23 -0700499void
500_print_expanded_object_macro (glcpp_parser_t *parser, const char *identifier)
Carl Worth33cc4002010-05-12 12:17:10 -0700501{
Carl Worthfcbbb462010-05-13 09:36:23 -0700502 macro_t *macro;
Carl Worth33cc4002010-05-12 12:17:10 -0700503
Carl Worthfcbbb462010-05-13 09:36:23 -0700504 macro = hash_table_find (parser->defines, identifier);
505 assert (! macro->is_function);
506
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700507 _print_expanded_macro_recursive (parser, identifier, identifier,
508 NULL, NULL);
Carl Worthfcbbb462010-05-13 09:36:23 -0700509}
510
511void
512_print_expanded_function_macro (glcpp_parser_t *parser,
513 const char *identifier,
514 list_t *arguments)
515{
Carl Worthfcbbb462010-05-13 09:36:23 -0700516 macro_t *macro;
517
518 macro = hash_table_find (parser->defines, identifier);
519 assert (macro->is_function);
520
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700521 if (_list_length (arguments) != _list_length (macro->parameter_list)) {
522 fprintf (stderr,
523 "Error: macro %s invoked with %d arguments (expected %d)\n",
524 identifier,
525 _list_length (arguments),
526 _list_length (macro->parameter_list));
527 return;
528 }
Carl Worthfcbbb462010-05-13 09:36:23 -0700529
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700530 _print_expanded_macro_recursive (parser, identifier, identifier,
531 macro->parameter_list, arguments);
Carl Worth33cc4002010-05-12 12:17:10 -0700532}