Imported Upstream version 1.39.3
[platform/upstream/gobject-introspection.git] / giscanner / scannerparser.y
1 /* GObject introspection: C parser -*- indent-tabs-mode: t; tab-width: 8 -*-
2  *
3  * Copyright (c) 1997 Sandro Sigala  <ssigala@globalnet.it>
4  * Copyright (c) 2007-2008 Jürg Billeter  <j@bitron.ch>
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 %{
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <glib.h>
35 #include <glib/gstdio.h>
36 #include "sourcescanner.h"
37 #include "scannerparser.h"
38
39 extern FILE *yyin;
40 extern int lineno;
41 extern char linebuf[2000];
42 extern char *yytext;
43
44 extern int yylex (GISourceScanner *scanner);
45 static void yyerror (GISourceScanner *scanner, const char *str);
46
47 extern void ctype_free (GISourceType * type);
48
49 static int last_enum_value = -1;
50 static gboolean is_bitfield;
51 static GHashTable *const_table = NULL;
52
53 /**
54  * parse_c_string_literal:
55  * @str: A string containing a C string literal
56  *
57  * Based on g_strcompress(), but also handles
58  * hexadecimal escapes.
59  */
60 static char *
61 parse_c_string_literal (const char *str)
62 {
63   const gchar *p = str, *num;
64   gchar *dest = g_malloc (strlen (str) + 1);
65   gchar *q = dest;
66
67   while (*p)
68     {
69       if (*p == '\\')
70         {
71           p++;
72           switch (*p)
73             {
74             case '\0':
75               g_warning ("parse_c_string_literal: trailing \\");
76               goto out;
77             case '0':  case '1':  case '2':  case '3':  case '4':
78             case '5':  case '6':  case '7':
79               *q = 0;
80               num = p;
81               while ((p < num + 3) && (*p >= '0') && (*p <= '7'))
82                 {
83                   *q = (*q * 8) + (*p - '0');
84                   p++;
85                 }
86               q++;
87               p--;
88               break;
89             case 'x':
90               *q = 0;
91               p++;
92               num = p;
93               while ((p < num + 2) && (g_ascii_isxdigit(*p)))
94                 {
95                   *q = (*q * 16) + g_ascii_xdigit_value(*p);
96                   p++;
97                 }
98               q++;
99               p--;
100               break;
101             case 'b':
102               *q++ = '\b';
103               break;
104             case 'f':
105               *q++ = '\f';
106               break;
107             case 'n':
108               *q++ = '\n';
109               break;
110             case 'r':
111               *q++ = '\r';
112               break;
113             case 't':
114               *q++ = '\t';
115               break;
116             default:            /* Also handles \" and \\ */
117               *q++ = *p;
118               break;
119             }
120         }
121       else
122         *q++ = *p;
123       p++;
124     }
125 out:
126   *q = 0;
127
128   return dest;
129 }
130
131 enum {
132   IRRELEVANT = 1,
133   NOT_GI_SCANNER = 2,
134   FOR_GI_SCANNER = 3,
135 };
136
137 static void
138 update_skipping (GISourceScanner *scanner)
139 {
140   GList *l;
141   for (l = scanner->conditionals.head; l != NULL; l = g_list_next (l))
142     {
143       if (GPOINTER_TO_INT (l->data) == NOT_GI_SCANNER)
144         {
145            scanner->skipping = TRUE;
146            return;
147         }
148     }
149
150   scanner->skipping = FALSE;
151 }
152
153 static void
154 push_conditional (GISourceScanner *scanner,
155                   gint type)
156 {
157   g_assert (type != 0);
158   g_queue_push_head (&scanner->conditionals, GINT_TO_POINTER (type));
159 }
160
161 static gint
162 pop_conditional (GISourceScanner *scanner)
163 {
164   gint type = GPOINTER_TO_INT (g_queue_pop_head (&scanner->conditionals));
165
166   if (type == 0)
167     {
168       gchar *filename = g_file_get_path (scanner->current_file);
169       fprintf (stderr, "%s:%d: mismatched %s", filename, lineno, yytext);
170       g_free (filename);
171     }
172
173   return type;
174 }
175
176 static void
177 warn_if_cond_has_gi_scanner (GISourceScanner *scanner,
178                              const gchar *text)
179 {
180   /* Some other conditional that is not __GI_SCANNER__ */
181   if (strstr (text, "__GI_SCANNER__"))
182     {
183       gchar *filename = g_file_get_path (scanner->current_file);
184       fprintf (stderr, "%s:%d: the __GI_SCANNER__ constant should only be used with simple #ifdef or #endif: %s",
185                filename, lineno, text);
186       g_free (filename);
187     }
188 }
189
190 static void
191 toggle_conditional (GISourceScanner *scanner)
192 {
193   switch (pop_conditional (scanner))
194     {
195     case FOR_GI_SCANNER:
196       push_conditional (scanner, NOT_GI_SCANNER);
197       break;
198     case NOT_GI_SCANNER:
199       push_conditional (scanner, FOR_GI_SCANNER);
200       break;
201     case 0:
202       break;
203     default:
204       push_conditional (scanner, IRRELEVANT);
205       break;
206     }
207 }
208
209 %}
210
211 %error-verbose
212 %union {
213   char *str;
214   GList *list;
215   GISourceSymbol *symbol;
216   GISourceType *ctype;
217   StorageClassSpecifier storage_class_specifier;
218   TypeQualifier type_qualifier;
219   FunctionSpecifier function_specifier;
220   UnaryOperator unary_operator;
221 }
222
223 %parse-param { GISourceScanner* scanner }
224 %lex-param { GISourceScanner* scanner }
225
226 %token <str> IDENTIFIER "identifier"
227 %token <str> TYPEDEF_NAME "typedef-name"
228
229 %token INTEGER FLOATING BOOLEAN CHARACTER STRING
230
231 %token INTL_CONST INTUL_CONST
232 %token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
233 %token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
234
235 %token AUTO BOOL BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
236 %token EXTENSION EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT
237 %token RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED
238 %token VOID VOLATILE WHILE
239
240 %token FUNCTION_MACRO OBJECT_MACRO
241 %token IFDEF_GI_SCANNER IFNDEF_GI_SCANNER
242 %token IFDEF_COND IFNDEF_COND IF_COND ELIF_COND ELSE_COND ENDIF_COND
243
244 %start translation_unit
245
246 %type <ctype> declaration_specifiers
247 %type <ctype> enum_specifier
248 %type <ctype> pointer
249 %type <ctype> specifier_qualifier_list
250 %type <ctype> type_name
251 %type <ctype> struct_or_union
252 %type <ctype> struct_or_union_specifier
253 %type <ctype> type_specifier
254 %type <str> identifier
255 %type <str> typedef_name
256 %type <str> identifier_or_typedef_name
257 %type <symbol> abstract_declarator
258 %type <symbol> init_declarator
259 %type <symbol> declarator
260 %type <symbol> enumerator
261 %type <symbol> direct_abstract_declarator
262 %type <symbol> direct_declarator
263 %type <symbol> parameter_declaration
264 %type <symbol> struct_declarator
265 %type <list> enumerator_list
266 %type <list> identifier_list
267 %type <list> init_declarator_list
268 %type <list> parameter_list
269 %type <list> struct_declaration
270 %type <list> struct_declaration_list
271 %type <list> struct_declarator_list
272 %type <storage_class_specifier> storage_class_specifier
273 %type <type_qualifier> type_qualifier
274 %type <type_qualifier> type_qualifier_list
275 %type <function_specifier> function_specifier
276 %type <symbol> expression
277 %type <symbol> constant_expression
278 %type <symbol> conditional_expression
279 %type <symbol> logical_and_expression
280 %type <symbol> logical_or_expression
281 %type <symbol> inclusive_or_expression
282 %type <symbol> exclusive_or_expression
283 %type <symbol> multiplicative_expression
284 %type <symbol> additive_expression
285 %type <symbol> shift_expression
286 %type <symbol> relational_expression
287 %type <symbol> equality_expression
288 %type <symbol> and_expression
289 %type <symbol> cast_expression
290 %type <symbol> assignment_expression
291 %type <symbol> unary_expression
292 %type <symbol> postfix_expression
293 %type <symbol> primary_expression
294 %type <unary_operator> unary_operator
295 %type <str> function_macro
296 %type <str> object_macro
297 %type <symbol> strings
298
299 %%
300
301 /* A.2.1 Expressions. */
302
303 primary_expression
304         : identifier
305           {
306                 $$ = g_hash_table_lookup (const_table, $1);
307                 if ($$ == NULL) {
308                         $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
309                 } else {
310                         $$ = gi_source_symbol_ref ($$);
311                 }
312           }
313         | INTEGER
314           {
315                 char *rest;
316                 guint64 value;
317                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
318                 $$->const_int_set = TRUE;
319                 if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
320                         value = g_ascii_strtoull (yytext + 2, &rest, 16);
321                 } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
322                         value = g_ascii_strtoull (yytext + 1, &rest, 8);
323                 } else {
324                         value = g_ascii_strtoull (yytext, &rest, 10);
325                 }
326                 $$->const_int = value;
327                 $$->const_int_is_unsigned = (rest && (rest[0] == 'U'));
328           }
329         | BOOLEAN
330           {
331                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
332                 $$->const_boolean_set = TRUE;
333                 $$->const_boolean = g_ascii_strcasecmp (yytext, "true") == 0 ? TRUE : FALSE;
334           }
335         | CHARACTER
336           {
337                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
338                 $$->const_int_set = TRUE;
339                 $$->const_int = g_utf8_get_char(yytext + 1);
340           }
341         | FLOATING
342           {
343                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
344                 $$->const_double_set = TRUE;
345                 $$->const_double = 0.0;
346         sscanf (yytext, "%lf", &($$->const_double));
347           }
348         | strings
349         | '(' expression ')'
350           {
351                 $$ = $2;
352           }
353         | EXTENSION '(' '{' block_item_list '}' ')'
354           {
355                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
356           }
357         ;
358
359 /* concatenate adjacent string literal tokens */
360 strings
361         : STRING
362           {
363                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
364                 yytext[strlen (yytext) - 1] = '\0';
365                 $$->const_string = parse_c_string_literal (yytext + 1);
366                 if (!g_utf8_validate ($$->const_string, -1, NULL))
367                   {
368 #if 0
369                     g_warning ("Ignoring non-UTF-8 constant string \"%s\"", yytext + 1);
370 #endif
371                     g_free($$->const_string);
372                     $$->const_string = NULL;
373                   }
374
375           }
376         | strings STRING
377           {
378                 char *strings, *string2;
379                 $$ = $1;
380                 yytext[strlen (yytext) - 1] = '\0';
381                 string2 = parse_c_string_literal (yytext + 1);
382                 strings = g_strconcat ($$->const_string, string2, NULL);
383                 g_free ($$->const_string);
384                 g_free (string2);
385                 $$->const_string = strings;
386           }
387         ;
388
389 identifier
390         : IDENTIFIER
391           {
392                 $$ = g_strdup (yytext);
393           }
394         ;
395
396 identifier_or_typedef_name
397         : identifier
398         | typedef_name
399         ;
400
401 postfix_expression
402         : primary_expression
403         | postfix_expression '[' expression ']'
404           {
405                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
406           }
407         | postfix_expression '(' argument_expression_list ')'
408           {
409                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
410           }
411         | postfix_expression '(' ')'
412           {
413                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
414           }
415         | postfix_expression '.' identifier_or_typedef_name
416           {
417                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
418           }
419         | postfix_expression ARROW identifier_or_typedef_name
420           {
421                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
422           }
423         | postfix_expression PLUSPLUS
424           {
425                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
426           }
427         | postfix_expression MINUSMINUS
428           {
429                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
430           }
431         ;
432
433 argument_expression_list
434         : assignment_expression
435         | argument_expression_list ',' assignment_expression
436         ;
437
438 unary_expression
439         : postfix_expression
440         | PLUSPLUS unary_expression
441           {
442                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
443           }
444         | MINUSMINUS unary_expression
445           {
446                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
447           }
448         | unary_operator cast_expression
449           {
450                 switch ($1) {
451                 case UNARY_PLUS:
452                         $$ = $2;
453                         break;
454                 case UNARY_MINUS:
455                         $$ = gi_source_symbol_copy ($2);
456                         $$->const_int = -$2->const_int;
457                         break;
458                 case UNARY_BITWISE_COMPLEMENT:
459                         $$ = gi_source_symbol_copy ($2);
460                         $$->const_int = ~$2->const_int;
461                         break;
462                 case UNARY_LOGICAL_NEGATION:
463                         $$ = gi_source_symbol_copy ($2);
464                         $$->const_int = !gi_source_symbol_get_const_boolean ($2);
465                         break;
466                 default:
467                         $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
468                         break;
469                 }
470           }
471         | INTL_CONST '(' unary_expression ')'
472           {
473                 $$ = $3;
474                 if ($$->const_int_set) {
475                         $$->base_type = gi_source_basic_type_new ($$->const_int_is_unsigned ? "guint64" : "gint64");
476                 }
477           }
478         | INTUL_CONST '(' unary_expression ')'
479           {
480                 $$ = $3;
481                 if ($$->const_int_set) {
482                         $$->base_type = gi_source_basic_type_new ("guint64");
483                 }
484           }
485         | SIZEOF unary_expression
486           {
487                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
488           }
489         | SIZEOF '(' type_name ')'
490           {
491                 ctype_free ($3);
492                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
493           }
494         ;
495
496 unary_operator
497         : '&'
498           {
499                 $$ = UNARY_ADDRESS_OF;
500           }
501         | '*'
502           {
503                 $$ = UNARY_POINTER_INDIRECTION;
504           }
505         | '+'
506           {
507                 $$ = UNARY_PLUS;
508           }
509         | '-'
510           {
511                 $$ = UNARY_MINUS;
512           }
513         | '~'
514           {
515                 $$ = UNARY_BITWISE_COMPLEMENT;
516           }
517         | '!'
518           {
519                 $$ = UNARY_LOGICAL_NEGATION;
520           }
521         ;
522
523 cast_expression
524         : unary_expression
525         | '(' type_name ')' cast_expression
526           {
527                 $$ = $4;
528                 if ($$->const_int_set || $$->const_double_set || $$->const_string != NULL) {
529                         $$->base_type = $2;
530                 } else {
531                         ctype_free ($2);
532                 }
533           }
534         ;
535
536 multiplicative_expression
537         : cast_expression
538         | multiplicative_expression '*' cast_expression
539           {
540                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
541                 $$->const_int_set = TRUE;
542                 $$->const_int = $1->const_int * $3->const_int;
543           }
544         | multiplicative_expression '/' cast_expression
545           {
546                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
547                 $$->const_int_set = TRUE;
548                 if ($3->const_int != 0) {
549                         $$->const_int = $1->const_int / $3->const_int;
550                 }
551           }
552         | multiplicative_expression '%' cast_expression
553           {
554                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
555                 $$->const_int_set = TRUE;
556                 if ($3->const_int != 0) {
557                         $$->const_int = $1->const_int % $3->const_int;
558                 }
559           }
560         ;
561
562 additive_expression
563         : multiplicative_expression
564         | additive_expression '+' multiplicative_expression
565           {
566                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
567                 $$->const_int_set = TRUE;
568                 $$->const_int = $1->const_int + $3->const_int;
569           }
570         | additive_expression '-' multiplicative_expression
571           {
572                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
573                 $$->const_int_set = TRUE;
574                 $$->const_int = $1->const_int - $3->const_int;
575           }
576         ;
577
578 shift_expression
579         : additive_expression
580         | shift_expression SL additive_expression
581           {
582                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
583                 $$->const_int_set = TRUE;
584                 $$->const_int = $1->const_int << $3->const_int;
585
586                 /* assume this is a bitfield/flags declaration
587                  * if a left shift operator is sued in an enum value
588                  * This mimics the glib-mkenum behavior.
589                  */
590                 is_bitfield = TRUE;
591           }
592         | shift_expression SR additive_expression
593           {
594                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
595                 $$->const_int_set = TRUE;
596                 $$->const_int = $1->const_int >> $3->const_int;
597           }
598         ;
599
600 relational_expression
601         : shift_expression
602         | relational_expression '<' shift_expression
603           {
604                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
605                 $$->const_int_set = TRUE;
606                 $$->const_int = $1->const_int < $3->const_int;
607           }
608         | relational_expression '>' shift_expression
609           {
610                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
611                 $$->const_int_set = TRUE;
612                 $$->const_int = $1->const_int > $3->const_int;
613           }
614         | relational_expression LTEQ shift_expression
615           {
616                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
617                 $$->const_int_set = TRUE;
618                 $$->const_int = $1->const_int <= $3->const_int;
619           }
620         | relational_expression GTEQ shift_expression
621           {
622                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
623                 $$->const_int_set = TRUE;
624                 $$->const_int = $1->const_int >= $3->const_int;
625           }
626         ;
627
628 equality_expression
629         : relational_expression
630         | equality_expression EQ relational_expression
631           {
632                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
633                 $$->const_int_set = TRUE;
634                 $$->const_int = $1->const_int == $3->const_int;
635           }
636         | equality_expression NOTEQ relational_expression
637           {
638                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
639                 $$->const_int_set = TRUE;
640                 $$->const_int = $1->const_int != $3->const_int;
641           }
642         ;
643
644 and_expression
645         : equality_expression
646         | and_expression '&' equality_expression
647           {
648                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
649                 $$->const_int_set = TRUE;
650                 $$->const_int = $1->const_int & $3->const_int;
651           }
652         ;
653
654 exclusive_or_expression
655         : and_expression
656         | exclusive_or_expression '^' and_expression
657           {
658                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
659                 $$->const_int_set = TRUE;
660                 $$->const_int = $1->const_int ^ $3->const_int;
661           }
662         ;
663
664 inclusive_or_expression
665         : exclusive_or_expression
666         | inclusive_or_expression '|' exclusive_or_expression
667           {
668                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
669                 $$->const_int_set = TRUE;
670                 $$->const_int = $1->const_int | $3->const_int;
671           }
672         ;
673
674 logical_and_expression
675         : inclusive_or_expression
676         | logical_and_expression ANDAND inclusive_or_expression
677           {
678                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
679                 $$->const_int_set = TRUE;
680                 $$->const_int =
681                   gi_source_symbol_get_const_boolean ($1) &&
682                   gi_source_symbol_get_const_boolean ($3);
683           }
684         ;
685
686 logical_or_expression
687         : logical_and_expression
688         | logical_or_expression OROR logical_and_expression
689           {
690                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_file, lineno);
691                 $$->const_int_set = TRUE;
692                 $$->const_int =
693                   gi_source_symbol_get_const_boolean ($1) ||
694                   gi_source_symbol_get_const_boolean ($3);
695           }
696         ;
697
698 conditional_expression
699         : logical_or_expression
700         | logical_or_expression '?' expression ':' expression
701           {
702                 $$ = gi_source_symbol_get_const_boolean ($1) ? $3 : $5;
703           }
704         ;
705
706 assignment_expression
707         : conditional_expression
708         | unary_expression assignment_operator assignment_expression
709           {
710                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
711           }
712         ;
713
714 assignment_operator
715         : '='
716         | MULEQ
717         | DIVEQ
718         | MODEQ
719         | ADDEQ
720         | SUBEQ
721         | SLEQ
722         | SREQ
723         | ANDEQ
724         | XOREQ
725         | OREQ
726         ;
727
728 expression
729         : assignment_expression
730         | expression ',' assignment_expression
731         | EXTENSION expression
732           {
733                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
734           }
735         ;
736
737 constant_expression
738         : conditional_expression
739         ;
740
741 /* A.2.2 Declarations. */
742
743 declaration
744         : declaration_specifiers init_declarator_list ';'
745           {
746                 GList *l;
747                 for (l = $2; l != NULL; l = l->next) {
748                         GISourceSymbol *sym = l->data;
749                         gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
750                         if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
751                                 sym->type = CSYMBOL_TYPE_TYPEDEF;
752                         } else if (sym->base_type->type == CTYPE_FUNCTION) {
753                                 sym->type = CSYMBOL_TYPE_FUNCTION;
754                         } else {
755                                 sym->type = CSYMBOL_TYPE_OBJECT;
756                         }
757                         gi_source_scanner_add_symbol (scanner, sym);
758                         gi_source_symbol_unref (sym);
759                 }
760                 ctype_free ($1);
761           }
762         | declaration_specifiers ';'
763           {
764                 ctype_free ($1);
765           }
766         ;
767
768 declaration_specifiers
769         : storage_class_specifier declaration_specifiers
770           {
771                 $$ = $2;
772                 $$->storage_class_specifier |= $1;
773           }
774         | storage_class_specifier
775           {
776                 $$ = gi_source_type_new (CTYPE_INVALID);
777                 $$->storage_class_specifier |= $1;
778           }
779         | type_specifier declaration_specifiers
780           {
781                 $$ = $1;
782                 /* combine basic types like unsigned int and long long */
783                 if ($$->type == CTYPE_BASIC_TYPE && $2->type == CTYPE_BASIC_TYPE) {
784                         char *name = g_strdup_printf ("%s %s", $$->name, $2->name);
785                         g_free ($$->name);
786                         $$->name = name;
787                         ctype_free ($2);
788                 } else {
789                         $$->base_type = $2;
790                 }
791           }
792         | type_specifier
793         | type_qualifier declaration_specifiers
794           {
795                 $$ = $2;
796                 $$->type_qualifier |= $1;
797           }
798         | type_qualifier
799           {
800                 $$ = gi_source_type_new (CTYPE_INVALID);
801                 $$->type_qualifier |= $1;
802           }
803         | function_specifier declaration_specifiers
804           {
805                 $$ = $2;
806                 $$->function_specifier |= $1;
807           }
808         | function_specifier
809           {
810                 $$ = gi_source_type_new (CTYPE_INVALID);
811                 $$->function_specifier |= $1;
812           }
813         ;
814
815 init_declarator_list
816         : init_declarator
817           {
818                 $$ = g_list_append (NULL, $1);
819           }
820         | init_declarator_list ',' init_declarator
821           {
822                 $$ = g_list_append ($1, $3);
823           }
824         ;
825
826 init_declarator
827         : declarator
828         | declarator '=' initializer
829         ;
830
831 storage_class_specifier
832         : TYPEDEF
833           {
834                 $$ = STORAGE_CLASS_TYPEDEF;
835           }
836         | EXTERN
837           {
838                 $$ = STORAGE_CLASS_EXTERN;
839           }
840         | STATIC
841           {
842                 $$ = STORAGE_CLASS_STATIC;
843           }
844         | AUTO
845           {
846                 $$ = STORAGE_CLASS_AUTO;
847           }
848         | REGISTER
849           {
850                 $$ = STORAGE_CLASS_REGISTER;
851           }
852         ;
853
854 type_specifier
855         : VOID
856           {
857                 $$ = gi_source_type_new (CTYPE_VOID);
858           }
859         | CHAR
860           {
861                 $$ = gi_source_basic_type_new ("char");
862           }
863         | SHORT
864           {
865                 $$ = gi_source_basic_type_new ("short");
866           }
867         | INT
868           {
869                 $$ = gi_source_basic_type_new ("int");
870           }
871         | LONG
872           {
873                 $$ = gi_source_basic_type_new ("long");
874           }
875         | FLOAT
876           {
877                 $$ = gi_source_basic_type_new ("float");
878           }
879         | DOUBLE
880           {
881                 $$ = gi_source_basic_type_new ("double");
882           }
883         | SIGNED
884           {
885                 $$ = gi_source_basic_type_new ("signed");
886           }
887         | UNSIGNED
888           {
889                 $$ = gi_source_basic_type_new ("unsigned");
890           }
891         | BOOL
892           {
893                 $$ = gi_source_basic_type_new ("bool");
894           }
895         | struct_or_union_specifier
896         | enum_specifier
897         | typedef_name
898           {
899                 $$ = gi_source_typedef_new ($1);
900                 g_free ($1);
901           }
902         ;
903
904 struct_or_union_specifier
905         : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
906           {
907                 GISourceSymbol *sym;
908                 $$ = $1;
909                 $$->name = $2;
910                 $$->child_list = $4;
911
912                 sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
913                 if ($$->type == CTYPE_STRUCT) {
914                         sym->type = CSYMBOL_TYPE_STRUCT;
915                 } else if ($$->type == CTYPE_UNION) {
916                         sym->type = CSYMBOL_TYPE_UNION;
917                 } else {
918                         g_assert_not_reached ();
919                 }
920                 sym->ident = g_strdup ($$->name);
921                 sym->base_type = gi_source_type_copy ($$);
922                 gi_source_scanner_add_symbol (scanner, sym);
923                 gi_source_symbol_unref (sym);
924           }
925         | struct_or_union '{' struct_declaration_list '}'
926           {
927                 $$ = $1;
928                 $$->child_list = $3;
929           }
930         | struct_or_union identifier_or_typedef_name
931           {
932                 $$ = $1;
933                 $$->name = $2;
934           }
935         ;
936
937 struct_or_union
938         : STRUCT
939           {
940                 scanner->private = FALSE;
941                 $$ = gi_source_struct_new (NULL);
942           }
943         | UNION
944           {
945                 scanner->private = FALSE;
946                 $$ = gi_source_union_new (NULL);
947           }
948         ;
949
950 struct_declaration_list
951         : struct_declaration
952         | struct_declaration_list struct_declaration
953           {
954                 $$ = g_list_concat ($1, $2);
955           }
956         ;
957
958 struct_declaration
959         : specifier_qualifier_list struct_declarator_list ';'
960           {
961             GList *l;
962             $$ = NULL;
963             for (l = $2; l != NULL; l = l->next)
964               {
965                 GISourceSymbol *sym = l->data;
966                 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF)
967                     sym->type = CSYMBOL_TYPE_TYPEDEF;
968                 else
969                     sym->type = CSYMBOL_TYPE_MEMBER;
970                 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
971                 sym->private = scanner->private;
972                 $$ = g_list_append ($$, sym);
973               }
974             ctype_free ($1);
975           }
976         ;
977
978 specifier_qualifier_list
979         : type_specifier specifier_qualifier_list
980           {
981                 $$ = $1;
982                 $$->base_type = $2;
983           }
984         | type_specifier
985         | type_qualifier specifier_qualifier_list
986           {
987                 $$ = $2;
988                 $$->type_qualifier |= $1;
989           }
990         | type_qualifier
991           {
992                 $$ = gi_source_type_new (CTYPE_INVALID);
993                 $$->type_qualifier |= $1;
994           }
995         ;
996
997 struct_declarator_list
998         : struct_declarator
999           {
1000                 $$ = g_list_append (NULL, $1);
1001           }
1002         | struct_declarator_list ',' struct_declarator
1003           {
1004                 $$ = g_list_append ($1, $3);
1005           }
1006         ;
1007
1008 struct_declarator
1009         : /* empty, support for anonymous structs and unions */
1010           {
1011                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1012           }
1013         | declarator
1014         | ':' constant_expression
1015           {
1016                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1017           }
1018         | declarator ':' constant_expression
1019           {
1020                 $$ = $1;
1021                 if ($3->const_int_set) {
1022                   $$->const_int_set = TRUE;
1023                   $$->const_int = $3->const_int;
1024                 }
1025           }
1026         ;
1027
1028 enum_specifier
1029         : enum_keyword identifier_or_typedef_name '{' enumerator_list '}'
1030           {
1031                 $$ = gi_source_enum_new ($2);
1032                 $$->child_list = $4;
1033                 $$->is_bitfield = is_bitfield || scanner->flags;
1034                 last_enum_value = -1;
1035           }
1036         | enum_keyword '{' enumerator_list '}'
1037           {
1038                 $$ = gi_source_enum_new (NULL);
1039                 $$->child_list = $3;
1040                 $$->is_bitfield = is_bitfield || scanner->flags;
1041                 last_enum_value = -1;
1042           }
1043         | enum_keyword identifier_or_typedef_name '{' enumerator_list ',' '}'
1044           {
1045                 $$ = gi_source_enum_new ($2);
1046                 $$->child_list = $4;
1047                 $$->is_bitfield = is_bitfield || scanner->flags;
1048                 last_enum_value = -1;
1049           }
1050         | enum_keyword '{' enumerator_list ',' '}'
1051           {
1052                 $$ = gi_source_enum_new (NULL);
1053                 $$->child_list = $3;
1054                 $$->is_bitfield = is_bitfield || scanner->flags;
1055                 last_enum_value = -1;
1056           }
1057         | enum_keyword identifier_or_typedef_name
1058           {
1059                 $$ = gi_source_enum_new ($2);
1060           }
1061         ;
1062
1063 enum_keyword
1064         : ENUM
1065           {
1066                 scanner->flags = FALSE;
1067                 scanner->private = FALSE;
1068           }
1069         ;
1070
1071 enumerator_list
1072         :
1073           {
1074                 /* reset flag before the first enum value */
1075                 is_bitfield = FALSE;
1076           }
1077           enumerator
1078           {
1079             $2->private = scanner->private;
1080             $$ = g_list_append (NULL, $2);
1081           }
1082         | enumerator_list ',' enumerator
1083           {
1084             $3->private = scanner->private;
1085             $$ = g_list_append ($1, $3);
1086           }
1087         ;
1088
1089 enumerator
1090         : identifier
1091           {
1092                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_file, lineno);
1093                 $$->ident = $1;
1094                 $$->const_int_set = TRUE;
1095                 $$->const_int = ++last_enum_value;
1096                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
1097           }
1098         | identifier '=' constant_expression
1099           {
1100                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_file, lineno);
1101                 $$->ident = $1;
1102                 $$->const_int_set = TRUE;
1103                 $$->const_int = $3->const_int;
1104                 last_enum_value = $$->const_int;
1105                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
1106           }
1107         ;
1108
1109 type_qualifier
1110         : CONST
1111           {
1112                 $$ = TYPE_QUALIFIER_CONST;
1113           }
1114         | RESTRICT
1115           {
1116                 $$ = TYPE_QUALIFIER_RESTRICT;
1117           }
1118         | EXTENSION
1119           {
1120                 $$ = TYPE_QUALIFIER_EXTENSION;
1121           }
1122         | VOLATILE
1123           {
1124                 $$ = TYPE_QUALIFIER_VOLATILE;
1125           }
1126         ;
1127
1128 function_specifier
1129         : INLINE
1130           {
1131                 $$ = FUNCTION_INLINE;
1132           }
1133         ;
1134
1135 declarator
1136         : pointer direct_declarator
1137           {
1138                 $$ = $2;
1139                 gi_source_symbol_merge_type ($$, $1);
1140           }
1141         | direct_declarator
1142         ;
1143
1144 direct_declarator
1145         : identifier
1146           {
1147                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1148                 $$->ident = $1;
1149           }
1150         | '(' declarator ')'
1151           {
1152                 $$ = $2;
1153           }
1154         | direct_declarator '[' assignment_expression ']'
1155           {
1156                 $$ = $1;
1157                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1158           }
1159         | direct_declarator '[' ']'
1160           {
1161                 $$ = $1;
1162                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1163           }
1164         | direct_declarator '(' parameter_list ')'
1165           {
1166                 GISourceType *func = gi_source_function_new ();
1167                 // ignore (void) parameter list
1168                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1169                         func->child_list = $3;
1170                 }
1171                 $$ = $1;
1172                 gi_source_symbol_merge_type ($$, func);
1173           }
1174         | direct_declarator '(' identifier_list ')'
1175           {
1176                 GISourceType *func = gi_source_function_new ();
1177                 func->child_list = $3;
1178                 $$ = $1;
1179                 gi_source_symbol_merge_type ($$, func);
1180           }
1181         | direct_declarator '(' ')'
1182           {
1183                 GISourceType *func = gi_source_function_new ();
1184                 $$ = $1;
1185                 gi_source_symbol_merge_type ($$, func);
1186           }
1187         ;
1188
1189 pointer
1190         : '*' type_qualifier_list
1191           {
1192                 $$ = gi_source_pointer_new (NULL);
1193                 $$->type_qualifier = $2;
1194           }
1195         | '*'
1196           {
1197                 $$ = gi_source_pointer_new (NULL);
1198           }
1199         | '*' type_qualifier_list pointer
1200           {
1201                 GISourceType **base = &($3->base_type);
1202
1203                 while (*base != NULL) {
1204                         base = &((*base)->base_type);
1205                 }
1206                 *base = gi_source_pointer_new (NULL);
1207                 (*base)->type_qualifier = $2;
1208                 $$ = $3;
1209           }
1210         | '*' pointer
1211           {
1212                 GISourceType **base = &($2->base_type);
1213
1214                 while (*base != NULL) {
1215                         base = &((*base)->base_type);
1216                 }
1217                 *base = gi_source_pointer_new (NULL);
1218                 $$ = $2;
1219           }
1220         ;
1221
1222 type_qualifier_list
1223         : type_qualifier
1224         | type_qualifier_list type_qualifier
1225           {
1226                 $$ = $1 | $2;
1227           }
1228         ;
1229
1230 parameter_list
1231         : parameter_declaration
1232           {
1233                 $$ = g_list_append (NULL, $1);
1234           }
1235         | parameter_list ',' parameter_declaration
1236           {
1237                 $$ = g_list_append ($1, $3);
1238           }
1239         ;
1240
1241 parameter_declaration
1242         : declaration_specifiers declarator
1243           {
1244                 $$ = $2;
1245                 gi_source_symbol_merge_type ($$, $1);
1246           }
1247         | declaration_specifiers abstract_declarator
1248           {
1249                 $$ = $2;
1250                 gi_source_symbol_merge_type ($$, $1);
1251           }
1252         | declaration_specifiers
1253           {
1254                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1255                 $$->base_type = $1;
1256           }
1257         | ELLIPSIS
1258           {
1259                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS, scanner->current_file, lineno);
1260           }
1261         ;
1262
1263 identifier_list
1264         : identifier
1265           {
1266                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1267                 sym->ident = $1;
1268                 $$ = g_list_append (NULL, sym);
1269           }
1270         | identifier_list ',' identifier
1271           {
1272                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1273                 sym->ident = $3;
1274                 $$ = g_list_append ($1, sym);
1275           }
1276         ;
1277
1278 type_name
1279         : specifier_qualifier_list
1280         | specifier_qualifier_list abstract_declarator
1281         ;
1282
1283 abstract_declarator
1284         : pointer
1285           {
1286                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1287                 gi_source_symbol_merge_type ($$, $1);
1288           }
1289         | direct_abstract_declarator
1290         | pointer direct_abstract_declarator
1291           {
1292                 $$ = $2;
1293                 gi_source_symbol_merge_type ($$, $1);
1294           }
1295         ;
1296
1297 direct_abstract_declarator
1298         : '(' abstract_declarator ')'
1299           {
1300                 $$ = $2;
1301           }
1302         | '[' ']'
1303           {
1304                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1305                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1306           }
1307         | '[' assignment_expression ']'
1308           {
1309                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1310                 gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
1311           }
1312         | direct_abstract_declarator '[' ']'
1313           {
1314                 $$ = $1;
1315                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1316           }
1317         | direct_abstract_declarator '[' assignment_expression ']'
1318           {
1319                 $$ = $1;
1320                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1321           }
1322         | '(' ')'
1323           {
1324                 GISourceType *func = gi_source_function_new ();
1325                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1326                 gi_source_symbol_merge_type ($$, func);
1327           }
1328         | '(' parameter_list ')'
1329           {
1330                 GISourceType *func = gi_source_function_new ();
1331                 // ignore (void) parameter list
1332                 if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
1333                         func->child_list = $2;
1334                 }
1335                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_file, lineno);
1336                 gi_source_symbol_merge_type ($$, func);
1337           }
1338         | direct_abstract_declarator '(' ')'
1339           {
1340                 GISourceType *func = gi_source_function_new ();
1341                 $$ = $1;
1342                 gi_source_symbol_merge_type ($$, func);
1343           }
1344         | direct_abstract_declarator '(' parameter_list ')'
1345           {
1346                 GISourceType *func = gi_source_function_new ();
1347                 // ignore (void) parameter list
1348                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1349                         func->child_list = $3;
1350                 }
1351                 $$ = $1;
1352                 gi_source_symbol_merge_type ($$, func);
1353           }
1354         ;
1355
1356 typedef_name
1357         : TYPEDEF_NAME
1358           {
1359                 $$ = g_strdup (yytext);
1360           }
1361         ;
1362
1363 initializer
1364         : assignment_expression
1365         | '{' initializer_list '}'
1366         | '{' initializer_list ',' '}'
1367         ;
1368
1369 initializer_list
1370         : initializer
1371         | initializer_list ',' initializer
1372         ;
1373
1374 /* A.2.3 Statements. */
1375
1376 statement
1377         : labeled_statement
1378         | compound_statement
1379         | expression_statement
1380         | selection_statement
1381         | iteration_statement
1382         | jump_statement
1383         ;
1384
1385 labeled_statement
1386         : identifier_or_typedef_name ':' statement
1387         | CASE constant_expression ':' statement
1388         | DEFAULT ':' statement
1389         ;
1390
1391 compound_statement
1392         : '{' '}'
1393         | '{' block_item_list '}'
1394         ;
1395
1396 block_item_list
1397         : block_item
1398         | block_item_list block_item
1399         ;
1400
1401 block_item
1402         : declaration
1403         | statement
1404         ;
1405
1406 expression_statement
1407         : ';'
1408         | expression ';'
1409         ;
1410
1411 selection_statement
1412         : IF '(' expression ')' statement
1413         | IF '(' expression ')' statement ELSE statement
1414         | SWITCH '(' expression ')' statement
1415         ;
1416
1417 iteration_statement
1418         : WHILE '(' expression ')' statement
1419         | DO statement WHILE '(' expression ')' ';'
1420         | FOR '(' ';' ';' ')' statement
1421         | FOR '(' expression ';' ';' ')' statement
1422         | FOR '(' ';' expression ';' ')' statement
1423         | FOR '(' expression ';' expression ';' ')' statement
1424         | FOR '(' ';' ';' expression ')' statement
1425         | FOR '(' expression ';' ';' expression ')' statement
1426         | FOR '(' ';' expression ';' expression ')' statement
1427         | FOR '(' expression ';' expression ';' expression ')' statement
1428         ;
1429
1430 jump_statement
1431         : GOTO identifier_or_typedef_name ';'
1432         | CONTINUE ';'
1433         | BREAK ';'
1434         | RETURN ';'
1435         | RETURN expression ';'
1436         ;
1437
1438 /* A.2.4 External definitions. */
1439
1440 translation_unit
1441         : external_declaration
1442         | translation_unit external_declaration
1443         ;
1444
1445 external_declaration
1446         : function_definition
1447         | declaration
1448         | macro
1449         ;
1450
1451 function_definition
1452         : declaration_specifiers declarator declaration_list compound_statement
1453         | declaration_specifiers declarator compound_statement
1454         ;
1455
1456 declaration_list
1457         : declaration
1458         | declaration_list declaration
1459         ;
1460
1461 /* Macros */
1462
1463 function_macro
1464         : FUNCTION_MACRO
1465           {
1466                 $$ = g_strdup (yytext + strlen ("#define "));
1467           }
1468         ;
1469
1470 object_macro
1471         : OBJECT_MACRO
1472           {
1473                 $$ = g_strdup (yytext + strlen ("#define "));
1474           }
1475         ;
1476
1477 function_macro_define
1478         : function_macro '(' identifier_list ')'
1479         ;
1480
1481 object_macro_define
1482         : object_macro constant_expression
1483           {
1484                 if ($2->const_int_set || $2->const_boolean_set || $2->const_double_set || $2->const_string != NULL) {
1485                         $2->ident = $1;
1486                         gi_source_scanner_add_symbol (scanner, $2);
1487                         gi_source_symbol_unref ($2);
1488                 }
1489           }
1490         ;
1491
1492 preproc_conditional
1493         : IFDEF_GI_SCANNER 
1494           {
1495                 push_conditional (scanner, FOR_GI_SCANNER);
1496                 update_skipping (scanner);
1497           }
1498         | IFNDEF_GI_SCANNER
1499           {
1500                 push_conditional (scanner, NOT_GI_SCANNER);
1501                 update_skipping (scanner);
1502           }
1503         | IFDEF_COND 
1504           {
1505                 warn_if_cond_has_gi_scanner (scanner, yytext);
1506                 push_conditional (scanner, IRRELEVANT);
1507           }
1508         | IFNDEF_COND
1509           {
1510                 warn_if_cond_has_gi_scanner (scanner, yytext);
1511                 push_conditional (scanner, IRRELEVANT);
1512           }
1513         | IF_COND 
1514           {
1515                 warn_if_cond_has_gi_scanner (scanner, yytext);
1516                 push_conditional (scanner, IRRELEVANT);
1517           }
1518         | ELIF_COND
1519           {
1520                 warn_if_cond_has_gi_scanner (scanner, yytext);
1521                 pop_conditional (scanner);
1522                 push_conditional (scanner, IRRELEVANT);
1523                 update_skipping (scanner);
1524           }
1525         | ELSE_COND
1526           {
1527                 toggle_conditional (scanner);
1528                 update_skipping (scanner);
1529           }
1530         | ENDIF_COND
1531           {
1532                 pop_conditional (scanner);
1533                 update_skipping (scanner);
1534           }
1535         ;
1536
1537 macro
1538         : function_macro_define
1539         | object_macro_define
1540         | preproc_conditional
1541         | error
1542         ;
1543
1544 %%
1545 static void
1546 yyerror (GISourceScanner *scanner, const char *s)
1547 {
1548   /* ignore errors while doing a macro scan as not all object macros
1549    * have valid expressions */
1550   if (!scanner->macro_scan)
1551     {
1552       fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
1553               g_file_get_parse_name (scanner->current_file), lineno, s, linebuf, yytext);
1554     }
1555 }
1556
1557 static int
1558 eat_hspace (FILE * f)
1559 {
1560   int c;
1561   do
1562     {
1563       c = fgetc (f);
1564     }
1565   while (c == ' ' || c == '\t');
1566   return c;
1567 }
1568
1569 static int
1570 pass_line (FILE * f, int c,
1571            FILE *out)
1572 {
1573   while (c != EOF && c != '\n')
1574     {
1575       if (out)
1576         fputc (c, out);
1577       c = fgetc (f);
1578     }
1579   if (c == '\n')
1580     {
1581       if (out)
1582         fputc (c, out);
1583       c = fgetc (f);
1584       if (c == ' ' || c == '\t')
1585         {
1586           c = eat_hspace (f);
1587         }
1588     }
1589   return c;
1590 }
1591
1592 static int
1593 eat_line (FILE * f, int c)
1594 {
1595   return pass_line (f, c, NULL);
1596 }
1597
1598 static int
1599 read_identifier (FILE * f, int c, char **identifier)
1600 {
1601   GString *id = g_string_new ("");
1602   while (g_ascii_isalnum (c) || c == '_')
1603     {
1604       g_string_append_c (id, c);
1605       c = fgetc (f);
1606     }
1607   *identifier = g_string_free (id, FALSE);
1608   return c;
1609 }
1610
1611 void
1612 gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
1613 {
1614   GError *error = NULL;
1615   char *tmp_name = NULL;
1616   FILE *fmacros =
1617     fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1618             "w+");
1619   GList *l;
1620   g_unlink (tmp_name);
1621
1622   for (l = filenames; l != NULL; l = l->next)
1623     {
1624       FILE *f = fopen (l->data, "r");
1625       int line = 1;
1626
1627       GString *define_line;
1628       char *str;
1629       gboolean error_line = FALSE;
1630       gboolean end_of_word;
1631       int c = eat_hspace (f);
1632       while (c != EOF)
1633         {
1634           if (c != '#')
1635             {
1636               /* ignore line */
1637               c = eat_line (f, c);
1638               line++;
1639               continue;
1640             }
1641
1642           /* print current location */
1643           str = g_strescape (l->data, "");
1644           fprintf (fmacros, "# %d \"%s\"\n", line, str);
1645           g_free (str);
1646
1647           c = eat_hspace (f);
1648           c = read_identifier (f, c, &str);
1649           end_of_word = (c == ' ' || c == '\t' || c == '\n' || c == EOF);
1650           if (end_of_word &&
1651               (g_str_equal (str, "if") ||
1652                g_str_equal (str, "endif") ||
1653                g_str_equal (str, "ifndef") ||
1654                g_str_equal (str, "ifdef") ||
1655                g_str_equal (str, "else") ||
1656                g_str_equal (str, "elif")))
1657             {
1658               fprintf (fmacros, "#%s ", str);
1659               g_free (str);
1660               c = pass_line (f, c, fmacros);
1661               line++;
1662               continue;
1663             }
1664           else if (strcmp (str, "define") != 0 || !end_of_word)
1665             {
1666               g_free (str);
1667               /* ignore line */
1668               c = eat_line (f, c);
1669               line++;
1670               continue;
1671             }
1672           g_free (str);
1673           c = eat_hspace (f);
1674           c = read_identifier (f, c, &str);
1675           if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1676             {
1677               g_free (str);
1678               /* ignore line */
1679               c = eat_line (f, c);
1680               line++;
1681               continue;
1682             }
1683           define_line = g_string_new ("#define ");
1684           g_string_append (define_line, str);
1685           g_free (str);
1686           if (c == '(')
1687             {
1688               while (c != ')')
1689                 {
1690                   g_string_append_c (define_line, c);
1691                   c = fgetc (f);
1692                   if (c == EOF || c == '\n')
1693                     {
1694                       error_line = TRUE;
1695                       break;
1696                     }
1697                 }
1698               if (error_line)
1699                 {
1700                   g_string_free (define_line, TRUE);
1701                   /* ignore line */
1702                   c = eat_line (f, c);
1703                   line++;
1704                   continue;
1705                 }
1706
1707               g_assert (c == ')');
1708               g_string_append_c (define_line, c);
1709               c = fgetc (f);
1710
1711               /* found function-like macro */
1712               fprintf (fmacros, "%s\n", define_line->str);
1713
1714               g_string_free (define_line, TRUE);
1715               /* ignore rest of line */
1716               c = eat_line (f, c);
1717               line++;
1718               continue;
1719             }
1720           if (c != ' ' && c != '\t')
1721             {
1722               g_string_free (define_line, TRUE);
1723               /* ignore line */
1724               c = eat_line (f, c);
1725               line++;
1726               continue;
1727             }
1728           while (c != EOF && c != '\n')
1729             {
1730               g_string_append_c (define_line, c);
1731               c = fgetc (f);
1732               if (c == '\\')
1733                 {
1734                   c = fgetc (f);
1735                   if (c == '\n')
1736                     {
1737                       /* fold lines when seeing backslash new-line sequence */
1738                       c = fgetc (f);
1739                     }
1740                   else
1741                     {
1742                       g_string_append_c (define_line, '\\');
1743                     }
1744                 }
1745             }
1746
1747           /* found object-like macro */
1748           fprintf (fmacros, "%s\n", define_line->str);
1749
1750           c = eat_line (f, c);
1751           line++;
1752         }
1753
1754       fclose (f);
1755     }
1756
1757   rewind (fmacros);
1758   gi_source_scanner_parse_file (scanner, fmacros);
1759 }
1760
1761 gboolean
1762 gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
1763 {
1764   g_return_val_if_fail (file != NULL, FALSE);
1765
1766   const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1767                                        g_free, (GDestroyNotify)gi_source_symbol_unref);
1768
1769   lineno = 1;
1770   yyin = file;
1771   yyparse (scanner);
1772
1773   g_hash_table_destroy (const_table);
1774   const_table = NULL;
1775
1776   yyin = NULL;
1777
1778   return TRUE;
1779 }
1780
1781 gboolean
1782 gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
1783 {
1784   lineno = 1;
1785   yyin = fopen (filename, "r");
1786
1787   while (yylex (scanner) != YYEOF)
1788     ;
1789
1790   fclose (yyin);
1791
1792   return TRUE;
1793 }