gimarshallingtests: Add string_ to boxed structure
[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 %}
132
133 %error-verbose
134 %union {
135   char *str;
136   GList *list;
137   GISourceSymbol *symbol;
138   GISourceType *ctype;
139   StorageClassSpecifier storage_class_specifier;
140   TypeQualifier type_qualifier;
141   FunctionSpecifier function_specifier;
142   UnaryOperator unary_operator;
143 }
144
145 %parse-param { GISourceScanner* scanner }
146 %lex-param { GISourceScanner* scanner }
147
148 %token <str> IDENTIFIER "identifier"
149 %token <str> TYPEDEF_NAME "typedef-name"
150
151 %token INTEGER FLOATING CHARACTER STRING
152
153 %token INTL_CONST INTUL_CONST
154 %token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
155 %token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
156
157 %token AUTO BOOL BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
158 %token EXTENSION EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT
159 %token RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED
160 %token VOID VOLATILE WHILE
161
162 %token FUNCTION_MACRO OBJECT_MACRO
163
164 %start translation_unit
165
166 %type <ctype> declaration_specifiers
167 %type <ctype> enum_specifier
168 %type <ctype> pointer
169 %type <ctype> specifier_qualifier_list
170 %type <ctype> type_name
171 %type <ctype> struct_or_union
172 %type <ctype> struct_or_union_specifier
173 %type <ctype> type_specifier
174 %type <str> identifier
175 %type <str> typedef_name
176 %type <str> identifier_or_typedef_name
177 %type <symbol> abstract_declarator
178 %type <symbol> init_declarator
179 %type <symbol> declarator
180 %type <symbol> enumerator
181 %type <symbol> direct_abstract_declarator
182 %type <symbol> direct_declarator
183 %type <symbol> parameter_declaration
184 %type <symbol> struct_declarator
185 %type <list> enumerator_list
186 %type <list> identifier_list
187 %type <list> init_declarator_list
188 %type <list> parameter_list
189 %type <list> struct_declaration
190 %type <list> struct_declaration_list
191 %type <list> struct_declarator_list
192 %type <storage_class_specifier> storage_class_specifier
193 %type <type_qualifier> type_qualifier
194 %type <type_qualifier> type_qualifier_list
195 %type <function_specifier> function_specifier
196 %type <symbol> expression
197 %type <symbol> constant_expression
198 %type <symbol> conditional_expression
199 %type <symbol> logical_and_expression
200 %type <symbol> logical_or_expression
201 %type <symbol> inclusive_or_expression
202 %type <symbol> exclusive_or_expression
203 %type <symbol> multiplicative_expression
204 %type <symbol> additive_expression
205 %type <symbol> shift_expression
206 %type <symbol> relational_expression
207 %type <symbol> equality_expression
208 %type <symbol> and_expression
209 %type <symbol> cast_expression
210 %type <symbol> assignment_expression
211 %type <symbol> unary_expression
212 %type <symbol> postfix_expression
213 %type <symbol> primary_expression
214 %type <unary_operator> unary_operator
215 %type <str> function_macro
216 %type <str> object_macro
217 %type <symbol> strings
218
219 %%
220
221 /* A.2.1 Expressions. */
222
223 primary_expression
224         : identifier
225           {
226                 $$ = g_hash_table_lookup (const_table, $1);
227                 if ($$ == NULL) {
228                         $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
229                 } else {
230                         $$ = gi_source_symbol_ref ($$);
231                 }
232           }
233         | INTEGER
234           {
235                 char *rest;
236                 guint64 value;
237                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
238                 $$->const_int_set = TRUE;
239                 if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
240                         value = g_ascii_strtoull (yytext + 2, &rest, 16);
241                 } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
242                         value = g_ascii_strtoull (yytext + 1, &rest, 8);
243                 } else {
244                         value = g_ascii_strtoull (yytext, &rest, 10);
245                 }
246                 $$->const_int = value;
247                 $$->const_int_is_unsigned = (rest && (rest[0] == 'U'));
248           }
249         | CHARACTER
250           {
251                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
252                 $$->const_int_set = TRUE;
253                 $$->const_int = g_utf8_get_char(yytext + 1);
254           }
255         | FLOATING
256           {
257                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
258                 $$->const_double_set = TRUE;
259                 $$->const_double = 0.0;
260         sscanf (yytext, "%lf", &($$->const_double));
261           }
262         | strings
263         | '(' expression ')'
264           {
265                 $$ = $2;
266           }
267         | EXTENSION '(' '{' block_item_list '}' ')'
268           {
269                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
270           }
271         ;
272
273 /* concatenate adjacent string literal tokens */
274 strings
275         : STRING
276           {
277                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
278                 yytext[strlen (yytext) - 1] = '\0';
279                 $$->const_string = parse_c_string_literal (yytext + 1);
280                 if (!g_utf8_validate ($$->const_string, -1, NULL))
281                   {
282 #if 0
283                     g_warning ("Ignoring non-UTF-8 constant string \"%s\"", yytext + 1);
284 #endif
285                     g_free($$->const_string);
286                     $$->const_string = NULL;
287                   }
288
289           }
290         | strings STRING
291           {
292                 char *strings, *string2;
293                 $$ = $1;
294                 yytext[strlen (yytext) - 1] = '\0';
295                 string2 = parse_c_string_literal (yytext + 1);
296                 strings = g_strconcat ($$->const_string, string2, NULL);
297                 g_free ($$->const_string);
298                 g_free (string2);
299                 $$->const_string = strings;
300           }
301         ;
302
303 identifier
304         : IDENTIFIER
305           {
306                 $$ = g_strdup (yytext);
307           }
308         ;
309
310 identifier_or_typedef_name
311         : identifier
312         | typedef_name
313         ;
314
315 postfix_expression
316         : primary_expression
317         | postfix_expression '[' expression ']'
318           {
319                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
320           }
321         | postfix_expression '(' argument_expression_list ')'
322           {
323                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
324           }
325         | postfix_expression '(' ')'
326           {
327                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
328           }
329         | postfix_expression '.' identifier_or_typedef_name
330           {
331                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
332           }
333         | postfix_expression ARROW identifier_or_typedef_name
334           {
335                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
336           }
337         | postfix_expression PLUSPLUS
338           {
339                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
340           }
341         | postfix_expression MINUSMINUS
342           {
343                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
344           }
345         ;
346
347 argument_expression_list
348         : assignment_expression
349         | argument_expression_list ',' assignment_expression
350         ;
351
352 unary_expression
353         : postfix_expression
354         | PLUSPLUS unary_expression
355           {
356                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
357           }
358         | MINUSMINUS unary_expression
359           {
360                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
361           }
362         | unary_operator cast_expression
363           {
364                 switch ($1) {
365                 case UNARY_PLUS:
366                         $$ = $2;
367                         break;
368                 case UNARY_MINUS:
369                         $$ = $2;
370                         $$->const_int = -$2->const_int;
371                         break;
372                 case UNARY_BITWISE_COMPLEMENT:
373                         $$ = $2;
374                         $$->const_int = ~$2->const_int;
375                         break;
376                 case UNARY_LOGICAL_NEGATION:
377                         $$ = $2;
378                         $$->const_int = !gi_source_symbol_get_const_boolean ($2);
379                         break;
380                 default:
381                         $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
382                         break;
383                 }
384           }
385         | INTL_CONST '(' unary_expression ')'
386           {
387                 $$ = $3;
388                 if ($$->const_int_set) {
389                         $$->base_type = gi_source_basic_type_new ($$->const_int_is_unsigned ? "guint64" : "gint64");
390                 }
391           }
392         | INTUL_CONST '(' unary_expression ')'
393           {
394                 $$ = $3;
395                 if ($$->const_int_set) {
396                         $$->base_type = gi_source_basic_type_new ("guint64");
397                 }
398           }
399         | SIZEOF unary_expression
400           {
401                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
402           }
403         | SIZEOF '(' type_name ')'
404           {
405                 ctype_free ($3);
406                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
407           }
408         ;
409
410 unary_operator
411         : '&'
412           {
413                 $$ = UNARY_ADDRESS_OF;
414           }
415         | '*'
416           {
417                 $$ = UNARY_POINTER_INDIRECTION;
418           }
419         | '+'
420           {
421                 $$ = UNARY_PLUS;
422           }
423         | '-'
424           {
425                 $$ = UNARY_MINUS;
426           }
427         | '~'
428           {
429                 $$ = UNARY_BITWISE_COMPLEMENT;
430           }
431         | '!'
432           {
433                 $$ = UNARY_LOGICAL_NEGATION;
434           }
435         ;
436
437 cast_expression
438         : unary_expression
439         | '(' type_name ')' cast_expression
440           {
441                 $$ = $4;
442                 if ($$->const_int_set || $$->const_double_set || $$->const_string != NULL) {
443                         $$->base_type = $2;
444                 } else {
445                         ctype_free ($2);
446                 }
447           }
448         ;
449
450 multiplicative_expression
451         : cast_expression
452         | multiplicative_expression '*' cast_expression
453           {
454                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
455                 $$->const_int_set = TRUE;
456                 $$->const_int = $1->const_int * $3->const_int;
457           }
458         | multiplicative_expression '/' cast_expression
459           {
460                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
461                 $$->const_int_set = TRUE;
462                 if ($3->const_int != 0) {
463                         $$->const_int = $1->const_int / $3->const_int;
464                 }
465           }
466         | multiplicative_expression '%' cast_expression
467           {
468                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
469                 $$->const_int_set = TRUE;
470                 if ($3->const_int != 0) {
471                         $$->const_int = $1->const_int % $3->const_int;
472                 }
473           }
474         ;
475
476 additive_expression
477         : multiplicative_expression
478         | additive_expression '+' multiplicative_expression
479           {
480                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
481                 $$->const_int_set = TRUE;
482                 $$->const_int = $1->const_int + $3->const_int;
483           }
484         | additive_expression '-' multiplicative_expression
485           {
486                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
487                 $$->const_int_set = TRUE;
488                 $$->const_int = $1->const_int - $3->const_int;
489           }
490         ;
491
492 shift_expression
493         : additive_expression
494         | shift_expression SL additive_expression
495           {
496                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
497                 $$->const_int_set = TRUE;
498                 $$->const_int = $1->const_int << $3->const_int;
499
500                 /* assume this is a bitfield/flags declaration
501                  * if a left shift operator is sued in an enum value
502                  * This mimics the glib-mkenum behavior.
503                  */
504                 is_bitfield = TRUE;
505           }
506         | shift_expression SR additive_expression
507           {
508                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
509                 $$->const_int_set = TRUE;
510                 $$->const_int = $1->const_int >> $3->const_int;
511           }
512         ;
513
514 relational_expression
515         : shift_expression
516         | relational_expression '<' shift_expression
517           {
518                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
519                 $$->const_int_set = TRUE;
520                 $$->const_int = $1->const_int < $3->const_int;
521           }
522         | relational_expression '>' shift_expression
523           {
524                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
525                 $$->const_int_set = TRUE;
526                 $$->const_int = $1->const_int > $3->const_int;
527           }
528         | relational_expression LTEQ shift_expression
529           {
530                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
531                 $$->const_int_set = TRUE;
532                 $$->const_int = $1->const_int <= $3->const_int;
533           }
534         | relational_expression GTEQ shift_expression
535           {
536                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
537                 $$->const_int_set = TRUE;
538                 $$->const_int = $1->const_int >= $3->const_int;
539           }
540         ;
541
542 equality_expression
543         : relational_expression
544         | equality_expression EQ relational_expression
545           {
546                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
547                 $$->const_int_set = TRUE;
548                 $$->const_int = $1->const_int == $3->const_int;
549           }
550         | equality_expression NOTEQ relational_expression
551           {
552                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
553                 $$->const_int_set = TRUE;
554                 $$->const_int = $1->const_int != $3->const_int;
555           }
556         ;
557
558 and_expression
559         : equality_expression
560         | and_expression '&' equality_expression
561           {
562                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
563                 $$->const_int_set = TRUE;
564                 $$->const_int = $1->const_int & $3->const_int;
565           }
566         ;
567
568 exclusive_or_expression
569         : and_expression
570         | exclusive_or_expression '^' and_expression
571           {
572                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
573                 $$->const_int_set = TRUE;
574                 $$->const_int = $1->const_int ^ $3->const_int;
575           }
576         ;
577
578 inclusive_or_expression
579         : exclusive_or_expression
580         | inclusive_or_expression '|' exclusive_or_expression
581           {
582                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
583                 $$->const_int_set = TRUE;
584                 $$->const_int = $1->const_int | $3->const_int;
585           }
586         ;
587
588 logical_and_expression
589         : inclusive_or_expression
590         | logical_and_expression ANDAND inclusive_or_expression
591           {
592                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
593                 $$->const_int_set = TRUE;
594                 $$->const_int =
595                   gi_source_symbol_get_const_boolean ($1) &&
596                   gi_source_symbol_get_const_boolean ($3);
597           }
598         ;
599
600 logical_or_expression
601         : logical_and_expression
602         | logical_or_expression OROR logical_and_expression
603           {
604                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
605                 $$->const_int_set = TRUE;
606                 $$->const_int =
607                   gi_source_symbol_get_const_boolean ($1) ||
608                   gi_source_symbol_get_const_boolean ($3);
609           }
610         ;
611
612 conditional_expression
613         : logical_or_expression
614         | logical_or_expression '?' expression ':' expression
615           {
616                 $$ = gi_source_symbol_get_const_boolean ($1) ? $3 : $5;
617           }
618         ;
619
620 assignment_expression
621         : conditional_expression
622         | unary_expression assignment_operator assignment_expression
623           {
624                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
625           }
626         ;
627
628 assignment_operator
629         : '='
630         | MULEQ
631         | DIVEQ
632         | MODEQ
633         | ADDEQ
634         | SUBEQ
635         | SLEQ
636         | SREQ
637         | ANDEQ
638         | XOREQ
639         | OREQ
640         ;
641
642 expression
643         : assignment_expression
644         | expression ',' assignment_expression
645         | EXTENSION expression
646           {
647                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
648           }
649         ;
650
651 constant_expression
652         : conditional_expression
653         ;
654
655 /* A.2.2 Declarations. */
656
657 declaration
658         : declaration_specifiers init_declarator_list ';'
659           {
660                 GList *l;
661                 for (l = $2; l != NULL; l = l->next) {
662                         GISourceSymbol *sym = l->data;
663                         gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
664                         if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
665                                 sym->type = CSYMBOL_TYPE_TYPEDEF;
666                         } else if (sym->base_type->type == CTYPE_FUNCTION) {
667                                 sym->type = CSYMBOL_TYPE_FUNCTION;
668                         } else {
669                                 sym->type = CSYMBOL_TYPE_OBJECT;
670                         }
671                         gi_source_scanner_add_symbol (scanner, sym);
672                         gi_source_symbol_unref (sym);
673                 }
674                 ctype_free ($1);
675           }
676         | declaration_specifiers ';'
677           {
678                 ctype_free ($1);
679           }
680         ;
681
682 declaration_specifiers
683         : storage_class_specifier declaration_specifiers
684           {
685                 $$ = $2;
686                 $$->storage_class_specifier |= $1;
687           }
688         | storage_class_specifier
689           {
690                 $$ = gi_source_type_new (CTYPE_INVALID);
691                 $$->storage_class_specifier |= $1;
692           }
693         | type_specifier declaration_specifiers
694           {
695                 $$ = $1;
696                 /* combine basic types like unsigned int and long long */
697                 if ($$->type == CTYPE_BASIC_TYPE && $2->type == CTYPE_BASIC_TYPE) {
698                         char *name = g_strdup_printf ("%s %s", $$->name, $2->name);
699                         g_free ($$->name);
700                         $$->name = name;
701                         ctype_free ($2);
702                 } else {
703                         $$->base_type = $2;
704                 }
705           }
706         | type_specifier
707         | type_qualifier declaration_specifiers
708           {
709                 $$ = $2;
710                 $$->type_qualifier |= $1;
711           }
712         | type_qualifier
713           {
714                 $$ = gi_source_type_new (CTYPE_INVALID);
715                 $$->type_qualifier |= $1;
716           }
717         | function_specifier declaration_specifiers
718           {
719                 $$ = $2;
720                 $$->function_specifier |= $1;
721           }
722         | function_specifier
723           {
724                 $$ = gi_source_type_new (CTYPE_INVALID);
725                 $$->function_specifier |= $1;
726           }
727         ;
728
729 init_declarator_list
730         : init_declarator
731           {
732                 $$ = g_list_append (NULL, $1);
733           }
734         | init_declarator_list ',' init_declarator
735           {
736                 $$ = g_list_append ($1, $3);
737           }
738         ;
739
740 init_declarator
741         : declarator
742         | declarator '=' initializer
743         ;
744
745 storage_class_specifier
746         : TYPEDEF
747           {
748                 $$ = STORAGE_CLASS_TYPEDEF;
749           }
750         | EXTERN
751           {
752                 $$ = STORAGE_CLASS_EXTERN;
753           }
754         | STATIC
755           {
756                 $$ = STORAGE_CLASS_STATIC;
757           }
758         | AUTO
759           {
760                 $$ = STORAGE_CLASS_AUTO;
761           }
762         | REGISTER
763           {
764                 $$ = STORAGE_CLASS_REGISTER;
765           }
766         ;
767
768 type_specifier
769         : VOID
770           {
771                 $$ = gi_source_type_new (CTYPE_VOID);
772           }
773         | CHAR
774           {
775                 $$ = gi_source_basic_type_new ("char");
776           }
777         | SHORT
778           {
779                 $$ = gi_source_basic_type_new ("short");
780           }
781         | INT
782           {
783                 $$ = gi_source_basic_type_new ("int");
784           }
785         | LONG
786           {
787                 $$ = gi_source_basic_type_new ("long");
788           }
789         | FLOAT
790           {
791                 $$ = gi_source_basic_type_new ("float");
792           }
793         | DOUBLE
794           {
795                 $$ = gi_source_basic_type_new ("double");
796           }
797         | SIGNED
798           {
799                 $$ = gi_source_basic_type_new ("signed");
800           }
801         | UNSIGNED
802           {
803                 $$ = gi_source_basic_type_new ("unsigned");
804           }
805         | BOOL
806           {
807                 $$ = gi_source_basic_type_new ("bool");
808           }
809         | struct_or_union_specifier
810         | enum_specifier
811         | typedef_name
812           {
813                 $$ = gi_source_typedef_new ($1);
814                 g_free ($1);
815           }
816         ;
817
818 struct_or_union_specifier
819         : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
820           {
821                 GISourceSymbol *sym;
822                 $$ = $1;
823                 $$->name = $2;
824                 $$->child_list = $4;
825
826                 sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
827                 if ($$->type == CTYPE_STRUCT) {
828                         sym->type = CSYMBOL_TYPE_STRUCT;
829                 } else if ($$->type == CTYPE_UNION) {
830                         sym->type = CSYMBOL_TYPE_UNION;
831                 } else {
832                         g_assert_not_reached ();
833                 }
834                 sym->ident = g_strdup ($$->name);
835                 sym->base_type = gi_source_type_copy ($$);
836                 gi_source_scanner_add_symbol (scanner, sym);
837                 gi_source_symbol_unref (sym);
838           }
839         | struct_or_union '{' struct_declaration_list '}'
840           {
841                 $$ = $1;
842                 $$->child_list = $3;
843           }
844         | struct_or_union identifier_or_typedef_name
845           {
846                 $$ = $1;
847                 $$->name = $2;
848           }
849         ;
850
851 struct_or_union
852         : STRUCT
853           {
854                 scanner->private = FALSE;
855                 $$ = gi_source_struct_new (NULL);
856           }
857         | UNION
858           {
859                 scanner->private = FALSE;
860                 $$ = gi_source_union_new (NULL);
861           }
862         ;
863
864 struct_declaration_list
865         : struct_declaration
866         | struct_declaration_list struct_declaration
867           {
868                 $$ = g_list_concat ($1, $2);
869           }
870         ;
871
872 struct_declaration
873         : specifier_qualifier_list struct_declarator_list ';'
874           {
875             GList *l;
876             $$ = NULL;
877             for (l = $2; l != NULL; l = l->next)
878               {
879                 GISourceSymbol *sym = l->data;
880                 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF)
881                     sym->type = CSYMBOL_TYPE_TYPEDEF;
882                 else
883                     sym->type = CSYMBOL_TYPE_MEMBER;
884                 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
885                 sym->private = scanner->private;
886                 $$ = g_list_append ($$, sym);
887               }
888             ctype_free ($1);
889           }
890         ;
891
892 specifier_qualifier_list
893         : type_specifier specifier_qualifier_list
894           {
895                 $$ = $1;
896                 $$->base_type = $2;
897           }
898         | type_specifier
899         | type_qualifier specifier_qualifier_list
900           {
901                 $$ = $2;
902                 $$->type_qualifier |= $1;
903           }
904         | type_qualifier
905           {
906                 $$ = gi_source_type_new (CTYPE_INVALID);
907                 $$->type_qualifier |= $1;
908           }
909         ;
910
911 struct_declarator_list
912         : struct_declarator
913           {
914                 $$ = g_list_append (NULL, $1);
915           }
916         | struct_declarator_list ',' struct_declarator
917           {
918                 $$ = g_list_append ($1, $3);
919           }
920         ;
921
922 struct_declarator
923         : /* empty, support for anonymous structs and unions */
924           {
925                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
926           }
927         | declarator
928         | ':' constant_expression
929           {
930                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
931           }
932         | declarator ':' constant_expression
933           {
934                 $$ = $1;
935                 if ($3->const_int_set) {
936                   $$->const_int_set = TRUE;
937                   $$->const_int = $3->const_int;
938                 }
939           }
940         ;
941
942 enum_specifier
943         : enum_keyword identifier_or_typedef_name '{' enumerator_list '}'
944           {
945                 $$ = gi_source_enum_new ($2);
946                 $$->child_list = $4;
947                 $$->is_bitfield = is_bitfield || scanner->flags;
948                 last_enum_value = -1;
949           }
950         | enum_keyword '{' enumerator_list '}'
951           {
952                 $$ = gi_source_enum_new (NULL);
953                 $$->child_list = $3;
954                 $$->is_bitfield = is_bitfield || scanner->flags;
955                 last_enum_value = -1;
956           }
957         | enum_keyword identifier_or_typedef_name '{' enumerator_list ',' '}'
958           {
959                 $$ = gi_source_enum_new ($2);
960                 $$->child_list = $4;
961                 $$->is_bitfield = is_bitfield || scanner->flags;
962                 last_enum_value = -1;
963           }
964         | enum_keyword '{' enumerator_list ',' '}'
965           {
966                 $$ = gi_source_enum_new (NULL);
967                 $$->child_list = $3;
968                 $$->is_bitfield = is_bitfield || scanner->flags;
969                 last_enum_value = -1;
970           }
971         | enum_keyword identifier_or_typedef_name
972           {
973                 $$ = gi_source_enum_new ($2);
974           }
975         ;
976
977 enum_keyword
978         : ENUM
979           {
980                 scanner->flags = FALSE;
981                 scanner->private = FALSE;
982           }
983         ;
984
985 enumerator_list
986         :
987           {
988                 /* reset flag before the first enum value */
989                 is_bitfield = FALSE;
990           }
991           enumerator
992           {
993             $2->private = scanner->private;
994             $$ = g_list_append (NULL, $2);
995           }
996         | enumerator_list ',' enumerator
997           {
998             $3->private = scanner->private;
999             $$ = g_list_append ($1, $3);
1000           }
1001         ;
1002
1003 enumerator
1004         : identifier
1005           {
1006                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_filename, lineno);
1007                 $$->ident = $1;
1008                 $$->const_int_set = TRUE;
1009                 $$->const_int = ++last_enum_value;
1010                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
1011           }
1012         | identifier '=' constant_expression
1013           {
1014                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_filename, lineno);
1015                 $$->ident = $1;
1016                 $$->const_int_set = TRUE;
1017                 $$->const_int = $3->const_int;
1018                 last_enum_value = $$->const_int;
1019                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
1020           }
1021         ;
1022
1023 type_qualifier
1024         : CONST
1025           {
1026                 $$ = TYPE_QUALIFIER_CONST;
1027           }
1028         | RESTRICT
1029           {
1030                 $$ = TYPE_QUALIFIER_RESTRICT;
1031           }
1032         | EXTENSION
1033           {
1034                 $$ = TYPE_QUALIFIER_EXTENSION;
1035           }
1036         | VOLATILE
1037           {
1038                 $$ = TYPE_QUALIFIER_VOLATILE;
1039           }
1040         ;
1041
1042 function_specifier
1043         : INLINE
1044           {
1045                 $$ = FUNCTION_INLINE;
1046           }
1047         ;
1048
1049 declarator
1050         : pointer direct_declarator
1051           {
1052                 $$ = $2;
1053                 gi_source_symbol_merge_type ($$, $1);
1054           }
1055         | direct_declarator
1056         ;
1057
1058 direct_declarator
1059         : identifier
1060           {
1061                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1062                 $$->ident = $1;
1063           }
1064         | '(' declarator ')'
1065           {
1066                 $$ = $2;
1067           }
1068         | direct_declarator '[' assignment_expression ']'
1069           {
1070                 $$ = $1;
1071                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1072           }
1073         | direct_declarator '[' ']'
1074           {
1075                 $$ = $1;
1076                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1077           }
1078         | direct_declarator '(' parameter_list ')'
1079           {
1080                 GISourceType *func = gi_source_function_new ();
1081                 // ignore (void) parameter list
1082                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1083                         func->child_list = $3;
1084                 }
1085                 $$ = $1;
1086                 gi_source_symbol_merge_type ($$, func);
1087           }
1088         | direct_declarator '(' identifier_list ')'
1089           {
1090                 GISourceType *func = gi_source_function_new ();
1091                 func->child_list = $3;
1092                 $$ = $1;
1093                 gi_source_symbol_merge_type ($$, func);
1094           }
1095         | direct_declarator '(' ')'
1096           {
1097                 GISourceType *func = gi_source_function_new ();
1098                 $$ = $1;
1099                 gi_source_symbol_merge_type ($$, func);
1100           }
1101         ;
1102
1103 pointer
1104         : '*' type_qualifier_list
1105           {
1106                 $$ = gi_source_pointer_new (NULL);
1107                 $$->type_qualifier = $2;
1108           }
1109         | '*'
1110           {
1111                 $$ = gi_source_pointer_new (NULL);
1112           }
1113         | '*' type_qualifier_list pointer
1114           {
1115                 GISourceType **base = &($3->base_type);
1116
1117                 while (*base != NULL) {
1118                         base = &((*base)->base_type);
1119                 }
1120                 *base = gi_source_pointer_new (NULL);
1121                 (*base)->type_qualifier = $2;
1122                 $$ = $3;
1123           }
1124         | '*' pointer
1125           {
1126                 GISourceType **base = &($2->base_type);
1127
1128                 while (*base != NULL) {
1129                         base = &((*base)->base_type);
1130                 }
1131                 *base = gi_source_pointer_new (NULL);
1132                 $$ = $2;
1133           }
1134         ;
1135
1136 type_qualifier_list
1137         : type_qualifier
1138         | type_qualifier_list type_qualifier
1139           {
1140                 $$ = $1 | $2;
1141           }
1142         ;
1143
1144 parameter_list
1145         : parameter_declaration
1146           {
1147                 $$ = g_list_append (NULL, $1);
1148           }
1149         | parameter_list ',' parameter_declaration
1150           {
1151                 $$ = g_list_append ($1, $3);
1152           }
1153         ;
1154
1155 parameter_declaration
1156         : declaration_specifiers declarator
1157           {
1158                 $$ = $2;
1159                 gi_source_symbol_merge_type ($$, $1);
1160           }
1161         | declaration_specifiers abstract_declarator
1162           {
1163                 $$ = $2;
1164                 gi_source_symbol_merge_type ($$, $1);
1165           }
1166         | declaration_specifiers
1167           {
1168                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1169                 $$->base_type = $1;
1170           }
1171         | ELLIPSIS
1172           {
1173                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS, scanner->current_filename, lineno);
1174           }
1175         ;
1176
1177 identifier_list
1178         : identifier
1179           {
1180                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1181                 sym->ident = $1;
1182                 $$ = g_list_append (NULL, sym);
1183           }
1184         | identifier_list ',' identifier
1185           {
1186                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1187                 sym->ident = $3;
1188                 $$ = g_list_append ($1, sym);
1189           }
1190         ;
1191
1192 type_name
1193         : specifier_qualifier_list
1194         | specifier_qualifier_list abstract_declarator
1195         ;
1196
1197 abstract_declarator
1198         : pointer
1199           {
1200                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1201                 gi_source_symbol_merge_type ($$, $1);
1202           }
1203         | direct_abstract_declarator
1204         | pointer direct_abstract_declarator
1205           {
1206                 $$ = $2;
1207                 gi_source_symbol_merge_type ($$, $1);
1208           }
1209         ;
1210
1211 direct_abstract_declarator
1212         : '(' abstract_declarator ')'
1213           {
1214                 $$ = $2;
1215           }
1216         | '[' ']'
1217           {
1218                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1219                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1220           }
1221         | '[' assignment_expression ']'
1222           {
1223                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1224                 gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
1225           }
1226         | direct_abstract_declarator '[' ']'
1227           {
1228                 $$ = $1;
1229                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1230           }
1231         | direct_abstract_declarator '[' assignment_expression ']'
1232           {
1233                 $$ = $1;
1234                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1235           }
1236         | '(' ')'
1237           {
1238                 GISourceType *func = gi_source_function_new ();
1239                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1240                 gi_source_symbol_merge_type ($$, func);
1241           }
1242         | '(' parameter_list ')'
1243           {
1244                 GISourceType *func = gi_source_function_new ();
1245                 // ignore (void) parameter list
1246                 if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
1247                         func->child_list = $2;
1248                 }
1249                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1250                 gi_source_symbol_merge_type ($$, func);
1251           }
1252         | direct_abstract_declarator '(' ')'
1253           {
1254                 GISourceType *func = gi_source_function_new ();
1255                 $$ = $1;
1256                 gi_source_symbol_merge_type ($$, func);
1257           }
1258         | direct_abstract_declarator '(' parameter_list ')'
1259           {
1260                 GISourceType *func = gi_source_function_new ();
1261                 // ignore (void) parameter list
1262                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1263                         func->child_list = $3;
1264                 }
1265                 $$ = $1;
1266                 gi_source_symbol_merge_type ($$, func);
1267           }
1268         ;
1269
1270 typedef_name
1271         : TYPEDEF_NAME
1272           {
1273                 $$ = g_strdup (yytext);
1274           }
1275         ;
1276
1277 initializer
1278         : assignment_expression
1279         | '{' initializer_list '}'
1280         | '{' initializer_list ',' '}'
1281         ;
1282
1283 initializer_list
1284         : initializer
1285         | initializer_list ',' initializer
1286         ;
1287
1288 /* A.2.3 Statements. */
1289
1290 statement
1291         : labeled_statement
1292         | compound_statement
1293         | expression_statement
1294         | selection_statement
1295         | iteration_statement
1296         | jump_statement
1297         ;
1298
1299 labeled_statement
1300         : identifier_or_typedef_name ':' statement
1301         | CASE constant_expression ':' statement
1302         | DEFAULT ':' statement
1303         ;
1304
1305 compound_statement
1306         : '{' '}'
1307         | '{' block_item_list '}'
1308         ;
1309
1310 block_item_list
1311         : block_item
1312         | block_item_list block_item
1313         ;
1314
1315 block_item
1316         : declaration
1317         | statement
1318         ;
1319
1320 expression_statement
1321         : ';'
1322         | expression ';'
1323         ;
1324
1325 selection_statement
1326         : IF '(' expression ')' statement
1327         | IF '(' expression ')' statement ELSE statement
1328         | SWITCH '(' expression ')' statement
1329         ;
1330
1331 iteration_statement
1332         : WHILE '(' expression ')' statement
1333         | DO statement WHILE '(' expression ')' ';'
1334         | FOR '(' ';' ';' ')' statement
1335         | FOR '(' expression ';' ';' ')' statement
1336         | FOR '(' ';' expression ';' ')' statement
1337         | FOR '(' expression ';' expression ';' ')' statement
1338         | FOR '(' ';' ';' expression ')' statement
1339         | FOR '(' expression ';' ';' expression ')' statement
1340         | FOR '(' ';' expression ';' expression ')' statement
1341         | FOR '(' expression ';' expression ';' expression ')' statement
1342         ;
1343
1344 jump_statement
1345         : GOTO identifier_or_typedef_name ';'
1346         | CONTINUE ';'
1347         | BREAK ';'
1348         | RETURN ';'
1349         | RETURN expression ';'
1350         ;
1351
1352 /* A.2.4 External definitions. */
1353
1354 translation_unit
1355         : external_declaration
1356         | translation_unit external_declaration
1357         ;
1358
1359 external_declaration
1360         : function_definition
1361         | declaration
1362         | macro
1363         ;
1364
1365 function_definition
1366         : declaration_specifiers declarator declaration_list compound_statement
1367         | declaration_specifiers declarator compound_statement
1368         ;
1369
1370 declaration_list
1371         : declaration
1372         | declaration_list declaration
1373         ;
1374
1375 /* Macros */
1376
1377 function_macro
1378         : FUNCTION_MACRO
1379           {
1380                 $$ = g_strdup (yytext + strlen ("#define "));
1381           }
1382         ;
1383
1384 object_macro
1385         : OBJECT_MACRO
1386           {
1387                 $$ = g_strdup (yytext + strlen ("#define "));
1388           }
1389         ;
1390
1391 function_macro_define
1392         : function_macro '(' identifier_list ')'
1393         ;
1394
1395 object_macro_define
1396         : object_macro constant_expression
1397           {
1398                 if ($2->const_int_set || $2->const_double_set || $2->const_string != NULL) {
1399                         $2->ident = $1;
1400                         gi_source_scanner_add_symbol (scanner, $2);
1401                         gi_source_symbol_unref ($2);
1402                 }
1403           }
1404         ;
1405
1406 macro
1407         : function_macro_define
1408         | object_macro_define
1409         | error
1410         ;
1411
1412 %%
1413 static void
1414 yyerror (GISourceScanner *scanner, const char *s)
1415 {
1416   /* ignore errors while doing a macro scan as not all object macros
1417    * have valid expressions */
1418   if (!scanner->macro_scan)
1419     {
1420       fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
1421               scanner->current_filename, lineno, s, linebuf, yytext);
1422     }
1423 }
1424
1425 static int
1426 eat_hspace (FILE * f)
1427 {
1428   int c;
1429   do
1430     {
1431       c = fgetc (f);
1432     }
1433   while (c == ' ' || c == '\t');
1434   return c;
1435 }
1436
1437 static int
1438 eat_line (FILE * f, int c)
1439 {
1440   while (c != EOF && c != '\n')
1441     {
1442       c = fgetc (f);
1443     }
1444   if (c == '\n')
1445     {
1446       c = fgetc (f);
1447       if (c == ' ' || c == '\t')
1448         {
1449           c = eat_hspace (f);
1450         }
1451     }
1452   return c;
1453 }
1454
1455 static int
1456 read_identifier (FILE * f, int c, char **identifier)
1457 {
1458   GString *id = g_string_new ("");
1459   while (g_ascii_isalnum (c) || c == '_')
1460     {
1461       g_string_append_c (id, c);
1462       c = fgetc (f);
1463     }
1464   *identifier = g_string_free (id, FALSE);
1465   return c;
1466 }
1467
1468 void
1469 gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
1470 {
1471   GError *error = NULL;
1472   char *tmp_name = NULL;
1473   FILE *fmacros =
1474     fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1475             "w+");
1476   GList *l;
1477   g_unlink (tmp_name);
1478
1479   for (l = filenames; l != NULL; l = l->next)
1480     {
1481       FILE *f = fopen (l->data, "r");
1482       int line = 1;
1483
1484       GString *define_line;
1485       char *str;
1486       gboolean error_line = FALSE;
1487       int c = eat_hspace (f);
1488       while (c != EOF)
1489         {
1490           if (c != '#')
1491             {
1492               /* ignore line */
1493               c = eat_line (f, c);
1494               line++;
1495               continue;
1496             }
1497
1498           /* print current location */
1499           str = g_strescape (l->data, "");
1500           fprintf (fmacros, "# %d \"%s\"\n", line, str);
1501           g_free (str);
1502
1503           c = eat_hspace (f);
1504           c = read_identifier (f, c, &str);
1505           if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1506             {
1507               g_free (str);
1508               /* ignore line */
1509               c = eat_line (f, c);
1510               line++;
1511               continue;
1512             }
1513           g_free (str);
1514           c = eat_hspace (f);
1515           c = read_identifier (f, c, &str);
1516           if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1517             {
1518               g_free (str);
1519               /* ignore line */
1520               c = eat_line (f, c);
1521               line++;
1522               continue;
1523             }
1524           define_line = g_string_new ("#define ");
1525           g_string_append (define_line, str);
1526           g_free (str);
1527           if (c == '(')
1528             {
1529               while (c != ')')
1530                 {
1531                   g_string_append_c (define_line, c);
1532                   c = fgetc (f);
1533                   if (c == EOF || c == '\n')
1534                     {
1535                       error_line = TRUE;
1536                       break;
1537                     }
1538                 }
1539               if (error_line)
1540                 {
1541                   g_string_free (define_line, TRUE);
1542                   /* ignore line */
1543                   c = eat_line (f, c);
1544                   line++;
1545                   continue;
1546                 }
1547
1548               g_assert (c == ')');
1549               g_string_append_c (define_line, c);
1550               c = fgetc (f);
1551
1552               /* found function-like macro */
1553               fprintf (fmacros, "%s\n", define_line->str);
1554
1555               g_string_free (define_line, TRUE);
1556               /* ignore rest of line */
1557               c = eat_line (f, c);
1558               line++;
1559               continue;
1560             }
1561           if (c != ' ' && c != '\t')
1562             {
1563               g_string_free (define_line, TRUE);
1564               /* ignore line */
1565               c = eat_line (f, c);
1566               line++;
1567               continue;
1568             }
1569           while (c != EOF && c != '\n')
1570             {
1571               g_string_append_c (define_line, c);
1572               c = fgetc (f);
1573               if (c == '\\')
1574                 {
1575                   c = fgetc (f);
1576                   if (c == '\n')
1577                     {
1578                       /* fold lines when seeing backslash new-line sequence */
1579                       c = fgetc (f);
1580                     }
1581                   else
1582                     {
1583                       g_string_append_c (define_line, '\\');
1584                     }
1585                 }
1586             }
1587
1588           /* found object-like macro */
1589           fprintf (fmacros, "%s\n", define_line->str);
1590
1591           c = eat_line (f, c);
1592           line++;
1593         }
1594
1595       fclose (f);
1596     }
1597
1598   rewind (fmacros);
1599   gi_source_scanner_parse_file (scanner, fmacros);
1600 }
1601
1602 gboolean
1603 gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
1604 {
1605   g_return_val_if_fail (file != NULL, FALSE);
1606
1607   const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1608                                        g_free, (GDestroyNotify)gi_source_symbol_unref);
1609
1610   lineno = 1;
1611   yyin = file;
1612   yyparse (scanner);
1613
1614   g_hash_table_destroy (const_table);
1615   const_table = NULL;
1616
1617   yyin = NULL;
1618
1619   return TRUE;
1620 }
1621
1622 gboolean
1623 gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
1624 {
1625   lineno = 1;
1626   yyin = fopen (filename, "r");
1627
1628   while (yylex (scanner) != YYEOF)
1629     ;
1630
1631   fclose (yyin);
1632
1633   return TRUE;
1634 }