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