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