blob: 26432f203254ff29884b74a8b998f21b47f1cc25 [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 Worth3a37b872010-05-10 11:44:09 -070028
Carl Wortha1e32bc2010-05-10 13:17:25 -070029#include "glcpp.h"
30
Carl Worth3a37b872010-05-10 11:44:09 -070031void
Carl Wortha1e32bc2010-05-10 13:17:25 -070032yyerror (void *scanner, const char *error);
Carl Worth3a37b872010-05-10 11:44:09 -070033
Carl Worth33cc4002010-05-12 12:17:10 -070034void
Carl Worthfcbbb462010-05-13 09:36:23 -070035_define_object_macro (glcpp_parser_t *parser,
36 const char *macro,
Carl Worth47252442010-05-19 13:54:37 -070037 token_list_t *replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -070038
39void
40_define_function_macro (glcpp_parser_t *parser,
41 const char *macro,
Carl Worthc5e98552010-05-14 10:12:21 -070042 string_list_t *parameters,
Carl Worth47252442010-05-19 13:54:37 -070043 token_list_t *replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -070044
Carl Wortha807fb72010-05-18 22:10:04 -070045void
Carl Worth2be8be02010-05-14 10:31:43 -070046_expand_object_macro (glcpp_parser_t *parser, const char *identifier);
47
Carl Wortha807fb72010-05-18 22:10:04 -070048void
Carl Worth2be8be02010-05-14 10:31:43 -070049_expand_function_macro (glcpp_parser_t *parser,
50 const char *identifier,
Carl Worth8f6a8282010-05-14 10:44:19 -070051 argument_list_t *arguments);
Carl Worthfcbbb462010-05-13 09:36:23 -070052
Carl Worth610053b2010-05-14 10:05:11 -070053string_list_t *
54_string_list_create (void *ctx);
Carl Worth33cc4002010-05-12 12:17:10 -070055
56void
Carl Worth610053b2010-05-14 10:05:11 -070057_string_list_append_item (string_list_t *list, const char *str);
Carl Worthfcbbb462010-05-13 09:36:23 -070058
59void
Carl Worth610053b2010-05-14 10:05:11 -070060_string_list_append_list (string_list_t *list, string_list_t *tail);
Carl Worthc6d5af32010-05-11 12:30:09 -070061
Carl Worthdcc2ecd2010-05-13 12:56:42 -070062int
Carl Worth610053b2010-05-14 10:05:11 -070063_string_list_contains (string_list_t *list, const char *member, int *index);
Carl Worthdcc2ecd2010-05-13 12:56:42 -070064
Carl Worthdcc2ecd2010-05-13 12:56:42 -070065int
Carl Worth610053b2010-05-14 10:05:11 -070066_string_list_length (string_list_t *list);
Carl Worthdcc2ecd2010-05-13 12:56:42 -070067
Carl Worth8f6a8282010-05-14 10:44:19 -070068argument_list_t *
69_argument_list_create (void *ctx);
70
71void
Carl Worth47252442010-05-19 13:54:37 -070072_argument_list_append (argument_list_t *list, token_list_t *argument);
Carl Worth8f6a8282010-05-14 10:44:19 -070073
74int
75_argument_list_length (argument_list_t *list);
76
Carl Worth47252442010-05-19 13:54:37 -070077token_list_t *
Carl Worth8f6a8282010-05-14 10:44:19 -070078_argument_list_member_at (argument_list_t *list, int index);
79
Carl Worth47252442010-05-19 13:54:37 -070080token_list_t *
81_token_list_create (void *ctx);
82
83void
84_token_list_append (token_list_t *list, int type, const char *value);
85
86void
87_token_list_append_list (token_list_t *list, token_list_t *tail);
88
Carl Worthaaa9acb2010-05-19 13:28:24 -070089static void
Carl Worthaaa9acb2010-05-19 13:28:24 -070090glcpp_parser_pop_expansion (glcpp_parser_t *parser);
91
Carl Worthb20d33c2010-05-20 22:27:07 -070092static void
93_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition);
94
95static void
96_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
97 int condition);
98
99static void
100_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser);
101
Carl Worth0293b2e2010-05-19 10:05:40 -0700102#define yylex glcpp_parser_lex
103
Carl Worth8f38aff2010-05-19 10:01:29 -0700104static int
Carl Worth0293b2e2010-05-19 10:05:40 -0700105glcpp_parser_lex (glcpp_parser_t *parser);
Carl Worth8f38aff2010-05-19 10:01:29 -0700106
Carl Worth3a37b872010-05-10 11:44:09 -0700107%}
108
Carl Worth33cc4002010-05-12 12:17:10 -0700109%union {
Carl Worth005b3202010-05-20 14:19:57 -0700110 int ival;
Carl Worth33cc4002010-05-12 12:17:10 -0700111 char *str;
Carl Worth8f6a8282010-05-14 10:44:19 -0700112 argument_list_t *argument_list;
Carl Worth47252442010-05-19 13:54:37 -0700113 string_list_t *string_list;
Carl Worthb5693832010-05-20 08:01:44 -0700114 token_t token;
Carl Worth47252442010-05-19 13:54:37 -0700115 token_list_t *token_list;
Carl Worth33cc4002010-05-12 12:17:10 -0700116}
117
Carl Worth0b27b5f2010-05-10 16:16:06 -0700118%parse-param {glcpp_parser_t *parser}
Carl Worth0293b2e2010-05-19 10:05:40 -0700119%lex-param {glcpp_parser_t *parser}
Carl Worth38aa8352010-05-10 11:52:29 -0700120
Carl Worthb20d33c2010-05-20 22:27:07 -0700121%token DEFINE ELIF ELSE ENDIF FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED IF IFDEF IFNDEF INTEGER OBJ_MACRO NEWLINE SEPARATOR SPACE TOKEN UNDEF
122%type <ival> expression INTEGER punctuator
Carl Worth005b3202010-05-20 14:19:57 -0700123%type <str> content FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED OBJ_MACRO
Carl Worth8f6a8282010-05-14 10:44:19 -0700124%type <argument_list> argument_list
Carl Worth47252442010-05-19 13:54:37 -0700125%type <string_list> macro parameter_list
Carl Worth9f3d2c42010-05-20 08:42:02 -0700126%type <token> TOKEN argument_word argument_word_or_comma
127%type <token_list> argument argument_or_comma replacement_list pp_tokens
Carl Worth3a37b872010-05-10 11:44:09 -0700128
Carl Worth796e1f02010-05-17 12:45:16 -0700129/* Hard to remove shift/reduce conflicts documented as follows:
130 *
131 * 1. '(' after FUNC_MACRO name which is correctly resolved to shift
132 * to form macro invocation rather than reducing directly to
133 * content.
Carl Worth69f390d2010-05-19 07:42:42 -0700134 *
135 * 2. Similarly, '(' after FUNC_MACRO which is correctly resolved to
136 * shift to form macro invocation rather than reducing directly to
137 * argument.
Carl Worth9f3d2c42010-05-20 08:42:02 -0700138 *
139 * 3. Similarly again now that we added argument_or_comma as well.
Carl Worth796e1f02010-05-17 12:45:16 -0700140 */
Carl Worth9f3d2c42010-05-20 08:42:02 -0700141%expect 3
Carl Worth796e1f02010-05-17 12:45:16 -0700142
Carl Worth3a37b872010-05-10 11:44:09 -0700143%%
144
Carl Worth005b3202010-05-20 14:19:57 -0700145 /* We do all printing at the input level.
146 *
147 * The value for "input" is simply TOKEN or SEPARATOR so we
148 * can decide whether it's necessary to print a space
149 * character between any two. */
Carl Worth33cc4002010-05-12 12:17:10 -0700150input:
Carl Worth005b3202010-05-20 14:19:57 -0700151 /* empty */ {
Carl Worth5a6b9a22010-05-20 14:29:43 -0700152 parser->just_printed_separator = 1;
Carl Worth005b3202010-05-20 14:19:57 -0700153 }
154| input content {
155 int is_token;
Carl Worthb20d33c2010-05-20 22:27:07 -0700156 int skipping = 0;
Carl Worth005b3202010-05-20 14:19:57 -0700157
Carl Worthb20d33c2010-05-20 22:27:07 -0700158 if (parser->skip_stack && parser->skip_stack->type != SKIP_NO_SKIP)
159 skipping = 1;
160
161 if ($2 && strlen ($2) && ! skipping) {
Carl Worth005b3202010-05-20 14:19:57 -0700162 int c = $2[0];
163 int is_not_separator = ((c >= 'a' && c <= 'z') ||
164 (c >= 'A' && c <= 'Z') ||
165 (c >= 'A' && c <= 'Z') ||
166 (c >= '0' && c <= '9') ||
167 (c == '_'));
168
Carl Worth5a6b9a22010-05-20 14:29:43 -0700169 if (! parser->just_printed_separator && is_not_separator)
170 {
Carl Worth005b3202010-05-20 14:19:57 -0700171 printf (" ");
Carl Worth5a6b9a22010-05-20 14:29:43 -0700172 }
Carl Worth005b3202010-05-20 14:19:57 -0700173 printf ("%s", $2);
Carl Worth5a6b9a22010-05-20 14:29:43 -0700174
Carl Worth005b3202010-05-20 14:19:57 -0700175 if (is_not_separator)
Carl Worth5a6b9a22010-05-20 14:29:43 -0700176 parser->just_printed_separator = 0;
Carl Worth005b3202010-05-20 14:19:57 -0700177 else
Carl Worth5a6b9a22010-05-20 14:29:43 -0700178 parser->just_printed_separator = 1;
Carl Worth005b3202010-05-20 14:19:57 -0700179 }
Carl Worth5a6b9a22010-05-20 14:29:43 -0700180
Carl Worth005b3202010-05-20 14:19:57 -0700181 if ($2)
182 talloc_free ($2);
Carl Worth876e5102010-05-20 14:38:06 -0700183
184 if (parser->need_newline) {
185 printf ("\n");
186 parser->just_printed_separator = 1;
187 parser->need_newline = 0;
188 }
Carl Worth005b3202010-05-20 14:19:57 -0700189 }
Carl Worth3a37b872010-05-10 11:44:09 -0700190;
191
Carl Worth33cc4002010-05-12 12:17:10 -0700192content:
Carl Worth9f62a7e2010-05-13 07:38:29 -0700193 IDENTIFIER {
Carl Worth005b3202010-05-20 14:19:57 -0700194 $$ = $1;
Carl Worth9f62a7e2010-05-13 07:38:29 -0700195 }
Carl Worthb5693832010-05-20 08:01:44 -0700196| IDENTIFIER_FINALIZED {
Carl Worth005b3202010-05-20 14:19:57 -0700197 $$ = $1;
Carl Worth9f62a7e2010-05-13 07:38:29 -0700198 }
Carl Worthb5693832010-05-20 08:01:44 -0700199| TOKEN {
Carl Worth005b3202010-05-20 14:19:57 -0700200 $$ = $1.value;
Carl Worthb5693832010-05-20 08:01:44 -0700201 }
Carl Worthacf87bc2010-05-17 10:34:29 -0700202| FUNC_MACRO {
Carl Worth005b3202010-05-20 14:19:57 -0700203 $$ = $1;
Carl Worthacf87bc2010-05-17 10:34:29 -0700204 }
Carl Wortha807fb72010-05-18 22:10:04 -0700205| directive {
Carl Worth005b3202010-05-20 14:19:57 -0700206 $$ = talloc_strdup (parser, "\n");
Carl Worth2be8be02010-05-14 10:31:43 -0700207 }
Carl Worth005b3202010-05-20 14:19:57 -0700208| punctuator {
209 $$ = talloc_asprintf (parser, "%c", $1);
210 }
211| macro {
212 $$ = NULL;
213 }
Carl Worthcd27e642010-05-12 13:11:50 -0700214;
215
Carl Worth005b3202010-05-20 14:19:57 -0700216punctuator:
217 '(' { $$ = '('; }
218| ')' { $$ = ')'; }
219| ',' { $$ = ','; }
220 ;
221
Carl Worthfcbbb462010-05-13 09:36:23 -0700222macro:
223 FUNC_MACRO '(' argument_list ')' {
Carl Wortha807fb72010-05-18 22:10:04 -0700224 _expand_function_macro (parser, $1, $3);
Carl Worthfcbbb462010-05-13 09:36:23 -0700225 }
226| OBJ_MACRO {
Carl Wortha807fb72010-05-18 22:10:04 -0700227 _expand_object_macro (parser, $1);
Carl Worthfcbbb462010-05-13 09:36:23 -0700228 talloc_free ($1);
229 }
230;
231
232argument_list:
Carl Worthac070e82010-05-14 11:33:00 -0700233 /* empty */ {
234 $$ = _argument_list_create (parser);
235 }
236| argument {
Carl Worth8f6a8282010-05-14 10:44:19 -0700237 $$ = _argument_list_create (parser);
238 _argument_list_append ($$, $1);
239 }
Carl Worthfcbbb462010-05-13 09:36:23 -0700240| argument_list ',' argument {
Carl Worth8f6a8282010-05-14 10:44:19 -0700241 _argument_list_append ($1, $3);
Carl Worthfcbbb462010-05-13 09:36:23 -0700242 $$ = $1;
243 }
244;
245
246argument:
Carl Worth59ca9892010-05-19 07:49:47 -0700247 argument_word {
Carl Worth47252442010-05-19 13:54:37 -0700248 $$ = _token_list_create (parser);
Carl Worthb5693832010-05-20 08:01:44 -0700249 _token_list_append ($$, $1.type, $1.value);
Carl Worthfcbbb462010-05-13 09:36:23 -0700250 }
Carl Worth59ca9892010-05-19 07:49:47 -0700251| argument argument_word {
Carl Worthb5693832010-05-20 08:01:44 -0700252 _token_list_append ($1, $2.type, $2.value);
253 talloc_free ($2.value);
Carl Worth3596bb12010-05-14 16:53:52 -0700254 $$ = $1;
Carl Worthfcbbb462010-05-13 09:36:23 -0700255 }
Carl Worth9f3d2c42010-05-20 08:42:02 -0700256| argument '(' argument_or_comma ')' {
Carl Worth47252442010-05-19 13:54:37 -0700257 _token_list_append ($1, '(', "(");
258 _token_list_append_list ($1, $3);
259 _token_list_append ($1, ')', ")");
Carl Worth3596bb12010-05-14 16:53:52 -0700260 $$ = $1;
261 }
Carl Worthfcbbb462010-05-13 09:36:23 -0700262;
263
Carl Worth59ca9892010-05-19 07:49:47 -0700264argument_word:
Carl Worthb5693832010-05-20 08:01:44 -0700265 IDENTIFIER { $$.type = IDENTIFIER; $$.value = $1; }
266| IDENTIFIER_FINALIZED { $$.type = IDENTIFIER_FINALIZED; $$.value = $1; }
Carl Worth59ca9892010-05-19 07:49:47 -0700267| TOKEN { $$ = $1; }
Carl Worthb5693832010-05-20 08:01:44 -0700268| FUNC_MACRO { $$.type = FUNC_MACRO; $$.value = $1; }
269| macro { $$.type = TOKEN; $$.value = xtalloc_strdup (parser, ""); }
Carl Worth59ca9892010-05-19 07:49:47 -0700270;
271
Carl Worth9f3d2c42010-05-20 08:42:02 -0700272 /* XXX: The body of argument_or_comma is the same as the body
273 * of argument, but with "argument" and "argument_word"
274 * changed to "argument_or_comma" and
275 * "argument_word_or_comma". It would be nice to have less
276 * redundancy here, but I'm not sure how.
277 *
278 * It would also be nice to have a less ugly grammar to have
279 * to implement, but such is the C preprocessor.
280 */
281argument_or_comma:
282 argument_word_or_comma {
283 $$ = _token_list_create (parser);
284 _token_list_append ($$, $1.type, $1.value);
285 }
286| argument_or_comma argument_word_or_comma {
287 _token_list_append ($1, $2.type, $2.value);
288 $$ = $1;
289 }
290| argument_or_comma '(' argument_or_comma ')' {
291 _token_list_append ($1, '(', "(");
292 _token_list_append_list ($1, $3);
293 _token_list_append ($1, ')', ")");
294 $$ = $1;
295 }
296;
297
298argument_word_or_comma:
299 IDENTIFIER { $$.type = IDENTIFIER; $$.value = $1; }
300| IDENTIFIER_FINALIZED { $$.type = IDENTIFIER_FINALIZED; $$.value = $1; }
301| TOKEN { $$ = $1; }
302| FUNC_MACRO { $$.type = FUNC_MACRO; $$.value = $1; }
303| macro { $$.type = TOKEN; $$.value = xtalloc_strdup (parser, ""); }
304| ',' { $$.type = ','; $$.value = xtalloc_strdup (parser, ","); }
305;
Carl Worth59ca9892010-05-19 07:49:47 -0700306
Carl Worth33cc4002010-05-12 12:17:10 -0700307directive:
Carl Worthaaa9acb2010-05-19 13:28:24 -0700308 DEFINE IDENTIFIER NEWLINE {
Carl Worth47252442010-05-19 13:54:37 -0700309 token_list_t *list = _token_list_create (parser);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700310 _define_object_macro (parser, $2, list);
Carl Worth0a93cbb2010-05-13 10:29:07 -0700311 }
Carl Worthaaa9acb2010-05-19 13:28:24 -0700312| DEFINE IDENTIFIER SPACE replacement_list NEWLINE {
313 _define_object_macro (parser, $2, $4);
314 }
315| DEFINE IDENTIFIER '(' parameter_list ')' replacement_list NEWLINE {
Carl Worth81f01432010-05-14 17:08:45 -0700316 _define_function_macro (parser, $2, $4, $6);
Carl Worthfcbbb462010-05-13 09:36:23 -0700317 }
Carl Worthb20d33c2010-05-20 22:27:07 -0700318| IF expression NEWLINE {
319 _glcpp_parser_skip_stack_push_if (parser, $2);
320 }
321| IFDEF IDENTIFIER NEWLINE {
322 string_list_t *macro = hash_table_find (parser->defines, $2);
323 talloc_free ($2);
324 _glcpp_parser_skip_stack_push_if (parser, macro != NULL);
325 }
326| IFNDEF IDENTIFIER NEWLINE {
327 string_list_t *macro = hash_table_find (parser->defines, $2);
328 talloc_free ($2);
329 _glcpp_parser_skip_stack_push_if (parser, macro == NULL);
330 }
331| ELIF expression NEWLINE {
332 _glcpp_parser_skip_stack_change_if (parser, "#elif", $2);
333 }
334| ELSE {
335 _glcpp_parser_skip_stack_change_if (parser, "else", 1);
336 }
337| ENDIF {
338 _glcpp_parser_skip_stack_pop (parser);
339 }
Carl Wortha807fb72010-05-18 22:10:04 -0700340| UNDEF IDENTIFIER {
341 string_list_t *macro = hash_table_find (parser->defines, $2);
342 if (macro) {
Carl Worthfcbbb462010-05-13 09:36:23 -0700343 /* XXX: Need hash table to support a real way
344 * to remove an element rather than prefixing
345 * a new node with data of NULL like this. */
346 hash_table_insert (parser->defines, NULL, $2);
Carl Wortha807fb72010-05-18 22:10:04 -0700347 talloc_free (macro);
Carl Worthfcbbb462010-05-13 09:36:23 -0700348 }
349 talloc_free ($2);
350 }
Carl Worth38bd27b2010-05-14 12:05:37 -0700351;
352
Carl Worthb20d33c2010-05-20 22:27:07 -0700353/* XXX: Need to fill out with all operators. */
354expression:
355 INTEGER {
356 $$ = $1;
357 }
358;
359
Carl Worthfcbbb462010-05-13 09:36:23 -0700360parameter_list:
361 /* empty */ {
Carl Worth610053b2010-05-14 10:05:11 -0700362 $$ = _string_list_create (parser);
Carl Worthfcbbb462010-05-13 09:36:23 -0700363 }
Carl Wortha807fb72010-05-18 22:10:04 -0700364| IDENTIFIER {
Carl Worth610053b2010-05-14 10:05:11 -0700365 $$ = _string_list_create (parser);
366 _string_list_append_item ($$, $1);
Carl Worthfcbbb462010-05-13 09:36:23 -0700367 talloc_free ($1);
368 }
Carl Wortha807fb72010-05-18 22:10:04 -0700369| parameter_list ',' IDENTIFIER {
Carl Worth610053b2010-05-14 10:05:11 -0700370 _string_list_append_item ($1, $3);
Carl Worthfcbbb462010-05-13 09:36:23 -0700371 talloc_free ($3);
372 $$ = $1;
373 }
374;
375
Carl Worthaaa9acb2010-05-19 13:28:24 -0700376replacement_list:
377 /* empty */ {
Carl Worth47252442010-05-19 13:54:37 -0700378 $$ = _token_list_create (parser);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700379 }
380| pp_tokens {
381 $$ = $1;
382 }
383;
384
385
386pp_tokens:
387 TOKEN {
Carl Worth47252442010-05-19 13:54:37 -0700388 $$ = _token_list_create (parser);
Carl Worthb5693832010-05-20 08:01:44 -0700389 _token_list_append ($$, $1.type, $1.value);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700390 }
391| pp_tokens TOKEN {
Carl Worthb5693832010-05-20 08:01:44 -0700392 _token_list_append ($1, $2.type, $2.value);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700393 $$ = $1;
394 }
395;
396
Carl Worth33cc4002010-05-12 12:17:10 -0700397%%
398
Carl Worth610053b2010-05-14 10:05:11 -0700399string_list_t *
400_string_list_create (void *ctx)
Carl Worth33cc4002010-05-12 12:17:10 -0700401{
Carl Worth610053b2010-05-14 10:05:11 -0700402 string_list_t *list;
Carl Worth33cc4002010-05-12 12:17:10 -0700403
Carl Worth610053b2010-05-14 10:05:11 -0700404 list = xtalloc (ctx, string_list_t);
Carl Worth33cc4002010-05-12 12:17:10 -0700405 list->head = NULL;
406 list->tail = NULL;
407
408 return list;
Carl Worth0b27b5f2010-05-10 16:16:06 -0700409}
Carl Worth0b27b5f2010-05-10 16:16:06 -0700410
Carl Worth33cc4002010-05-12 12:17:10 -0700411void
Carl Worth610053b2010-05-14 10:05:11 -0700412_string_list_append_list (string_list_t *list, string_list_t *tail)
Carl Worthfcbbb462010-05-13 09:36:23 -0700413{
414 if (list->head == NULL) {
415 list->head = tail->head;
416 } else {
417 list->tail->next = tail->head;
418 }
419
420 list->tail = tail->tail;
421}
422
423void
Carl Worth610053b2010-05-14 10:05:11 -0700424_string_list_append_item (string_list_t *list, const char *str)
Carl Worth33cc4002010-05-12 12:17:10 -0700425{
Carl Worth610053b2010-05-14 10:05:11 -0700426 string_node_t *node;
Carl Worth3a37b872010-05-10 11:44:09 -0700427
Carl Worth610053b2010-05-14 10:05:11 -0700428 node = xtalloc (list, string_node_t);
Carl Worth5070a202010-05-12 12:45:33 -0700429 node->str = xtalloc_strdup (node, str);
Carl Worth33cc4002010-05-12 12:17:10 -0700430
431 node->next = NULL;
432
433 if (list->head == NULL) {
434 list->head = node;
435 } else {
436 list->tail->next = node;
437 }
438
439 list->tail = node;
440}
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700441
442int
Carl Worth610053b2010-05-14 10:05:11 -0700443_string_list_contains (string_list_t *list, const char *member, int *index)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700444{
Carl Worth610053b2010-05-14 10:05:11 -0700445 string_node_t *node;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700446 int i;
447
448 if (list == NULL)
449 return 0;
450
451 for (i = 0, node = list->head; node; i++, node = node->next) {
452 if (strcmp (node->str, member) == 0) {
Carl Worth420d05a2010-05-17 10:15:23 -0700453 if (index)
454 *index = i;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700455 return 1;
456 }
457 }
458
459 return 0;
460}
461
462int
Carl Worth610053b2010-05-14 10:05:11 -0700463_string_list_length (string_list_t *list)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700464{
465 int length = 0;
Carl Worth610053b2010-05-14 10:05:11 -0700466 string_node_t *node;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700467
468 if (list == NULL)
469 return 0;
470
471 for (node = list->head; node; node = node->next)
472 length++;
473
474 return length;
475}
476
Carl Worth8f6a8282010-05-14 10:44:19 -0700477argument_list_t *
478_argument_list_create (void *ctx)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700479{
Carl Worth8f6a8282010-05-14 10:44:19 -0700480 argument_list_t *list;
481
482 list = xtalloc (ctx, argument_list_t);
483 list->head = NULL;
484 list->tail = NULL;
485
486 return list;
487}
488
489void
Carl Worth47252442010-05-19 13:54:37 -0700490_argument_list_append (argument_list_t *list, token_list_t *argument)
Carl Worth8f6a8282010-05-14 10:44:19 -0700491{
492 argument_node_t *node;
493
494 if (argument == NULL || argument->head == NULL)
495 return;
496
497 node = xtalloc (list, argument_node_t);
498 node->argument = argument;
499
500 node->next = NULL;
501
502 if (list->head == NULL) {
503 list->head = node;
504 } else {
505 list->tail->next = node;
506 }
507
508 list->tail = node;
509}
510
511int
512_argument_list_length (argument_list_t *list)
513{
514 int length = 0;
515 argument_node_t *node;
516
517 if (list == NULL)
518 return 0;
519
520 for (node = list->head; node; node = node->next)
521 length++;
522
523 return length;
524}
525
Carl Worth47252442010-05-19 13:54:37 -0700526token_list_t *
Carl Worth8f6a8282010-05-14 10:44:19 -0700527_argument_list_member_at (argument_list_t *list, int index)
528{
529 argument_node_t *node;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700530 int i;
531
532 if (list == NULL)
533 return NULL;
534
535 node = list->head;
536 for (i = 0; i < index; i++) {
537 node = node->next;
538 if (node == NULL)
539 break;
540 }
541
542 if (node)
Carl Worth8f6a8282010-05-14 10:44:19 -0700543 return node->argument;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700544
545 return NULL;
546}
Carl Worth47252442010-05-19 13:54:37 -0700547
548token_list_t *
549_token_list_create (void *ctx)
550{
551 token_list_t *list;
552
553 list = xtalloc (ctx, token_list_t);
554 list->head = NULL;
555 list->tail = NULL;
556
557 return list;
558}
559
560void
561_token_list_append (token_list_t *list, int type, const char *value)
562{
563 token_node_t *node;
564
565 node = xtalloc (list, token_node_t);
566 node->type = type;
567 node->value = xtalloc_strdup (list, value);
568
569 node->next = NULL;
570
571 if (list->head == NULL) {
572 list->head = node;
573 } else {
574 list->tail->next = node;
575 }
576
577 list->tail = node;
578}
579
580void
581_token_list_append_list (token_list_t *list, token_list_t *tail)
582{
583 if (list->head == NULL) {
584 list->head = tail->head;
585 } else {
586 list->tail->next = tail->head;
587 }
588
589 list->tail = tail->tail;
590}
Carl Worth33cc4002010-05-12 12:17:10 -0700591
Carl Worth3a37b872010-05-10 11:44:09 -0700592void
Carl Wortha1e32bc2010-05-10 13:17:25 -0700593yyerror (void *scanner, const char *error)
Carl Worth3a37b872010-05-10 11:44:09 -0700594{
595 fprintf (stderr, "Parse error: %s\n", error);
596}
Carl Worth0b27b5f2010-05-10 16:16:06 -0700597
Carl Worth33cc4002010-05-12 12:17:10 -0700598glcpp_parser_t *
599glcpp_parser_create (void)
Carl Worth0b27b5f2010-05-10 16:16:06 -0700600{
Carl Worth33cc4002010-05-12 12:17:10 -0700601 glcpp_parser_t *parser;
602
Carl Worth5070a202010-05-12 12:45:33 -0700603 parser = xtalloc (NULL, glcpp_parser_t);
Carl Worth33cc4002010-05-12 12:17:10 -0700604
Carl Worth8f38aff2010-05-19 10:01:29 -0700605 glcpp_lex_init_extra (parser, &parser->scanner);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700606 parser->defines = hash_table_ctor (32, hash_table_string_hash,
607 hash_table_string_compare);
Carl Wortha807fb72010-05-18 22:10:04 -0700608 parser->expansions = NULL;
609
Carl Worth5a6b9a22010-05-20 14:29:43 -0700610 parser->just_printed_separator = 1;
Carl Worth876e5102010-05-20 14:38:06 -0700611 parser->need_newline = 0;
Carl Worth5a6b9a22010-05-20 14:29:43 -0700612
Carl Worthb20d33c2010-05-20 22:27:07 -0700613 parser->skip_stack = NULL;
614
Carl Worth33cc4002010-05-12 12:17:10 -0700615 return parser;
Carl Worth0b27b5f2010-05-10 16:16:06 -0700616}
617
618int
619glcpp_parser_parse (glcpp_parser_t *parser)
620{
621 return yyparse (parser);
622}
623
624void
Carl Worth33cc4002010-05-12 12:17:10 -0700625glcpp_parser_destroy (glcpp_parser_t *parser)
Carl Worth0b27b5f2010-05-10 16:16:06 -0700626{
Carl Worth876e5102010-05-20 14:38:06 -0700627 if (parser->need_newline)
628 printf ("\n");
Carl Worthb20d33c2010-05-20 22:27:07 -0700629 if (parser->skip_stack)
630 fprintf (stderr, "Error: Unterminated #if\n");
Carl Worth8f38aff2010-05-19 10:01:29 -0700631 glcpp_lex_destroy (parser->scanner);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700632 hash_table_dtor (parser->defines);
Carl Worth33cc4002010-05-12 12:17:10 -0700633 talloc_free (parser);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700634}
Carl Worthc6d5af32010-05-11 12:30:09 -0700635
Carl Worthbe0e2e92010-05-19 07:29:22 -0700636static int
637glcpp_parser_is_expanding (glcpp_parser_t *parser, const char *member)
638{
639 expansion_node_t *node;
640
641 for (node = parser->expansions; node; node = node->next) {
642 if (node->macro &&
643 strcmp (node->macro->identifier, member) == 0)
644 {
645 return 1;
646 }
647 }
648
649 return 0;
650}
651
Carl Wortha807fb72010-05-18 22:10:04 -0700652token_class_t
653glcpp_parser_classify_token (glcpp_parser_t *parser,
654 const char *identifier,
655 int *parameter_index)
Carl Worth9f62a7e2010-05-13 07:38:29 -0700656{
Carl Worthfcbbb462010-05-13 09:36:23 -0700657 macro_t *macro;
658
Carl Worthc10a51b2010-05-20 15:15:26 -0700659 /* Is this token a defined macro? */
Carl Worthfcbbb462010-05-13 09:36:23 -0700660 macro = hash_table_find (parser->defines, identifier);
661
662 if (macro == NULL)
Carl Wortha807fb72010-05-18 22:10:04 -0700663 return TOKEN_CLASS_IDENTIFIER;
Carl Worthfcbbb462010-05-13 09:36:23 -0700664
Carl Worthbe0e2e92010-05-19 07:29:22 -0700665 /* Don't consider this a macro if we are already actively
666 * expanding this macro. */
667 if (glcpp_parser_is_expanding (parser, identifier))
Carl Worthb5693832010-05-20 08:01:44 -0700668 return TOKEN_CLASS_IDENTIFIER_FINALIZED;
Carl Worthbe0e2e92010-05-19 07:29:22 -0700669
670 /* Definitely a macro. Just need to check if it's function-like. */
Carl Worthfcbbb462010-05-13 09:36:23 -0700671 if (macro->is_function)
Carl Wortha807fb72010-05-18 22:10:04 -0700672 return TOKEN_CLASS_FUNC_MACRO;
Carl Worthfcbbb462010-05-13 09:36:23 -0700673 else
Carl Wortha807fb72010-05-18 22:10:04 -0700674 return TOKEN_CLASS_OBJ_MACRO;
Carl Worth9f62a7e2010-05-13 07:38:29 -0700675}
676
Carl Worth33cc4002010-05-12 12:17:10 -0700677void
Carl Worthfcbbb462010-05-13 09:36:23 -0700678_define_object_macro (glcpp_parser_t *parser,
679 const char *identifier,
Carl Worth47252442010-05-19 13:54:37 -0700680 token_list_t *replacements)
Carl Worthfcbbb462010-05-13 09:36:23 -0700681{
682 macro_t *macro;
683
684 macro = xtalloc (parser, macro_t);
685
686 macro->is_function = 0;
Carl Worthc5e98552010-05-14 10:12:21 -0700687 macro->parameters = NULL;
Carl Wortha807fb72010-05-18 22:10:04 -0700688 macro->identifier = talloc_strdup (macro, identifier);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700689 macro->replacements = talloc_steal (macro, replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -0700690
691 hash_table_insert (parser->defines, macro, identifier);
692}
693
694void
695_define_function_macro (glcpp_parser_t *parser,
696 const char *identifier,
Carl Worthc5e98552010-05-14 10:12:21 -0700697 string_list_t *parameters,
Carl Worth47252442010-05-19 13:54:37 -0700698 token_list_t *replacements)
Carl Worthfcbbb462010-05-13 09:36:23 -0700699{
700 macro_t *macro;
701
702 macro = xtalloc (parser, macro_t);
703
704 macro->is_function = 1;
Carl Worthc5e98552010-05-14 10:12:21 -0700705 macro->parameters = talloc_steal (macro, parameters);
Carl Wortha807fb72010-05-18 22:10:04 -0700706 macro->identifier = talloc_strdup (macro, identifier);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700707 macro->replacements = talloc_steal (macro, replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -0700708
709 hash_table_insert (parser->defines, macro, identifier);
710}
711
Carl Wortha807fb72010-05-18 22:10:04 -0700712static void
Carl Worthc10a51b2010-05-20 15:15:26 -0700713_glcpp_parser_push_expansion (glcpp_parser_t *parser,
714 macro_t *macro,
715 token_node_t *replacements)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700716{
Carl Wortha807fb72010-05-18 22:10:04 -0700717 expansion_node_t *node;
718
719 node = xtalloc (parser, expansion_node_t);
720
721 node->macro = macro;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700722 node->replacements = replacements;
Carl Wortha807fb72010-05-18 22:10:04 -0700723
724 node->next = parser->expansions;
725 parser->expansions = node;
Carl Wortha807fb72010-05-18 22:10:04 -0700726}
727
Carl Worthaaa9acb2010-05-19 13:28:24 -0700728static void
Carl Wortha807fb72010-05-18 22:10:04 -0700729glcpp_parser_pop_expansion (glcpp_parser_t *parser)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700730{
Carl Wortha807fb72010-05-18 22:10:04 -0700731 expansion_node_t *node;
Carl Worth420d05a2010-05-17 10:15:23 -0700732
Carl Wortha807fb72010-05-18 22:10:04 -0700733 node = parser->expansions;
Carl Worth420d05a2010-05-17 10:15:23 -0700734
Carl Wortha807fb72010-05-18 22:10:04 -0700735 if (node == NULL) {
736 fprintf (stderr, "Internal error: _expansion_list_pop called on an empty list.\n");
737 exit (1);
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700738 }
739
Carl Wortha807fb72010-05-18 22:10:04 -0700740 parser->expansions = node->next;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700741
Carl Wortha807fb72010-05-18 22:10:04 -0700742 talloc_free (node);
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700743}
744
Carl Wortha807fb72010-05-18 22:10:04 -0700745void
Carl Worth2be8be02010-05-14 10:31:43 -0700746_expand_object_macro (glcpp_parser_t *parser, const char *identifier)
Carl Worth33cc4002010-05-12 12:17:10 -0700747{
Carl Worthfcbbb462010-05-13 09:36:23 -0700748 macro_t *macro;
Carl Worth33cc4002010-05-12 12:17:10 -0700749
Carl Worthfcbbb462010-05-13 09:36:23 -0700750 macro = hash_table_find (parser->defines, identifier);
751 assert (! macro->is_function);
Carl Worthbe0e2e92010-05-19 07:29:22 -0700752 assert (! glcpp_parser_is_expanding (parser, identifier));
Carl Worthfcbbb462010-05-13 09:36:23 -0700753
Carl Worthc10a51b2010-05-20 15:15:26 -0700754 _glcpp_parser_push_expansion (parser, macro, macro->replacements->head);
Carl Worthfcbbb462010-05-13 09:36:23 -0700755}
756
Carl Wortha807fb72010-05-18 22:10:04 -0700757void
Carl Worth2be8be02010-05-14 10:31:43 -0700758_expand_function_macro (glcpp_parser_t *parser,
759 const char *identifier,
Carl Worth8f6a8282010-05-14 10:44:19 -0700760 argument_list_t *arguments)
Carl Worthfcbbb462010-05-13 09:36:23 -0700761{
Carl Worthfcbbb462010-05-13 09:36:23 -0700762 macro_t *macro;
Carl Worthc10a51b2010-05-20 15:15:26 -0700763 token_list_t *expanded;
764 token_node_t *i, *j;
765 int parameter_index;
Carl Worthfcbbb462010-05-13 09:36:23 -0700766
767 macro = hash_table_find (parser->defines, identifier);
768 assert (macro->is_function);
Carl Worthbe0e2e92010-05-19 07:29:22 -0700769 assert (! glcpp_parser_is_expanding (parser, identifier));
Carl Worthfcbbb462010-05-13 09:36:23 -0700770
Carl Worth8f6a8282010-05-14 10:44:19 -0700771 if (_argument_list_length (arguments) !=
Carl Worth2be8be02010-05-14 10:31:43 -0700772 _string_list_length (macro->parameters))
773 {
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700774 fprintf (stderr,
775 "Error: macro %s invoked with %d arguments (expected %d)\n",
776 identifier,
Carl Worth8f6a8282010-05-14 10:44:19 -0700777 _argument_list_length (arguments),
Carl Worthc5e98552010-05-14 10:12:21 -0700778 _string_list_length (macro->parameters));
Carl Wortha807fb72010-05-18 22:10:04 -0700779 return;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700780 }
Carl Worthfcbbb462010-05-13 09:36:23 -0700781
Carl Worthc10a51b2010-05-20 15:15:26 -0700782 expanded = _token_list_create (macro);
783
784 for (i = macro->replacements->head; i; i = i->next) {
785 if (_string_list_contains (macro->parameters, i->value,
786 &parameter_index))
787 {
788 token_list_t *argument;
789 argument = _argument_list_member_at (arguments,
790 parameter_index);
791 for (j = argument->head; j; j = j->next)
792 {
793 _token_list_append (expanded, j->type,
794 j->value);
795 }
796 } else {
797 _token_list_append (expanded, i->type, i->value);
798 }
799 }
800
801 _glcpp_parser_push_expansion (parser, macro, expanded->head);
Carl Worth33cc4002010-05-12 12:17:10 -0700802}
Carl Worth8f38aff2010-05-19 10:01:29 -0700803
804static int
Carl Worth0293b2e2010-05-19 10:05:40 -0700805glcpp_parser_lex (glcpp_parser_t *parser)
Carl Worth8f38aff2010-05-19 10:01:29 -0700806{
Carl Worthaaa9acb2010-05-19 13:28:24 -0700807 expansion_node_t *expansion;
Carl Worth47252442010-05-19 13:54:37 -0700808 token_node_t *replacements;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700809 int parameter_index;
Carl Worthd8327e52010-05-20 15:18:54 -0700810 const char *token;
811 token_class_t class;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700812
813 /* Who says C can't do efficient tail recursion? */
814 RECURSE:
815
816 expansion = parser->expansions;
817
818 if (expansion == NULL)
819 return glcpp_lex (parser->scanner);
820
821 replacements = expansion->replacements;
822
823 /* Pop expansion when replacements is exhausted. */
824 if (replacements == NULL) {
825 glcpp_parser_pop_expansion (parser);
826 goto RECURSE;
827 }
828
829 expansion->replacements = replacements->next;
830
Carl Worthd8327e52010-05-20 15:18:54 -0700831 token = replacements->value;
832
833 /* Implement token pasting. */
834 if (replacements->next && strcmp (replacements->next->value, "##") == 0) {
835 token_node_t *next_node;
836
837 next_node = replacements->next->next;
838
839 if (next_node == NULL) {
840 fprintf (stderr, "Error: '##' cannot appear at the end of a macro expansion.\n");
841 exit (1);
842 }
843
844 token = xtalloc_asprintf (parser, "%s%s",
845 token, next_node->value);
846 expansion->replacements = next_node->next;
847 }
848
849
850 if (strcmp (token, "(") == 0)
Carl Worthaaa9acb2010-05-19 13:28:24 -0700851 return '(';
Carl Worthd8327e52010-05-20 15:18:54 -0700852 else if (strcmp (token, ")") == 0)
Carl Worthaaa9acb2010-05-19 13:28:24 -0700853 return ')';
Carl Worthaaa9acb2010-05-19 13:28:24 -0700854
Carl Worthd8327e52010-05-20 15:18:54 -0700855 yylval.str = xtalloc_strdup (parser, token);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700856
Carl Worthb5693832010-05-20 08:01:44 -0700857 /* Carefully refuse to expand any finalized identifier. */
858 if (replacements->type == IDENTIFIER_FINALIZED)
859 return IDENTIFIER_FINALIZED;
860
Carl Worthaaa9acb2010-05-19 13:28:24 -0700861 switch (glcpp_parser_classify_token (parser, yylval.str,
862 &parameter_index))
863 {
Carl Worthaaa9acb2010-05-19 13:28:24 -0700864 case TOKEN_CLASS_IDENTIFIER:
865 return IDENTIFIER;
866 break;
Carl Worthb5693832010-05-20 08:01:44 -0700867 case TOKEN_CLASS_IDENTIFIER_FINALIZED:
868 return IDENTIFIER_FINALIZED;
869 break;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700870 case TOKEN_CLASS_FUNC_MACRO:
871 return FUNC_MACRO;
872 break;
873 default:
874 case TOKEN_CLASS_OBJ_MACRO:
875 return OBJ_MACRO;
876 break;
877 }
Carl Worth8f38aff2010-05-19 10:01:29 -0700878}
Carl Worthb20d33c2010-05-20 22:27:07 -0700879
880static void
881_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition)
882{
883 skip_type_t current = SKIP_NO_SKIP;
884 skip_node_t *node;
885
886 if (parser->skip_stack)
887 current = parser->skip_stack->type;
888
889 node = xtalloc (parser, skip_node_t);
890
891 if (current == SKIP_NO_SKIP) {
892 if (condition)
893 node->type = SKIP_NO_SKIP;
894 else
895 node->type = SKIP_TO_ELSE;
896 } else {
897 node->type = SKIP_TO_ENDIF;
898 }
899
900 node->next = parser->skip_stack;
901 parser->skip_stack = node;
902}
903
904static void
905_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
906 int condition)
907{
908 if (parser->skip_stack == NULL) {
909 fprintf (stderr, "Error: %s without #if\n", type);
910 exit (1);
911 }
912
913 if (parser->skip_stack->type == SKIP_TO_ELSE) {
914 if (condition)
915 parser->skip_stack->type = SKIP_NO_SKIP;
916 } else {
917 parser->skip_stack->type = SKIP_TO_ENDIF;
918 }
919}
920
921static void
922_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser)
923{
924 skip_node_t *node;
925
926 if (parser->skip_stack == NULL) {
927 fprintf (stderr, "Error: #endif without #if\n");
928 exit (1);
929 }
930
931 node = parser->skip_stack;
932 parser->skip_stack = node->next;
933 talloc_free (node);
934}