__extension__ can be put in front of expressions
[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         | EXTENSION expression
538           {
539                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
540           }
541         ;
542
543 constant_expression
544         : conditional_expression
545         ;
546
547 /* A.2.2 Declarations. */
548
549 declaration
550         : declaration_specifiers init_declarator_list ';'
551           {
552                 GList *l;
553                 for (l = $2; l != NULL; l = l->next) {
554                         GISourceSymbol *sym = l->data;
555                         gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
556                         if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
557                                 sym->type = CSYMBOL_TYPE_TYPEDEF;
558                         } else if (sym->base_type->type == CTYPE_FUNCTION) {
559                                 sym->type = CSYMBOL_TYPE_FUNCTION;
560                         } else {
561                                 sym->type = CSYMBOL_TYPE_OBJECT;
562                         }
563                         gi_source_scanner_add_symbol (scanner, sym);
564                         gi_source_symbol_unref (sym);
565                 }
566                 ctype_free ($1);
567           }
568         | declaration_specifiers ';'
569           {
570                 ctype_free ($1);
571           }
572         ;
573
574 declaration_specifiers
575         : storage_class_specifier declaration_specifiers
576           {
577                 $$ = $2;
578                 $$->storage_class_specifier |= $1;
579           }
580         | storage_class_specifier
581           {
582                 $$ = gi_source_type_new (CTYPE_INVALID);
583                 $$->storage_class_specifier |= $1;
584           }
585         | type_specifier declaration_specifiers
586           {
587                 $$ = $1;
588                 /* combine basic types like unsigned int and long long */
589                 if ($$->type == CTYPE_BASIC_TYPE && $2->type == CTYPE_BASIC_TYPE) {
590                         char *name = g_strdup_printf ("%s %s", $$->name, $2->name);
591                         g_free ($$->name);
592                         $$->name = name;
593                         ctype_free ($2);
594                 } else {
595                         $$->base_type = $2;
596                 }
597           }
598         | type_specifier
599         | type_qualifier declaration_specifiers
600           {
601                 $$ = $2;
602                 $$->type_qualifier |= $1;
603           }
604         | type_qualifier
605           {
606                 $$ = gi_source_type_new (CTYPE_INVALID);
607                 $$->type_qualifier |= $1;
608           }
609         | function_specifier declaration_specifiers
610           {
611                 $$ = $2;
612                 $$->function_specifier |= $1;
613           }
614         | function_specifier
615           {
616                 $$ = gi_source_type_new (CTYPE_INVALID);
617                 $$->function_specifier |= $1;
618           }
619         ;
620
621 init_declarator_list
622         : init_declarator
623           {
624                 $$ = g_list_append (NULL, $1);
625           }
626         | init_declarator_list ',' init_declarator
627           {
628                 $$ = g_list_append ($1, $3);
629           }
630         ;
631
632 init_declarator
633         : declarator
634         | declarator '=' initializer
635         ;
636
637 storage_class_specifier
638         : TYPEDEF
639           {
640                 $$ = STORAGE_CLASS_TYPEDEF;
641           }
642         | EXTERN
643           {
644                 $$ = STORAGE_CLASS_EXTERN;
645           }
646         | STATIC
647           {
648                 $$ = STORAGE_CLASS_STATIC;
649           }
650         | AUTO
651           {
652                 $$ = STORAGE_CLASS_AUTO;
653           }
654         | REGISTER
655           {
656                 $$ = STORAGE_CLASS_REGISTER;
657           }
658         ;
659
660 type_specifier
661         : VOID
662           {
663                 $$ = gi_source_type_new (CTYPE_VOID);
664           }
665         | CHAR
666           {
667                 $$ = gi_source_basic_type_new ("char");
668           }
669         | SHORT
670           {
671                 $$ = gi_source_basic_type_new ("short");
672           }
673         | INT
674           {
675                 $$ = gi_source_basic_type_new ("int");
676           }
677         | LONG
678           {
679                 $$ = gi_source_basic_type_new ("long");
680           }
681         | FLOAT
682           {
683                 $$ = gi_source_basic_type_new ("float");
684           }
685         | DOUBLE
686           {
687                 $$ = gi_source_basic_type_new ("double");
688           }
689         | SIGNED
690           {
691                 $$ = gi_source_basic_type_new ("signed");
692           }
693         | UNSIGNED
694           {
695                 $$ = gi_source_basic_type_new ("unsigned");
696           }
697         | BOOL
698           {
699                 $$ = gi_source_basic_type_new ("bool");
700           }
701         | struct_or_union_specifier
702         | enum_specifier
703         | typedef_name
704           {
705                 $$ = gi_source_typedef_new ($1);
706                 g_free ($1);
707           }
708         ;
709
710 struct_or_union_specifier
711         : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
712           {
713                 $$ = $1;
714                 $$->name = $2;
715                 $$->child_list = $4;
716
717                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
718                 if ($$->type == CTYPE_STRUCT) {
719                         sym->type = CSYMBOL_TYPE_STRUCT;
720                 } else if ($$->type == CTYPE_UNION) {
721                         sym->type = CSYMBOL_TYPE_UNION;
722                 } else {
723                         g_assert_not_reached ();
724                 }
725                 sym->ident = g_strdup ($$->name);
726                 sym->base_type = gi_source_type_copy ($$);
727                 gi_source_scanner_add_symbol (scanner, sym);
728                 gi_source_symbol_unref (sym);
729           }
730         | struct_or_union '{' struct_declaration_list '}'
731           {
732                 $$ = $1;
733                 $$->child_list = $3;
734           }
735         | struct_or_union identifier_or_typedef_name
736           {
737                 $$ = $1;
738                 $$->name = $2;
739           }
740         ;
741
742 struct_or_union
743         : STRUCT
744           {
745                 $$ = gi_source_struct_new (NULL);
746           }
747         | UNION
748           {
749                 $$ = gi_source_union_new (NULL);
750           }
751         ;
752
753 struct_declaration_list
754         : struct_declaration
755         | struct_declaration_list struct_declaration
756           {
757                 $$ = g_list_concat ($1, $2);
758           }
759         ;
760
761 struct_declaration
762         : specifier_qualifier_list struct_declarator_list ';'
763           {
764             GList *l;
765             $$ = NULL;
766             for (l = $2; l != NULL; l = l->next)
767               {
768                 GISourceSymbol *sym = l->data;
769                 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF)
770                     sym->type = CSYMBOL_TYPE_TYPEDEF;
771                 else
772                     sym->type = CSYMBOL_TYPE_MEMBER;
773                 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
774                 $$ = g_list_append ($$, sym);
775               }
776             ctype_free ($1);
777           }
778         ;
779
780 specifier_qualifier_list
781         : type_specifier specifier_qualifier_list
782           {
783                 $$ = $1;
784                 $$->base_type = $2;
785           }
786         | type_specifier
787         | type_qualifier specifier_qualifier_list
788           {
789                 $$ = $2;
790                 $$->type_qualifier |= $1;
791           }
792         | type_qualifier
793           {
794                 $$ = gi_source_type_new (CTYPE_INVALID);
795                 $$->type_qualifier |= $1;
796           }
797         ;
798
799 struct_declarator_list
800         : struct_declarator
801           {
802                 $$ = g_list_append (NULL, $1);
803           }
804         | struct_declarator_list ',' struct_declarator
805           {
806                 $$ = g_list_append ($1, $3);
807           }
808         ;
809
810 struct_declarator
811         : /* empty, support for anonymous structs and unions */
812           {
813                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
814           }
815         | declarator
816         | ':' constant_expression
817           {
818                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
819           }
820         | declarator ':' constant_expression
821           {
822                 $$ = $1;
823                 if ($3->const_int_set) {
824                   $$->const_int_set = TRUE;
825                   $$->const_int = $3->const_int;
826                 }
827           }
828         ;
829
830 enum_specifier
831         : ENUM identifier_or_typedef_name '{' enumerator_list '}'
832           {
833                 $$ = gi_source_enum_new ($2);
834                 $$->child_list = $4;
835                 $$->is_bitfield = is_bitfield;
836                 last_enum_value = -1;
837           }
838         | ENUM '{' enumerator_list '}'
839           {
840                 $$ = gi_source_enum_new (NULL);
841                 $$->child_list = $3;
842                 $$->is_bitfield = is_bitfield;
843                 last_enum_value = -1;
844           }
845         | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
846           {
847                 $$ = gi_source_enum_new ($2);
848                 $$->child_list = $4;
849                 $$->is_bitfield = is_bitfield;
850                 last_enum_value = -1;
851           }
852         | ENUM '{' enumerator_list ',' '}'
853           {
854                 $$ = gi_source_enum_new (NULL);
855                 $$->child_list = $3;
856                 $$->is_bitfield = is_bitfield;
857                 last_enum_value = -1;
858           }
859         | ENUM identifier_or_typedef_name
860           {
861                 $$ = gi_source_enum_new ($2);
862           }
863         ;
864
865 enumerator_list
866         :
867           {
868                 /* reset flag before the first enum value */
869                 is_bitfield = FALSE;
870           }
871           enumerator
872           {
873                 $$ = g_list_append (NULL, $2);
874           }
875         | enumerator_list ',' enumerator
876           {
877                 $$ = g_list_append ($1, $3);
878           }
879         ;
880
881 enumerator
882         : identifier
883           {
884                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT);
885                 $$->ident = $1;
886                 $$->const_int_set = TRUE;
887                 $$->const_int = ++last_enum_value;
888                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
889           }
890         | identifier '=' constant_expression
891           {
892                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT);
893                 $$->ident = $1;
894                 $$->const_int_set = TRUE;
895                 $$->const_int = $3->const_int;
896                 last_enum_value = $$->const_int;
897                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
898           }
899         ;
900
901 type_qualifier
902         : CONST
903           {
904                 $$ = TYPE_QUALIFIER_CONST;
905           }
906         | RESTRICT
907           {
908                 $$ = TYPE_QUALIFIER_RESTRICT;
909           }
910         | EXTENSION
911           {
912                 $$ = TYPE_QUALIFIER_EXTENSION;
913           }
914         | VOLATILE
915           {
916                 $$ = TYPE_QUALIFIER_VOLATILE;
917           }
918         ;
919
920 function_specifier
921         : INLINE
922           {
923                 $$ = FUNCTION_INLINE;
924           }
925         ;
926
927 declarator
928         : pointer direct_declarator
929           {
930                 $$ = $2;
931                 gi_source_symbol_merge_type ($$, $1);
932           }
933         | direct_declarator
934         ;
935
936 direct_declarator
937         : identifier
938           {
939                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
940                 $$->ident = $1;
941           }
942         | '(' declarator ')'
943           {
944                 $$ = $2;
945           }
946         | direct_declarator '[' assignment_expression ']'
947           {
948                 $$ = $1;
949                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
950           }
951         | direct_declarator '[' ']'
952           {
953                 $$ = $1;
954                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
955           }
956         | direct_declarator '(' parameter_list ')'
957           {
958                 GISourceType *func = gi_source_function_new ();
959                 // ignore (void) parameter list
960                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
961                         func->child_list = $3;
962                 }
963                 $$ = $1;
964                 gi_source_symbol_merge_type ($$, func);
965           }
966         | direct_declarator '(' identifier_list ')'
967           {
968                 GISourceType *func = gi_source_function_new ();
969                 func->child_list = $3;
970                 $$ = $1;
971                 gi_source_symbol_merge_type ($$, func);
972           }
973         | direct_declarator '(' ')'
974           {
975                 GISourceType *func = gi_source_function_new ();
976                 $$ = $1;
977                 gi_source_symbol_merge_type ($$, func);
978           }
979         ;
980
981 pointer
982         : '*' type_qualifier_list
983           {
984                 $$ = gi_source_pointer_new (NULL);
985                 $$->type_qualifier = $2;
986           }
987         | '*'
988           {
989                 $$ = gi_source_pointer_new (NULL);
990           }
991         | '*' type_qualifier_list pointer
992           {
993                 $$ = gi_source_pointer_new ($3);
994                 $$->type_qualifier = $2;
995           }
996         | '*' pointer
997           {
998                 $$ = gi_source_pointer_new ($2);
999           }
1000         ;
1001
1002 type_qualifier_list
1003         : type_qualifier
1004         | type_qualifier_list type_qualifier
1005           {
1006                 $$ = $1 | $2;
1007           }
1008         ;
1009
1010 parameter_list
1011         : parameter_declaration
1012           {
1013                 $$ = g_list_append (NULL, $1);
1014           }
1015         | parameter_list ',' parameter_declaration
1016           {
1017                 $$ = g_list_append ($1, $3);
1018           }
1019         ;
1020
1021 parameter_declaration
1022         : declaration_specifiers declarator
1023           {
1024                 $$ = $2;
1025                 gi_source_symbol_merge_type ($$, $1);
1026           }
1027         | declaration_specifiers abstract_declarator
1028           {
1029                 $$ = $2;
1030                 gi_source_symbol_merge_type ($$, $1);
1031           }
1032         | declaration_specifiers
1033           {
1034                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1035                 $$->base_type = $1;
1036           }
1037         | ELLIPSIS
1038           {
1039                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS);
1040           }
1041         ;
1042
1043 identifier_list
1044         : identifier
1045           {
1046                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1047                 sym->ident = $1;
1048                 $$ = g_list_append (NULL, sym);
1049           }
1050         | identifier_list ',' identifier
1051           {
1052                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1053                 sym->ident = $3;
1054                 $$ = g_list_append ($1, sym);
1055           }
1056         ;
1057
1058 type_name
1059         : specifier_qualifier_list
1060         | specifier_qualifier_list abstract_declarator
1061         ;
1062
1063 abstract_declarator
1064         : pointer
1065           {
1066                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1067                 gi_source_symbol_merge_type ($$, $1);
1068           }
1069         | direct_abstract_declarator
1070         | pointer direct_abstract_declarator
1071           {
1072                 $$ = $2;
1073                 gi_source_symbol_merge_type ($$, $1);
1074           }
1075         ;
1076
1077 direct_abstract_declarator
1078         : '(' abstract_declarator ')'
1079           {
1080                 $$ = $2;
1081           }
1082         | '[' ']'
1083           {
1084                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1085                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1086           }
1087         | '[' assignment_expression ']'
1088           {
1089                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1090                 gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
1091           }
1092         | direct_abstract_declarator '[' ']'
1093           {
1094                 $$ = $1;
1095                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1096           }
1097         | direct_abstract_declarator '[' assignment_expression ']'
1098           {
1099                 $$ = $1;
1100                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1101           }
1102         | '(' ')'
1103           {
1104                 GISourceType *func = gi_source_function_new ();
1105                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1106                 gi_source_symbol_merge_type ($$, func);
1107           }
1108         | '(' parameter_list ')'
1109           {
1110                 GISourceType *func = gi_source_function_new ();
1111                 // ignore (void) parameter list
1112                 if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
1113                         func->child_list = $2;
1114                 }
1115                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
1116                 gi_source_symbol_merge_type ($$, func);
1117           }
1118         | direct_abstract_declarator '(' ')'
1119           {
1120                 GISourceType *func = gi_source_function_new ();
1121                 $$ = $1;
1122                 gi_source_symbol_merge_type ($$, func);
1123           }
1124         | direct_abstract_declarator '(' parameter_list ')'
1125           {
1126                 GISourceType *func = gi_source_function_new ();
1127                 // ignore (void) parameter list
1128                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1129                         func->child_list = $3;
1130                 }
1131                 $$ = $1;
1132                 gi_source_symbol_merge_type ($$, func);
1133           }
1134         ;
1135
1136 typedef_name
1137         : TYPEDEF_NAME
1138           {
1139                 $$ = g_strdup (yytext);
1140           }
1141         ;
1142
1143 initializer
1144         : assignment_expression
1145         | '{' initializer_list '}'
1146         | '{' initializer_list ',' '}'
1147         ;
1148
1149 initializer_list
1150         : initializer
1151         | initializer_list ',' initializer
1152         ;
1153
1154 /* A.2.3 Statements. */
1155
1156 statement
1157         : labeled_statement
1158         | compound_statement
1159         | expression_statement
1160         | selection_statement
1161         | iteration_statement
1162         | jump_statement
1163         ;
1164
1165 labeled_statement
1166         : identifier_or_typedef_name ':' statement
1167         | CASE constant_expression ':' statement
1168         | DEFAULT ':' statement
1169         ;
1170
1171 compound_statement
1172         : '{' '}'
1173         | '{' block_item_list '}'
1174         ;
1175
1176 block_item_list
1177         : block_item
1178         | block_item_list block_item
1179         ;
1180
1181 block_item
1182         : declaration
1183         | statement
1184         ;
1185
1186 expression_statement
1187         : ';'
1188         | expression ';'
1189         ;
1190
1191 selection_statement
1192         : IF '(' expression ')' statement
1193         | IF '(' expression ')' statement ELSE statement
1194         | SWITCH '(' expression ')' statement
1195         ;
1196
1197 iteration_statement
1198         : WHILE '(' expression ')' statement
1199         | DO statement WHILE '(' expression ')' ';'
1200         | FOR '(' ';' ';' ')' statement
1201         | FOR '(' expression ';' ';' ')' statement
1202         | FOR '(' ';' expression ';' ')' statement
1203         | FOR '(' expression ';' expression ';' ')' statement
1204         | FOR '(' ';' ';' expression ')' statement
1205         | FOR '(' expression ';' ';' expression ')' statement
1206         | FOR '(' ';' expression ';' expression ')' statement
1207         | FOR '(' expression ';' expression ';' expression ')' statement
1208         ;
1209
1210 jump_statement
1211         : GOTO identifier_or_typedef_name ';'
1212         | CONTINUE ';'
1213         | BREAK ';'
1214         | RETURN ';'
1215         | RETURN expression ';'
1216         ;
1217
1218 /* A.2.4 External definitions. */
1219
1220 translation_unit
1221         : external_declaration
1222         | translation_unit external_declaration
1223         ;
1224
1225 external_declaration
1226         : function_definition
1227         | declaration
1228         | macro
1229         ;
1230
1231 function_definition
1232         : declaration_specifiers declarator declaration_list compound_statement
1233         | declaration_specifiers declarator compound_statement
1234         ;
1235
1236 declaration_list
1237         : declaration
1238         | declaration_list declaration
1239         ;
1240
1241 /* Macros */
1242
1243 function_macro
1244         : FUNCTION_MACRO
1245           {
1246                 $$ = g_strdup (yytext + strlen ("#define "));
1247           }
1248         ;
1249
1250 object_macro
1251         : OBJECT_MACRO
1252           {
1253                 $$ = g_strdup (yytext + strlen ("#define "));
1254           }
1255         ;
1256
1257 function_macro_define
1258         : function_macro '(' identifier_list ')'
1259         ;
1260
1261 object_macro_define
1262         : object_macro constant_expression
1263           {
1264                 if ($2->const_int_set || $2->const_double_set || $2->const_string != NULL) {
1265                         $2->ident = $1;
1266                         gi_source_scanner_add_symbol (scanner, $2);
1267                         gi_source_symbol_unref ($2);
1268                 }
1269           }
1270         ;
1271
1272 macro
1273         : function_macro_define
1274         | object_macro_define
1275         | error
1276         ;
1277
1278 %%
1279 static void
1280 yyerror (GISourceScanner *scanner, const char *s)
1281 {
1282   /* ignore errors while doing a macro scan as not all object macros
1283    * have valid expressions */
1284   if (!scanner->macro_scan)
1285     {
1286       fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
1287               scanner->current_filename, lineno, s, linebuf, yytext);
1288     }
1289 }
1290
1291 static int
1292 eat_hspace (FILE * f)
1293 {
1294   int c;
1295   do
1296     {
1297       c = fgetc (f);
1298     }
1299   while (c == ' ' || c == '\t');
1300   return c;
1301 }
1302
1303 static int
1304 eat_line (FILE * f, int c)
1305 {
1306   while (c != EOF && c != '\n')
1307     {
1308       c = fgetc (f);
1309     }
1310   if (c == '\n')
1311     {
1312       c = fgetc (f);
1313       if (c == ' ' || c == '\t')
1314         {
1315           c = eat_hspace (f);
1316         }
1317     }
1318   return c;
1319 }
1320
1321 static int
1322 read_identifier (FILE * f, int c, char **identifier)
1323 {
1324   GString *id = g_string_new ("");
1325   while (g_ascii_isalnum (c) || c == '_')
1326     {
1327       g_string_append_c (id, c);
1328       c = fgetc (f);
1329     }
1330   *identifier = g_string_free (id, FALSE);
1331   return c;
1332 }
1333
1334 void
1335 gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
1336 {
1337   GError *error = NULL;
1338   char *tmp_name = NULL;
1339   FILE *fmacros =
1340     fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1341             "w+");
1342   g_unlink (tmp_name);
1343
1344   GList *l;
1345   for (l = filenames; l != NULL; l = l->next)
1346     {
1347       FILE *f = fopen (l->data, "r");
1348       int line = 1;
1349
1350       GString *define_line;
1351       char *str;
1352       gboolean error_line = FALSE;
1353       int c = eat_hspace (f);
1354       while (c != EOF)
1355         {
1356           if (c != '#')
1357             {
1358               /* ignore line */
1359               c = eat_line (f, c);
1360               line++;
1361               continue;
1362             }
1363
1364           /* print current location */
1365           str = g_strescape (l->data, "");
1366           fprintf (fmacros, "# %d \"%s\"\n", line, str);
1367           g_free (str);
1368
1369           c = eat_hspace (f);
1370           c = read_identifier (f, c, &str);
1371           if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1372             {
1373               g_free (str);
1374               /* ignore line */
1375               c = eat_line (f, c);
1376               line++;
1377               continue;
1378             }
1379           g_free (str);
1380           c = eat_hspace (f);
1381           c = read_identifier (f, c, &str);
1382           if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1383             {
1384               g_free (str);
1385               /* ignore line */
1386               c = eat_line (f, c);
1387               line++;
1388               continue;
1389             }
1390           define_line = g_string_new ("#define ");
1391           g_string_append (define_line, str);
1392           g_free (str);
1393           if (c == '(')
1394             {
1395               while (c != ')')
1396                 {
1397                   g_string_append_c (define_line, c);
1398                   c = fgetc (f);
1399                   if (c == EOF || c == '\n')
1400                     {
1401                       error_line = TRUE;
1402                       break;
1403                     }
1404                 }
1405               if (error_line)
1406                 {
1407                   g_string_free (define_line, TRUE);
1408                   /* ignore line */
1409                   c = eat_line (f, c);
1410                   line++;
1411                   continue;
1412                 }
1413
1414               g_assert (c == ')');
1415               g_string_append_c (define_line, c);
1416               c = fgetc (f);
1417
1418               /* found function-like macro */
1419               fprintf (fmacros, "%s\n", define_line->str);
1420
1421               g_string_free (define_line, TRUE);
1422               /* ignore rest of line */
1423               c = eat_line (f, c);
1424               line++;
1425               continue;
1426             }
1427           if (c != ' ' && c != '\t')
1428             {
1429               g_string_free (define_line, TRUE);
1430               /* ignore line */
1431               c = eat_line (f, c);
1432               line++;
1433               continue;
1434             }
1435           while (c != EOF && c != '\n')
1436             {
1437               g_string_append_c (define_line, c);
1438               c = fgetc (f);
1439               if (c == '\\')
1440                 {
1441                   c = fgetc (f);
1442                   if (c == '\n')
1443                     {
1444                       /* fold lines when seeing backslash new-line sequence */
1445                       c = fgetc (f);
1446                     }
1447                   else
1448                     {
1449                       g_string_append_c (define_line, '\\');
1450                     }
1451                 }
1452             }
1453
1454           /* found object-like macro */
1455           fprintf (fmacros, "%s\n", define_line->str);
1456
1457           c = eat_line (f, c);
1458           line++;
1459         }
1460
1461       fclose (f);
1462     }
1463
1464   rewind (fmacros);
1465   gi_source_scanner_parse_file (scanner, fmacros);
1466 }
1467
1468 gboolean
1469 gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
1470 {
1471   g_return_val_if_fail (file != NULL, FALSE);
1472   
1473   const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1474                                        g_free, (GDestroyNotify)gi_source_symbol_unref);
1475   
1476   lineno = 1;
1477   yyin = file;
1478   yyparse (scanner);
1479   
1480   g_hash_table_destroy (const_table);
1481   const_table = NULL;
1482   
1483   yyin = NULL;
1484
1485   return TRUE;
1486 }
1487
1488 gboolean
1489 gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
1490 {
1491   yyin = fopen (filename, "r");
1492
1493   while (yylex (scanner) != YYEOF)
1494     ;
1495
1496   fclose (yyin);
1497   
1498   return TRUE;
1499 }