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;
54 * parse_c_string_literal:
55 * @str: A string containing a C string literal
57 * Based on g_strcompress(), but also handles
58 * hexadecimal escapes.
61 parse_c_string_literal (const char *str)
63 const gchar *p = str, *num;
64 gchar *dest = g_malloc (strlen (str) + 1);
75 g_warning ("parse_c_string_literal: trailing \\");
77 case '0': case '1': case '2': case '3': case '4':
78 case '5': case '6': case '7':
81 while ((p < num + 3) && (*p >= '0') && (*p <= '7'))
83 *q = (*q * 8) + (*p - '0');
93 while ((p < num + 2) && (g_ascii_isxdigit(*p)))
95 *q = (*q * 16) + g_ascii_xdigit_value(*p);
116 default: /* Also handles \" and \\ */
137 GISourceSymbol *symbol;
139 StorageClassSpecifier storage_class_specifier;
140 TypeQualifier type_qualifier;
141 FunctionSpecifier function_specifier;
142 UnaryOperator unary_operator;
145 %parse-param { GISourceScanner* scanner }
146 %lex-param { GISourceScanner* scanner }
148 %token <str> IDENTIFIER "identifier"
149 %token <str> TYPEDEF_NAME "typedef-name"
151 %token INTEGER FLOATING CHARACTER STRING
153 %token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
154 %token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
156 %token AUTO BOOL BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
157 %token EXTENSION EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT
158 %token RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED
159 %token VOID VOLATILE WHILE
161 %token FUNCTION_MACRO OBJECT_MACRO
163 %start translation_unit
165 %type <ctype> declaration_specifiers
166 %type <ctype> enum_specifier
167 %type <ctype> pointer
168 %type <ctype> specifier_qualifier_list
169 %type <ctype> type_name
170 %type <ctype> struct_or_union
171 %type <ctype> struct_or_union_specifier
172 %type <ctype> type_specifier
173 %type <str> identifier
174 %type <str> typedef_name
175 %type <str> identifier_or_typedef_name
176 %type <symbol> abstract_declarator
177 %type <symbol> init_declarator
178 %type <symbol> declarator
179 %type <symbol> enumerator
180 %type <symbol> direct_abstract_declarator
181 %type <symbol> direct_declarator
182 %type <symbol> parameter_declaration
183 %type <symbol> struct_declarator
184 %type <list> enumerator_list
185 %type <list> identifier_list
186 %type <list> init_declarator_list
187 %type <list> parameter_list
188 %type <list> struct_declaration
189 %type <list> struct_declaration_list
190 %type <list> struct_declarator_list
191 %type <storage_class_specifier> storage_class_specifier
192 %type <type_qualifier> type_qualifier
193 %type <type_qualifier> type_qualifier_list
194 %type <function_specifier> function_specifier
195 %type <symbol> expression
196 %type <symbol> constant_expression
197 %type <symbol> conditional_expression
198 %type <symbol> logical_and_expression
199 %type <symbol> logical_or_expression
200 %type <symbol> inclusive_or_expression
201 %type <symbol> exclusive_or_expression
202 %type <symbol> multiplicative_expression
203 %type <symbol> additive_expression
204 %type <symbol> shift_expression
205 %type <symbol> relational_expression
206 %type <symbol> equality_expression
207 %type <symbol> and_expression
208 %type <symbol> cast_expression
209 %type <symbol> assignment_expression
210 %type <symbol> unary_expression
211 %type <symbol> postfix_expression
212 %type <symbol> primary_expression
213 %type <unary_operator> unary_operator
214 %type <str> function_macro
215 %type <str> object_macro
216 %type <symbol> strings
220 /* A.2.1 Expressions. */
225 $$ = g_hash_table_lookup (const_table, $1);
227 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
229 $$ = gi_source_symbol_ref ($$);
234 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
235 $$->const_int_set = TRUE;
236 if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
237 $$->const_int = g_ascii_strtoll (yytext + 2, NULL, 16);
238 } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
239 $$->const_int = g_ascii_strtoll (yytext + 1, NULL, 8);
241 $$->const_int = g_ascii_strtoll (yytext, NULL, 10);
246 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
247 $$->const_int_set = TRUE;
248 $$->const_int = g_utf8_get_char(yytext + 1);
252 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
253 $$->const_double_set = TRUE;
254 $$->const_double = 0.0;
255 sscanf (yytext, "%lf", &($$->const_double));
262 | EXTENSION '(' '{' block_item_list '}' ')'
264 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
268 /* concatenate adjacent string literal tokens */
272 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
273 yytext[strlen (yytext) - 1] = '\0';
274 $$->const_string = parse_c_string_literal (yytext + 1);
275 if (!g_utf8_validate ($$->const_string, -1, NULL))
278 g_warning ("Ignoring non-UTF-8 constant string \"%s\"", yytext + 1);
280 g_free($$->const_string);
281 $$->const_string = NULL;
287 char *strings, *string2;
289 yytext[strlen (yytext) - 1] = '\0';
290 string2 = parse_c_string_literal (yytext + 1);
291 strings = g_strconcat ($$->const_string, string2, NULL);
292 g_free ($$->const_string);
294 $$->const_string = strings;
301 $$ = g_strdup (yytext);
305 identifier_or_typedef_name
312 | postfix_expression '[' expression ']'
314 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
316 | postfix_expression '(' argument_expression_list ')'
318 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
320 | postfix_expression '(' ')'
322 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
324 | postfix_expression '.' identifier_or_typedef_name
326 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
328 | postfix_expression ARROW identifier_or_typedef_name
330 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
332 | postfix_expression PLUSPLUS
334 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
336 | postfix_expression MINUSMINUS
338 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
342 argument_expression_list
343 : assignment_expression
344 | argument_expression_list ',' assignment_expression
349 | PLUSPLUS unary_expression
351 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
353 | MINUSMINUS unary_expression
355 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
357 | unary_operator cast_expression
365 $$->const_int = -$2->const_int;
367 case UNARY_BITWISE_COMPLEMENT:
369 $$->const_int = ~$2->const_int;
371 case UNARY_LOGICAL_NEGATION:
373 $$->const_int = !gi_source_symbol_get_const_boolean ($2);
376 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
380 | SIZEOF unary_expression
382 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
384 | SIZEOF '(' type_name ')'
387 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
394 $$ = UNARY_ADDRESS_OF;
398 $$ = UNARY_POINTER_INDIRECTION;
410 $$ = UNARY_BITWISE_COMPLEMENT;
414 $$ = UNARY_LOGICAL_NEGATION;
420 | '(' type_name ')' cast_expression
427 multiplicative_expression
429 | multiplicative_expression '*' cast_expression
431 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
432 $$->const_int_set = TRUE;
433 $$->const_int = $1->const_int * $3->const_int;
435 | multiplicative_expression '/' cast_expression
437 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
438 $$->const_int_set = TRUE;
439 if ($3->const_int != 0) {
440 $$->const_int = $1->const_int / $3->const_int;
443 | multiplicative_expression '%' cast_expression
445 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
446 $$->const_int_set = TRUE;
447 if ($3->const_int != 0) {
448 $$->const_int = $1->const_int % $3->const_int;
454 : multiplicative_expression
455 | additive_expression '+' multiplicative_expression
457 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
458 $$->const_int_set = TRUE;
459 $$->const_int = $1->const_int + $3->const_int;
461 | additive_expression '-' multiplicative_expression
463 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
464 $$->const_int_set = TRUE;
465 $$->const_int = $1->const_int - $3->const_int;
470 : additive_expression
471 | shift_expression SL additive_expression
473 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
474 $$->const_int_set = TRUE;
475 $$->const_int = $1->const_int << $3->const_int;
477 /* assume this is a bitfield/flags declaration
478 * if a left shift operator is sued in an enum value
479 * This mimics the glib-mkenum behavior.
483 | shift_expression SR additive_expression
485 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
486 $$->const_int_set = TRUE;
487 $$->const_int = $1->const_int >> $3->const_int;
491 relational_expression
493 | relational_expression '<' shift_expression
495 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
496 $$->const_int_set = TRUE;
497 $$->const_int = $1->const_int < $3->const_int;
499 | relational_expression '>' shift_expression
501 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
502 $$->const_int_set = TRUE;
503 $$->const_int = $1->const_int > $3->const_int;
505 | relational_expression LTEQ shift_expression
507 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
508 $$->const_int_set = TRUE;
509 $$->const_int = $1->const_int <= $3->const_int;
511 | relational_expression GTEQ shift_expression
513 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
514 $$->const_int_set = TRUE;
515 $$->const_int = $1->const_int >= $3->const_int;
520 : relational_expression
521 | equality_expression EQ relational_expression
523 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
524 $$->const_int_set = TRUE;
525 $$->const_int = $1->const_int == $3->const_int;
527 | equality_expression NOTEQ relational_expression
529 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
530 $$->const_int_set = TRUE;
531 $$->const_int = $1->const_int != $3->const_int;
536 : equality_expression
537 | and_expression '&' equality_expression
539 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
540 $$->const_int_set = TRUE;
541 $$->const_int = $1->const_int & $3->const_int;
545 exclusive_or_expression
547 | exclusive_or_expression '^' and_expression
549 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
550 $$->const_int_set = TRUE;
551 $$->const_int = $1->const_int ^ $3->const_int;
555 inclusive_or_expression
556 : exclusive_or_expression
557 | inclusive_or_expression '|' exclusive_or_expression
559 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
560 $$->const_int_set = TRUE;
561 $$->const_int = $1->const_int | $3->const_int;
565 logical_and_expression
566 : inclusive_or_expression
567 | logical_and_expression ANDAND inclusive_or_expression
569 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
570 $$->const_int_set = TRUE;
572 gi_source_symbol_get_const_boolean ($1) &&
573 gi_source_symbol_get_const_boolean ($3);
577 logical_or_expression
578 : logical_and_expression
579 | logical_or_expression OROR logical_and_expression
581 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
582 $$->const_int_set = TRUE;
584 gi_source_symbol_get_const_boolean ($1) ||
585 gi_source_symbol_get_const_boolean ($3);
589 conditional_expression
590 : logical_or_expression
591 | logical_or_expression '?' expression ':' conditional_expression
593 $$ = gi_source_symbol_get_const_boolean ($1) ? $3 : $5;
597 assignment_expression
598 : conditional_expression
599 | unary_expression assignment_operator assignment_expression
601 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
620 : assignment_expression
621 | expression ',' assignment_expression
622 | EXTENSION expression
624 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
629 : conditional_expression
632 /* A.2.2 Declarations. */
635 : declaration_specifiers init_declarator_list ';'
638 for (l = $2; l != NULL; l = l->next) {
639 GISourceSymbol *sym = l->data;
640 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
641 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
642 sym->type = CSYMBOL_TYPE_TYPEDEF;
643 } else if (sym->base_type->type == CTYPE_FUNCTION) {
644 sym->type = CSYMBOL_TYPE_FUNCTION;
646 sym->type = CSYMBOL_TYPE_OBJECT;
648 gi_source_scanner_add_symbol (scanner, sym);
649 gi_source_symbol_unref (sym);
653 | declaration_specifiers ';'
659 declaration_specifiers
660 : storage_class_specifier declaration_specifiers
663 $$->storage_class_specifier |= $1;
665 | storage_class_specifier
667 $$ = gi_source_type_new (CTYPE_INVALID);
668 $$->storage_class_specifier |= $1;
670 | type_specifier declaration_specifiers
673 /* combine basic types like unsigned int and long long */
674 if ($$->type == CTYPE_BASIC_TYPE && $2->type == CTYPE_BASIC_TYPE) {
675 char *name = g_strdup_printf ("%s %s", $$->name, $2->name);
684 | type_qualifier declaration_specifiers
687 $$->type_qualifier |= $1;
691 $$ = gi_source_type_new (CTYPE_INVALID);
692 $$->type_qualifier |= $1;
694 | function_specifier declaration_specifiers
697 $$->function_specifier |= $1;
701 $$ = gi_source_type_new (CTYPE_INVALID);
702 $$->function_specifier |= $1;
709 $$ = g_list_append (NULL, $1);
711 | init_declarator_list ',' init_declarator
713 $$ = g_list_append ($1, $3);
719 | declarator '=' initializer
722 storage_class_specifier
725 $$ = STORAGE_CLASS_TYPEDEF;
729 $$ = STORAGE_CLASS_EXTERN;
733 $$ = STORAGE_CLASS_STATIC;
737 $$ = STORAGE_CLASS_AUTO;
741 $$ = STORAGE_CLASS_REGISTER;
748 $$ = gi_source_type_new (CTYPE_VOID);
752 $$ = gi_source_basic_type_new ("char");
756 $$ = gi_source_basic_type_new ("short");
760 $$ = gi_source_basic_type_new ("int");
764 $$ = gi_source_basic_type_new ("long");
768 $$ = gi_source_basic_type_new ("float");
772 $$ = gi_source_basic_type_new ("double");
776 $$ = gi_source_basic_type_new ("signed");
780 $$ = gi_source_basic_type_new ("unsigned");
784 $$ = gi_source_basic_type_new ("bool");
786 | struct_or_union_specifier
790 $$ = gi_source_typedef_new ($1);
795 struct_or_union_specifier
796 : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
802 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
803 if ($$->type == CTYPE_STRUCT) {
804 sym->type = CSYMBOL_TYPE_STRUCT;
805 } else if ($$->type == CTYPE_UNION) {
806 sym->type = CSYMBOL_TYPE_UNION;
808 g_assert_not_reached ();
810 sym->ident = g_strdup ($$->name);
811 sym->base_type = gi_source_type_copy ($$);
812 gi_source_scanner_add_symbol (scanner, sym);
813 gi_source_symbol_unref (sym);
815 | struct_or_union '{' struct_declaration_list '}'
820 | struct_or_union identifier_or_typedef_name
830 scanner->private = FALSE;
831 $$ = gi_source_struct_new (NULL);
835 scanner->private = FALSE;
836 $$ = gi_source_union_new (NULL);
840 struct_declaration_list
842 | struct_declaration_list struct_declaration
844 $$ = g_list_concat ($1, $2);
849 : specifier_qualifier_list struct_declarator_list ';'
853 for (l = $2; l != NULL; l = l->next)
855 GISourceSymbol *sym = l->data;
856 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF)
857 sym->type = CSYMBOL_TYPE_TYPEDEF;
859 sym->type = CSYMBOL_TYPE_MEMBER;
860 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
861 sym->private = scanner->private;
862 $$ = g_list_append ($$, sym);
868 specifier_qualifier_list
869 : type_specifier specifier_qualifier_list
875 | type_qualifier specifier_qualifier_list
878 $$->type_qualifier |= $1;
882 $$ = gi_source_type_new (CTYPE_INVALID);
883 $$->type_qualifier |= $1;
887 struct_declarator_list
890 $$ = g_list_append (NULL, $1);
892 | struct_declarator_list ',' struct_declarator
894 $$ = g_list_append ($1, $3);
899 : /* empty, support for anonymous structs and unions */
901 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
904 | ':' constant_expression
906 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
908 | declarator ':' constant_expression
911 if ($3->const_int_set) {
912 $$->const_int_set = TRUE;
913 $$->const_int = $3->const_int;
919 : enum_keyword identifier_or_typedef_name '{' enumerator_list '}'
921 $$ = gi_source_enum_new ($2);
923 $$->is_bitfield = is_bitfield || scanner->flags;
924 last_enum_value = -1;
926 | enum_keyword '{' enumerator_list '}'
928 $$ = gi_source_enum_new (NULL);
930 $$->is_bitfield = is_bitfield || scanner->flags;
931 last_enum_value = -1;
933 | enum_keyword identifier_or_typedef_name '{' enumerator_list ',' '}'
935 $$ = gi_source_enum_new ($2);
937 $$->is_bitfield = is_bitfield || scanner->flags;
938 last_enum_value = -1;
940 | enum_keyword '{' enumerator_list ',' '}'
942 $$ = gi_source_enum_new (NULL);
944 $$->is_bitfield = is_bitfield || scanner->flags;
945 last_enum_value = -1;
947 | enum_keyword identifier_or_typedef_name
949 $$ = gi_source_enum_new ($2);
956 scanner->flags = FALSE;
957 scanner->private = FALSE;
964 /* reset flag before the first enum value */
969 $2->private = scanner->private;
970 $$ = g_list_append (NULL, $2);
972 | enumerator_list ',' enumerator
974 $3->private = scanner->private;
975 $$ = g_list_append ($1, $3);
982 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_filename, lineno);
984 $$->const_int_set = TRUE;
985 $$->const_int = ++last_enum_value;
986 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
988 | identifier '=' constant_expression
990 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_filename, lineno);
992 $$->const_int_set = TRUE;
993 $$->const_int = $3->const_int;
994 last_enum_value = $$->const_int;
995 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
1002 $$ = TYPE_QUALIFIER_CONST;
1006 $$ = TYPE_QUALIFIER_RESTRICT;
1010 $$ = TYPE_QUALIFIER_EXTENSION;
1014 $$ = TYPE_QUALIFIER_VOLATILE;
1021 $$ = FUNCTION_INLINE;
1026 : pointer direct_declarator
1029 gi_source_symbol_merge_type ($$, $1);
1037 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1040 | '(' declarator ')'
1044 | direct_declarator '[' assignment_expression ']'
1047 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1049 | direct_declarator '[' ']'
1052 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1054 | direct_declarator '(' parameter_list ')'
1056 GISourceType *func = gi_source_function_new ();
1057 // ignore (void) parameter list
1058 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1059 func->child_list = $3;
1062 gi_source_symbol_merge_type ($$, func);
1064 | direct_declarator '(' identifier_list ')'
1066 GISourceType *func = gi_source_function_new ();
1067 func->child_list = $3;
1069 gi_source_symbol_merge_type ($$, func);
1071 | direct_declarator '(' ')'
1073 GISourceType *func = gi_source_function_new ();
1075 gi_source_symbol_merge_type ($$, func);
1080 : '*' type_qualifier_list
1082 $$ = gi_source_pointer_new (NULL);
1083 $$->type_qualifier = $2;
1087 $$ = gi_source_pointer_new (NULL);
1089 | '*' type_qualifier_list pointer
1091 GISourceType **base = &($3->base_type);
1093 while (*base != NULL) {
1094 base = &((*base)->base_type);
1096 *base = gi_source_pointer_new (NULL);
1097 (*base)->type_qualifier = $2;
1102 GISourceType **base = &($2->base_type);
1104 while (*base != NULL) {
1105 base = &((*base)->base_type);
1107 *base = gi_source_pointer_new (NULL);
1114 | type_qualifier_list type_qualifier
1121 : parameter_declaration
1123 $$ = g_list_append (NULL, $1);
1125 | parameter_list ',' parameter_declaration
1127 $$ = g_list_append ($1, $3);
1131 parameter_declaration
1132 : declaration_specifiers declarator
1135 gi_source_symbol_merge_type ($$, $1);
1137 | declaration_specifiers abstract_declarator
1140 gi_source_symbol_merge_type ($$, $1);
1142 | declaration_specifiers
1144 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1149 $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS, scanner->current_filename, lineno);
1156 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1158 $$ = g_list_append (NULL, sym);
1160 | identifier_list ',' identifier
1162 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1164 $$ = g_list_append ($1, sym);
1169 : specifier_qualifier_list
1170 | specifier_qualifier_list abstract_declarator
1176 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1177 gi_source_symbol_merge_type ($$, $1);
1179 | direct_abstract_declarator
1180 | pointer direct_abstract_declarator
1183 gi_source_symbol_merge_type ($$, $1);
1187 direct_abstract_declarator
1188 : '(' abstract_declarator ')'
1194 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1195 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1197 | '[' assignment_expression ']'
1199 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1200 gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
1202 | direct_abstract_declarator '[' ']'
1205 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1207 | direct_abstract_declarator '[' assignment_expression ']'
1210 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1214 GISourceType *func = gi_source_function_new ();
1215 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1216 gi_source_symbol_merge_type ($$, func);
1218 | '(' parameter_list ')'
1220 GISourceType *func = gi_source_function_new ();
1221 // ignore (void) parameter list
1222 if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
1223 func->child_list = $2;
1225 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1226 gi_source_symbol_merge_type ($$, func);
1228 | direct_abstract_declarator '(' ')'
1230 GISourceType *func = gi_source_function_new ();
1232 gi_source_symbol_merge_type ($$, func);
1234 | direct_abstract_declarator '(' parameter_list ')'
1236 GISourceType *func = gi_source_function_new ();
1237 // ignore (void) parameter list
1238 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1239 func->child_list = $3;
1242 gi_source_symbol_merge_type ($$, func);
1249 $$ = g_strdup (yytext);
1254 : assignment_expression
1255 | '{' initializer_list '}'
1256 | '{' initializer_list ',' '}'
1261 | initializer_list ',' initializer
1264 /* A.2.3 Statements. */
1268 | compound_statement
1269 | expression_statement
1270 | selection_statement
1271 | iteration_statement
1276 : identifier_or_typedef_name ':' statement
1277 | CASE constant_expression ':' statement
1278 | DEFAULT ':' statement
1283 | '{' block_item_list '}'
1288 | block_item_list block_item
1296 expression_statement
1302 : IF '(' expression ')' statement
1303 | IF '(' expression ')' statement ELSE statement
1304 | SWITCH '(' expression ')' statement
1308 : WHILE '(' expression ')' statement
1309 | DO statement WHILE '(' expression ')' ';'
1310 | FOR '(' ';' ';' ')' statement
1311 | FOR '(' expression ';' ';' ')' statement
1312 | FOR '(' ';' expression ';' ')' statement
1313 | FOR '(' expression ';' expression ';' ')' statement
1314 | FOR '(' ';' ';' expression ')' statement
1315 | FOR '(' expression ';' ';' expression ')' statement
1316 | FOR '(' ';' expression ';' expression ')' statement
1317 | FOR '(' expression ';' expression ';' expression ')' statement
1321 : GOTO identifier_or_typedef_name ';'
1325 | RETURN expression ';'
1328 /* A.2.4 External definitions. */
1331 : external_declaration
1332 | translation_unit external_declaration
1335 external_declaration
1336 : function_definition
1342 : declaration_specifiers declarator declaration_list compound_statement
1343 | declaration_specifiers declarator compound_statement
1348 | declaration_list declaration
1356 $$ = g_strdup (yytext + strlen ("#define "));
1363 $$ = g_strdup (yytext + strlen ("#define "));
1367 function_macro_define
1368 : function_macro '(' identifier_list ')'
1372 : object_macro constant_expression
1374 if ($2->const_int_set || $2->const_double_set || $2->const_string != NULL) {
1376 gi_source_scanner_add_symbol (scanner, $2);
1377 gi_source_symbol_unref ($2);
1383 : function_macro_define
1384 | object_macro_define
1390 yyerror (GISourceScanner *scanner, const char *s)
1392 /* ignore errors while doing a macro scan as not all object macros
1393 * have valid expressions */
1394 if (!scanner->macro_scan)
1396 fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
1397 scanner->current_filename, lineno, s, linebuf, yytext);
1402 eat_hspace (FILE * f)
1409 while (c == ' ' || c == '\t');
1414 eat_line (FILE * f, int c)
1416 while (c != EOF && c != '\n')
1423 if (c == ' ' || c == '\t')
1432 read_identifier (FILE * f, int c, char **identifier)
1434 GString *id = g_string_new ("");
1435 while (g_ascii_isalnum (c) || c == '_')
1437 g_string_append_c (id, c);
1440 *identifier = g_string_free (id, FALSE);
1445 gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
1447 GError *error = NULL;
1448 char *tmp_name = NULL;
1450 fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1452 g_unlink (tmp_name);
1455 for (l = filenames; l != NULL; l = l->next)
1457 FILE *f = fopen (l->data, "r");
1460 GString *define_line;
1462 gboolean error_line = FALSE;
1463 int c = eat_hspace (f);
1469 c = eat_line (f, c);
1474 /* print current location */
1475 str = g_strescape (l->data, "");
1476 fprintf (fmacros, "# %d \"%s\"\n", line, str);
1480 c = read_identifier (f, c, &str);
1481 if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1485 c = eat_line (f, c);
1491 c = read_identifier (f, c, &str);
1492 if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1496 c = eat_line (f, c);
1500 define_line = g_string_new ("#define ");
1501 g_string_append (define_line, str);
1507 g_string_append_c (define_line, c);
1509 if (c == EOF || c == '\n')
1517 g_string_free (define_line, TRUE);
1519 c = eat_line (f, c);
1524 g_assert (c == ')');
1525 g_string_append_c (define_line, c);
1528 /* found function-like macro */
1529 fprintf (fmacros, "%s\n", define_line->str);
1531 g_string_free (define_line, TRUE);
1532 /* ignore rest of line */
1533 c = eat_line (f, c);
1537 if (c != ' ' && c != '\t')
1539 g_string_free (define_line, TRUE);
1541 c = eat_line (f, c);
1545 while (c != EOF && c != '\n')
1547 g_string_append_c (define_line, c);
1554 /* fold lines when seeing backslash new-line sequence */
1559 g_string_append_c (define_line, '\\');
1564 /* found object-like macro */
1565 fprintf (fmacros, "%s\n", define_line->str);
1567 c = eat_line (f, c);
1575 gi_source_scanner_parse_file (scanner, fmacros);
1579 gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
1581 g_return_val_if_fail (file != NULL, FALSE);
1583 const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1584 g_free, (GDestroyNotify)gi_source_symbol_unref);
1590 g_hash_table_destroy (const_table);
1599 gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
1602 yyin = fopen (filename, "r");
1604 while (yylex (scanner) != YYEOF)