Handle enumerations with the full range of signed and unsigned values
[platform/upstream/gobject-introspection.git] / giscanner / scannerparser.y
1 /* GObject introspection: C parser
2  *
3  * Copyright (c) 1997 Sandro Sigala  <ssigala@globalnet.it>
4  * Copyright (c) 2007-2008 Jürg Billeter  <j@bitron.ch>
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 %{
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <glib.h>
35 #include <glib/gstdio.h>
36 #include "sourcescanner.h"
37 #include "scannerparser.h"
38
39 extern FILE *yyin;
40 extern int lineno;
41 extern char linebuf[2000];
42 extern char *yytext;
43
44 extern int yylex (GISourceScanner *scanner);
45 static void yyerror (GISourceScanner *scanner, const char *str);
46
47 extern void ctype_free (GISourceType * type);
48
49 static int last_enum_value = -1;
50 static gboolean is_bitfield;
51 static GHashTable *const_table = NULL;
52 %}
53
54 %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, lineno);
149                 } else {
150                         $$ = gi_source_symbol_ref ($$);
151                 }
152           }
153         | INTEGER
154           {
155                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
156                 $$->const_int_set = TRUE;
157                 if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
158                         $$->const_int = g_ascii_strtoll (yytext + 2, NULL, 16);
159                 } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
160                         $$->const_int = g_ascii_strtoll (yytext + 1, NULL, 8);
161                 } else {
162                         $$->const_int = g_ascii_strtoll (yytext, NULL, 10);
163                 }
164           }
165         | CHARACTER
166           {
167                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
168           }
169         | FLOATING
170           {
171                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
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, lineno);
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, lineno);
230           }
231         | postfix_expression '(' argument_expression_list ')'
232           {
233                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
234           }
235         | postfix_expression '(' ')'
236           {
237                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
238           }
239         | postfix_expression '.' identifier_or_typedef_name
240           {
241                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
242           }
243         | postfix_expression ARROW identifier_or_typedef_name
244           {
245                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
246           }
247         | postfix_expression PLUSPLUS
248           {
249                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
250           }
251         | postfix_expression MINUSMINUS
252           {
253                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
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, lineno);
267           }
268         | MINUSMINUS unary_expression
269           {
270                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
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, lineno);
292                         break;
293                 }
294           }
295         | SIZEOF unary_expression
296           {
297                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
298           }
299         | SIZEOF '(' type_name ')'
300           {
301                 ctype_free ($3);
302                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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, lineno);
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                 scanner->private = FALSE;
746                 $$ = gi_source_struct_new (NULL);
747           }
748         | UNION
749           {
750                 scanner->private = FALSE;
751                 $$ = gi_source_union_new (NULL);
752           }
753         ;
754
755 struct_declaration_list
756         : struct_declaration
757         | struct_declaration_list struct_declaration
758           {
759                 $$ = g_list_concat ($1, $2);
760           }
761         ;
762
763 struct_declaration
764         : specifier_qualifier_list struct_declarator_list ';'
765           {
766             GList *l;
767             $$ = NULL;
768             for (l = $2; l != NULL; l = l->next)
769               {
770                 GISourceSymbol *sym = l->data;
771                 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF)
772                     sym->type = CSYMBOL_TYPE_TYPEDEF;
773                 else
774                     sym->type = CSYMBOL_TYPE_MEMBER;
775                 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
776                 sym->private = scanner->private;
777                 $$ = g_list_append ($$, sym);
778               }
779             ctype_free ($1);
780           }
781         ;
782
783 specifier_qualifier_list
784         : type_specifier specifier_qualifier_list
785           {
786                 $$ = $1;
787                 $$->base_type = $2;
788           }
789         | type_specifier
790         | type_qualifier specifier_qualifier_list
791           {
792                 $$ = $2;
793                 $$->type_qualifier |= $1;
794           }
795         | type_qualifier
796           {
797                 $$ = gi_source_type_new (CTYPE_INVALID);
798                 $$->type_qualifier |= $1;
799           }
800         ;
801
802 struct_declarator_list
803         : struct_declarator
804           {
805                 $$ = g_list_append (NULL, $1);
806           }
807         | struct_declarator_list ',' struct_declarator
808           {
809                 $$ = g_list_append ($1, $3);
810           }
811         ;
812
813 struct_declarator
814         : /* empty, support for anonymous structs and unions */
815           {
816                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
817           }
818         | declarator
819         | ':' constant_expression
820           {
821                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
822           }
823         | declarator ':' constant_expression
824           {
825                 $$ = $1;
826                 if ($3->const_int_set) {
827                   $$->const_int_set = TRUE;
828                   $$->const_int = $3->const_int;
829                 }
830           }
831         ;
832
833 enum_specifier
834         : ENUM identifier_or_typedef_name '{' enumerator_list '}'
835           {
836                 scanner->private = FALSE;
837                 $$ = gi_source_enum_new ($2);
838                 $$->child_list = $4;
839                 $$->is_bitfield = is_bitfield;
840                 last_enum_value = -1;
841           }
842         | ENUM '{' enumerator_list '}'
843           {
844                 scanner->private = FALSE;
845                 $$ = gi_source_enum_new (NULL);
846                 $$->child_list = $3;
847                 $$->is_bitfield = is_bitfield;
848                 last_enum_value = -1;
849           }
850         | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
851           {
852                 scanner->private = FALSE;
853                 $$ = gi_source_enum_new ($2);
854                 $$->child_list = $4;
855                 $$->is_bitfield = is_bitfield;
856                 last_enum_value = -1;
857           }
858         | ENUM '{' enumerator_list ',' '}'
859           {
860                 scanner->private = FALSE;
861                 $$ = gi_source_enum_new (NULL);
862                 $$->child_list = $3;
863                 $$->is_bitfield = is_bitfield;
864                 last_enum_value = -1;
865           }
866         | ENUM identifier_or_typedef_name
867           {
868                 scanner->private = FALSE;
869                 $$ = gi_source_enum_new ($2);
870           }
871         ;
872
873 enumerator_list
874         :
875           {
876                 /* reset flag before the first enum value */
877                 is_bitfield = FALSE;
878           }
879           enumerator
880           {
881             $2->private = scanner->private;
882             $$ = g_list_append (NULL, $2);
883           }
884         | enumerator_list ',' enumerator
885           {
886             $3->private = scanner->private;
887             $$ = g_list_append ($1, $3);
888           }
889         ;
890
891 enumerator
892         : identifier
893           {
894                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, lineno);
895                 $$->ident = $1;
896                 $$->const_int_set = TRUE;
897                 $$->const_int = ++last_enum_value;
898                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
899           }
900         | identifier '=' constant_expression
901           {
902                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, lineno);
903                 $$->ident = $1;
904                 $$->const_int_set = TRUE;
905                 $$->const_int = $3->const_int;
906                 last_enum_value = $$->const_int;
907                 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
908           }
909         ;
910
911 type_qualifier
912         : CONST
913           {
914                 $$ = TYPE_QUALIFIER_CONST;
915           }
916         | RESTRICT
917           {
918                 $$ = TYPE_QUALIFIER_RESTRICT;
919           }
920         | EXTENSION
921           {
922                 $$ = TYPE_QUALIFIER_EXTENSION;
923           }
924         | VOLATILE
925           {
926                 $$ = TYPE_QUALIFIER_VOLATILE;
927           }
928         ;
929
930 function_specifier
931         : INLINE
932           {
933                 $$ = FUNCTION_INLINE;
934           }
935         ;
936
937 declarator
938         : pointer direct_declarator
939           {
940                 $$ = $2;
941                 gi_source_symbol_merge_type ($$, $1);
942           }
943         | direct_declarator
944         ;
945
946 direct_declarator
947         : identifier
948           {
949                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
950                 $$->ident = $1;
951           }
952         | '(' declarator ')'
953           {
954                 $$ = $2;
955           }
956         | direct_declarator '[' assignment_expression ']'
957           {
958                 $$ = $1;
959                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
960           }
961         | direct_declarator '[' ']'
962           {
963                 $$ = $1;
964                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
965           }
966         | direct_declarator '(' parameter_list ')'
967           {
968                 GISourceType *func = gi_source_function_new ();
969                 // ignore (void) parameter list
970                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
971                         func->child_list = $3;
972                 }
973                 $$ = $1;
974                 gi_source_symbol_merge_type ($$, func);
975           }
976         | direct_declarator '(' identifier_list ')'
977           {
978                 GISourceType *func = gi_source_function_new ();
979                 func->child_list = $3;
980                 $$ = $1;
981                 gi_source_symbol_merge_type ($$, func);
982           }
983         | direct_declarator '(' ')'
984           {
985                 GISourceType *func = gi_source_function_new ();
986                 $$ = $1;
987                 gi_source_symbol_merge_type ($$, func);
988           }
989         ;
990
991 pointer
992         : '*' type_qualifier_list
993           {
994                 $$ = gi_source_pointer_new (NULL);
995                 $$->type_qualifier = $2;
996           }
997         | '*'
998           {
999                 $$ = gi_source_pointer_new (NULL);
1000           }
1001         | '*' type_qualifier_list pointer
1002           {
1003                 $$ = gi_source_pointer_new ($3);
1004                 $$->type_qualifier = $2;
1005           }
1006         | '*' pointer
1007           {
1008                 $$ = gi_source_pointer_new ($2);
1009           }
1010         ;
1011
1012 type_qualifier_list
1013         : type_qualifier
1014         | type_qualifier_list type_qualifier
1015           {
1016                 $$ = $1 | $2;
1017           }
1018         ;
1019
1020 parameter_list
1021         : parameter_declaration
1022           {
1023                 $$ = g_list_append (NULL, $1);
1024           }
1025         | parameter_list ',' parameter_declaration
1026           {
1027                 $$ = g_list_append ($1, $3);
1028           }
1029         ;
1030
1031 parameter_declaration
1032         : declaration_specifiers declarator
1033           {
1034                 $$ = $2;
1035                 gi_source_symbol_merge_type ($$, $1);
1036           }
1037         | declaration_specifiers abstract_declarator
1038           {
1039                 $$ = $2;
1040                 gi_source_symbol_merge_type ($$, $1);
1041           }
1042         | declaration_specifiers
1043           {
1044                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1045                 $$->base_type = $1;
1046           }
1047         | ELLIPSIS
1048           {
1049                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS, lineno);
1050           }
1051         ;
1052
1053 identifier_list
1054         : identifier
1055           {
1056                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1057                 sym->ident = $1;
1058                 $$ = g_list_append (NULL, sym);
1059           }
1060         | identifier_list ',' identifier
1061           {
1062                 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1063                 sym->ident = $3;
1064                 $$ = g_list_append ($1, sym);
1065           }
1066         ;
1067
1068 type_name
1069         : specifier_qualifier_list
1070         | specifier_qualifier_list abstract_declarator
1071         ;
1072
1073 abstract_declarator
1074         : pointer
1075           {
1076                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1077                 gi_source_symbol_merge_type ($$, $1);
1078           }
1079         | direct_abstract_declarator
1080         | pointer direct_abstract_declarator
1081           {
1082                 $$ = $2;
1083                 gi_source_symbol_merge_type ($$, $1);
1084           }
1085         ;
1086
1087 direct_abstract_declarator
1088         : '(' abstract_declarator ')'
1089           {
1090                 $$ = $2;
1091           }
1092         | '[' ']'
1093           {
1094                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1095                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1096           }
1097         | '[' assignment_expression ']'
1098           {
1099                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1100                 gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
1101           }
1102         | direct_abstract_declarator '[' ']'
1103           {
1104                 $$ = $1;
1105                 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1106           }
1107         | direct_abstract_declarator '[' assignment_expression ']'
1108           {
1109                 $$ = $1;
1110                 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1111           }
1112         | '(' ')'
1113           {
1114                 GISourceType *func = gi_source_function_new ();
1115                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1116                 gi_source_symbol_merge_type ($$, func);
1117           }
1118         | '(' parameter_list ')'
1119           {
1120                 GISourceType *func = gi_source_function_new ();
1121                 // ignore (void) parameter list
1122                 if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
1123                         func->child_list = $2;
1124                 }
1125                 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1126                 gi_source_symbol_merge_type ($$, func);
1127           }
1128         | direct_abstract_declarator '(' ')'
1129           {
1130                 GISourceType *func = gi_source_function_new ();
1131                 $$ = $1;
1132                 gi_source_symbol_merge_type ($$, func);
1133           }
1134         | direct_abstract_declarator '(' parameter_list ')'
1135           {
1136                 GISourceType *func = gi_source_function_new ();
1137                 // ignore (void) parameter list
1138                 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1139                         func->child_list = $3;
1140                 }
1141                 $$ = $1;
1142                 gi_source_symbol_merge_type ($$, func);
1143           }
1144         ;
1145
1146 typedef_name
1147         : TYPEDEF_NAME
1148           {
1149                 $$ = g_strdup (yytext);
1150           }
1151         ;
1152
1153 initializer
1154         : assignment_expression
1155         | '{' initializer_list '}'
1156         | '{' initializer_list ',' '}'
1157         ;
1158
1159 initializer_list
1160         : initializer
1161         | initializer_list ',' initializer
1162         ;
1163
1164 /* A.2.3 Statements. */
1165
1166 statement
1167         : labeled_statement
1168         | compound_statement
1169         | expression_statement
1170         | selection_statement
1171         | iteration_statement
1172         | jump_statement
1173         ;
1174
1175 labeled_statement
1176         : identifier_or_typedef_name ':' statement
1177         | CASE constant_expression ':' statement
1178         | DEFAULT ':' statement
1179         ;
1180
1181 compound_statement
1182         : '{' '}'
1183         | '{' block_item_list '}'
1184         ;
1185
1186 block_item_list
1187         : block_item
1188         | block_item_list block_item
1189         ;
1190
1191 block_item
1192         : declaration
1193         | statement
1194         ;
1195
1196 expression_statement
1197         : ';'
1198         | expression ';'
1199         ;
1200
1201 selection_statement
1202         : IF '(' expression ')' statement
1203         | IF '(' expression ')' statement ELSE statement
1204         | SWITCH '(' expression ')' statement
1205         ;
1206
1207 iteration_statement
1208         : WHILE '(' expression ')' statement
1209         | DO statement WHILE '(' expression ')' ';'
1210         | FOR '(' ';' ';' ')' statement
1211         | FOR '(' expression ';' ';' ')' statement
1212         | FOR '(' ';' expression ';' ')' statement
1213         | FOR '(' expression ';' expression ';' ')' statement
1214         | FOR '(' ';' ';' expression ')' statement
1215         | FOR '(' expression ';' ';' expression ')' statement
1216         | FOR '(' ';' expression ';' expression ')' statement
1217         | FOR '(' expression ';' expression ';' expression ')' statement
1218         ;
1219
1220 jump_statement
1221         : GOTO identifier_or_typedef_name ';'
1222         | CONTINUE ';'
1223         | BREAK ';'
1224         | RETURN ';'
1225         | RETURN expression ';'
1226         ;
1227
1228 /* A.2.4 External definitions. */
1229
1230 translation_unit
1231         : external_declaration
1232         | translation_unit external_declaration
1233         ;
1234
1235 external_declaration
1236         : function_definition
1237         | declaration
1238         | macro
1239         ;
1240
1241 function_definition
1242         : declaration_specifiers declarator declaration_list compound_statement
1243         | declaration_specifiers declarator compound_statement
1244         ;
1245
1246 declaration_list
1247         : declaration
1248         | declaration_list declaration
1249         ;
1250
1251 /* Macros */
1252
1253 function_macro
1254         : FUNCTION_MACRO
1255           {
1256                 $$ = g_strdup (yytext + strlen ("#define "));
1257           }
1258         ;
1259
1260 object_macro
1261         : OBJECT_MACRO
1262           {
1263                 $$ = g_strdup (yytext + strlen ("#define "));
1264           }
1265         ;
1266
1267 function_macro_define
1268         : function_macro '(' identifier_list ')'
1269         ;
1270
1271 object_macro_define
1272         : object_macro constant_expression
1273           {
1274                 if ($2->const_int_set || $2->const_double_set || $2->const_string != NULL) {
1275                         $2->ident = $1;
1276                         gi_source_scanner_add_symbol (scanner, $2);
1277                         gi_source_symbol_unref ($2);
1278                 }
1279           }
1280         ;
1281
1282 macro
1283         : function_macro_define
1284         | object_macro_define
1285         | error
1286         ;
1287
1288 %%
1289 static void
1290 yyerror (GISourceScanner *scanner, const char *s)
1291 {
1292   /* ignore errors while doing a macro scan as not all object macros
1293    * have valid expressions */
1294   if (!scanner->macro_scan)
1295     {
1296       fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
1297               scanner->current_filename, lineno, s, linebuf, yytext);
1298     }
1299 }
1300
1301 static int
1302 eat_hspace (FILE * f)
1303 {
1304   int c;
1305   do
1306     {
1307       c = fgetc (f);
1308     }
1309   while (c == ' ' || c == '\t');
1310   return c;
1311 }
1312
1313 static int
1314 eat_line (FILE * f, int c)
1315 {
1316   while (c != EOF && c != '\n')
1317     {
1318       c = fgetc (f);
1319     }
1320   if (c == '\n')
1321     {
1322       c = fgetc (f);
1323       if (c == ' ' || c == '\t')
1324         {
1325           c = eat_hspace (f);
1326         }
1327     }
1328   return c;
1329 }
1330
1331 static int
1332 read_identifier (FILE * f, int c, char **identifier)
1333 {
1334   GString *id = g_string_new ("");
1335   while (g_ascii_isalnum (c) || c == '_')
1336     {
1337       g_string_append_c (id, c);
1338       c = fgetc (f);
1339     }
1340   *identifier = g_string_free (id, FALSE);
1341   return c;
1342 }
1343
1344 void
1345 gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
1346 {
1347   GError *error = NULL;
1348   char *tmp_name = NULL;
1349   FILE *fmacros =
1350     fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1351             "w+");
1352   g_unlink (tmp_name);
1353
1354   GList *l;
1355   for (l = filenames; l != NULL; l = l->next)
1356     {
1357       FILE *f = fopen (l->data, "r");
1358       int line = 1;
1359
1360       GString *define_line;
1361       char *str;
1362       gboolean error_line = FALSE;
1363       int c = eat_hspace (f);
1364       while (c != EOF)
1365         {
1366           if (c != '#')
1367             {
1368               /* ignore line */
1369               c = eat_line (f, c);
1370               line++;
1371               continue;
1372             }
1373
1374           /* print current location */
1375           str = g_strescape (l->data, "");
1376           fprintf (fmacros, "# %d \"%s\"\n", line, str);
1377           g_free (str);
1378
1379           c = eat_hspace (f);
1380           c = read_identifier (f, c, &str);
1381           if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1382             {
1383               g_free (str);
1384               /* ignore line */
1385               c = eat_line (f, c);
1386               line++;
1387               continue;
1388             }
1389           g_free (str);
1390           c = eat_hspace (f);
1391           c = read_identifier (f, c, &str);
1392           if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1393             {
1394               g_free (str);
1395               /* ignore line */
1396               c = eat_line (f, c);
1397               line++;
1398               continue;
1399             }
1400           define_line = g_string_new ("#define ");
1401           g_string_append (define_line, str);
1402           g_free (str);
1403           if (c == '(')
1404             {
1405               while (c != ')')
1406                 {
1407                   g_string_append_c (define_line, c);
1408                   c = fgetc (f);
1409                   if (c == EOF || c == '\n')
1410                     {
1411                       error_line = TRUE;
1412                       break;
1413                     }
1414                 }
1415               if (error_line)
1416                 {
1417                   g_string_free (define_line, TRUE);
1418                   /* ignore line */
1419                   c = eat_line (f, c);
1420                   line++;
1421                   continue;
1422                 }
1423
1424               g_assert (c == ')');
1425               g_string_append_c (define_line, c);
1426               c = fgetc (f);
1427
1428               /* found function-like macro */
1429               fprintf (fmacros, "%s\n", define_line->str);
1430
1431               g_string_free (define_line, TRUE);
1432               /* ignore rest of line */
1433               c = eat_line (f, c);
1434               line++;
1435               continue;
1436             }
1437           if (c != ' ' && c != '\t')
1438             {
1439               g_string_free (define_line, TRUE);
1440               /* ignore line */
1441               c = eat_line (f, c);
1442               line++;
1443               continue;
1444             }
1445           while (c != EOF && c != '\n')
1446             {
1447               g_string_append_c (define_line, c);
1448               c = fgetc (f);
1449               if (c == '\\')
1450                 {
1451                   c = fgetc (f);
1452                   if (c == '\n')
1453                     {
1454                       /* fold lines when seeing backslash new-line sequence */
1455                       c = fgetc (f);
1456                     }
1457                   else
1458                     {
1459                       g_string_append_c (define_line, '\\');
1460                     }
1461                 }
1462             }
1463
1464           /* found object-like macro */
1465           fprintf (fmacros, "%s\n", define_line->str);
1466
1467           c = eat_line (f, c);
1468           line++;
1469         }
1470
1471       fclose (f);
1472     }
1473
1474   rewind (fmacros);
1475   gi_source_scanner_parse_file (scanner, fmacros);
1476 }
1477
1478 gboolean
1479 gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
1480 {
1481   g_return_val_if_fail (file != NULL, FALSE);
1482
1483   const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1484                                        g_free, (GDestroyNotify)gi_source_symbol_unref);
1485
1486   lineno = 1;
1487   yyin = file;
1488   yyparse (scanner);
1489
1490   g_hash_table_destroy (const_table);
1491   const_table = NULL;
1492
1493   yyin = NULL;
1494
1495   return TRUE;
1496 }
1497
1498 gboolean
1499 gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
1500 {
1501   lineno = 1;
1502   yyin = fopen (filename, "r");
1503
1504   while (yylex (scanner) != YYEOF)
1505     ;
1506
1507   fclose (yyin);
1508
1509   return TRUE;
1510 }