1 /* GObject introspection: C parser -*- indent-tabs-mode: t; tab-width: 8 -*-
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 INTL_CONST INTUL_CONST
154 %token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
155 %token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
157 %token AUTO BOOL BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
158 %token EXTENSION EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT
159 %token RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED
160 %token VOID VOLATILE WHILE
162 %token FUNCTION_MACRO OBJECT_MACRO
164 %start translation_unit
166 %type <ctype> declaration_specifiers
167 %type <ctype> enum_specifier
168 %type <ctype> pointer
169 %type <ctype> specifier_qualifier_list
170 %type <ctype> type_name
171 %type <ctype> struct_or_union
172 %type <ctype> struct_or_union_specifier
173 %type <ctype> type_specifier
174 %type <str> identifier
175 %type <str> typedef_name
176 %type <str> identifier_or_typedef_name
177 %type <symbol> abstract_declarator
178 %type <symbol> init_declarator
179 %type <symbol> declarator
180 %type <symbol> enumerator
181 %type <symbol> direct_abstract_declarator
182 %type <symbol> direct_declarator
183 %type <symbol> parameter_declaration
184 %type <symbol> struct_declarator
185 %type <list> enumerator_list
186 %type <list> identifier_list
187 %type <list> init_declarator_list
188 %type <list> parameter_list
189 %type <list> struct_declaration
190 %type <list> struct_declaration_list
191 %type <list> struct_declarator_list
192 %type <storage_class_specifier> storage_class_specifier
193 %type <type_qualifier> type_qualifier
194 %type <type_qualifier> type_qualifier_list
195 %type <function_specifier> function_specifier
196 %type <symbol> expression
197 %type <symbol> constant_expression
198 %type <symbol> conditional_expression
199 %type <symbol> logical_and_expression
200 %type <symbol> logical_or_expression
201 %type <symbol> inclusive_or_expression
202 %type <symbol> exclusive_or_expression
203 %type <symbol> multiplicative_expression
204 %type <symbol> additive_expression
205 %type <symbol> shift_expression
206 %type <symbol> relational_expression
207 %type <symbol> equality_expression
208 %type <symbol> and_expression
209 %type <symbol> cast_expression
210 %type <symbol> assignment_expression
211 %type <symbol> unary_expression
212 %type <symbol> postfix_expression
213 %type <symbol> primary_expression
214 %type <unary_operator> unary_operator
215 %type <str> function_macro
216 %type <str> object_macro
217 %type <symbol> strings
221 /* A.2.1 Expressions. */
226 $$ = g_hash_table_lookup (const_table, $1);
228 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
230 $$ = gi_source_symbol_ref ($$);
237 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
238 $$->const_int_set = TRUE;
239 if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
240 value = g_ascii_strtoull (yytext + 2, &rest, 16);
241 } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
242 value = g_ascii_strtoull (yytext + 1, &rest, 8);
244 value = g_ascii_strtoull (yytext, &rest, 10);
246 $$->const_int = value;
247 $$->const_int_is_unsigned = (rest && (rest[0] == 'U'));
251 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
252 $$->const_int_set = TRUE;
253 $$->const_int = g_utf8_get_char(yytext + 1);
257 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
258 $$->const_double_set = TRUE;
259 $$->const_double = 0.0;
260 sscanf (yytext, "%lf", &($$->const_double));
267 | EXTENSION '(' '{' block_item_list '}' ')'
269 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
273 /* concatenate adjacent string literal tokens */
277 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
278 yytext[strlen (yytext) - 1] = '\0';
279 $$->const_string = parse_c_string_literal (yytext + 1);
280 if (!g_utf8_validate ($$->const_string, -1, NULL))
283 g_warning ("Ignoring non-UTF-8 constant string \"%s\"", yytext + 1);
285 g_free($$->const_string);
286 $$->const_string = NULL;
292 char *strings, *string2;
294 yytext[strlen (yytext) - 1] = '\0';
295 string2 = parse_c_string_literal (yytext + 1);
296 strings = g_strconcat ($$->const_string, string2, NULL);
297 g_free ($$->const_string);
299 $$->const_string = strings;
306 $$ = g_strdup (yytext);
310 identifier_or_typedef_name
317 | postfix_expression '[' expression ']'
319 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
321 | postfix_expression '(' argument_expression_list ')'
323 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
325 | postfix_expression '(' ')'
327 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
329 | postfix_expression '.' identifier_or_typedef_name
331 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
333 | postfix_expression ARROW identifier_or_typedef_name
335 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
337 | postfix_expression PLUSPLUS
339 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
341 | postfix_expression MINUSMINUS
343 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
347 argument_expression_list
348 : assignment_expression
349 | argument_expression_list ',' assignment_expression
354 | PLUSPLUS unary_expression
356 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
358 | MINUSMINUS unary_expression
360 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
362 | unary_operator cast_expression
370 $$->const_int = -$2->const_int;
372 case UNARY_BITWISE_COMPLEMENT:
374 $$->const_int = ~$2->const_int;
376 case UNARY_LOGICAL_NEGATION:
378 $$->const_int = !gi_source_symbol_get_const_boolean ($2);
381 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
385 | INTL_CONST '(' unary_expression ')'
388 if ($$->const_int_set) {
389 $$->base_type = gi_source_basic_type_new ($$->const_int_is_unsigned ? "guint64" : "gint64");
392 | INTUL_CONST '(' unary_expression ')'
395 if ($$->const_int_set) {
396 $$->base_type = gi_source_basic_type_new ("guint64");
399 | SIZEOF unary_expression
401 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
403 | SIZEOF '(' type_name ')'
406 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
413 $$ = UNARY_ADDRESS_OF;
417 $$ = UNARY_POINTER_INDIRECTION;
429 $$ = UNARY_BITWISE_COMPLEMENT;
433 $$ = UNARY_LOGICAL_NEGATION;
439 | '(' type_name ')' cast_expression
442 if ($$->const_int_set || $$->const_double_set || $$->const_string != NULL) {
450 multiplicative_expression
452 | multiplicative_expression '*' cast_expression
454 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
455 $$->const_int_set = TRUE;
456 $$->const_int = $1->const_int * $3->const_int;
458 | multiplicative_expression '/' cast_expression
460 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
461 $$->const_int_set = TRUE;
462 if ($3->const_int != 0) {
463 $$->const_int = $1->const_int / $3->const_int;
466 | multiplicative_expression '%' cast_expression
468 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
469 $$->const_int_set = TRUE;
470 if ($3->const_int != 0) {
471 $$->const_int = $1->const_int % $3->const_int;
477 : multiplicative_expression
478 | additive_expression '+' multiplicative_expression
480 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
481 $$->const_int_set = TRUE;
482 $$->const_int = $1->const_int + $3->const_int;
484 | additive_expression '-' multiplicative_expression
486 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
487 $$->const_int_set = TRUE;
488 $$->const_int = $1->const_int - $3->const_int;
493 : additive_expression
494 | shift_expression SL additive_expression
496 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
497 $$->const_int_set = TRUE;
498 $$->const_int = $1->const_int << $3->const_int;
500 /* assume this is a bitfield/flags declaration
501 * if a left shift operator is sued in an enum value
502 * This mimics the glib-mkenum behavior.
506 | shift_expression SR additive_expression
508 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
509 $$->const_int_set = TRUE;
510 $$->const_int = $1->const_int >> $3->const_int;
514 relational_expression
516 | relational_expression '<' shift_expression
518 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
519 $$->const_int_set = TRUE;
520 $$->const_int = $1->const_int < $3->const_int;
522 | relational_expression '>' shift_expression
524 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
525 $$->const_int_set = TRUE;
526 $$->const_int = $1->const_int > $3->const_int;
528 | relational_expression LTEQ shift_expression
530 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
531 $$->const_int_set = TRUE;
532 $$->const_int = $1->const_int <= $3->const_int;
534 | relational_expression GTEQ shift_expression
536 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
537 $$->const_int_set = TRUE;
538 $$->const_int = $1->const_int >= $3->const_int;
543 : relational_expression
544 | equality_expression EQ relational_expression
546 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
547 $$->const_int_set = TRUE;
548 $$->const_int = $1->const_int == $3->const_int;
550 | equality_expression NOTEQ relational_expression
552 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
553 $$->const_int_set = TRUE;
554 $$->const_int = $1->const_int != $3->const_int;
559 : equality_expression
560 | and_expression '&' equality_expression
562 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
563 $$->const_int_set = TRUE;
564 $$->const_int = $1->const_int & $3->const_int;
568 exclusive_or_expression
570 | exclusive_or_expression '^' and_expression
572 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
573 $$->const_int_set = TRUE;
574 $$->const_int = $1->const_int ^ $3->const_int;
578 inclusive_or_expression
579 : exclusive_or_expression
580 | inclusive_or_expression '|' exclusive_or_expression
582 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
583 $$->const_int_set = TRUE;
584 $$->const_int = $1->const_int | $3->const_int;
588 logical_and_expression
589 : inclusive_or_expression
590 | logical_and_expression ANDAND inclusive_or_expression
592 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
593 $$->const_int_set = TRUE;
595 gi_source_symbol_get_const_boolean ($1) &&
596 gi_source_symbol_get_const_boolean ($3);
600 logical_or_expression
601 : logical_and_expression
602 | logical_or_expression OROR logical_and_expression
604 $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, scanner->current_filename, lineno);
605 $$->const_int_set = TRUE;
607 gi_source_symbol_get_const_boolean ($1) ||
608 gi_source_symbol_get_const_boolean ($3);
612 conditional_expression
613 : logical_or_expression
614 | logical_or_expression '?' expression ':' expression
616 $$ = gi_source_symbol_get_const_boolean ($1) ? $3 : $5;
620 assignment_expression
621 : conditional_expression
622 | unary_expression assignment_operator assignment_expression
624 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
643 : assignment_expression
644 | expression ',' assignment_expression
645 | EXTENSION expression
647 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
652 : conditional_expression
655 /* A.2.2 Declarations. */
658 : declaration_specifiers init_declarator_list ';'
661 for (l = $2; l != NULL; l = l->next) {
662 GISourceSymbol *sym = l->data;
663 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
664 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
665 sym->type = CSYMBOL_TYPE_TYPEDEF;
666 } else if (sym->base_type->type == CTYPE_FUNCTION) {
667 sym->type = CSYMBOL_TYPE_FUNCTION;
669 sym->type = CSYMBOL_TYPE_OBJECT;
671 gi_source_scanner_add_symbol (scanner, sym);
672 gi_source_symbol_unref (sym);
676 | declaration_specifiers ';'
682 declaration_specifiers
683 : storage_class_specifier declaration_specifiers
686 $$->storage_class_specifier |= $1;
688 | storage_class_specifier
690 $$ = gi_source_type_new (CTYPE_INVALID);
691 $$->storage_class_specifier |= $1;
693 | type_specifier declaration_specifiers
696 /* combine basic types like unsigned int and long long */
697 if ($$->type == CTYPE_BASIC_TYPE && $2->type == CTYPE_BASIC_TYPE) {
698 char *name = g_strdup_printf ("%s %s", $$->name, $2->name);
707 | type_qualifier declaration_specifiers
710 $$->type_qualifier |= $1;
714 $$ = gi_source_type_new (CTYPE_INVALID);
715 $$->type_qualifier |= $1;
717 | function_specifier declaration_specifiers
720 $$->function_specifier |= $1;
724 $$ = gi_source_type_new (CTYPE_INVALID);
725 $$->function_specifier |= $1;
732 $$ = g_list_append (NULL, $1);
734 | init_declarator_list ',' init_declarator
736 $$ = g_list_append ($1, $3);
742 | declarator '=' initializer
745 storage_class_specifier
748 $$ = STORAGE_CLASS_TYPEDEF;
752 $$ = STORAGE_CLASS_EXTERN;
756 $$ = STORAGE_CLASS_STATIC;
760 $$ = STORAGE_CLASS_AUTO;
764 $$ = STORAGE_CLASS_REGISTER;
771 $$ = gi_source_type_new (CTYPE_VOID);
775 $$ = gi_source_basic_type_new ("char");
779 $$ = gi_source_basic_type_new ("short");
783 $$ = gi_source_basic_type_new ("int");
787 $$ = gi_source_basic_type_new ("long");
791 $$ = gi_source_basic_type_new ("float");
795 $$ = gi_source_basic_type_new ("double");
799 $$ = gi_source_basic_type_new ("signed");
803 $$ = gi_source_basic_type_new ("unsigned");
807 $$ = gi_source_basic_type_new ("bool");
809 | struct_or_union_specifier
813 $$ = gi_source_typedef_new ($1);
818 struct_or_union_specifier
819 : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
826 sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
827 if ($$->type == CTYPE_STRUCT) {
828 sym->type = CSYMBOL_TYPE_STRUCT;
829 } else if ($$->type == CTYPE_UNION) {
830 sym->type = CSYMBOL_TYPE_UNION;
832 g_assert_not_reached ();
834 sym->ident = g_strdup ($$->name);
835 sym->base_type = gi_source_type_copy ($$);
836 gi_source_scanner_add_symbol (scanner, sym);
837 gi_source_symbol_unref (sym);
839 | struct_or_union '{' struct_declaration_list '}'
844 | struct_or_union identifier_or_typedef_name
854 scanner->private = FALSE;
855 $$ = gi_source_struct_new (NULL);
859 scanner->private = FALSE;
860 $$ = gi_source_union_new (NULL);
864 struct_declaration_list
866 | struct_declaration_list struct_declaration
868 $$ = g_list_concat ($1, $2);
873 : specifier_qualifier_list struct_declarator_list ';'
877 for (l = $2; l != NULL; l = l->next)
879 GISourceSymbol *sym = l->data;
880 if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF)
881 sym->type = CSYMBOL_TYPE_TYPEDEF;
883 sym->type = CSYMBOL_TYPE_MEMBER;
884 gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
885 sym->private = scanner->private;
886 $$ = g_list_append ($$, sym);
892 specifier_qualifier_list
893 : type_specifier specifier_qualifier_list
899 | type_qualifier specifier_qualifier_list
902 $$->type_qualifier |= $1;
906 $$ = gi_source_type_new (CTYPE_INVALID);
907 $$->type_qualifier |= $1;
911 struct_declarator_list
914 $$ = g_list_append (NULL, $1);
916 | struct_declarator_list ',' struct_declarator
918 $$ = g_list_append ($1, $3);
923 : /* empty, support for anonymous structs and unions */
925 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
928 | ':' constant_expression
930 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
932 | declarator ':' constant_expression
935 if ($3->const_int_set) {
936 $$->const_int_set = TRUE;
937 $$->const_int = $3->const_int;
943 : enum_keyword identifier_or_typedef_name '{' enumerator_list '}'
945 $$ = gi_source_enum_new ($2);
947 $$->is_bitfield = is_bitfield || scanner->flags;
948 last_enum_value = -1;
950 | enum_keyword '{' enumerator_list '}'
952 $$ = gi_source_enum_new (NULL);
954 $$->is_bitfield = is_bitfield || scanner->flags;
955 last_enum_value = -1;
957 | enum_keyword identifier_or_typedef_name '{' enumerator_list ',' '}'
959 $$ = gi_source_enum_new ($2);
961 $$->is_bitfield = is_bitfield || scanner->flags;
962 last_enum_value = -1;
964 | enum_keyword '{' enumerator_list ',' '}'
966 $$ = gi_source_enum_new (NULL);
968 $$->is_bitfield = is_bitfield || scanner->flags;
969 last_enum_value = -1;
971 | enum_keyword identifier_or_typedef_name
973 $$ = gi_source_enum_new ($2);
980 scanner->flags = FALSE;
981 scanner->private = FALSE;
988 /* reset flag before the first enum value */
993 $2->private = scanner->private;
994 $$ = g_list_append (NULL, $2);
996 | enumerator_list ',' enumerator
998 $3->private = scanner->private;
999 $$ = g_list_append ($1, $3);
1006 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_filename, lineno);
1008 $$->const_int_set = TRUE;
1009 $$->const_int = ++last_enum_value;
1010 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
1012 | identifier '=' constant_expression
1014 $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, scanner->current_filename, lineno);
1016 $$->const_int_set = TRUE;
1017 $$->const_int = $3->const_int;
1018 last_enum_value = $$->const_int;
1019 g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
1026 $$ = TYPE_QUALIFIER_CONST;
1030 $$ = TYPE_QUALIFIER_RESTRICT;
1034 $$ = TYPE_QUALIFIER_EXTENSION;
1038 $$ = TYPE_QUALIFIER_VOLATILE;
1045 $$ = FUNCTION_INLINE;
1050 : pointer direct_declarator
1053 gi_source_symbol_merge_type ($$, $1);
1061 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1064 | '(' declarator ')'
1068 | direct_declarator '[' assignment_expression ']'
1071 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1073 | direct_declarator '[' ']'
1076 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1078 | direct_declarator '(' parameter_list ')'
1080 GISourceType *func = gi_source_function_new ();
1081 // ignore (void) parameter list
1082 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1083 func->child_list = $3;
1086 gi_source_symbol_merge_type ($$, func);
1088 | direct_declarator '(' identifier_list ')'
1090 GISourceType *func = gi_source_function_new ();
1091 func->child_list = $3;
1093 gi_source_symbol_merge_type ($$, func);
1095 | direct_declarator '(' ')'
1097 GISourceType *func = gi_source_function_new ();
1099 gi_source_symbol_merge_type ($$, func);
1104 : '*' type_qualifier_list
1106 $$ = gi_source_pointer_new (NULL);
1107 $$->type_qualifier = $2;
1111 $$ = gi_source_pointer_new (NULL);
1113 | '*' type_qualifier_list pointer
1115 GISourceType **base = &($3->base_type);
1117 while (*base != NULL) {
1118 base = &((*base)->base_type);
1120 *base = gi_source_pointer_new (NULL);
1121 (*base)->type_qualifier = $2;
1126 GISourceType **base = &($2->base_type);
1128 while (*base != NULL) {
1129 base = &((*base)->base_type);
1131 *base = gi_source_pointer_new (NULL);
1138 | type_qualifier_list type_qualifier
1145 : parameter_declaration
1147 $$ = g_list_append (NULL, $1);
1149 | parameter_list ',' parameter_declaration
1151 $$ = g_list_append ($1, $3);
1155 parameter_declaration
1156 : declaration_specifiers declarator
1159 gi_source_symbol_merge_type ($$, $1);
1161 | declaration_specifiers abstract_declarator
1164 gi_source_symbol_merge_type ($$, $1);
1166 | declaration_specifiers
1168 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1173 $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS, scanner->current_filename, lineno);
1180 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1182 $$ = g_list_append (NULL, sym);
1184 | identifier_list ',' identifier
1186 GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1188 $$ = g_list_append ($1, sym);
1193 : specifier_qualifier_list
1194 | specifier_qualifier_list abstract_declarator
1200 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1201 gi_source_symbol_merge_type ($$, $1);
1203 | direct_abstract_declarator
1204 | pointer direct_abstract_declarator
1207 gi_source_symbol_merge_type ($$, $1);
1211 direct_abstract_declarator
1212 : '(' abstract_declarator ')'
1218 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1219 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1221 | '[' assignment_expression ']'
1223 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1224 gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
1226 | direct_abstract_declarator '[' ']'
1229 gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
1231 | direct_abstract_declarator '[' assignment_expression ']'
1234 gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
1238 GISourceType *func = gi_source_function_new ();
1239 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1240 gi_source_symbol_merge_type ($$, func);
1242 | '(' parameter_list ')'
1244 GISourceType *func = gi_source_function_new ();
1245 // ignore (void) parameter list
1246 if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
1247 func->child_list = $2;
1249 $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, scanner->current_filename, lineno);
1250 gi_source_symbol_merge_type ($$, func);
1252 | direct_abstract_declarator '(' ')'
1254 GISourceType *func = gi_source_function_new ();
1256 gi_source_symbol_merge_type ($$, func);
1258 | direct_abstract_declarator '(' parameter_list ')'
1260 GISourceType *func = gi_source_function_new ();
1261 // ignore (void) parameter list
1262 if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
1263 func->child_list = $3;
1266 gi_source_symbol_merge_type ($$, func);
1273 $$ = g_strdup (yytext);
1278 : assignment_expression
1279 | '{' initializer_list '}'
1280 | '{' initializer_list ',' '}'
1285 | initializer_list ',' initializer
1288 /* A.2.3 Statements. */
1292 | compound_statement
1293 | expression_statement
1294 | selection_statement
1295 | iteration_statement
1300 : identifier_or_typedef_name ':' statement
1301 | CASE constant_expression ':' statement
1302 | DEFAULT ':' statement
1307 | '{' block_item_list '}'
1312 | block_item_list block_item
1320 expression_statement
1326 : IF '(' expression ')' statement
1327 | IF '(' expression ')' statement ELSE statement
1328 | SWITCH '(' expression ')' statement
1332 : WHILE '(' expression ')' statement
1333 | DO statement WHILE '(' expression ')' ';'
1334 | FOR '(' ';' ';' ')' statement
1335 | FOR '(' expression ';' ';' ')' statement
1336 | FOR '(' ';' expression ';' ')' statement
1337 | FOR '(' expression ';' expression ';' ')' statement
1338 | FOR '(' ';' ';' expression ')' statement
1339 | FOR '(' expression ';' ';' expression ')' statement
1340 | FOR '(' ';' expression ';' expression ')' statement
1341 | FOR '(' expression ';' expression ';' expression ')' statement
1345 : GOTO identifier_or_typedef_name ';'
1349 | RETURN expression ';'
1352 /* A.2.4 External definitions. */
1355 : external_declaration
1356 | translation_unit external_declaration
1359 external_declaration
1360 : function_definition
1366 : declaration_specifiers declarator declaration_list compound_statement
1367 | declaration_specifiers declarator compound_statement
1372 | declaration_list declaration
1380 $$ = g_strdup (yytext + strlen ("#define "));
1387 $$ = g_strdup (yytext + strlen ("#define "));
1391 function_macro_define
1392 : function_macro '(' identifier_list ')'
1396 : object_macro constant_expression
1398 if ($2->const_int_set || $2->const_double_set || $2->const_string != NULL) {
1400 gi_source_scanner_add_symbol (scanner, $2);
1401 gi_source_symbol_unref ($2);
1407 : function_macro_define
1408 | object_macro_define
1414 yyerror (GISourceScanner *scanner, const char *s)
1416 /* ignore errors while doing a macro scan as not all object macros
1417 * have valid expressions */
1418 if (!scanner->macro_scan)
1420 fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
1421 scanner->current_filename, lineno, s, linebuf, yytext);
1426 eat_hspace (FILE * f)
1433 while (c == ' ' || c == '\t');
1438 eat_line (FILE * f, int c)
1440 while (c != EOF && c != '\n')
1447 if (c == ' ' || c == '\t')
1456 read_identifier (FILE * f, int c, char **identifier)
1458 GString *id = g_string_new ("");
1459 while (g_ascii_isalnum (c) || c == '_')
1461 g_string_append_c (id, c);
1464 *identifier = g_string_free (id, FALSE);
1469 gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
1471 GError *error = NULL;
1472 char *tmp_name = NULL;
1474 fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1477 g_unlink (tmp_name);
1479 for (l = filenames; l != NULL; l = l->next)
1481 FILE *f = fopen (l->data, "r");
1484 GString *define_line;
1486 gboolean error_line = FALSE;
1487 int c = eat_hspace (f);
1493 c = eat_line (f, c);
1498 /* print current location */
1499 str = g_strescape (l->data, "");
1500 fprintf (fmacros, "# %d \"%s\"\n", line, str);
1504 c = read_identifier (f, c, &str);
1505 if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1509 c = eat_line (f, c);
1515 c = read_identifier (f, c, &str);
1516 if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1520 c = eat_line (f, c);
1524 define_line = g_string_new ("#define ");
1525 g_string_append (define_line, str);
1531 g_string_append_c (define_line, c);
1533 if (c == EOF || c == '\n')
1541 g_string_free (define_line, TRUE);
1543 c = eat_line (f, c);
1548 g_assert (c == ')');
1549 g_string_append_c (define_line, c);
1552 /* found function-like macro */
1553 fprintf (fmacros, "%s\n", define_line->str);
1555 g_string_free (define_line, TRUE);
1556 /* ignore rest of line */
1557 c = eat_line (f, c);
1561 if (c != ' ' && c != '\t')
1563 g_string_free (define_line, TRUE);
1565 c = eat_line (f, c);
1569 while (c != EOF && c != '\n')
1571 g_string_append_c (define_line, c);
1578 /* fold lines when seeing backslash new-line sequence */
1583 g_string_append_c (define_line, '\\');
1588 /* found object-like macro */
1589 fprintf (fmacros, "%s\n", define_line->str);
1591 c = eat_line (f, c);
1599 gi_source_scanner_parse_file (scanner, fmacros);
1603 gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
1605 g_return_val_if_fail (file != NULL, FALSE);
1607 const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1608 g_free, (GDestroyNotify)gi_source_symbol_unref);
1614 g_hash_table_destroy (const_table);
1623 gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
1626 yyin = fopen (filename, "r");
1628 while (yylex (scanner) != YYEOF)