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