[SYMBOL_LINES] Support for line numbers on Symbols
[gnome.gobject-introspection] / giscanner / scannerparser.y
index dbde322..600aee0 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <glib.h>
+#include <glib/gstdio.h>
 #include "sourcescanner.h"
 #include "scannerparser.h"
 
 extern FILE *yyin;
 extern int lineno;
+extern char linebuf[2000];
 extern char *yytext;
 
 extern int yylex (GISourceScanner *scanner);
 static void yyerror (GISourceScanner *scanner, const char *str);
  
+extern void ctype_free (GISourceType * type);
+
 static int last_enum_value = -1;
+static gboolean is_bitfield;
 static GHashTable *const_table = NULL;
 %}
 
@@ -100,7 +105,6 @@ static GHashTable *const_table = NULL;
 %type <list> enumerator_list
 %type <list> identifier_list
 %type <list> init_declarator_list
-%type <list> parameter_type_list
 %type <list> parameter_list
 %type <list> struct_declaration
 %type <list> struct_declaration_list
@@ -141,14 +145,14 @@ primary_expression
          {
                $$ = g_hash_table_lookup (const_table, $1);
                if ($$ == NULL) {
-                       $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+                       $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                } else {
                        $$ = gi_source_symbol_ref ($$);
                }
          }
        | INTEGER
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
                        $$->const_int = strtol (yytext + 2, NULL, 16);
@@ -160,11 +164,14 @@ primary_expression
          }
        | CHARACTER
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | FLOATING
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
+               $$->const_double_set = TRUE;
+               $$->const_double = 0.0;
+        sscanf (yytext, "%lf", &($$->const_double));
          }
        | strings
        | '(' expression ')'
@@ -177,9 +184,18 @@ primary_expression
 strings
        : STRING
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                yytext[strlen (yytext) - 1] = '\0';
                $$->const_string = g_strcompress (yytext + 1);
+                if (!g_utf8_validate ($$->const_string, -1, NULL))
+                  {
+#if 0
+                    g_warning ("Ignoring non-UTF-8 constant string \"%s\"", yytext + 1);
+#endif                    
+                    g_free($$->const_string);
+                    $$->const_string = NULL;
+                  }
+
          }
        | strings STRING
          {
@@ -210,31 +226,31 @@ postfix_expression
        : primary_expression
        | postfix_expression '[' expression ']'
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | postfix_expression '(' argument_expression_list ')'
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | postfix_expression '(' ')'
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | postfix_expression '.' identifier_or_typedef_name
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | postfix_expression ARROW identifier_or_typedef_name
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | postfix_expression PLUSPLUS
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | postfix_expression MINUSMINUS
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        ;
 
@@ -247,11 +263,11 @@ unary_expression
        : postfix_expression
        | PLUSPLUS unary_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | MINUSMINUS unary_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | unary_operator cast_expression
          {
@@ -272,18 +288,18 @@ unary_expression
                        $$->const_int = !gi_source_symbol_get_const_boolean ($2);
                        break;
                default:
-                       $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+                       $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                        break;
                }
          }
        | SIZEOF unary_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | SIZEOF '(' type_name ')'
          {
                ctype_free ($3);
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        ;
 
@@ -327,13 +343,13 @@ multiplicative_expression
        : cast_expression
        | multiplicative_expression '*' cast_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int * $3->const_int;
          }
        | multiplicative_expression '/' cast_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                if ($3->const_int != 0) {
                        $$->const_int = $1->const_int / $3->const_int;
@@ -341,9 +357,11 @@ multiplicative_expression
          }
        | multiplicative_expression '%' cast_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
-               $$->const_int = $1->const_int % $3->const_int;
+               if ($3->const_int != 0) {
+                       $$->const_int = $1->const_int % $3->const_int;
+               }
          }
        ;
 
@@ -351,13 +369,13 @@ additive_expression
        : multiplicative_expression
        | additive_expression '+' multiplicative_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int + $3->const_int;
          }
        | additive_expression '-' multiplicative_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int - $3->const_int;
          }
@@ -367,13 +385,19 @@ shift_expression
        : additive_expression
        | shift_expression SL additive_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int << $3->const_int;
+
+               /* assume this is a bitfield/flags declaration
+                * if a left shift operator is sued in an enum value
+                 * This mimics the glib-mkenum behavior.
+                */
+               is_bitfield = TRUE;
          }
        | shift_expression SR additive_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int >> $3->const_int;
          }
@@ -383,25 +407,25 @@ relational_expression
        : shift_expression
        | relational_expression '<' shift_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int < $3->const_int;
          }
        | relational_expression '>' shift_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int > $3->const_int;
          }
        | relational_expression LTEQ shift_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int <= $3->const_int;
          }
        | relational_expression GTEQ shift_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int >= $3->const_int;
          }
@@ -411,13 +435,13 @@ equality_expression
        : relational_expression
        | equality_expression EQ relational_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int == $3->const_int;
          }
        | equality_expression NOTEQ relational_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int != $3->const_int;
          }
@@ -427,7 +451,7 @@ and_expression
        : equality_expression
        | and_expression '&' equality_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int & $3->const_int;
          }
@@ -437,7 +461,7 @@ exclusive_or_expression
        : and_expression
        | exclusive_or_expression '^' and_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int ^ $3->const_int;
          }
@@ -447,7 +471,7 @@ inclusive_or_expression
        : exclusive_or_expression
        | inclusive_or_expression '|' exclusive_or_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int = $1->const_int | $3->const_int;
          }
@@ -457,7 +481,7 @@ logical_and_expression
        : inclusive_or_expression
        | logical_and_expression ANDAND inclusive_or_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int =
                  gi_source_symbol_get_const_boolean ($1) &&
@@ -469,7 +493,7 @@ logical_or_expression
        : logical_and_expression
        | logical_or_expression OROR logical_and_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
                $$->const_int_set = TRUE;
                $$->const_int =
                  gi_source_symbol_get_const_boolean ($1) ||
@@ -489,7 +513,7 @@ assignment_expression
        : conditional_expression
        | unary_expression assignment_operator assignment_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        ;
 
@@ -510,8 +534,9 @@ assignment_operator
 expression
        : assignment_expression
        | expression ',' assignment_expression
+       | EXTENSION expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        ;
 
@@ -560,7 +585,15 @@ declaration_specifiers
        | type_specifier declaration_specifiers
          {
                $$ = $1;
-               $$->base_type = $2;
+               /* combine basic types like unsigned int and long long */
+               if ($$->type == CTYPE_BASIC_TYPE && $2->type == CTYPE_BASIC_TYPE) {
+                       char *name = g_strdup_printf ("%s %s", $$->name, $2->name);
+                       g_free ($$->name);
+                       $$->name = name;
+                       ctype_free ($2);
+               } else {
+                       $$->base_type = $2;
+               }
          }
        | type_specifier
        | type_qualifier declaration_specifiers
@@ -681,7 +714,7 @@ struct_or_union_specifier
                $$->name = $2;
                $$->child_list = $4;
 
-               GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                if ($$->type == CTYPE_STRUCT) {
                        sym->type = CSYMBOL_TYPE_STRUCT;
                } else if ($$->type == CTYPE_UNION) {
@@ -777,14 +810,21 @@ struct_declarator_list
 struct_declarator
        : /* empty, support for anonymous structs and unions */
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | declarator
        | ':' constant_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
          }
        | declarator ':' constant_expression
+         {
+               $$ = $1;
+               if ($3->const_int_set) {
+                 $$->const_int_set = TRUE;
+                 $$->const_int = $3->const_int;
+               }
+         }
        ;
 
 enum_specifier
@@ -792,24 +832,28 @@ enum_specifier
          {
                $$ = gi_source_enum_new ($2);
                $$->child_list = $4;
+               $$->is_bitfield = is_bitfield;
                last_enum_value = -1;
          }
        | ENUM '{' enumerator_list '}'
          {
                $$ = gi_source_enum_new (NULL);
                $$->child_list = $3;
+               $$->is_bitfield = is_bitfield;
                last_enum_value = -1;
          }
        | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
          {
                $$ = gi_source_enum_new ($2);
                $$->child_list = $4;
+               $$->is_bitfield = is_bitfield;
                last_enum_value = -1;
          }
        | ENUM '{' enumerator_list ',' '}'
          {
                $$ = gi_source_enum_new (NULL);
                $$->child_list = $3;
+               $$->is_bitfield = is_bitfield;
                last_enum_value = -1;
          }
        | ENUM identifier_or_typedef_name
@@ -819,9 +863,14 @@ enum_specifier
        ;
 
 enumerator_list
-       : enumerator
+       :
          {
-               $$ = g_list_append (NULL, $1);
+               /* reset flag before the first enum value */
+               is_bitfield = FALSE;
+         }
+         enumerator
+         {
+               $$ = g_list_append (NULL, $2);
          }
        | enumerator_list ',' enumerator
          {
@@ -832,7 +881,7 @@ enumerator_list
 enumerator
        : identifier
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, lineno);
                $$->ident = $1;
                $$->const_int_set = TRUE;
                $$->const_int = ++last_enum_value;
@@ -840,7 +889,7 @@ enumerator
          }
        | identifier '=' constant_expression
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT, lineno);
                $$->ident = $1;
                $$->const_int_set = TRUE;
                $$->const_int = $3->const_int;
@@ -887,7 +936,7 @@ declarator
 direct_declarator
        : identifier
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                $$->ident = $1;
          }
        | '(' declarator ')'
@@ -897,14 +946,14 @@ direct_declarator
        | direct_declarator '[' assignment_expression ']'
          {
                $$ = $1;
-               gi_source_symbol_merge_type ($$, gi_source_array_new ());
+               gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
          }
        | direct_declarator '[' ']'
          {
                $$ = $1;
-               gi_source_symbol_merge_type ($$, gi_source_array_new ());
+               gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
          }
-       | direct_declarator '(' parameter_type_list ')'
+       | direct_declarator '(' parameter_list ')'
          {
                GISourceType *func = gi_source_function_new ();
                // ignore (void) parameter list
@@ -958,11 +1007,6 @@ type_qualifier_list
          }
        ;
 
-parameter_type_list
-       : parameter_list
-       | parameter_list ',' ELLIPSIS
-       ;
-
 parameter_list
        : parameter_declaration
          {
@@ -987,21 +1031,25 @@ parameter_declaration
          }
        | declaration_specifiers
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                $$->base_type = $1;
          }
+       | ELLIPSIS
+         {
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_ELLIPSIS, lineno);
+         }
        ;
 
 identifier_list
        : identifier
          {
-               GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                sym->ident = $1;
                $$ = g_list_append (NULL, sym);
          }
        | identifier_list ',' identifier
          {
-               GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                sym->ident = $3;
                $$ = g_list_append ($1, sym);
          }
@@ -1015,7 +1063,7 @@ type_name
 abstract_declarator
        : pointer
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                gi_source_symbol_merge_type ($$, $1);
          }
        | direct_abstract_declarator
@@ -1033,38 +1081,38 @@ direct_abstract_declarator
          }
        | '[' ']'
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
-               gi_source_symbol_merge_type ($$, gi_source_array_new ());
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
+               gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
          }
        | '[' assignment_expression ']'
          {
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
-               gi_source_symbol_merge_type ($$, gi_source_array_new ());
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
+               gi_source_symbol_merge_type ($$, gi_source_array_new ($2));
          }
        | direct_abstract_declarator '[' ']'
          {
                $$ = $1;
-               gi_source_symbol_merge_type ($$, gi_source_array_new ());
+               gi_source_symbol_merge_type ($$, gi_source_array_new (NULL));
          }
        | direct_abstract_declarator '[' assignment_expression ']'
          {
                $$ = $1;
-               gi_source_symbol_merge_type ($$, gi_source_array_new ());
+               gi_source_symbol_merge_type ($$, gi_source_array_new ($3));
          }
        | '(' ')'
          {
                GISourceType *func = gi_source_function_new ();
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                gi_source_symbol_merge_type ($$, func);
          }
-       | '(' parameter_type_list ')'
+       | '(' parameter_list ')'
          {
                GISourceType *func = gi_source_function_new ();
                // ignore (void) parameter list
                if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
                        func->child_list = $2;
                }
-               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+               $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID, lineno);
                gi_source_symbol_merge_type ($$, func);
          }
        | direct_abstract_declarator '(' ')'
@@ -1073,7 +1121,7 @@ direct_abstract_declarator
                $$ = $1;
                gi_source_symbol_merge_type ($$, func);
          }
-       | direct_abstract_declarator '(' parameter_type_list ')'
+       | direct_abstract_declarator '(' parameter_list ')'
          {
                GISourceType *func = gi_source_function_new ();
                // ignore (void) parameter list
@@ -1213,7 +1261,7 @@ function_macro_define
 object_macro_define
        : object_macro constant_expression
          {
-               if ($2->const_int_set || $2->const_string != NULL) {
+               if ($2->const_int_set || $2->const_double_set || $2->const_string != NULL) {
                        $2->ident = $1;
                        gi_source_scanner_add_symbol (scanner, $2);
                        gi_source_symbol_unref ($2);
@@ -1235,9 +1283,186 @@ yyerror (GISourceScanner *scanner, const char *s)
    * have valid expressions */
   if (!scanner->macro_scan)
     {
-      fprintf(stderr, "%s:%d: %s\n",
-             scanner->current_filename, lineno, s);
+      fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n",
+             scanner->current_filename, lineno, s, linebuf, yytext);
+    }
+}
+
+static int
+eat_hspace (FILE * f)
+{
+  int c;
+  do
+    {
+      c = fgetc (f);
     }
+  while (c == ' ' || c == '\t');
+  return c;
+}
+
+static int
+eat_line (FILE * f, int c)
+{
+  while (c != EOF && c != '\n')
+    {
+      c = fgetc (f);
+    }
+  if (c == '\n')
+    {
+      c = fgetc (f);
+      if (c == ' ' || c == '\t')
+        {
+          c = eat_hspace (f);
+        }
+    }
+  return c;
+}
+
+static int
+read_identifier (FILE * f, int c, char **identifier)
+{
+  GString *id = g_string_new ("");
+  while (g_ascii_isalnum (c) || c == '_')
+    {
+      g_string_append_c (id, c);
+      c = fgetc (f);
+    }
+  *identifier = g_string_free (id, FALSE);
+  return c;
+}
+
+void
+gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
+{
+  GError *error = NULL;
+  char *tmp_name = NULL;
+  FILE *fmacros =
+    fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
+            "w+");
+  g_unlink (tmp_name);
+
+  GList *l;
+  for (l = filenames; l != NULL; l = l->next)
+    {
+      FILE *f = fopen (l->data, "r");
+      int line = 1;
+
+      GString *define_line;
+      char *str;
+      gboolean error_line = FALSE;
+      int c = eat_hspace (f);
+      while (c != EOF)
+        {
+          if (c != '#')
+            {
+              /* ignore line */
+              c = eat_line (f, c);
+              line++;
+              continue;
+            }
+
+          /* print current location */
+          str = g_strescape (l->data, "");
+          fprintf (fmacros, "# %d \"%s\"\n", line, str);
+          g_free (str);
+
+          c = eat_hspace (f);
+          c = read_identifier (f, c, &str);
+          if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
+            {
+              g_free (str);
+              /* ignore line */
+              c = eat_line (f, c);
+              line++;
+              continue;
+            }
+          g_free (str);
+          c = eat_hspace (f);
+          c = read_identifier (f, c, &str);
+          if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
+            {
+              g_free (str);
+              /* ignore line */
+              c = eat_line (f, c);
+              line++;
+              continue;
+            }
+          define_line = g_string_new ("#define ");
+          g_string_append (define_line, str);
+          g_free (str);
+          if (c == '(')
+            {
+              while (c != ')')
+                {
+                  g_string_append_c (define_line, c);
+                  c = fgetc (f);
+                  if (c == EOF || c == '\n')
+                    {
+                      error_line = TRUE;
+                      break;
+                    }
+                }
+              if (error_line)
+                {
+                  g_string_free (define_line, TRUE);
+                  /* ignore line */
+                  c = eat_line (f, c);
+                  line++;
+                  continue;
+                }
+
+              g_assert (c == ')');
+              g_string_append_c (define_line, c);
+              c = fgetc (f);
+
+              /* found function-like macro */
+              fprintf (fmacros, "%s\n", define_line->str);
+
+              g_string_free (define_line, TRUE);
+              /* ignore rest of line */
+              c = eat_line (f, c);
+              line++;
+              continue;
+            }
+          if (c != ' ' && c != '\t')
+            {
+              g_string_free (define_line, TRUE);
+              /* ignore line */
+              c = eat_line (f, c);
+              line++;
+              continue;
+            }
+          while (c != EOF && c != '\n')
+            {
+              g_string_append_c (define_line, c);
+              c = fgetc (f);
+              if (c == '\\')
+                {
+                  c = fgetc (f);
+                  if (c == '\n')
+                    {
+                      /* fold lines when seeing backslash new-line sequence */
+                      c = fgetc (f);
+                    }
+                  else
+                    {
+                      g_string_append_c (define_line, '\\');
+                    }
+                }
+            }
+
+          /* found object-like macro */
+          fprintf (fmacros, "%s\n", define_line->str);
+
+          c = eat_line (f, c);
+          line++;
+        }
+
+      fclose (f);
+    }
+
+  rewind (fmacros);
+  gi_source_scanner_parse_file (scanner, fmacros);
 }
 
 gboolean