Import gen-introspect to generate introspection information by parsing C
authorJuerg Billeter <j@bitron.ch>
Fri, 30 Nov 2007 22:46:43 +0000 (22:46 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Fri, 30 Nov 2007 22:46:43 +0000 (22:46 +0000)
2007-11-30  Juerg Billeter  <j@bitron.ch>

* configure.ac:
* src/Makefile.am:
* src/clexer.l:
* src/cparser.y:
* src/gen-introspect.c: (g_idl_node_cmp), (g_igenerator_new),
(g_igenerator_write_inline), (g_igenerator_write),
(g_igenerator_write_indent), (g_igenerator_write_unindent),
(field_generate), (value_generate), (constant_generate),
(property_generate), (function_generate), (vfunc_generate),
(signal_generate), (interface_generate), (struct_generate),
(union_generate), (boxed_generate), (enum_generate),
(node_generate), (module_generate), (get_type_from_type_id),
(str_replace), (g_igenerator_process_properties),
(g_igenerator_process_signals), (g_igenerator_process_types),
(get_type_from_ctype), (g_igenerator_process_function_symbol),
(g_igenerator_process_unregistered_struct_typedef),
(g_igenerator_process_struct_typedef),
(g_igenerator_process_union_typedef),
(g_igenerator_process_enum_typedef),
(g_igenerator_process_function_typedef),
(g_igenerator_process_constant), (g_igenerator_process_symbols),
(g_igenerator_add_symbol), (g_igenerator_is_typedef),
(g_igenerator_generate), (main), (csymbol_new),
(csymbol_get_const_boolean), (ctype_new), (ctype_copy),
(cbasic_type_new), (ctypedef_new), (cstruct_new), (cunion_new),
(cenum_new), (cpointer_new), (carray_new), (cfunction_new),
(eat_hspace), (eat_line), (read_identifier),
(g_igenerator_parse_macros):
* src/gen-introspect.h:

Import gen-introspect to generate introspection information by
parsing C headers.

svn path=/trunk/; revision=63

ChangeLog
configure.ac
src/Makefile.am
src/clexer.l [new file with mode: 0644]
src/cparser.y [new file with mode: 0644]
src/gen-introspect.c [new file with mode: 0644]
src/gen-introspect.h [new file with mode: 0644]

index 16cbcf9200a318ce1c3d50470b77452c4115abba..0c5ae5e52564caa477c1d1c6a9b16cd8aac1a9e5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2007-11-30  Jürg Billeter  <j@bitron.ch>
+
+       * configure.ac:
+       * src/Makefile.am:
+       * src/clexer.l:
+       * src/cparser.y:
+       * src/gen-introspect.c: (g_idl_node_cmp), (g_igenerator_new),
+       (g_igenerator_write_inline), (g_igenerator_write),
+       (g_igenerator_write_indent), (g_igenerator_write_unindent),
+       (field_generate), (value_generate), (constant_generate),
+       (property_generate), (function_generate), (vfunc_generate),
+       (signal_generate), (interface_generate), (struct_generate),
+       (union_generate), (boxed_generate), (enum_generate),
+       (node_generate), (module_generate), (get_type_from_type_id),
+       (str_replace), (g_igenerator_process_properties),
+       (g_igenerator_process_signals), (g_igenerator_process_types),
+       (get_type_from_ctype), (g_igenerator_process_function_symbol),
+       (g_igenerator_process_unregistered_struct_typedef),
+       (g_igenerator_process_struct_typedef),
+       (g_igenerator_process_union_typedef),
+       (g_igenerator_process_enum_typedef),
+       (g_igenerator_process_function_typedef),
+       (g_igenerator_process_constant), (g_igenerator_process_symbols),
+       (g_igenerator_add_symbol), (g_igenerator_is_typedef),
+       (g_igenerator_generate), (main), (csymbol_new),
+       (csymbol_get_const_boolean), (ctype_new), (ctype_copy),
+       (cbasic_type_new), (ctypedef_new), (cstruct_new), (cunion_new),
+       (cenum_new), (cpointer_new), (carray_new), (cfunction_new),
+       (eat_hspace), (eat_line), (read_identifier),
+       (g_igenerator_parse_macros):
+       * src/gen-introspect.h:
+
+       Import gen-introspect to generate introspection information by
+       parsing C headers.
+
 2007-11-30  Jürg Billeter  <j@bitron.ch>
 
        * src/gidlnode.c: (g_idl_node_new): support creating callback nodes
index 6ab03de2fccfa56fc7ad521b90c500ff67afd0ac..91e0ed6ba0f363558274510066fb31631aee3445 100644 (file)
@@ -10,12 +10,23 @@ AC_CONFIG_HEADER([config.h])
 
 # Checks for programs.
 AC_PROG_CC
+AM_PROG_CC_C_O
 AC_PROG_LIBTOOL
 
+AC_PROG_LEX
+if test "$LEX" = :; then
+       AC_MSG_ERROR([flex not found but required])
+fi
+
+AC_CHECK_PROGS(YACC, 'bison -y' byacc yacc, :)
+if test "$YACC" = :; then
+       AC_MSG_ERROR([bison not found but required])
+fi
+
 # Checks for libraries.
 AC_CHECK_LIB([dl], [dlopen])
 
-PKG_CHECK_MODULES(GIREPO, glib-2.0 gobject-2.0 gmodule-2.0 libffi)
+PKG_CHECK_MODULES(GIREPO, glib-2.0 gobject-2.0 gmodule-2.0 gthread-2.0 libffi)
 
 
 # Checks for header files.
index 97c0ccdcc560da7ad22123eca65e9b4b4ed68e4e..02ea1a2bb99783df6e1965e99014d17c1930c222 100644 (file)
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
 lib_LTLIBRARIES = libgirepository.la
-bin_PROGRAMS = g-idl-compiler g-idl-generate
+bin_PROGRAMS = g-idl-compiler g-idl-generate gen-introspect
 
 
 libgirepository_la_SOURCES =                   \
@@ -28,3 +28,17 @@ g_idl_generate_LDADD = -ldl $(GIREPO_LIBS) libgirepository.la
 
 girepodir = $(includedir)/glib-2.0/gobject-introspection
 girepo_HEADERS = girepository.h
+
+BUILT_SOURCES = cparser.h
+AM_YFLAGS = -d
+
+gen_introspect_SOURCES =                       \
+       clexer.l                                \
+       cparser.y                               \
+       gidlmodule.c                            \
+       gidlnode.c                              \
+       gen-introspect.c                        \
+       gen-introspect.h
+gen_introspect_CFLAGS = $(GIREPO_CFLAGS)
+gen_introspect_LDADD = -ldl $(GIREPO_LIBS)
+
diff --git a/src/clexer.l b/src/clexer.l
new file mode 100644 (file)
index 0000000..b0c9cd6
--- /dev/null
@@ -0,0 +1,251 @@
+/* GObject introspection: C lexer
+ *
+ * Copyright (c) 1997 Sandro Sigala  <ssigala@globalnet.it>
+ * Copyright (c) 2007 Jürg Billeter  <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <ctype.h>
+#include <stdio.h>
+
+#include "gen-introspect.h"
+#include "cparser.h"
+
+int lineno;
+
+static int yywrap (void);
+static void skip_comment (void);
+static void process_directive (void);
+static int check_identifier (const char *);
+%}
+
+intsuffix                              ([uU][lL]?)|([lL][uU]?)
+fracconst                              ([0-9]*\.[0-9]+)|([0-9]+\.)
+exppart                                        [eE][-+]?[0-9]+
+floatsuffix                            [fFlL]
+chartext                               ([^'])|(\\.)
+stringtext                             ([^"])|(\\.)
+
+%%
+
+"\n"                                   { ++lineno; }
+[\t\f\v\r ]+                           { /* Ignore whitespace. */ }
+
+"/*"                                   { skip_comment(); }
+"//".*                                 { }
+
+"#define "[a-zA-Z_][a-zA-Z_0-9]*"("    { yyless (yyleng - 1); return FUNCTION_MACRO; }
+"#define "[a-zA-Z_][a-zA-Z_0-9]*       { return OBJECT_MACRO; }
+
+"#"                                    { process_directive(); }
+
+"{"                                    { return '{'; }
+"<%"                                   { return '{'; }
+"}"                                    { return '}'; }
+"%>"                                   { return '}'; }
+"["                                    { return '['; }
+"<:"                                   { return '['; }
+"]"                                    { return ']'; }
+":>"                                   { return ']'; }
+"("                                    { return '('; }
+")"                                    { return ')'; }
+";"                                    { return ';'; }
+":"                                    { return ':'; }
+"..."                                  { return ELLIPSIS; }
+"?"                                    { return '?'; }
+"."                                    { return '.'; }
+"+"                                    { return '+'; }
+"-"                                    { return '-'; }
+"*"                                    { return '*'; }
+"/"                                    { return '/'; }
+"%"                                    { return '%'; }
+"^"                                    { return '^'; }
+"&"                                    { return '&'; }
+"|"                                    { return '|'; }
+"~"                                    { return '~'; }
+"!"                                    { return '!'; }
+"="                                    { return '='; }
+"<"                                    { return '<'; }
+">"                                    { return '>'; }
+"+="                                   { return ADDEQ; }
+"-="                                   { return SUBEQ; }
+"*="                                   { return MULEQ; }
+"/="                                   { return DIVEQ; }
+"%="                                   { return MODEQ; }
+"^="                                   { return XOREQ; }
+"&="                                   { return ANDEQ; }
+"|="                                   { return OREQ; }
+"<<"                                   { return SL; }
+">>"                                   { return SR; }
+"<<="                                  { return SLEQ; }
+">>="                                  { return SREQ; }
+"=="                                   { return EQ; }
+"!="                                   { return NOTEQ; }
+"<="                                   { return LTEQ; }
+">="                                   { return GTEQ; }
+"&&"                                   { return ANDAND; }
+"||"                                   { return OROR; }
+"++"                                   { return PLUSPLUS; }
+"--"                                   { return MINUSMINUS; }
+","                                    { return ','; }
+"->"                                   { return ARROW; }
+
+[a-zA-Z_][a-zA-Z_0-9]*                 { if (the_igenerator->macro_scan) return IDENTIFIER; else REJECT; }
+
+"auto"                                 { return AUTO; }
+"break"                                        { return BREAK; }
+"case"                                 { return CASE; }
+"char"                                 { return CHAR; }
+"const"                                        { return CONST; }
+"continue"                             { return CONTINUE; }
+"default"                              { return DEFAULT; }
+"do"                                   { return DO; }
+"double"                               { return DOUBLE; }
+"else"                                 { return ELSE; }
+"enum"                                 { return ENUM; }
+"extern"                               { return EXTERN; }
+"float"                                        { return FLOAT; }
+"for"                                  { return FOR; }
+"goto"                                 { return GOTO; }
+"if"                                   { return IF; }
+"inline"                               { return INLINE; }
+"int"                                  { return INT; }
+"long"                                 { return LONG; }
+"register"                             { return REGISTER; }
+"restrict"                             { return RESTRICT; }
+"return"                               { return RETURN; }
+"short"                                        { return SHORT; }
+"signed"                               { return SIGNED; }
+"sizeof"                               { return SIZEOF; }
+"static"                               { return STATIC; }
+"struct"                               { return STRUCT; }
+"switch"                               { return SWITCH; }
+"typedef"                              { return TYPEDEF; }
+"union"                                        { return UNION; }
+"unsigned"                             { return UNSIGNED; }
+"void"                                 { return VOID; }
+"volatile"                             { return VOLATILE; }
+"while"                                        { return WHILE; }
+
+[a-zA-Z_][a-zA-Z_0-9]*                 { return check_identifier(yytext); }
+
+"0"[xX][0-9a-fA-F]+{intsuffix}?                { return INTEGER; }
+"0"[0-7]+{intsuffix}?                  { return INTEGER; }
+[0-9]+{intsuffix}?                     { return INTEGER; }
+
+{fracconst}{exppart}?{floatsuffix}?    { return FLOATING; }
+[0-9]+{exppart}{floatsuffix}?          { return FLOATING; }
+
+"'"{chartext}*"'"                      { return CHARACTER; }
+"L'"{chartext}*"'"                     { return CHARACTER; }
+
+"\""{stringtext}*"\""                  { return STRING; }
+"L\""{stringtext}*"\""                 { return STRING; }
+
+.                                      { fprintf(stderr, "%s:%d: unexpected character `%c'\n", the_igenerator->current_filename, lineno, yytext[0]); }
+
+%%
+
+static int yywrap (void)
+{
+       return 1;
+}
+
+static void skip_comment (void)
+{
+       int c1, c2;
+
+       c1 = input();
+       c2 = input();
+
+       while (c2 != EOF && !(c1 == '*' && c2 == '/')) {
+               if (c1 == '\n')
+                       ++lineno;
+               c1 = c2;
+               c2 = input();
+       }
+}
+
+static int check_identifier (const char *s)
+{
+       /*
+        * This function checks if `s' is a type name or an
+        * identifier.
+        */
+
+       if (g_igenerator_is_typedef (the_igenerator, s)) {
+               return TYPEDEF_NAME;
+       } else if (strcmp (s, "__builtin_va_list") == 0) {
+               return TYPEDEF_NAME;
+       }
+
+       return IDENTIFIER;
+}
+
+static void process_directive (void)
+{
+       /* extract current filename from #line directives */
+       GString *filename_builder;
+       gboolean in_string, found_filename;
+
+       lineno = 0;
+       found_filename = FALSE;
+       in_string = FALSE;
+       filename_builder = g_string_new ("");
+
+       int c = input ();
+       while (c != EOF && c != '\n') {
+               if (!in_string) {
+                       if (c == '\"') {
+                               in_string = TRUE;
+                               found_filename = TRUE;
+                       } else if (c >= '0' && c <= '9') {
+                               if (!found_filename) {
+                                       lineno = lineno * 10 + (c - '0');
+                               }
+                       }
+               } else {
+                       if (c == '\"') {
+                               in_string = FALSE;
+                       } else if (c == '\\') {
+                               g_string_append_c (filename_builder, c);
+                               c = input ();
+                               g_string_append_c (filename_builder, c);
+                       } else {
+                               g_string_append_c (filename_builder, c);
+                       }
+               }
+               c = input ();
+       }
+
+       if (filename_builder->len > 0) {
+               char *filename = g_strcompress (filename_builder->str);
+               g_free (the_igenerator->current_filename);
+               the_igenerator->current_filename = filename;
+       }
+
+       g_string_free (filename_builder, TRUE);
+}
+
diff --git a/src/cparser.y b/src/cparser.y
new file mode 100644 (file)
index 0000000..c29ca8f
--- /dev/null
@@ -0,0 +1,1236 @@
+/* GObject introspection: C parser
+ *
+ * Copyright (c) 1997 Sandro Sigala  <ssigala@globalnet.it>
+ * Copyright (c) 2007 Jürg Billeter  <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gen-introspect.h"
+
+extern FILE *yyin;
+extern int lineno;
+extern char *yytext;
+
+extern int yylex (void);
+static void yyerror(const char *s);
+
+static int last_enum_value = -1;
+static GHashTable *const_table = NULL;
+
+/* use specified type as base type of symbol */
+static void csymbol_merge_type (CSymbol *symbol, CType *type)
+{
+       CType **foundation_type = &(symbol->base_type);
+       while (*foundation_type != NULL) {
+               foundation_type = &((*foundation_type)->base_type);
+       }
+       *foundation_type = ctype_copy (type);
+}
+%}
+
+%error-verbose
+%union {
+       char *str;
+       GList *list;
+       CSymbol *symbol;
+       CType *ctype;
+       StorageClassSpecifier storage_class_specifier;
+       TypeQualifier type_qualifier;
+       FunctionSpecifier function_specifier;
+       UnaryOperator unary_operator;
+}
+
+%token <str> IDENTIFIER "identifier"
+%token <str> TYPEDEF_NAME "typedef-name"
+
+%token INTEGER FLOATING CHARACTER STRING
+
+%token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
+%token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
+
+%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
+%token EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT RETURN SHORT
+%token SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE
+%token WHILE
+
+%token FUNCTION_MACRO OBJECT_MACRO
+
+%start translation_unit
+
+%type <ctype> declaration_specifiers
+%type <ctype> enum_specifier
+%type <ctype> pointer
+%type <ctype> specifier_qualifier_list
+%type <ctype> struct_or_union
+%type <ctype> struct_or_union_specifier
+%type <ctype> type_specifier
+%type <str> identifier
+%type <str> typedef_name
+%type <str> identifier_or_typedef_name
+%type <symbol> abstract_declarator
+%type <symbol> init_declarator
+%type <symbol> declarator
+%type <symbol> enumerator
+%type <symbol> direct_abstract_declarator
+%type <symbol> direct_declarator
+%type <symbol> parameter_declaration
+%type <symbol> struct_declarator
+%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
+%type <list> struct_declarator_list
+%type <storage_class_specifier> storage_class_specifier
+%type <type_qualifier> type_qualifier
+%type <type_qualifier> type_qualifier_list
+%type <function_specifier> function_specifier
+%type <symbol> expression
+%type <symbol> constant_expression
+%type <symbol> conditional_expression
+%type <symbol> logical_and_expression
+%type <symbol> logical_or_expression
+%type <symbol> inclusive_or_expression
+%type <symbol> exclusive_or_expression
+%type <symbol> multiplicative_expression
+%type <symbol> additive_expression
+%type <symbol> shift_expression
+%type <symbol> relational_expression
+%type <symbol> equality_expression
+%type <symbol> and_expression
+%type <symbol> cast_expression
+%type <symbol> assignment_expression
+%type <symbol> unary_expression
+%type <symbol> postfix_expression
+%type <symbol> primary_expression
+%type <unary_operator> unary_operator
+%type <str> function_macro
+%type <str> object_macro
+%type <symbol> strings
+
+%%
+
+/* A.2.1 Expressions. */
+
+primary_expression
+       : identifier
+         {
+               $$ = g_hash_table_lookup (const_table, $1);
+               if ($$ == NULL) {
+                       $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               }
+         }
+       | INTEGER
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
+                       $$->const_int = strtol (yytext + 2, NULL, 16);
+               } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
+                       $$->const_int = strtol (yytext + 1, NULL, 8);
+               } else {
+                       $$->const_int = atoi (yytext);
+               }
+         }
+       | CHARACTER
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | FLOATING
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | strings
+       | '(' expression ')'
+         {
+               $$ = $2;
+         }
+       ;
+
+/* concatenate adjacent string literal tokens */
+strings
+       : STRING
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               yytext[strlen (yytext) - 1] = '\0';
+               $$->const_string = g_strcompress (yytext + 1);
+         }
+       | strings STRING
+         {
+               char *strings, *string2;
+               $$ = $1;
+               yytext[strlen (yytext) - 1] = '\0';
+               string2 = g_strcompress (yytext + 1);
+               strings = g_strconcat ($$->const_string, string2, NULL);
+               g_free ($$->const_string);
+               g_free (string2);
+               $$->const_string = strings;
+         }
+       ;
+
+identifier
+       : IDENTIFIER
+         {
+               $$ = g_strdup (yytext);
+         }
+       ;
+
+identifier_or_typedef_name
+       : identifier
+       | typedef_name
+       ;
+
+postfix_expression
+       : primary_expression
+       | postfix_expression '[' expression ']'
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | postfix_expression '(' argument_expression_list ')'
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | postfix_expression '(' ')'
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | postfix_expression '.' identifier_or_typedef_name
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | postfix_expression ARROW identifier_or_typedef_name
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | postfix_expression PLUSPLUS
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | postfix_expression MINUSMINUS
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       ;
+
+argument_expression_list
+       : assignment_expression
+       | argument_expression_list ',' assignment_expression
+       ;
+
+unary_expression
+       : postfix_expression
+       | PLUSPLUS unary_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | MINUSMINUS unary_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | unary_operator cast_expression
+         {
+               switch ($1) {
+               case UNARY_PLUS:
+                       $$ = $2;
+                       break;
+               case UNARY_MINUS:
+                       $$ = $2;
+                       $$->const_int = -$2->const_int;
+                       break;
+               case UNARY_BITWISE_COMPLEMENT:
+                       $$ = $2;
+                       $$->const_int = ~$2->const_int;
+                       break;
+               case UNARY_LOGICAL_NEGATION:
+                       $$ = $2;
+                       $$->const_int = !csymbol_get_const_boolean ($2);
+                       break;
+               default:
+                       $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+                       break;
+               }
+         }
+       | SIZEOF unary_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | SIZEOF '(' type_name ')'
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       ;
+
+unary_operator
+       : '&'
+         {
+               $$ = UNARY_ADDRESS_OF;
+         }
+       | '*'
+         {
+               $$ = UNARY_POINTER_INDIRECTION;
+         }
+       | '+'
+         {
+               $$ = UNARY_PLUS;
+         }
+       | '-'
+         {
+               $$ = UNARY_MINUS;
+         }
+       | '~'
+         {
+               $$ = UNARY_BITWISE_COMPLEMENT;
+         }
+       | '!'
+         {
+               $$ = UNARY_LOGICAL_NEGATION;
+         }
+       ;
+
+cast_expression
+       : unary_expression
+       | '(' type_name ')' cast_expression
+         {
+               $$ = $4;
+         }
+       ;
+
+multiplicative_expression
+       : cast_expression
+       | multiplicative_expression '*' cast_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int * $3->const_int;
+         }
+       | multiplicative_expression '/' cast_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               if ($3->const_int != 0) {
+                       $$->const_int = $1->const_int / $3->const_int;
+               }
+         }
+       | multiplicative_expression '%' cast_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int % $3->const_int;
+         }
+       ;
+
+additive_expression
+       : multiplicative_expression
+       | additive_expression '+' multiplicative_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int + $3->const_int;
+         }
+       | additive_expression '-' multiplicative_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int - $3->const_int;
+         }
+       ;
+
+shift_expression
+       : additive_expression
+       | shift_expression SL additive_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int << $3->const_int;
+         }
+       | shift_expression SR additive_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int >> $3->const_int;
+         }
+       ;
+
+relational_expression
+       : shift_expression
+       | relational_expression '<' shift_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int < $3->const_int;
+         }
+       | relational_expression '>' shift_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int > $3->const_int;
+         }
+       | relational_expression LTEQ shift_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int <= $3->const_int;
+         }
+       | relational_expression GTEQ shift_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int >= $3->const_int;
+         }
+       ;
+
+equality_expression
+       : relational_expression
+       | equality_expression EQ relational_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int == $3->const_int;
+         }
+       | equality_expression NOTEQ relational_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int != $3->const_int;
+         }
+       ;
+
+and_expression
+       : equality_expression
+       | and_expression '&' equality_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int & $3->const_int;
+         }
+       ;
+
+exclusive_or_expression
+       : and_expression
+       | exclusive_or_expression '^' and_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int ^ $3->const_int;
+         }
+       ;
+
+inclusive_or_expression
+       : exclusive_or_expression
+       | inclusive_or_expression '|' exclusive_or_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = $1->const_int | $3->const_int;
+         }
+       ;
+
+logical_and_expression
+       : inclusive_or_expression
+       | logical_and_expression ANDAND inclusive_or_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = csymbol_get_const_boolean ($1) && csymbol_get_const_boolean ($3);
+         }
+       ;
+
+logical_or_expression
+       : logical_and_expression
+       | logical_or_expression OROR logical_and_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+               $$->const_int_set = TRUE;
+               $$->const_int = csymbol_get_const_boolean ($1) || csymbol_get_const_boolean ($3);
+         }
+       ;
+
+conditional_expression
+       : logical_or_expression
+       | logical_or_expression '?' expression ':' conditional_expression
+         {
+               $$ = csymbol_get_const_boolean ($1) ? $3 : $5;
+         }
+       ;
+
+assignment_expression
+       : conditional_expression
+       | unary_expression assignment_operator assignment_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       ;
+
+assignment_operator
+       : '='
+       | MULEQ
+       | DIVEQ
+       | MODEQ
+       | ADDEQ
+       | SUBEQ
+       | SLEQ
+       | SREQ
+       | ANDEQ
+       | XOREQ
+       | OREQ
+       ;
+
+expression
+       : assignment_expression
+       | expression ',' assignment_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       ;
+
+constant_expression
+       : conditional_expression
+       ;
+
+/* A.2.2 Declarations. */
+
+declaration
+       : declaration_specifiers init_declarator_list ';'
+         {
+               GList *l;
+               for (l = $2; l != NULL; l = l->next) {
+                       CSymbol *sym = l->data;
+                       csymbol_merge_type (sym, $1);
+                       if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+                               sym->type = CSYMBOL_TYPE_TYPEDEF;
+                       } else if (sym->base_type->type == CTYPE_FUNCTION) {
+                               sym->type = CSYMBOL_TYPE_FUNCTION;
+                       } else {
+                               sym->type = CSYMBOL_TYPE_OBJECT;
+                       }
+                       g_igenerator_add_symbol (the_igenerator, sym);
+               }
+         }
+       | declaration_specifiers ';'
+       ;
+
+declaration_specifiers
+       : storage_class_specifier declaration_specifiers
+         {
+               $$ = $2;
+               $$->storage_class_specifier |= $1;
+         }
+       | storage_class_specifier
+         {
+               $$ = ctype_new (CTYPE_INVALID);
+               $$->storage_class_specifier |= $1;
+         }
+       | type_specifier declaration_specifiers
+         {
+               $$ = $1;
+               $$->base_type = $2;
+         }
+       | type_specifier
+       | type_qualifier declaration_specifiers
+         {
+               $$ = $2;
+               $$->type_qualifier |= $1;
+         }
+       | type_qualifier
+         {
+               $$ = ctype_new (CTYPE_INVALID);
+               $$->type_qualifier |= $1;
+         }
+       | function_specifier declaration_specifiers
+         {
+               $$ = $2;
+               $$->function_specifier |= $1;
+         }
+       | function_specifier
+         {
+               $$ = ctype_new (CTYPE_INVALID);
+               $$->function_specifier |= $1;
+         }
+       ;
+
+init_declarator_list
+       : init_declarator
+         {
+               $$ = g_list_append (NULL, $1);
+         }
+       | init_declarator_list ',' init_declarator
+         {
+               $$ = g_list_append ($1, $3);
+         }
+       ;
+
+init_declarator
+       : declarator
+       | declarator '=' initializer
+       ;
+
+storage_class_specifier
+       : TYPEDEF
+         {
+               $$ = STORAGE_CLASS_TYPEDEF;
+         }
+       | EXTERN
+         {
+               $$ = STORAGE_CLASS_EXTERN;
+         }
+       | STATIC
+         {
+               $$ = STORAGE_CLASS_STATIC;
+         }
+       | AUTO
+         {
+               $$ = STORAGE_CLASS_AUTO;
+         }
+       | REGISTER
+         {
+               $$ = STORAGE_CLASS_REGISTER;
+         }
+       ;
+
+type_specifier
+       : VOID
+         {
+               $$ = ctype_new (CTYPE_VOID);
+         }
+       | CHAR
+         {
+               $$ = cbasic_type_new ("char");
+         }
+       | SHORT
+         {
+               $$ = cbasic_type_new ("short");
+         }
+       | INT
+         {
+               $$ = cbasic_type_new ("int");
+         }
+       | LONG
+         {
+               $$ = cbasic_type_new ("long");
+         }
+       | FLOAT
+         {
+               $$ = cbasic_type_new ("float");
+         }
+       | DOUBLE
+         {
+               $$ = cbasic_type_new ("double");
+         }
+       | SIGNED
+         {
+               $$ = cbasic_type_new ("signed");
+         }
+       | UNSIGNED
+         {
+               $$ = cbasic_type_new ("unsigned");
+         }
+       | struct_or_union_specifier
+       | enum_specifier
+       | typedef_name
+         {
+               $$ = ctypedef_new ($1);
+         }
+       ;
+
+struct_or_union_specifier
+       : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
+         {
+               $$ = $1;
+               $$->name = $2;
+               $$->child_list = $4;
+
+               CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+               if ($$->type == CTYPE_STRUCT) {
+                       sym->type = CSYMBOL_TYPE_STRUCT;
+               } else if ($$->type == CTYPE_UNION) {
+                       sym->type = CSYMBOL_TYPE_UNION;
+               } else {
+                       g_assert_not_reached ();
+               }
+               sym->ident = g_strdup ($$->name);
+               sym->base_type = ctype_copy ($$);
+               g_igenerator_add_symbol (the_igenerator, sym);
+         }
+       | struct_or_union '{' struct_declaration_list '}'
+         {
+               $$ = $1;
+               $$->child_list = $3;
+         }
+       | struct_or_union identifier_or_typedef_name
+         {
+               $$ = $1;
+               $$->name = $2;
+         }
+       ;
+
+struct_or_union
+       : STRUCT
+         {
+               $$ = cstruct_new (NULL);
+         }
+       | UNION
+         {
+               $$ = cunion_new (NULL);
+         }
+       ;
+
+struct_declaration_list
+       : struct_declaration
+       | struct_declaration_list struct_declaration
+         {
+               $$ = g_list_concat ($1, $2);
+         }
+       ;
+
+struct_declaration
+       : specifier_qualifier_list struct_declarator_list ';'
+         {
+               GList *l;
+               $$ = NULL;
+               for (l = $2; l != NULL; l = l->next) {
+                       CSymbol *sym = l->data;
+                       if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+                               sym->type = CSYMBOL_TYPE_TYPEDEF;
+                       }
+                       csymbol_merge_type (sym, $1);
+                       $$ = g_list_append ($$, sym);
+               }
+         }
+       ;
+
+specifier_qualifier_list
+       : type_specifier specifier_qualifier_list
+         {
+               $$ = $1;
+               $$->base_type = $2;
+         }
+       | type_specifier
+       | type_qualifier specifier_qualifier_list
+         {
+               $$ = $2;
+               $$->type_qualifier |= $1;
+         }
+       | type_qualifier
+         {
+               $$ = ctype_new (CTYPE_INVALID);
+               $$->type_qualifier |= $1;
+         }
+       ;
+
+struct_declarator_list
+       : struct_declarator
+         {
+               $$ = g_list_append (NULL, $1);
+         }
+       | struct_declarator_list ',' struct_declarator
+         {
+               $$ = g_list_append ($1, $3);
+         }
+       ;
+
+struct_declarator
+       : /* empty, support for anonymous structs and unions */
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | declarator
+       | ':' constant_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+         }
+       | declarator ':' constant_expression
+       ;
+
+enum_specifier
+       : ENUM identifier_or_typedef_name '{' enumerator_list '}'
+         {
+               $$ = cenum_new ($2);
+               $$->child_list = $4;
+               last_enum_value = -1;
+         }
+       | ENUM '{' enumerator_list '}'
+         {
+               $$ = cenum_new (NULL);
+               $$->child_list = $3;
+               last_enum_value = -1;
+         }
+       | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
+         {
+               $$ = cenum_new ($2);
+               $$->child_list = $4;
+               last_enum_value = -1;
+         }
+       | ENUM '{' enumerator_list ',' '}'
+         {
+               $$ = cenum_new (NULL);
+               $$->child_list = $3;
+               last_enum_value = -1;
+         }
+       | ENUM identifier_or_typedef_name
+         {
+               $$ = cenum_new ($2);
+         }
+       ;
+
+enumerator_list
+       : enumerator
+         {
+               $$ = g_list_append (NULL, $1);
+         }
+       | enumerator_list ',' enumerator
+         {
+               $$ = g_list_append ($1, $3);
+         }
+       ;
+
+enumerator
+       : identifier
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_OBJECT);
+               $$->ident = $1;
+               $$->const_int_set = TRUE;
+               $$->const_int = ++last_enum_value;
+               g_hash_table_insert (const_table, $$->ident, $$);
+         }
+       | identifier '=' constant_expression
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_OBJECT);
+               $$->ident = $1;
+               $$->const_int_set = TRUE;
+               $$->const_int = $3->const_int;
+               last_enum_value = $$->const_int;
+               g_hash_table_insert (const_table, $$->ident, $$);
+         }
+       ;
+
+type_qualifier
+       : CONST
+         {
+               $$ = TYPE_QUALIFIER_CONST;
+         }
+       | RESTRICT
+         {
+               $$ = TYPE_QUALIFIER_RESTRICT;
+         }
+       | VOLATILE
+         {
+               $$ = TYPE_QUALIFIER_VOLATILE;
+         }
+       ;
+
+function_specifier
+       : INLINE
+         {
+               $$ = FUNCTION_INLINE;
+         }
+       ;
+
+declarator
+       : pointer direct_declarator
+         {
+               $$ = $2;
+               csymbol_merge_type ($$, $1);
+         }
+       | direct_declarator
+       ;
+
+direct_declarator
+       : identifier
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               $$->ident = $1;
+         }
+       | '(' declarator ')'
+         {
+               $$ = $2;
+         }
+       | direct_declarator '[' assignment_expression ']'
+         {
+               $$ = $1;
+               csymbol_merge_type ($$, carray_new ());
+         }
+       | direct_declarator '[' ']'
+         {
+               $$ = $1;
+               csymbol_merge_type ($$, carray_new ());
+         }
+       | direct_declarator '(' parameter_type_list ')'
+         {
+               CType *func = cfunction_new ();
+               // ignore (void) parameter list
+               if ($3 != NULL && ($3->next != NULL || ((CSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+                       func->child_list = $3;
+               }
+               $$ = $1;
+               csymbol_merge_type ($$, func);
+         }
+       | direct_declarator '(' identifier_list ')'
+         {
+               CType *func = cfunction_new ();
+               func->child_list = $3;
+               $$ = $1;
+               csymbol_merge_type ($$, func);
+         }
+       | direct_declarator '(' ')'
+         {
+               CType *func = cfunction_new ();
+               $$ = $1;
+               csymbol_merge_type ($$, func);
+         }
+       ;
+
+pointer
+       : '*' type_qualifier_list
+         {
+               $$ = cpointer_new (NULL);
+               $$->type_qualifier = $2;
+         }
+       | '*'
+         {
+               $$ = cpointer_new (NULL);
+         }
+       | '*' type_qualifier_list pointer
+         {
+               $$ = cpointer_new ($3);
+               $$->type_qualifier = $2;
+         }
+       | '*' pointer
+         {
+               $$ = cpointer_new ($2);
+         }
+       ;
+
+type_qualifier_list
+       : type_qualifier
+       | type_qualifier_list type_qualifier
+         {
+               $$ = $1 | $2;
+         }
+       ;
+
+parameter_type_list
+       : parameter_list
+       | parameter_list ',' ELLIPSIS
+       ;
+
+parameter_list
+       : parameter_declaration
+         {
+               $$ = g_list_append (NULL, $1);
+         }
+       | parameter_list ',' parameter_declaration
+         {
+               $$ = g_list_append ($1, $3);
+         }
+       ;
+
+parameter_declaration
+       : declaration_specifiers declarator
+         {
+               $$ = $2;
+               csymbol_merge_type ($$, $1);
+         }
+       | declaration_specifiers abstract_declarator
+         {
+               $$ = $2;
+               csymbol_merge_type ($$, $1);
+         }
+       | declaration_specifiers
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               $$->base_type = $1;
+         }
+       ;
+
+identifier_list
+       : identifier
+         {
+               CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+               sym->ident = $1;
+               $$ = g_list_append (NULL, sym);
+         }
+       | identifier_list ',' identifier
+         {
+               CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+               sym->ident = $3;
+               $$ = g_list_append ($1, sym);
+         }
+       ;
+
+type_name
+       : specifier_qualifier_list
+       | specifier_qualifier_list abstract_declarator
+       ;
+
+abstract_declarator
+       : pointer
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               csymbol_merge_type ($$, $1);
+         }
+       | direct_abstract_declarator
+       | pointer direct_abstract_declarator
+         {
+               $$ = $2;
+               csymbol_merge_type ($$, $1);
+         }
+       ;
+
+direct_abstract_declarator
+       : '(' abstract_declarator ')'
+         {
+               $$ = $2;
+         }
+       | '[' ']'
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               csymbol_merge_type ($$, carray_new ());
+         }
+       | '[' assignment_expression ']'
+         {
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               csymbol_merge_type ($$, carray_new ());
+         }
+       | direct_abstract_declarator '[' ']'
+         {
+               $$ = $1;
+               csymbol_merge_type ($$, carray_new ());
+         }
+       | direct_abstract_declarator '[' assignment_expression ']'
+         {
+               $$ = $1;
+               csymbol_merge_type ($$, carray_new ());
+         }
+       | '(' ')'
+         {
+               CType *func = cfunction_new ();
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               csymbol_merge_type ($$, func);
+         }
+       | '(' parameter_type_list ')'
+         {
+               CType *func = cfunction_new ();
+               // ignore (void) parameter list
+               if ($2 != NULL && ($2->next != NULL || ((CSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
+                       func->child_list = $2;
+               }
+               $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+               csymbol_merge_type ($$, func);
+         }
+       | direct_abstract_declarator '(' ')'
+         {
+               CType *func = cfunction_new ();
+               $$ = $1;
+               csymbol_merge_type ($$, func);
+         }
+       | direct_abstract_declarator '(' parameter_type_list ')'
+         {
+               CType *func = cfunction_new ();
+               // ignore (void) parameter list
+               if ($3 != NULL && ($3->next != NULL || ((CSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+                       func->child_list = $3;
+               }
+               $$ = $1;
+               csymbol_merge_type ($$, func);
+         }
+       ;
+
+typedef_name
+       : TYPEDEF_NAME
+         {
+               $$ = g_strdup (yytext);
+         }
+       ;
+
+initializer
+       : assignment_expression
+       | '{' initializer_list '}'
+       | '{' initializer_list ',' '}'
+       ;
+
+initializer_list
+       : initializer
+       | initializer_list ',' initializer
+       ;
+
+/* A.2.3 Statements. */
+
+statement
+       : labeled_statement
+       | compound_statement
+       | expression_statement
+       | selection_statement
+       | iteration_statement
+       | jump_statement
+       ;
+
+labeled_statement
+       : identifier_or_typedef_name ':' statement
+       | CASE constant_expression ':' statement
+       | DEFAULT ':' statement
+       ;
+
+compound_statement
+       : '{' '}'
+       | '{' block_item_list '}'
+       ;
+
+block_item_list
+       : block_item
+       | block_item_list block_item
+       ;
+
+block_item
+       : declaration
+       | statement
+       ;
+
+expression_statement
+       : ';'
+       | expression ';'
+       ;
+
+selection_statement
+       : IF '(' expression ')' statement
+       | IF '(' expression ')' statement ELSE statement
+       | SWITCH '(' expression ')' statement
+       ;
+
+iteration_statement
+       : WHILE '(' expression ')' statement
+       | DO statement WHILE '(' expression ')' ';'
+       | FOR '(' ';' ';' ')' statement
+       | FOR '(' expression ';' ';' ')' statement
+       | FOR '(' ';' expression ';' ')' statement
+       | FOR '(' expression ';' expression ';' ')' statement
+       | FOR '(' ';' ';' expression ')' statement
+       | FOR '(' expression ';' ';' expression ')' statement
+       | FOR '(' ';' expression ';' expression ')' statement
+       | FOR '(' expression ';' expression ';' expression ')' statement
+       ;
+
+jump_statement
+       : GOTO identifier_or_typedef_name ';'
+       | CONTINUE ';'
+       | BREAK ';'
+       | RETURN ';'
+       | RETURN expression ';'
+       ;
+
+/* A.2.4 External definitions. */
+
+translation_unit
+       : external_declaration
+       | translation_unit external_declaration
+       ;
+
+external_declaration
+       : function_definition
+       | declaration
+       | macro
+       ;
+
+function_definition
+       : declaration_specifiers declarator declaration_list compound_statement
+       | declaration_specifiers declarator compound_statement
+       ;
+
+declaration_list
+       : declaration
+       | declaration_list declaration
+       ;
+
+/* Macros */
+
+function_macro
+       : FUNCTION_MACRO
+         {
+               $$ = g_strdup (yytext + strlen ("#define "));
+         }
+       ;
+
+object_macro
+       : OBJECT_MACRO
+         {
+               $$ = g_strdup (yytext + strlen ("#define "));
+         }
+       ;
+
+function_macro_define
+       : function_macro '(' identifier_list ')'
+       ;
+
+object_macro_define
+       : object_macro constant_expression
+         {
+               if ($2->const_int_set || $2->const_string != NULL) {
+                       $2->ident = $1;
+                       g_igenerator_add_symbol (the_igenerator, $2);
+               }
+         }
+       ;
+
+macro
+       : function_macro_define
+       | object_macro_define
+       | error
+       ;
+
+%%
+
+static void
+yyerror(const char *s)
+{
+       /* ignore errors while doing a macro scan as not all object macros
+        * have valid expressions */
+       if (!the_igenerator->macro_scan) {
+               fprintf(stderr, "%s:%d: %s\n", the_igenerator->current_filename, lineno, s);
+       }
+}
+
+void g_igenerator_parse (GIGenerator *igenerator, FILE *f)
+{
+       yyin = f;
+       if (yyin == NULL) {
+               return;
+       }
+
+       const_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+       lineno = 1;
+       yyparse();
+
+       g_hash_table_unref (const_table);
+       const_table = NULL;
+
+       fclose (yyin);
+       yyin = NULL;
+}
+
diff --git a/src/gen-introspect.c b/src/gen-introspect.c
new file mode 100644 (file)
index 0000000..a4b522c
--- /dev/null
@@ -0,0 +1,1914 @@
+/* GObject introspection: gen-introspect
+ *
+ * Copyright (C) 2007  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <gmodule.h>
+#include "gen-introspect.h"
+#include "gidlmodule.h"
+#include "gidlnode.h"
+
+typedef GType (*TypeFunction) (void);
+
+static void node_generate (GIGenerator * igenerator, GIdlNode * node);
+static void g_igenerator_parse_macros (GIGenerator * igenerator);
+
+static int
+g_idl_node_cmp (GIdlNode * a, GIdlNode * b)
+{
+  if (a->type < b->type)
+    {
+      return -1;
+    }
+  else if (a->type > b->type)
+    {
+      return 1;
+    }
+  else
+    {
+      return strcmp (a->name, b->name);
+    }
+}
+
+GIGenerator *
+g_igenerator_new (void)
+{
+  GIGenerator *igenerator = g_new0 (GIGenerator, 1);
+  igenerator->namespace = "";
+  igenerator->lower_case_namespace = g_strdup ("");
+  igenerator->typedef_table = g_hash_table_new (g_str_hash, g_str_equal);
+  igenerator->struct_or_union_or_enum_table =
+    g_hash_table_new (g_str_hash, g_str_equal);
+
+  igenerator->type_map = g_hash_table_new (g_str_hash, g_str_equal);
+  igenerator->type_by_lower_case_prefix =
+    g_hash_table_new (g_str_hash, g_str_equal);
+
+  the_igenerator = igenerator;
+
+  return igenerator;
+}
+
+static void
+g_igenerator_write_inline (GIGenerator * igenerator, const char *s)
+{
+  fprintf (stdout, "%s", s);
+}
+
+static void
+g_igenerator_write (GIGenerator * igenerator, const char *s)
+{
+  int i;
+  for (i = 0; i < igenerator->indent; i++)
+    {
+      fprintf (stdout, "\t");
+    }
+
+  g_igenerator_write_inline (igenerator, s);
+}
+
+static void
+g_igenerator_write_indent (GIGenerator * igenerator, const char *s)
+{
+  g_igenerator_write (igenerator, s);
+  igenerator->indent++;
+}
+
+static void
+g_igenerator_write_unindent (GIGenerator * igenerator, const char *s)
+{
+  igenerator->indent--;
+  g_igenerator_write (igenerator, s);
+}
+
+static void
+field_generate (GIGenerator * igenerator, GIdlNodeField * node)
+{
+  char *markup =
+    g_markup_printf_escaped ("<field name=\"%s\" type=\"%s\"/>\n",
+                            node->node.name, node->type->unparsed);
+  g_igenerator_write (igenerator, markup);
+  g_free (markup);
+}
+
+static void
+value_generate (GIGenerator * igenerator, GIdlNodeValue * node)
+{
+  char *markup =
+    g_markup_printf_escaped ("<member name=\"%s\" value=\"%d\"/>\n",
+                            node->node.name, node->value);
+  g_igenerator_write (igenerator, markup);
+  g_free (markup);
+}
+
+static void
+constant_generate (GIGenerator * igenerator, GIdlNodeConstant * node)
+{
+  char *markup =
+    g_markup_printf_escaped
+    ("<constant name=\"%s\" type=\"%s\" value=\"%s\"/>\n", node->node.name,
+     node->type->unparsed, node->value);
+  g_igenerator_write (igenerator, markup);
+  g_free (markup);
+}
+
+static void
+property_generate (GIGenerator * igenerator, GIdlNodeProperty * node)
+{
+  char *markup =
+    g_markup_printf_escaped
+    ("<property name=\"%s\" type=\"%s\" readable=\"%s\" writable=\"%s\" construct=\"%s\" construct-only=\"%s\"/>\n",
+     node->node.name, node->type->unparsed, node->readable ? "1" : "0",
+     node->writable ? "1" : "0", node->construct ? "1" : "0",
+     node->construct_only ? "1" : "0");
+  g_igenerator_write (igenerator, markup);
+  g_free (markup);
+}
+
+static void
+function_generate (GIGenerator * igenerator, GIdlNodeFunction * node)
+{
+  char *markup;
+  const char *tag_name;
+  if (node->node.type == G_IDL_NODE_CALLBACK)
+    {
+      tag_name = "callback";
+      markup =
+       g_markup_printf_escaped ("<callback name=\"%s\">\n", node->node.name);
+    }
+  else if (node->is_constructor)
+    {
+      tag_name = "constructor";
+      markup =
+       g_markup_printf_escaped ("<constructor name=\"%s\" symbol=\"%s\">\n",
+                                node->node.name, node->symbol);
+    }
+  else if (node->is_method)
+    {
+      tag_name = "method";
+      markup =
+       g_markup_printf_escaped ("<method name=\"%s\" symbol=\"%s\">\n",
+                                node->node.name, node->symbol);
+    }
+  else
+    {
+      tag_name = "function";
+      markup =
+       g_markup_printf_escaped ("<function name=\"%s\" symbol=\"%s\">\n",
+                                node->node.name, node->symbol);
+    }
+
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  markup =
+    g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
+                            node->result->type->unparsed);
+  g_igenerator_write (igenerator, markup);
+  g_free (markup);
+  if (node->parameters != NULL)
+    {
+      GList *l;
+      g_igenerator_write_indent (igenerator, "<parameters>\n");
+      for (l = node->parameters; l != NULL; l = l->next)
+       {
+         GIdlNodeParam *param = l->data;
+         markup =
+           g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
+                                    param->node.name, param->type->unparsed);
+         g_igenerator_write (igenerator, markup);
+         g_free (markup);
+       }
+      g_igenerator_write_unindent (igenerator, "</parameters>\n");
+    }
+  markup = g_strdup_printf ("</%s>\n", tag_name);
+  g_igenerator_write_unindent (igenerator, markup);
+  g_free (markup);
+}
+
+static void
+vfunc_generate (GIGenerator * igenerator, GIdlNodeVFunc * node)
+{
+  char *markup =
+    g_markup_printf_escaped ("<vfunc name=\"%s\">\n", node->node.name);
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  markup =
+    g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
+                            node->result->type->unparsed);
+  g_igenerator_write (igenerator, markup);
+  g_free (markup);
+  if (node->parameters != NULL)
+    {
+      GList *l;
+      g_igenerator_write_indent (igenerator, "<parameters>\n");
+      for (l = node->parameters; l != NULL; l = l->next)
+       {
+         GIdlNodeParam *param = l->data;
+         markup =
+           g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
+                                    param->node.name, param->type->unparsed);
+         g_igenerator_write (igenerator, markup);
+         g_free (markup);
+       }
+      g_igenerator_write_unindent (igenerator, "</parameters>\n");
+    }
+  g_igenerator_write_unindent (igenerator, "</vfunc>\n");
+}
+
+static void
+signal_generate (GIGenerator * igenerator, GIdlNodeSignal * node)
+{
+  char *markup;
+  const char *when = "LAST";
+  if (node->run_first)
+    {
+      when = "FIRST";
+    }
+  else if (node->run_cleanup)
+    {
+      when = "CLEANUP";
+    }
+  markup =
+    g_markup_printf_escaped ("<signal name=\"%s\" when=\"%s\">\n",
+                            node->node.name, when);
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  markup =
+    g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
+                            node->result->type->unparsed);
+  g_igenerator_write (igenerator, markup);
+  g_free (markup);
+  if (node->parameters != NULL)
+    {
+      GList *l;
+      g_igenerator_write_indent (igenerator, "<parameters>\n");
+      for (l = node->parameters; l != NULL; l = l->next)
+       {
+         GIdlNodeParam *param = l->data;
+         markup =
+           g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
+                                    param->node.name, param->type->unparsed);
+         g_igenerator_write (igenerator, markup);
+         g_free (markup);
+       }
+      g_igenerator_write_unindent (igenerator, "</parameters>\n");
+    }
+  g_igenerator_write_unindent (igenerator, "</signal>\n");
+}
+
+static void
+interface_generate (GIGenerator * igenerator, GIdlNodeInterface * node)
+{
+  GList *l;
+  char *markup;
+  if (node->node.type == G_IDL_NODE_OBJECT)
+    {
+      markup =
+       g_markup_printf_escaped
+       ("<object name=\"%s\" parent=\"%s\" type-name=\"%s\" get-type=\"%s\">\n",
+        node->node.name, node->parent, node->gtype_name, node->gtype_init);
+    }
+  else if (node->node.type == G_IDL_NODE_INTERFACE)
+    {
+      markup =
+       g_markup_printf_escaped
+       ("<interface name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n",
+        node->node.name, node->gtype_name, node->gtype_init);
+    }
+
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  if (node->node.type == G_IDL_NODE_OBJECT && node->interfaces != NULL)
+    {
+      GList *l;
+      g_igenerator_write_indent (igenerator, "<implements>\n");
+      for (l = node->interfaces; l != NULL; l = l->next)
+       {
+         markup =
+           g_markup_printf_escaped ("<interface name=\"%s\"/>\n",
+                                    (char *) l->data);
+         g_igenerator_write (igenerator, markup);
+         g_free (markup);
+       }
+      g_igenerator_write_unindent (igenerator, "</implements>\n");
+    }
+  else if (node->node.type == G_IDL_NODE_INTERFACE
+          && node->prerequisites != NULL)
+    {
+      GList *l;
+      g_igenerator_write_indent (igenerator, "<requires>\n");
+      for (l = node->prerequisites; l != NULL; l = l->next)
+       {
+         markup =
+           g_markup_printf_escaped ("<interface name=\"%s\"/>\n",
+                                    (char *) l->data);
+         g_igenerator_write (igenerator, markup);
+         g_free (markup);
+       }
+      g_igenerator_write_unindent (igenerator, "</requires>\n");
+    }
+
+  for (l = node->members; l != NULL; l = l->next)
+    {
+      node_generate (igenerator, l->data);
+    }
+
+  if (node->node.type == G_IDL_NODE_OBJECT)
+    {
+      g_igenerator_write_unindent (igenerator, "</object>\n");
+    }
+  else if (node->node.type == G_IDL_NODE_INTERFACE)
+    {
+      g_igenerator_write_unindent (igenerator, "</interface>\n");
+    }
+}
+
+static void
+struct_generate (GIGenerator * igenerator, GIdlNodeStruct * node)
+{
+  GList *l;
+  char *markup =
+    g_markup_printf_escaped ("<struct name=\"%s\">\n", node->node.name);
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  for (l = node->members; l != NULL; l = l->next)
+    {
+      node_generate (igenerator, l->data);
+    }
+  g_igenerator_write_unindent (igenerator, "</struct>\n");
+}
+
+static void
+union_generate (GIGenerator * igenerator, GIdlNodeUnion * node)
+{
+  GList *l;
+  char *markup =
+    g_markup_printf_escaped ("<union name=\"%s\">\n", node->node.name);
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  for (l = node->members; l != NULL; l = l->next)
+    {
+      node_generate (igenerator, l->data);
+    }
+  g_igenerator_write_unindent (igenerator, "</union>\n");
+}
+
+static void
+boxed_generate (GIGenerator * igenerator, GIdlNodeBoxed * node)
+{
+  GList *l;
+  char *markup =
+    g_markup_printf_escaped
+    ("<boxed name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n",
+     node->node.name, node->gtype_name, node->gtype_init);
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  for (l = node->members; l != NULL; l = l->next)
+    {
+      node_generate (igenerator, l->data);
+    }
+  g_igenerator_write_unindent (igenerator, "</boxed>\n");
+}
+
+static void
+enum_generate (GIGenerator * igenerator, GIdlNodeEnum * node)
+{
+  GList *l;
+  char *markup;
+  const char *tag_name = NULL;
+
+  if (node->node.type == G_IDL_NODE_ENUM)
+    {
+      tag_name = "enum";
+    }
+  else if (node->node.type == G_IDL_NODE_FLAGS)
+    {
+      tag_name = "flags";
+    }
+  markup =
+    g_markup_printf_escaped ("<%s name=\"%s\">\n", tag_name, node->node.name);
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+
+  for (l = node->values; l != NULL; l = l->next)
+    {
+      node_generate (igenerator, l->data);
+    }
+
+  markup = g_strdup_printf ("</%s>\n", tag_name);
+  g_igenerator_write_unindent (igenerator, markup);
+  g_free (markup);
+}
+
+static void
+node_generate (GIGenerator * igenerator, GIdlNode * node)
+{
+  switch (node->type)
+    {
+    case G_IDL_NODE_FUNCTION:
+    case G_IDL_NODE_CALLBACK:
+      function_generate (igenerator, (GIdlNodeFunction *) node);
+      break;
+    case G_IDL_NODE_VFUNC:
+      vfunc_generate (igenerator, (GIdlNodeVFunc *) node);
+      break;
+    case G_IDL_NODE_OBJECT:
+    case G_IDL_NODE_INTERFACE:
+      interface_generate (igenerator, (GIdlNodeInterface *) node);
+      break;
+    case G_IDL_NODE_STRUCT:
+      struct_generate (igenerator, (GIdlNodeStruct *) node);
+      break;
+    case G_IDL_NODE_UNION:
+      union_generate (igenerator, (GIdlNodeUnion *) node);
+      break;
+    case G_IDL_NODE_BOXED:
+      boxed_generate (igenerator, (GIdlNodeBoxed *) node);
+      break;
+    case G_IDL_NODE_ENUM:
+    case G_IDL_NODE_FLAGS:
+      enum_generate (igenerator, (GIdlNodeEnum *) node);
+      break;
+    case G_IDL_NODE_PROPERTY:
+      property_generate (igenerator, (GIdlNodeProperty *) node);
+      break;
+    case G_IDL_NODE_FIELD:
+      field_generate (igenerator, (GIdlNodeField *) node);
+      break;
+    case G_IDL_NODE_SIGNAL:
+      signal_generate (igenerator, (GIdlNodeSignal *) node);
+      break;
+    case G_IDL_NODE_VALUE:
+      value_generate (igenerator, (GIdlNodeValue *) node);
+      break;
+    case G_IDL_NODE_CONSTANT:
+      constant_generate (igenerator, (GIdlNodeConstant *) node);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
+module_generate (GIGenerator * igenerator, GIdlModule * module)
+{
+  GList *l;
+  char *markup =
+    g_markup_printf_escaped ("<namespace name=\"%s\">\n", module->name);
+  g_igenerator_write_indent (igenerator, markup);
+  g_free (markup);
+  for (l = module->entries; l != NULL; l = l->next)
+    {
+      node_generate (igenerator, l->data);
+    }
+  g_igenerator_write_unindent (igenerator, "</namespace>\n");
+}
+
+static GIdlNodeType *
+get_type_from_type_id (GType type_id)
+{
+  GIdlNodeType *gitype = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+
+  GType type_fundamental = g_type_fundamental (type_id);
+
+  if (type_fundamental == G_TYPE_STRING)
+    {
+      gitype->unparsed = g_strdup ("char*");
+    }
+  else if (type_id == G_TYPE_STRV)
+    {
+      gitype->unparsed = g_strdup ("char*[]");
+    }
+  else if (type_fundamental == G_TYPE_INTERFACE
+          || type_fundamental == G_TYPE_BOXED
+          || type_fundamental == G_TYPE_OBJECT)
+    {
+      gitype->unparsed = g_strdup_printf ("%s*", g_type_name (type_id));
+    }
+  else if (type_fundamental == G_TYPE_PARAM)
+    {
+      gitype->unparsed = g_strdup ("GParamSpec*");
+    }
+  else
+    {
+      gitype->unparsed = g_strdup (g_type_name (type_id));
+    }
+
+  return gitype;
+}
+
+static char *
+str_replace (const char *str, const char *needle, const char *replacement)
+{
+  char **strings = g_strsplit (str, needle, 0);
+  char *result = g_strjoinv (replacement, strings);
+  g_strfreev (strings);
+  return result;
+}
+
+static void
+g_igenerator_process_properties (GIGenerator * igenerator,
+                                GIdlNodeInterface * ginode, GType type_id)
+{
+  int i;
+  guint n_properties;
+  GParamSpec **properties;
+
+  if (ginode->node.type == G_IDL_NODE_OBJECT)
+    {
+      GObjectClass *type_class = g_type_class_ref (type_id);
+      properties = g_object_class_list_properties (type_class, &n_properties);
+    }
+  else if (ginode->node.type == G_IDL_NODE_INTERFACE)
+    {
+      GTypeInterface *iface = g_type_default_interface_ref (type_id);
+      properties = g_object_interface_list_properties (iface, &n_properties);
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+
+  for (i = 0; i < n_properties; i++)
+    {
+      /* ignore inherited properties */
+      if (properties[i]->owner_type != type_id)
+       {
+         continue;
+       }
+      GIdlNodeProperty *giprop =
+       (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
+      giprop->node.name = properties[i]->name;
+      ginode->members =
+       g_list_insert_sorted (ginode->members, giprop,
+                             (GCompareFunc) g_idl_node_cmp);
+      giprop->type = get_type_from_type_id (properties[i]->value_type);
+      giprop->readable = (properties[i]->flags & G_PARAM_READABLE) != 0;
+      giprop->writable = (properties[i]->flags & G_PARAM_WRITABLE) != 0;
+      giprop->construct = (properties[i]->flags & G_PARAM_CONSTRUCT) != 0;
+      giprop->construct_only =
+       (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) != 0;
+    }
+}
+
+static void
+g_igenerator_process_signals (GIGenerator * igenerator,
+                             GIdlNodeInterface * ginode, GType type_id)
+{
+  int i, j;
+  guint n_signal_ids;
+  guint *signal_ids = g_signal_list_ids (type_id, &n_signal_ids);
+
+  for (i = 0; i < n_signal_ids; i++)
+    {
+      GSignalQuery signal_query;
+      g_signal_query (signal_ids[i], &signal_query);
+      GIdlNodeSignal *gisig =
+       (GIdlNodeSignal *) g_idl_node_new (G_IDL_NODE_SIGNAL);
+      gisig->node.name = g_strdup (signal_query.signal_name);
+      ginode->members =
+       g_list_insert_sorted (ginode->members, gisig,
+                             (GCompareFunc) g_idl_node_cmp);
+
+      gisig->run_first =
+       (signal_query.signal_flags & G_SIGNAL_RUN_FIRST) != 0;
+      gisig->run_last = (signal_query.signal_flags & G_SIGNAL_RUN_LAST) != 0;
+      gisig->run_cleanup =
+       (signal_query.signal_flags & G_SIGNAL_RUN_CLEANUP) != 0;
+
+      /* add sender parameter */
+      GIdlNodeParam *giparam =
+       (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+      gisig->parameters = g_list_append (gisig->parameters, giparam);
+      giparam->node.name = g_strdup ("object");
+      giparam->type = get_type_from_type_id (type_id);
+
+      for (j = 0; j < signal_query.n_params; j++)
+       {
+         giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+         gisig->parameters = g_list_append (gisig->parameters, giparam);
+         giparam->node.name = g_strdup_printf ("p%d", j);
+         giparam->type = get_type_from_type_id (signal_query.param_types[j]);
+       }
+      gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+      gisig->result->type = get_type_from_type_id (signal_query.return_type);
+    }
+}
+
+static void
+g_igenerator_process_types (GIGenerator * igenerator)
+{
+  int i;
+  GList *lib_l;
+
+  /* ensure to initialize GObject */
+  g_type_class_ref (G_TYPE_OBJECT);
+
+  for (lib_l = igenerator->libraries; lib_l != NULL; lib_l = lib_l->next)
+    {
+      GList *l;
+      GModule *module =
+       g_module_open (lib_l->data, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+      if (module == NULL)
+       {
+         g_critical ("Couldn't open module: %s", (char *) lib_l->data);
+         continue;
+       }
+      for (l = igenerator->get_type_symbols; l != NULL; l = l->next)
+       {
+         char *get_type_symbol = l->data;
+
+         if (get_type_symbol == NULL)
+           {
+             /* ignore already processed functions */
+             continue;
+           }
+
+         TypeFunction type_fun;
+         if (!g_module_symbol
+             (module, get_type_symbol, (gpointer *) & type_fun))
+           {
+             continue;
+           }
+
+         /* symbol found, ignore in future iterations */
+         l->data = NULL;
+
+         GType type_id = type_fun ();
+         GType type_fundamental = g_type_fundamental (type_id);
+         char *lower_case_prefix =
+           str_replace (g_strndup
+                        (get_type_symbol,
+                         strlen (get_type_symbol) - strlen ("_get_type")),
+                        "_", "");
+         if (type_fundamental == G_TYPE_OBJECT)
+           {
+             char *alt_lower_case_prefix;
+             GIdlNodeInterface *ginode =
+               (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
+             ginode->node.name = g_strdup (g_type_name (type_id));
+             igenerator->module->entries =
+               g_list_insert_sorted (igenerator->module->entries, ginode,
+                                     (GCompareFunc) g_idl_node_cmp);
+             g_hash_table_insert (igenerator->type_map, ginode->node.name,
+                                  ginode);
+             g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                                  lower_case_prefix, ginode);
+             alt_lower_case_prefix = g_ascii_strdown (ginode->node.name, -1);
+             if (strcmp (alt_lower_case_prefix, lower_case_prefix) != 0)
+               {
+                 /* alternative prefix sometimes necessary, for example for GdkWindow  */
+                 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                                      alt_lower_case_prefix, ginode);
+               }
+             else
+               {
+                 g_free (alt_lower_case_prefix);
+               }
+             ginode->gtype_name = ginode->node.name;
+             ginode->gtype_init = get_type_symbol;
+             ginode->parent =
+               g_strdup (g_type_name (g_type_parent (type_id)));
+
+             guint n_type_interfaces;
+             GType *type_interfaces =
+               g_type_interfaces (type_id, &n_type_interfaces);
+             for (i = 0; i < n_type_interfaces; i++)
+               {
+                 char *iface_name =
+                   g_strdup (g_type_name (type_interfaces[i]));
+                 /* workaround for AtkImplementorIface */
+                 if (g_str_has_suffix (iface_name, "Iface"))
+                   {
+                     iface_name[strlen (iface_name) - strlen ("Iface")] =
+                       '\0';
+                   }
+                 ginode->interfaces =
+                   g_list_append (ginode->interfaces, iface_name);
+               }
+
+             g_igenerator_process_properties (igenerator, ginode, type_id);
+             g_igenerator_process_signals (igenerator, ginode, type_id);
+           }
+         else if (type_fundamental == G_TYPE_INTERFACE)
+           {
+             GIdlNodeInterface *ginode =
+               (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
+             ginode->node.name = g_strdup (g_type_name (type_id));
+             /* workaround for AtkImplementorIface */
+             if (g_str_has_suffix (ginode->node.name, "Iface"))
+               {
+                 ginode->node.name[strlen (ginode->node.name) -
+                                   strlen ("Iface")] = '\0';
+               }
+             igenerator->module->entries =
+               g_list_insert_sorted (igenerator->module->entries, ginode,
+                                     (GCompareFunc) g_idl_node_cmp);
+             g_hash_table_insert (igenerator->type_map, ginode->node.name,
+                                  ginode);
+             g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                                  lower_case_prefix, ginode);
+             ginode->gtype_name = ginode->node.name;
+             ginode->gtype_init = get_type_symbol;
+
+             gboolean is_gobject = FALSE;
+             guint n_iface_prereqs;
+             GType *iface_prereqs =
+               g_type_interface_prerequisites (type_id, &n_iface_prereqs);
+             for (i = 0; i < n_iface_prereqs; i++)
+               {
+                 if (g_type_fundamental (iface_prereqs[i]) == G_TYPE_OBJECT)
+                   {
+                     is_gobject = TRUE;
+                   }
+                 ginode->prerequisites =
+                   g_list_append (ginode->prerequisites,
+                                  g_strdup (g_type_name (iface_prereqs[i])));
+               }
+
+             if (is_gobject)
+               {
+                 g_igenerator_process_properties (igenerator, ginode,
+                                                  type_id);
+               }
+             else
+               {
+                 g_type_default_interface_ref (type_id);
+               }
+             g_igenerator_process_signals (igenerator, ginode, type_id);
+           }
+         else if (type_fundamental == G_TYPE_BOXED)
+           {
+             GIdlNodeBoxed *ginode =
+               (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
+             ginode->node.name = g_strdup (g_type_name (type_id));
+             igenerator->module->entries =
+               g_list_insert_sorted (igenerator->module->entries, ginode,
+                                     (GCompareFunc) g_idl_node_cmp);
+             g_hash_table_insert (igenerator->type_map, ginode->node.name,
+                                  ginode);
+             g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                                  lower_case_prefix, ginode);
+             ginode->gtype_name = ginode->node.name;
+             ginode->gtype_init = get_type_symbol;
+           }
+         else if (type_fundamental == G_TYPE_ENUM)
+           {
+             GIdlNodeEnum *ginode =
+               (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+             ginode->node.name = g_strdup (g_type_name (type_id));
+             igenerator->module->entries =
+               g_list_insert_sorted (igenerator->module->entries, ginode,
+                                     (GCompareFunc) g_idl_node_cmp);
+             g_hash_table_insert (igenerator->type_map, ginode->node.name,
+                                  ginode);
+             g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                                  lower_case_prefix, ginode);
+             ginode->gtype_name = ginode->node.name;
+             ginode->gtype_init = get_type_symbol;
+
+             GEnumClass *type_class = g_type_class_ref (type_id);
+             for (i = 0; i < type_class->n_values; i++)
+               {
+                 GIdlNodeValue *gival =
+                   (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+                 ginode->values = g_list_append (ginode->values, gival);
+                 gival->node.name =
+                   g_strdup (type_class->values[i].value_name);
+                 gival->value = type_class->values[i].value;
+               }
+           }
+         else if (type_fundamental == G_TYPE_FLAGS)
+           {
+             GIdlNodeEnum *ginode =
+               (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
+             ginode->node.name = g_strdup (g_type_name (type_id));
+             igenerator->module->entries =
+               g_list_insert_sorted (igenerator->module->entries, ginode,
+                                     (GCompareFunc) g_idl_node_cmp);
+             g_hash_table_insert (igenerator->type_map, ginode->node.name,
+                                  ginode);
+             g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                                  lower_case_prefix, ginode);
+             ginode->gtype_name = ginode->node.name;
+             ginode->gtype_init = get_type_symbol;
+
+             GFlagsClass *type_class = g_type_class_ref (type_id);
+             for (i = 0; i < type_class->n_values; i++)
+               {
+                 GIdlNodeValue *gival =
+                   (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+                 ginode->values = g_list_append (ginode->values, gival);
+                 gival->node.name =
+                   g_strdup (type_class->values[i].value_name);
+                 gival->value = type_class->values[i].value;
+               }
+           }
+       }
+    }
+}
+
+static GIdlNodeType *
+get_type_from_ctype (CType * ctype)
+{
+  GIdlNodeType *gitype = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+  if (ctype->type == CTYPE_VOID)
+    {
+      gitype->unparsed = g_strdup ("void");
+    }
+  else if (ctype->type == CTYPE_BASIC_TYPE)
+    {
+      gitype->unparsed = g_strdup (ctype->name);
+    }
+  else if (ctype->type == CTYPE_TYPEDEF)
+    {
+      gitype->unparsed = g_strdup (ctype->name);
+    }
+  else if (ctype->type == CTYPE_STRUCT)
+    {
+      if (ctype->name == NULL)
+       {
+         /* anonymous struct */
+         gitype->unparsed = g_strdup ("gpointer");
+       }
+      else
+       {
+         gitype->unparsed = g_strdup_printf ("struct %s", ctype->name);
+       }
+    }
+  else if (ctype->type == CTYPE_UNION)
+    {
+      if (ctype->name == NULL)
+       {
+         /* anonymous union */
+         gitype->unparsed = g_strdup ("gpointer");
+       }
+      else
+       {
+         gitype->unparsed = g_strdup_printf ("union %s", ctype->name);
+       }
+    }
+  else if (ctype->type == CTYPE_ENUM)
+    {
+      if (ctype->name == NULL)
+       {
+         /* anonymous enum */
+         gitype->unparsed = g_strdup ("gint");
+       }
+      else
+       {
+         gitype->unparsed = g_strdup_printf ("enum %s", ctype->name);
+       }
+    }
+  else if (ctype->type == CTYPE_POINTER)
+    {
+      if (ctype->base_type->type == CTYPE_FUNCTION)
+       {
+         /* anonymous function pointer */
+         gitype->unparsed = g_strdup ("GCallback");
+       }
+      else
+       {
+         GIdlNodeType *gibasetype = get_type_from_ctype (ctype->base_type);
+         gitype->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
+       }
+    }
+  else if (ctype->type == CTYPE_ARRAY)
+    {
+      GIdlNodeType *gibasetype = get_type_from_ctype (ctype->base_type);
+      gitype->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
+    }
+  else
+    {
+      gitype->unparsed = g_strdup ("unknown");
+    }
+  return gitype;
+}
+
+static void
+g_igenerator_process_function_symbol (GIGenerator * igenerator, CSymbol * sym)
+{
+  GIdlNodeFunction *gifunc =
+    (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
+  /* check whether this is a type method */
+  char *last_underscore = strrchr (sym->ident, '_');
+  while (last_underscore != NULL)
+    {
+      char *prefix =
+       str_replace (g_strndup (sym->ident, last_underscore - sym->ident),
+                    "_", "");
+      GIdlNode *ginode =
+       g_hash_table_lookup (igenerator->type_by_lower_case_prefix, prefix);
+      if (ginode != NULL)
+       {
+         gifunc->node.name = g_strdup (last_underscore + 1);
+         if (strcmp (gifunc->node.name, "get_type") == 0)
+           {
+             /* ignore get_type functions in registered types */
+             return;
+           }
+         if ((ginode->type == G_IDL_NODE_OBJECT
+              || ginode->type == G_IDL_NODE_BOXED)
+             && g_str_has_prefix (gifunc->node.name, "new"))
+           {
+             gifunc->is_constructor = TRUE;
+           }
+         else
+           {
+             gifunc->is_method = TRUE;
+           }
+         if (ginode->type == G_IDL_NODE_OBJECT
+             || ginode->type == G_IDL_NODE_INTERFACE)
+           {
+             GIdlNodeInterface *giiface = (GIdlNodeInterface *) ginode;
+             giiface->members =
+               g_list_insert_sorted (giiface->members, gifunc,
+                                     (GCompareFunc) g_idl_node_cmp);
+             break;
+           }
+         else if (ginode->type == G_IDL_NODE_BOXED)
+           {
+             GIdlNodeBoxed *giboxed = (GIdlNodeBoxed *) ginode;
+             giboxed->members =
+               g_list_insert_sorted (giboxed->members, gifunc,
+                                     (GCompareFunc) g_idl_node_cmp);
+             break;
+           }
+         else if (ginode->type == G_IDL_NODE_STRUCT)
+           {
+             GIdlNodeStruct *gistruct = (GIdlNodeStruct *) ginode;
+             gistruct->members =
+               g_list_insert_sorted (gistruct->members, gifunc,
+                                     (GCompareFunc) g_idl_node_cmp);
+             break;
+           }
+         else if (ginode->type == G_IDL_NODE_UNION)
+           {
+             GIdlNodeUnion *giunion = (GIdlNodeUnion *) ginode;
+             giunion->members =
+               g_list_insert_sorted (giunion->members, gifunc,
+                                     (GCompareFunc) g_idl_node_cmp);
+             break;
+           }
+       }
+      else if (strcmp (igenerator->lower_case_namespace, prefix) == 0)
+       {
+         gifunc->node.name = g_strdup (last_underscore + 1);
+         gifunc->is_constructor = FALSE;
+         gifunc->is_method = FALSE;
+         igenerator->module->entries =
+           g_list_insert_sorted (igenerator->module->entries, gifunc,
+                                 (GCompareFunc) g_idl_node_cmp);
+         break;
+       }
+      last_underscore =
+       g_utf8_strrchr (sym->ident, last_underscore - sym->ident, '_');
+    }
+
+  /* create a namespace function if no prefix matches */
+  if (gifunc->node.name == NULL)
+    {
+      gifunc->node.name = sym->ident;
+      gifunc->is_constructor = FALSE;
+      gifunc->is_method = FALSE;
+      igenerator->module->entries =
+       g_list_insert_sorted (igenerator->module->entries, gifunc,
+                             (GCompareFunc) g_idl_node_cmp);
+    }
+
+  gifunc->symbol = sym->ident;
+  gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+  gifunc->result->type = get_type_from_ctype (sym->base_type->base_type);
+  GList *param_l;
+  int i;
+  for (param_l = sym->base_type->child_list, i = 1; param_l != NULL;
+       param_l = param_l->next, i++)
+    {
+      CSymbol *param_sym = param_l->data;
+      GIdlNodeParam *param =
+       (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+      if (param_sym->ident == NULL)
+       {
+         param->node.name = g_strdup_printf ("p%d", i);
+       }
+      else
+       {
+         param->node.name = param_sym->ident;
+       }
+      param->type = get_type_from_ctype (param_sym->base_type);
+      gifunc->parameters = g_list_append (gifunc->parameters, param);
+    }
+}
+
+static void
+g_igenerator_process_unregistered_struct_typedef (GIGenerator * igenerator,
+                                                 CSymbol * sym,
+                                                 CType * struct_type)
+{
+  GIdlNodeStruct *ginode =
+    (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+  ginode->node.name = sym->ident;
+  igenerator->module->entries =
+    g_list_insert_sorted (igenerator->module->entries, ginode,
+                         (GCompareFunc) g_idl_node_cmp);
+  char *lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+  g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+  g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                      lower_case_prefix, ginode);
+
+  GList *member_l;
+  for (member_l = struct_type->child_list; member_l != NULL;
+       member_l = member_l->next)
+    {
+      CSymbol *member = member_l->data;
+      GIdlNodeField *gifield =
+       (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+      ginode->members = g_list_append (ginode->members, gifield);
+      gifield->node.name = member->ident;
+      gifield->type = get_type_from_ctype (member->base_type);
+    }
+}
+
+static void
+g_igenerator_process_struct_typedef (GIGenerator * igenerator, CSymbol * sym)
+{
+  CType *struct_type = sym->base_type;
+  gboolean opaque_type = FALSE;
+  if (struct_type->child_list == NULL)
+    {
+      g_assert (struct_type->name != NULL);
+      CSymbol *struct_symbol =
+       g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
+                            struct_type->name);
+      if (struct_symbol != NULL)
+       {
+         struct_type = struct_symbol->base_type;
+       }
+    }
+  if (struct_type->child_list == NULL)
+    {
+      opaque_type = TRUE;
+    }
+  GIdlNode *gitype = g_hash_table_lookup (igenerator->type_map, sym->ident);
+  if (gitype != NULL)
+    {
+      /* struct of a GTypeInstance */
+      if (!opaque_type
+         && (gitype->type == G_IDL_NODE_OBJECT
+             || gitype->type == G_IDL_NODE_INTERFACE))
+       {
+         GIdlNodeInterface *ginode = (GIdlNodeInterface *) gitype;
+         GList *member_l;
+         /* ignore first field => parent */
+         for (member_l = struct_type->child_list->next; member_l != NULL;
+              member_l = member_l->next)
+           {
+             CSymbol *member = member_l->data;
+             /* ignore private / reserved members */
+             if (member->ident[0] == '_'
+                 || g_str_has_prefix (member->ident, "priv"))
+               {
+                 continue;
+               }
+             GIdlNodeField *gifield =
+               (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+             ginode->members = g_list_append (ginode->members, gifield);
+             gifield->node.name = member->ident;
+             gifield->type = get_type_from_ctype (member->base_type);
+           }
+       }
+      else if (gitype->type == G_IDL_NODE_BOXED)
+       {
+         GIdlNodeBoxed *ginode = (GIdlNodeBoxed *) gitype;
+         GList *member_l;
+         for (member_l = struct_type->child_list; member_l != NULL;
+              member_l = member_l->next)
+           {
+             CSymbol *member = member_l->data;
+             GIdlNodeField *gifield =
+               (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+             ginode->members = g_list_append (ginode->members, gifield);
+             gifield->node.name = member->ident;
+             gifield->type = get_type_from_ctype (member->base_type);
+           }
+       }
+    }
+  else if (!opaque_type
+          && (g_str_has_suffix (sym->ident, "Class")
+              || g_str_has_suffix (sym->ident, "Iface")
+              || g_str_has_suffix (sym->ident, "Interface")))
+    {
+      char *base_name;
+      if (g_str_has_suffix (sym->ident, "Interface"))
+       {
+         base_name =
+           g_strndup (sym->ident,
+                      strlen (sym->ident) - strlen ("Interface"));
+       }
+      else
+       {
+         base_name =
+           g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class"));
+       }
+      gitype = g_hash_table_lookup (igenerator->type_map, base_name);
+      if (gitype == NULL
+         || (gitype->type != G_IDL_NODE_OBJECT
+             && gitype->type != G_IDL_NODE_INTERFACE))
+       {
+         g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
+                                                           struct_type);
+         return;
+       }
+      GIdlNodeInterface *ginode = (GIdlNodeInterface *) gitype;
+
+      /* ignore first field => parent */
+      GList *member_l;
+      for (member_l = struct_type->child_list->next; member_l != NULL;
+          member_l = member_l->next)
+       {
+         CSymbol *member = member_l->data;
+         /* ignore private / reserved members */
+         if (member->ident[0] == '_')
+           {
+             continue;
+           }
+         if (member->base_type->type == CTYPE_POINTER
+             && member->base_type->base_type->type == CTYPE_FUNCTION)
+           {
+             /* ignore default handlers of signals */
+             gboolean found_signal = FALSE;
+             GList *type_member_l;
+             for (type_member_l = ginode->members; type_member_l != NULL;
+                  type_member_l = type_member_l->next)
+               {
+                 GIdlNode *type_member = type_member_l->data;
+                 char *normalized_name =
+                   str_replace (type_member->name, "-", "_");
+                 if (type_member->type == G_IDL_NODE_SIGNAL
+                     && strcmp (normalized_name, member->ident) == 0)
+                   {
+                     GList *vfunc_param_l;
+                     GList *sig_param_l;
+                     GIdlNodeSignal *sig = (GIdlNodeSignal *) type_member;
+                     found_signal = TRUE;
+                     /* set signal parameter names */
+                     for (vfunc_param_l =
+                          member->base_type->base_type->child_list,
+                          sig_param_l = sig->parameters;
+                          vfunc_param_l != NULL && sig_param_l != NULL;
+                          vfunc_param_l = vfunc_param_l->next, sig_param_l =
+                          sig_param_l->next)
+                       {
+                         CSymbol *vfunc_param = vfunc_param_l->data;
+                         GIdlNodeParam *sig_param = sig_param_l->data;
+                         if (vfunc_param->ident != NULL)
+                           {
+                             g_free (sig_param->node.name);
+                             sig_param->node.name =
+                               g_strdup (vfunc_param->ident);
+                           }
+                       }
+                     break;
+                   }
+               }
+             if (found_signal)
+               {
+                 continue;
+               }
+
+             GIdlNodeVFunc *givfunc =
+               (GIdlNodeVFunc *) g_idl_node_new (G_IDL_NODE_VFUNC);
+             givfunc->node.name = member->ident;
+             ginode->members =
+               g_list_insert_sorted (ginode->members, givfunc,
+                                     (GCompareFunc) g_idl_node_cmp);
+             givfunc->result =
+               (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+             givfunc->result->type =
+               get_type_from_ctype (member->base_type->base_type->base_type);
+             GList *param_l;
+             int i;
+             for (param_l = member->base_type->base_type->child_list, i = 1;
+                  param_l != NULL; param_l = param_l->next, i++)
+               {
+                 CSymbol *param_sym = param_l->data;
+                 GIdlNodeParam *param =
+                   (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+                 if (param_sym->ident == NULL)
+                   {
+                     param->node.name = g_strdup_printf ("p%d", i);
+                   }
+                 else
+                   {
+                     param->node.name = param_sym->ident;
+                   }
+                 param->type = get_type_from_ctype (param_sym->base_type);
+                 givfunc->parameters =
+                   g_list_append (givfunc->parameters, param);
+               }
+           }
+       }
+    }
+  else if (g_str_has_suffix (sym->ident, "Private"))
+    {
+      /* ignore private structs */
+    }
+  else
+    {
+      g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
+                                                       struct_type);
+    }
+}
+
+static void
+g_igenerator_process_union_typedef (GIGenerator * igenerator, CSymbol * sym)
+{
+  CType *union_type = sym->base_type;
+  gboolean opaque_type = FALSE;
+  if (union_type->child_list == NULL)
+    {
+      g_assert (union_type->name != NULL);
+      CSymbol *union_symbol =
+       g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
+                            union_type->name);
+      if (union_symbol != NULL)
+       {
+         union_type = union_symbol->base_type;
+       }
+    }
+  if (union_type->child_list == NULL)
+    {
+      opaque_type = TRUE;
+    }
+  GIdlNode *gitype = g_hash_table_lookup (igenerator->type_map, sym->ident);
+  if (gitype != NULL)
+    {
+      g_assert (gitype->type == G_IDL_NODE_BOXED);
+      GIdlNodeBoxed *ginode = (GIdlNodeBoxed *) gitype;
+      GList *member_l;
+      for (member_l = union_type->child_list; member_l != NULL;
+          member_l = member_l->next)
+       {
+         CSymbol *member = member_l->data;
+         GIdlNodeField *gifield =
+           (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+         ginode->members = g_list_append (ginode->members, gifield);
+         gifield->node.name = member->ident;
+         gifield->type = get_type_from_ctype (member->base_type);
+       }
+    }
+  else
+    {
+      GIdlNodeUnion *ginode =
+       (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
+      ginode->node.name = sym->ident;
+      igenerator->module->entries =
+       g_list_insert_sorted (igenerator->module->entries, ginode,
+                             (GCompareFunc) g_idl_node_cmp);
+      char *lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+      g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+      g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                          lower_case_prefix, ginode);
+
+      ginode->node.name = sym->ident;
+      GList *member_l;
+      for (member_l = union_type->child_list; member_l != NULL;
+          member_l = member_l->next)
+       {
+         CSymbol *member = member_l->data;
+         GIdlNodeField *gifield =
+           (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+         ginode->members = g_list_append (ginode->members, gifield);
+         gifield->node.name = member->ident;
+         gifield->type = get_type_from_ctype (member->base_type);
+       }
+    }
+}
+
+static void
+g_igenerator_process_enum_typedef (GIGenerator * igenerator, CSymbol * sym)
+{
+  CType *enum_type = sym->base_type;
+  if (enum_type->child_list == NULL)
+    {
+      g_assert (enum_type->name != NULL);
+      CSymbol *enum_symbol =
+       g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
+                            enum_type->name);
+      if (enum_symbol != NULL)
+       {
+         enum_type = enum_symbol->base_type;
+       }
+    }
+  if (enum_type->child_list == NULL)
+    {
+      /* opaque type */
+      return;
+    }
+  GIdlNodeEnum *ginode =
+    g_hash_table_lookup (igenerator->type_map, sym->ident);
+  if (ginode != NULL)
+    {
+      return;
+    }
+
+  ginode = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+  ginode->node.name = sym->ident;
+  igenerator->module->entries =
+    g_list_insert_sorted (igenerator->module->entries, ginode,
+                         (GCompareFunc) g_idl_node_cmp);
+
+  GList *member_l;
+  for (member_l = enum_type->child_list; member_l != NULL;
+       member_l = member_l->next)
+    {
+      CSymbol *member = member_l->data;
+      GIdlNodeValue *gival =
+       (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+      ginode->values = g_list_append (ginode->values, gival);
+      gival->node.name = member->ident;
+      gival->value = member->const_int;
+    }
+}
+
+static void
+g_igenerator_process_function_typedef (GIGenerator * igenerator,
+                                      CSymbol * sym)
+{
+  /* handle callback types */
+  GIdlNodeFunction *gifunc =
+    (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_CALLBACK);
+
+  gifunc->node.name = sym->ident;
+  igenerator->module->entries =
+    g_list_insert_sorted (igenerator->module->entries, gifunc,
+                         (GCompareFunc) g_idl_node_cmp);
+
+  gifunc->symbol = sym->ident;
+  gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+  gifunc->result->type =
+    get_type_from_ctype (sym->base_type->base_type->base_type);
+  GList *param_l;
+  int i;
+  for (param_l = sym->base_type->base_type->child_list, i = 1;
+       param_l != NULL; param_l = param_l->next, i++)
+    {
+      CSymbol *param_sym = param_l->data;
+      GIdlNodeParam *param =
+       (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+      if (param_sym->ident == NULL)
+       {
+         param->node.name = g_strdup_printf ("p%d", i);
+       }
+      else
+       {
+         param->node.name = param_sym->ident;
+       }
+      param->type = get_type_from_ctype (param_sym->base_type);
+      gifunc->parameters = g_list_append (gifunc->parameters, param);
+    }
+}
+
+static void
+g_igenerator_process_constant (GIGenerator * igenerator, CSymbol * sym)
+{
+  GIdlNodeConstant *giconst =
+    (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+  giconst->node.name = sym->ident;
+  igenerator->module->entries =
+    g_list_insert_sorted (igenerator->module->entries, giconst,
+                         (GCompareFunc) g_idl_node_cmp);
+
+  giconst->type = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+  if (sym->const_int_set)
+    {
+      giconst->type->unparsed = g_strdup ("int");
+      giconst->value = g_strdup_printf ("%d", sym->const_int);
+    }
+  else if (sym->const_string != NULL)
+    {
+      giconst->type->unparsed = g_strdup ("char*");
+      giconst->value = sym->const_string;
+    }
+}
+
+static void
+g_igenerator_process_symbols (GIGenerator * igenerator)
+{
+  GList *l;
+  /* process type symbols first to ensure complete type hashtables */
+  /* type symbols */
+  for (l = igenerator->symbol_list; l != NULL; l = l->next)
+    {
+      CSymbol *sym = l->data;
+      if (sym->ident[0] == '_')
+       {
+         /* ignore private / reserved symbols */
+         continue;
+       }
+      if (sym->type == CSYMBOL_TYPE_TYPEDEF)
+       {
+         if (sym->base_type->type == CTYPE_STRUCT)
+           {
+             g_igenerator_process_struct_typedef (igenerator, sym);
+           }
+         else if (sym->base_type->type == CTYPE_UNION)
+           {
+             g_igenerator_process_union_typedef (igenerator, sym);
+           }
+         else if (sym->base_type->type == CTYPE_ENUM)
+           {
+             g_igenerator_process_enum_typedef (igenerator, sym);
+           }
+         else if (sym->base_type->type == CTYPE_POINTER
+                  && sym->base_type->base_type->type == CTYPE_FUNCTION)
+           {
+             g_igenerator_process_function_typedef (igenerator, sym);
+           }
+         else
+           {
+             GIdlNodeStruct *ginode =
+               (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+             ginode->node.name = sym->ident;
+             igenerator->module->entries =
+               g_list_insert_sorted (igenerator->module->entries, ginode,
+                                     (GCompareFunc) g_idl_node_cmp);
+             char *lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+             g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+             g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+                                  lower_case_prefix, ginode);
+           }
+       }
+    }
+  /* other symbols */
+  for (l = igenerator->symbol_list; l != NULL; l = l->next)
+    {
+      CSymbol *sym = l->data;
+      if (sym->ident[0] == '_')
+       {
+         /* ignore private / reserved symbols */
+         continue;
+       }
+      if (sym->type == CSYMBOL_TYPE_FUNCTION)
+       {
+         g_igenerator_process_function_symbol (igenerator, sym);
+       }
+      else if (sym->type == CSYMBOL_TYPE_CONST)
+       {
+         g_igenerator_process_constant (igenerator, sym);
+       }
+    }
+}
+
+void
+g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol)
+{
+  /* only add symbols of main file */
+  gboolean found_filename = FALSE;
+  GList *l;
+  for (l = igenerator->filenames; l != NULL; l = l->next)
+    {
+      if (strcmp (l->data, igenerator->current_filename) == 0)
+       {
+         found_filename = TRUE;
+         break;
+       }
+    }
+  if (found_filename || igenerator->macro_scan)
+    {
+      igenerator->symbol_list =
+       g_list_prepend (igenerator->symbol_list, symbol);
+    }
+
+  if (symbol->type == CSYMBOL_TYPE_TYPEDEF)
+    {
+      g_hash_table_insert (igenerator->typedef_table, symbol->ident, symbol);
+    }
+  else if (symbol->type == CSYMBOL_TYPE_STRUCT
+          || symbol->type == CSYMBOL_TYPE_UNION
+          || symbol->type == CSYMBOL_TYPE_ENUM)
+    {
+      g_hash_table_insert (igenerator->struct_or_union_or_enum_table,
+                          symbol->ident, symbol);
+    }
+}
+
+gboolean
+g_igenerator_is_typedef (GIGenerator * igenerator, const char *name)
+{
+  gboolean b = g_hash_table_lookup (igenerator->typedef_table, name) != NULL;
+  return b;
+}
+
+void
+g_igenerator_generate (GIGenerator * igenerator)
+{
+  GList *l;
+  for (l = igenerator->symbol_list; l != NULL; l = l->next)
+    {
+      CSymbol *sym = l->data;
+      if (sym->type == CSYMBOL_TYPE_FUNCTION
+         && g_str_has_suffix (sym->ident, "_get_type"))
+       {
+         if (sym->base_type->child_list == NULL)
+           {
+             // ignore get_type functions with parameters
+             igenerator->get_type_symbols =
+               g_list_prepend (igenerator->get_type_symbols, sym->ident);
+           }
+       }
+    }
+  g_igenerator_process_types (igenerator);
+  g_igenerator_process_symbols (igenerator);
+
+  g_igenerator_write (igenerator, "<?xml version=\"1.0\"?>\n");
+  g_igenerator_write_indent (igenerator, "<api version=\"1.0\">\n");
+  module_generate (igenerator, igenerator->module);
+  g_igenerator_write_unindent (igenerator, "</api>\n");
+}
+
+int
+main (int argc, char **argv)
+{
+  g_type_init ();
+
+  /* initialize threading as this may be required by libraries that we'll use */
+  g_thread_init (NULL);
+
+  GIGenerator *igenerator = g_igenerator_new ();
+
+  int cpp_argc = 0;
+  char **cpp_argv = g_new0 (char *, argc + 2);
+  cpp_argv[cpp_argc++] = "cc";
+  cpp_argv[cpp_argc++] = "-E";
+
+  int i;
+  for (i = 1; i < argc; i++)
+    {
+      if (argv[i][0] == '-')
+       {
+         switch (argv[i][1])
+           {
+           case '-':
+             if (g_str_has_prefix (argv[i], "--namespace="))
+               {
+                 igenerator->namespace = argv[i] + strlen ("--namespace=");
+                 g_free (igenerator->lower_case_namespace);
+                 igenerator->lower_case_namespace =
+                   g_ascii_strdown (igenerator->namespace, -1);
+               }
+             break;
+           case 'I':
+           case 'D':
+           case 'U':
+             cpp_argv[cpp_argc++] = argv[i];
+             break;
+           }
+       }
+      else if (g_str_has_suffix (argv[i], ".h"))
+       {
+         igenerator->filenames =
+           g_list_append (igenerator->filenames, argv[i]);
+       }
+      else if (g_str_has_suffix (argv[i], ".la") ||
+              g_str_has_suffix (argv[i], ".so") ||
+              g_str_has_suffix (argv[i], ".dll"))
+       {
+         igenerator->libraries =
+           g_list_append (igenerator->libraries, argv[i]);
+       }
+    }
+
+
+  GError *error = NULL;
+
+  char *tmp_name = NULL;
+  FILE *f =
+    fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
+           "w");
+
+
+  GList *l;
+  for (l = igenerator->filenames; l != NULL; l = l->next)
+    {
+      fprintf (f, "#include <%s>\n", (char *) l->data);
+    }
+
+
+  fclose (f);
+
+  cpp_argv[cpp_argc++] = tmp_name;
+  cpp_argv[cpp_argc++] = NULL;
+
+  int cpp_out = -1;
+  g_spawn_async_with_pipes (NULL, cpp_argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
+                           NULL, NULL, NULL, &cpp_out, NULL, &error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  g_igenerator_parse (igenerator, fdopen (cpp_out, "r"));
+
+  g_unlink (tmp_name);
+
+  g_igenerator_parse_macros (igenerator);
+
+  igenerator->module = g_idl_module_new (igenerator->namespace);
+  g_igenerator_generate (igenerator);
+
+  return 0;
+}
+
+CSymbol *
+csymbol_new (CSymbolType type)
+{
+  CSymbol *s = g_new0 (CSymbol, 1);
+  s->type = type;
+  return s;
+}
+
+gboolean
+csymbol_get_const_boolean (CSymbol * symbol)
+{
+  return (symbol->const_int_set && symbol->const_int) || symbol->const_string;
+}
+
+CType *
+ctype_new (CTypeType type)
+{
+  CType *t = g_new0 (CType, 1);
+  t->type = type;
+  return t;
+}
+
+CType *
+ctype_copy (CType * type)
+{
+  return g_memdup (type, sizeof (CType));
+}
+
+CType *
+cbasic_type_new (const char *name)
+{
+  CType *basic_type = ctype_new (CTYPE_BASIC_TYPE);
+  basic_type->name = g_strdup (name);
+  return basic_type;
+}
+
+CType *
+ctypedef_new (const char *name)
+{
+  CType *typedef_ = ctype_new (CTYPE_TYPEDEF);
+  typedef_->name = g_strdup (name);
+  return typedef_;
+}
+
+CType *
+cstruct_new (const char *name)
+{
+  CType *struct_ = ctype_new (CTYPE_STRUCT);
+  struct_->name = g_strdup (name);
+  return struct_;
+}
+
+CType *
+cunion_new (const char *name)
+{
+  CType *union_ = ctype_new (CTYPE_UNION);
+  union_->name = g_strdup (name);
+  return union_;
+}
+
+CType *
+cenum_new (const char *name)
+{
+  CType *enum_ = ctype_new (CTYPE_ENUM);
+  enum_->name = g_strdup (name);
+  return enum_;
+}
+
+CType *
+cpointer_new (CType * base_type)
+{
+  CType *pointer = ctype_new (CTYPE_POINTER);
+  pointer->base_type = base_type;
+  return pointer;
+}
+
+CType *
+carray_new (void)
+{
+  CType *array = ctype_new (CTYPE_ARRAY);
+  return array;
+}
+
+CType *
+cfunction_new (void)
+{
+  CType *func = ctype_new (CTYPE_FUNCTION);
+  return func;
+}
+
+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 (isalnum (c) || c == '_')
+    {
+      g_string_append_c (id, c);
+      c = fgetc (f);
+    }
+  *identifier = g_string_free (id, FALSE);
+  return c;
+}
+
+static void
+g_igenerator_parse_macros (GIGenerator * igenerator)
+{
+  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 = igenerator->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);
+    }
+
+  igenerator->macro_scan = TRUE;
+  rewind (fmacros);
+  g_igenerator_parse (igenerator, fmacros);
+  igenerator->macro_scan = FALSE;
+}
diff --git a/src/gen-introspect.h b/src/gen-introspect.h
new file mode 100644 (file)
index 0000000..23f0aa0
--- /dev/null
@@ -0,0 +1,162 @@
+/* GObject introspection: gen-introspect
+ *
+ * Copyright (C) 2007  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+#ifndef __GEN_INTROSPECT_H__
+#define __GEN_INTROSPECT_H__
+
+#include <glib.h>
+#include "gidlmodule.h"
+
+G_BEGIN_DECLS typedef struct _GIGenerator GIGenerator;
+typedef struct _CSymbol CSymbol;
+typedef struct _CType CType;
+
+struct _GIGenerator
+{
+  const char *namespace;
+  char *lower_case_namespace;
+  /* specified files to be parsed */
+  GList *filenames;
+  GList *libraries;
+  /* source reference of current lexer position */
+  char *current_filename;
+  GList *symbol_list;
+  GHashTable *typedef_table;
+  GHashTable *struct_or_union_or_enum_table;
+
+  gboolean macro_scan;
+
+  GIdlModule *module;
+  GList *get_type_symbols;
+  GHashTable *type_map;
+  GHashTable *type_by_lower_case_prefix;
+
+  int indent;
+};
+
+GIGenerator *g_igenerator_new (void);
+void g_igenerator_parse (GIGenerator * igenerator, FILE * f);
+void g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol);
+gboolean g_igenerator_is_typedef (GIGenerator * igenerator, const char *name);
+void g_igenerator_generate (GIGenerator * igenerator);
+
+GIGenerator *the_igenerator;
+
+typedef enum
+{
+  CSYMBOL_TYPE_INVALID,
+  CSYMBOL_TYPE_CONST,
+  CSYMBOL_TYPE_OBJECT,
+  CSYMBOL_TYPE_FUNCTION,
+  CSYMBOL_TYPE_STRUCT,
+  CSYMBOL_TYPE_UNION,
+  CSYMBOL_TYPE_ENUM,
+  CSYMBOL_TYPE_TYPEDEF
+} CSymbolType;
+
+struct _CSymbol
+{
+  CSymbolType type;
+  int id;
+  char *ident;
+  CType *base_type;
+  gboolean const_int_set;
+  int const_int;
+  char *const_string;
+};
+
+CSymbol *csymbol_new (CSymbolType type);
+gboolean csymbol_get_const_boolean (CSymbol * symbol);
+
+typedef enum
+{
+  CTYPE_INVALID,
+  CTYPE_VOID,
+  CTYPE_BASIC_TYPE,
+  CTYPE_TYPEDEF,
+  CTYPE_STRUCT,
+  CTYPE_UNION,
+  CTYPE_ENUM,
+  CTYPE_POINTER,
+  CTYPE_ARRAY,
+  CTYPE_FUNCTION
+} CTypeType;
+
+typedef enum
+{
+  STORAGE_CLASS_NONE = 0,
+  STORAGE_CLASS_TYPEDEF = 1 << 1,
+  STORAGE_CLASS_EXTERN = 1 << 2,
+  STORAGE_CLASS_STATIC = 1 << 3,
+  STORAGE_CLASS_AUTO = 1 << 4,
+  STORAGE_CLASS_REGISTER = 1 << 5
+} StorageClassSpecifier;
+
+typedef enum
+{
+  TYPE_QUALIFIER_NONE = 0,
+  TYPE_QUALIFIER_CONST = 1 << 1,
+  TYPE_QUALIFIER_RESTRICT = 1 << 2,
+  TYPE_QUALIFIER_VOLATILE = 1 << 3
+} TypeQualifier;
+
+typedef enum
+{
+  FUNCTION_NONE = 0,
+  FUNCTION_INLINE = 1 << 1
+} FunctionSpecifier;
+
+typedef enum
+{
+  UNARY_ADDRESS_OF,
+  UNARY_POINTER_INDIRECTION,
+  UNARY_PLUS,
+  UNARY_MINUS,
+  UNARY_BITWISE_COMPLEMENT,
+  UNARY_LOGICAL_NEGATION
+} UnaryOperator;
+
+struct _CType
+{
+  CTypeType type;
+  StorageClassSpecifier storage_class_specifier;
+  TypeQualifier type_qualifier;
+  FunctionSpecifier function_specifier;
+  char *name;
+  CType *base_type;
+  GList *child_list;
+};
+
+CType *ctype_new (CTypeType type);
+CType *ctype_copy (CType * type);
+CType *cbasic_type_new (const char *name);
+CType *ctypedef_new (const char *name);
+CType *cstruct_new (const char *name);
+CType *cunion_new (const char *name);
+CType *cenum_new (const char *name);
+CType *cpointer_new (CType * base_type);
+CType *carray_new (void);
+CType *cfunction_new (void);
+
+G_END_DECLS
+#endif