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