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