1 /* GObject introspection: C parser
3 * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
4 * Copyright (c) 2007-2008 Jürg Billeter <j@bitron.ch>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
35 #include <glib/gstdio.h>
36 #include "sourcescanner.h"
37 #include "scannerparser.h"
41 extern char linebuf[2000];
44 extern int yylex (GISourceScanner *scanner);
45 static void yyerror (GISourceScanner *scanner, const char *str);
47 extern void ctype_free (GISourceType * type);
49 static int last_enum_value = -1;
50 static gboolean is_bitfield;
51 static GHashTable *const_table = NULL;
58 GISourceSymbol *symbol;
60 StorageClassSpecifier storage_class_specifier;
61 TypeQualifier type_qualifier;
62 FunctionSpecifier function_specifier;
63 UnaryOperator unary_operator;
66 %parse-param { GISourceScanner* scanner }
67 %lex-param { GISourceScanner* scanner }
69 %token <str> IDENTIFIER "identifier"
70 %token <str> TYPEDEF_NAME "typedef-name"
72 %token INTEGER FLOATING CHARACTER STRING
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
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
82 %token FUNCTION_MACRO OBJECT_MACRO
84 %start translation_unit
86 %type <ctype> declaration_specifiers
87 %type <ctype> enum_specifier
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
141 /* A.2.1 Expressions. */
146 $$ = g_hash_table_lookup (const_table, $1);
148 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
150 $$ = gi_source_symbol_ref ($$);
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);
162 $$->const_int = g_ascii_strtoll (yytext, NULL, 10);
167 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
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));
183 /* concatenate adjacent string literal tokens */
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))
193 g_warning ("Ignoring non-UTF-8 constant string \"%s\"", yytext + 1);
195 g_free($$->const_string);
196 $$->const_string = NULL;
202 char *strings, *string2;
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);
209 $$->const_string = strings;
216 $$ = g_strdup (yytext);
220 identifier_or_typedef_name
227 | postfix_expression '[' expression ']'
229 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
231 | postfix_expression '(' argument_expression_list ')'
233 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
235 | postfix_expression '(' ')'
237 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
239 | postfix_expression '.' identifier_or_typedef_name
241 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
243 | postfix_expression ARROW identifier_or_typedef_name
245 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
247 | postfix_expression PLUSPLUS
249 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
251 | postfix_expression MINUSMINUS
253 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
257 argument_expression_list
258 : assignment_expression
259 | argument_expression_list ',' assignment_expression
264 | PLUSPLUS unary_expression
266 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
268 | MINUSMINUS unary_expression
270 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
272 | unary_operator cast_expression
280 $$->const_int = -$2->const_int;
282 case UNARY_BITWISE_COMPLEMENT:
284 $$->const_int = ~$2->const_int;
286 case UNARY_LOGICAL_NEGATION:
288 $$->const_int = !gi_source_symbol_get_const_boolean ($2);
291 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
295 | SIZEOF unary_expression
297 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
299 | SIZEOF '(' type_name ')'
302 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
309 $$ = UNARY_ADDRESS_OF;
313 $$ = UNARY_POINTER_INDIRECTION;
325 $$ = UNARY_BITWISE_COMPLEMENT;
329 $$ = UNARY_LOGICAL_NEGATION;
335 | '(' type_name ')' cast_expression
342 multiplicative_expression
344 | multiplicative_expression '*' cast_expression
346 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
347 $$->const_int_set = TRUE;
348 $$->const_int = $1->const_int * $3->const_int;
350 | multiplicative_expression '/' cast_expression
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;
358 | multiplicative_expression '%' cast_expression
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;
369 : multiplicative_expression
370 | additive_expression '+' multiplicative_expression
372 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
373 $$->const_int_set = TRUE;
374 $$->const_int = $1->const_int + $3->const_int;
376 | additive_expression '-' multiplicative_expression
378 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
379 $$->const_int_set = TRUE;
380 $$->const_int = $1->const_int - $3->const_int;
385 : additive_expression
386 | shift_expression SL additive_expression
388 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
389 $$->const_int_set = TRUE;
390 $$->const_int = $1->const_int << $3->const_int;
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.
398 | shift_expression SR additive_expression
400 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
401 $$->const_int_set = TRUE;
402 $$->const_int = $1->const_int >> $3->const_int;
406 relational_expression
408 | relational_expression '<' shift_expression
410 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
411 $$->const_int_set = TRUE;
412 $$->const_int = $1->const_int < $3->const_int;
414 | relational_expression '>' shift_expression
416 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
417 $$->const_int_set = TRUE;
418 $$->const_int = $1->const_int > $3->const_int;
420 | relational_expression LTEQ shift_expression
422 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
423 $$->const_int_set = TRUE;
424 $$->const_int = $1->const_int <= $3->const_int;
426 | relational_expression GTEQ shift_expression
428 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
429 $$->const_int_set = TRUE;
430 $$->const_int = $1->const_int >= $3->const_int;
435 : relational_expression
436 | equality_expression EQ relational_expression
438 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
439 $$->const_int_set = TRUE;
440 $$->const_int = $1->const_int == $3->const_int;
442 | equality_expression NOTEQ relational_expression
444 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
445 $$->const_int_set = TRUE;
446 $$->const_int = $1->const_int != $3->const_int;
451 : equality_expression
452 | and_expression '&' equality_expression
454 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
455 $$->const_int_set = TRUE;
456 $$->const_int = $1->const_int & $3->const_int;
460 exclusive_or_expression
462 | exclusive_or_expression '^' and_expression
464 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
465 $$->const_int_set = TRUE;
466 $$->const_int = $1->const_int ^ $3->const_int;
470 inclusive_or_expression
471 : exclusive_or_expression
472 | inclusive_or_expression '|' exclusive_or_expression
474 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
475 $$->const_int_set = TRUE;
476 $$->const_int = $1->const_int | $3->const_int;
480 logical_and_expression
481 : inclusive_or_expression
482 | logical_and_expression ANDAND inclusive_or_expression
484 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
485 $$->const_int_set = TRUE;
487 gi_source_symbol_get_const_boolean ($1) &&
488 gi_source_symbol_get_const_boolean ($3);
492 logical_or_expression
493 : logical_and_expression
494 | logical_or_expression OROR logical_and_expression
496 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
497 $$->const_int_set = TRUE;
499 gi_source_symbol_get_const_boolean ($1) ||
500 gi_source_symbol_get_const_boolean ($3);
504 conditional_expression
505 : logical_or_expression
506 | logical_or_expression '?' expression ':' conditional_expression
508 $$ = gi_source_symbol_get_const_boolean ($1) ? $3 : $5;
512 assignment_expression
513 : conditional_expression
514 | unary_expression assignment_operator assignment_expression
516 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
535 : assignment_expression
536 | expression ',' assignment_expression
537 | EXTENSION expression
539 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
544 : conditional_expression
547 /* A.2.2 Declarations. */
550 : declaration_specifiers init_declarator_list ';'
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;
561 sym->type = CSYMBOL_TYPE_OBJECT;
563 gi_source_scanner_add_symbol (scanner, sym);
564 gi_source_symbol_unref (sym);
568 | declaration_specifiers ';'
574 declaration_specifiers
575 : storage_class_specifier declaration_specifiers
578 $$->storage_class_specifier |= $1;
580 | storage_class_specifier
582 $$ = gi_source_type_new (CTYPE_INVALID);
583 $$->storage_class_specifier |= $1;
585 | type_specifier declaration_specifiers
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);
599 | type_qualifier declaration_specifiers
602 $$->type_qualifier |= $1;
606 $$ = gi_source_type_new (CTYPE_INVALID);
607 $$->type_qualifier |= $1;
609 | function_specifier declaration_specifiers
612 $$->function_specifier |= $1;
616 $$ = gi_source_type_new (CTYPE_INVALID);
617 $$->function_specifier |= $1;
624 $$ = g_list_append (NULL, $1);
626 | init_declarator_list ',' init_declarator
628 $$ = g_list_append ($1, $3);
634 | declarator '=' initializer
637 storage_class_specifier
640 $$ = STORAGE_CLASS_TYPEDEF;
644 $$ = STORAGE_CLASS_EXTERN;
648 $$ = STORAGE_CLASS_STATIC;
652 $$ = STORAGE_CLASS_AUTO;
656 $$ = STORAGE_CLASS_REGISTER;
663 $$ = gi_source_type_new (CTYPE_VOID);
667 $$ = gi_source_basic_type_new ("char");
671 $$ = gi_source_basic_type_new ("short");
675 $$ = gi_source_basic_type_new ("int");
679 $$ = gi_source_basic_type_new ("long");
683 $$ = gi_source_basic_type_new ("float");
687 $$ = gi_source_basic_type_new ("double");
691 $$ = gi_source_basic_type_new ("signed");
695 $$ = gi_source_basic_type_new ("unsigned");
699 $$ = gi_source_basic_type_new ("bool");
701 | struct_or_union_specifier
705 $$ = gi_source_typedef_new ($1);
710 struct_or_union_specifier
711 : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
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;
723 g_assert_not_reached ();
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);
730 | struct_or_union '{' struct_declaration_list '}'
735 | struct_or_union identifier_or_typedef_name
745 scanner->private = FALSE;
746 $$ = gi_source_struct_new (NULL);
750 scanner->private = FALSE;
751 $$ = gi_source_union_new (NULL);
755 struct_declaration_list
757 | struct_declaration_list struct_declaration
759 $$ = g_list_concat ($1, $2);
764 : specifier_qualifier_list struct_declarator_list ';'
768 for (l = $2; l != NULL; l = l->next)
770 GISourceSymbol *sym = l->data;
771 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF)
772 sym->type = CSYMBOL_TYPE_TYPEDEF;
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);
783 specifier_qualifier_list
784 : type_specifier specifier_qualifier_list
790 | type_qualifier specifier_qualifier_list
793 $$->type_qualifier |= $1;
797 $$ = gi_source_type_new (CTYPE_INVALID);
798 $$->type_qualifier |= $1;
802 struct_declarator_list
805 $$ = g_list_append (NULL, $1);
807 | struct_declarator_list ',' struct_declarator
809 $$ = g_list_append ($1, $3);
814 : /* empty, support for anonymous structs and unions */
816 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
819 | ':' constant_expression
821 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
823 | declarator ':' constant_expression
826 if ($3->const_int_set) {
827 $$->const_int_set = TRUE;
828 $$->const_int = $3->const_int;
834 : ENUM identifier_or_typedef_name '{' enumerator_list '}'
836 scanner->private = FALSE;
837 $$ = gi_source_enum_new ($2);
839 $$->is_bitfield = is_bitfield;
840 last_enum_value = -1;
842 | ENUM '{' enumerator_list '}'
844 scanner->private = FALSE;
845 $$ = gi_source_enum_new (NULL);
847 $$->is_bitfield = is_bitfield;
848 last_enum_value = -1;
850 | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
852 scanner->private = FALSE;
853 $$ = gi_source_enum_new ($2);
855 $$->is_bitfield = is_bitfield;
856 last_enum_value = -1;
858 | ENUM '{' enumerator_list ',' '}'
860 scanner->private = FALSE;
861 $$ = gi_source_enum_new (NULL);
863 $$->is_bitfield = is_bitfield;
864 last_enum_value = -1;
866 | ENUM identifier_or_typedef_name
868 scanner->private = FALSE;
869 $$ = gi_source_enum_new ($2);
876 /* reset flag before the first enum value */
881 $2->private = scanner->private;
882 $$ = g_list_append (NULL, $2);
884 | enumerator_list ',' enumerator
886 $3->private = scanner->private;
887 $$ = g_list_append ($1, $3);
894 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, lineno);
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 ($$));
900 | identifier '=' constant_expression
902 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, lineno);
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 ($$));
914 $$ = TYPE_QUALIFIER_CONST;
918 $$ = TYPE_QUALIFIER_RESTRICT;
922 $$ = TYPE_QUALIFIER_EXTENSION;
926 $$ = TYPE_QUALIFIER_VOLATILE;
933 $$ = FUNCTION_INLINE;
938 : pointer direct_declarator
941 gi_source_symbol_merge_type ($$, $1);
949 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
956 | direct_declarator '[' assignment_expression ']'
959 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
961 | direct_declarator '[' ']'
964 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
966 | direct_declarator '(' parameter_list ')'
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;
974 gi_source_symbol_merge_type ($$, func);
976 | direct_declarator '(' identifier_list ')'
978 GISourceType *func = gi_source_function_new ();
979 func->child_list = $3;
981 gi_source_symbol_merge_type ($$, func);
983 | direct_declarator '(' ')'
985 GISourceType *func = gi_source_function_new ();
987 gi_source_symbol_merge_type ($$, func);
992 : '*' type_qualifier_list
994 $$ = gi_source_pointer_new (NULL);
995 $$->type_qualifier = $2;
999 $$ = gi_source_pointer_new (NULL);
1001 | '*' type_qualifier_list pointer
1003 $$ = gi_source_pointer_new ($3);
1004 $$->type_qualifier = $2;
1008 $$ = gi_source_pointer_new ($2);
1014 | type_qualifier_list type_qualifier
1021 : parameter_declaration
1023 $$ = g_list_append (NULL, $1);
1025 | parameter_list ',' parameter_declaration
1027 $$ = g_list_append ($1, $3);
1031 parameter_declaration
1032 : declaration_specifiers declarator
1035 gi_source_symbol_merge_type ($$, $1);
1037 | declaration_specifiers abstract_declarator
1040 gi_source_symbol_merge_type ($$, $1);
1042 | declaration_specifiers
1044 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1049 $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS, lineno);
1056 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1058 $$ = g_list_append (NULL, sym);
1060 | identifier_list ',' identifier
1062 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1064 $$ = g_list_append ($1, sym);
1069 : specifier_qualifier_list
1070 | specifier_qualifier_list abstract_declarator
1076 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1077 gi_source_symbol_merge_type ($$, $1);
1079 | direct_abstract_declarator
1080 | pointer direct_abstract_declarator
1083 gi_source_symbol_merge_type ($$, $1);
1087 direct_abstract_declarator
1088 : '(' abstract_declarator ')'
1094 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1095 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1097 | '[' assignment_expression ']'
1099 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1100 gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
1102 | direct_abstract_declarator '[' ']'
1105 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1107 | direct_abstract_declarator '[' assignment_expression ']'
1110 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1114 GISourceType *func = gi_source_function_new ();
1115 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1116 gi_source_symbol_merge_type ($$, func);
1118 | '(' parameter_list ')'
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;
1125 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
1126 gi_source_symbol_merge_type ($$, func);
1128 | direct_abstract_declarator '(' ')'
1130 GISourceType *func = gi_source_function_new ();
1132 gi_source_symbol_merge_type ($$, func);
1134 | direct_abstract_declarator '(' parameter_list ')'
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;
1142 gi_source_symbol_merge_type ($$, func);
1149 $$ = g_strdup (yytext);
1154 : assignment_expression
1155 | '{' initializer_list '}'
1156 | '{' initializer_list ',' '}'
1161 | initializer_list ',' initializer
1164 /* A.2.3 Statements. */
1168 | compound_statement
1169 | expression_statement
1170 | selection_statement
1171 | iteration_statement
1176 : identifier_or_typedef_name ':' statement
1177 | CASE constant_expression ':' statement
1178 | DEFAULT ':' statement
1183 | '{' block_item_list '}'
1188 | block_item_list block_item
1196 expression_statement
1202 : IF '(' expression ')' statement
1203 | IF '(' expression ')' statement ELSE statement
1204 | SWITCH '(' expression ')' 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
1221 : GOTO identifier_or_typedef_name ';'
1225 | RETURN expression ';'
1228 /* A.2.4 External definitions. */
1231 : external_declaration
1232 | translation_unit external_declaration
1235 external_declaration
1236 : function_definition
1242 : declaration_specifiers declarator declaration_list compound_statement
1243 | declaration_specifiers declarator compound_statement
1248 | declaration_list declaration
1256 $$ = g_strdup (yytext + strlen ("#define "));
1263 $$ = g_strdup (yytext + strlen ("#define "));
1267 function_macro_define
1268 : function_macro '(' identifier_list ')'
1272 : object_macro constant_expression
1274 if ($2->const_int_set || $2->const_double_set || $2->const_string != NULL) {
1276 gi_source_scanner_add_symbol (scanner, $2);
1277 gi_source_symbol_unref ($2);
1283 : function_macro_define
1284 | object_macro_define
1290 yyerror (GISourceScanner *scanner, const char *s)
1292 /* ignore errors while doing a macro scan as not all object macros
1293 * have valid expressions */
1294 if (!scanner->macro_scan)
1296 fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
1297 scanner->current_filename, lineno, s, linebuf, yytext);
1302 eat_hspace (FILE * f)
1309 while (c == ' ' || c == '\t');
1314 eat_line (FILE * f, int c)
1316 while (c != EOF && c != '\n')
1323 if (c == ' ' || c == '\t')
1332 read_identifier (FILE * f, int c, char **identifier)
1334 GString *id = g_string_new ("");
1335 while (g_ascii_isalnum (c) || c == '_')
1337 g_string_append_c (id, c);
1340 *identifier = g_string_free (id, FALSE);
1345 gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
1347 GError *error = NULL;
1348 char *tmp_name = NULL;
1350 fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1352 g_unlink (tmp_name);
1355 for (l = filenames; l != NULL; l = l->next)
1357 FILE *f = fopen (l->data, "r");
1360 GString *define_line;
1362 gboolean error_line = FALSE;
1363 int c = eat_hspace (f);
1369 c = eat_line (f, c);
1374 /* print current location */
1375 str = g_strescape (l->data, "");
1376 fprintf (fmacros, "# %d \"%s\"\n", line, str);
1380 c = read_identifier (f, c, &str);
1381 if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1385 c = eat_line (f, c);
1391 c = read_identifier (f, c, &str);
1392 if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1396 c = eat_line (f, c);
1400 define_line = g_string_new ("#define ");
1401 g_string_append (define_line, str);
1407 g_string_append_c (define_line, c);
1409 if (c == EOF || c == '\n')
1417 g_string_free (define_line, TRUE);
1419 c = eat_line (f, c);
1424 g_assert (c == ')');
1425 g_string_append_c (define_line, c);
1428 /* found function-like macro */
1429 fprintf (fmacros, "%s\n", define_line->str);
1431 g_string_free (define_line, TRUE);
1432 /* ignore rest of line */
1433 c = eat_line (f, c);
1437 if (c != ' ' && c != '\t')
1439 g_string_free (define_line, TRUE);
1441 c = eat_line (f, c);
1445 while (c != EOF && c != '\n')
1447 g_string_append_c (define_line, c);
1454 /* fold lines when seeing backslash new-line sequence */
1459 g_string_append_c (define_line, '\\');
1464 /* found object-like macro */
1465 fprintf (fmacros, "%s\n", define_line->str);
1467 c = eat_line (f, c);
1475 gi_source_scanner_parse_file (scanner, fmacros);
1479 gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
1481 g_return_val_if_fail (file != NULL, FALSE);
1483 const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1484 g_free, (GDestroyNotify)gi_source_symbol_unref);
1490 g_hash_table_destroy (const_table);
1499 gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
1502 yyin = fopen (filename, "r");
1504 while (yylex (scanner) != YYEOF)