]> git.draconx.ca Git - gob-dx.git/blobdiff - src/parse.y
Release 2.0.13
[gob-dx.git] / src / parse.y
index 36f9abc19c338fbb3e39e42edcab411bae14743d..53d32eb3d055fd0f82314be3b71b8adbeccedaaa 100644 (file)
@@ -1,6 +1,7 @@
 /* GOB C Preprocessor
  * Copyright (C) 1999-2000 the Free Software Foundation.
- * Copyright (C) 2001 George Lebl
+ * Copyright (C) 2000 Eazel, Inc.
+ * Copyright (C) 2001-2004 George (Jiri) Lebl
  *
  * Author: George Lebl
  *
 #include "main.h"
 #include "util.h"
 
+/* FIXME: add gettext support */
 #define _(x) (x)
        
 GList *nodes = NULL;
 
 static GList *class_nodes = NULL;
 Node *class = NULL;
+GList *enums = NULL;
+static GList *enum_vals = NULL;
+static GList *flag_vals = NULL;
+static GList *error_vals = NULL;
 
+static gboolean abstract = FALSE;
 static char *chunk_size = NULL;
-static char *bonobo_x_class = NULL;
+static char *bonobo_object_class = NULL;
+static int glade_xml = FALSE;
+static GList *interfaces = NULL;
 static GList *typestack = NULL;
 static GList *funcargs = NULL;
 static GList *checks = NULL;
@@ -54,6 +63,7 @@ static int destructor_line = 0;
 static gboolean destructor_simple = TRUE;
 static char *initializer = NULL;
 static int initializer_line = 0;
+static int glade_widget = FALSE;
 
 static char *onerror = NULL;
 static char *defreturn = NULL;
@@ -71,6 +81,7 @@ int yylex(void);
 
 extern int ccode_line;
 extern int line_no;
+extern gboolean for_cpp;
 
 extern char *yytext;
 
@@ -118,6 +129,7 @@ push_variable (char *name, int scope, int line_no, char *postfix)
        var = node_new (VARIABLE_NODE,
                        "scope", scope,
                        "vtype:steal", type,
+                       "glade_widget", glade_widget,
                        "id:steal", name,
                        "line_no", line_no,
                        "destructor_unref", destructor_unref,
@@ -126,8 +138,10 @@ push_variable (char *name, int scope, int line_no, char *postfix)
                        "destructor_simple", destructor_simple,
                        "initializer:steal", initializer,
                        "initializer_line", initializer_line,
+                       "initializer_simple", TRUE,
                        NULL);
        class_nodes = g_list_append(class_nodes, var);
+       glade_widget = FALSE;
 }
 
 static void
@@ -343,8 +357,8 @@ set_return_value(char *type, char *val)
 static void
 export_accessors (const char *var_name,
                  gboolean do_get,
-                 gboolean do_set,
                  int get_lineno,
+                 gboolean do_set,
                  int set_lineno,
                  Type *type,
                  const char *gtktype,
@@ -432,6 +446,62 @@ export_accessors (const char *var_name,
        node_free ((Node *)the_type);
 }
 
+static char *
+get_prop_enum_flag_cast (Property *prop)
+{
+       char *tmp, *ret;
+       if (prop->extra_gtktype == NULL ||
+       /* HACK!  just in case someone made this
+        * work with 2.0.0 by using the TYPE
+        * macro directly */
+           ((strstr (prop->extra_gtktype, "_TYPE_") != NULL ||
+             strstr (prop->extra_gtktype, "TYPE_") == prop->extra_gtktype) &&
+            strchr (prop->extra_gtktype, ':') == NULL)) {
+               if (prop->ptype != NULL)
+                       return get_type (prop->ptype, TRUE);
+               else
+                       return g_strdup ("");
+       }
+       tmp = remove_sep (prop->extra_gtktype);
+       ret = g_strdup_printf ("(%s) ", tmp);
+       g_free (tmp);
+       return ret;
+}
+
+static void
+add_construct_glade (char * file, char * root, char * domain)
+{
+       Node *var;
+       Type * type;
+       GList * flags = NULL;
+       
+       type = (Type *)node_new (TYPE_NODE,
+                                "name", "GladeXML",
+                                "pointer", "*",
+                                NULL);
+       initializer = g_strdup_printf("\t{\n"
+                                     "\tGtkWidget * root;\n"
+                                     "\t%%1$s->_priv->_glade_xml = glade_xml_new(%s, %s, %s);\n"
+                                     "\troot = glade_xml_get_widget(%%1$s->_priv->_glade_xml, %s);\n"
+                                     "\tgtk_widget_show(root);\n"
+                                     "\tgtk_container_add(GTK_CONTAINER(%%1$s), root);\n"
+                                     "\tglade_xml_signal_autoconnect_full(%%1$s->_priv->_glade_xml, (GladeXMLConnectFunc)___glade_xml_connect_foreach, (gpointer)%%1$s);\n"
+                                     "}\n", file, root, domain ? domain : "NULL", root);
+       
+       var = node_new (VARIABLE_NODE,
+                       "scope", PRIVATE_SCOPE,
+                       "vtype:steal", type,
+                       "glade_widget", FALSE,
+                       "id:steal", "_glade_xml",
+                       "destructor_unref", FALSE,
+                       "destructor", "g_object_unref", 
+                       "destructor_simple", TRUE,
+                       "initializer", initializer,
+                       "initializer_simple", FALSE,
+                       NULL);
+       class_nodes = g_list_prepend(class_nodes, var);
+}
+
 static void
 property_link_and_export (Node *node)
 {
@@ -462,38 +532,42 @@ property_link_and_export (Node *node)
                }
 
                if (strcmp (prop->gtktype, "STRING") == 0) {
-                       set = g_strdup_printf("g_free (%s->%s); "
-                                             "%s->%s = g_value_dup_string (VAL);",
+                       set = g_strdup_printf("{ char *old = %s->%s; "
+                                             "%s->%s = g_value_dup_string (VAL); g_free (old); }",
                                              root, prop->name,
                                              root, prop->name);
                        get = g_strdup_printf("g_value_set_string (VAL, %s->%s);",
                                              root, prop->name);
                } else if (strcmp (prop->gtktype, "OBJECT") == 0) {
-                       set = g_strdup_printf("{ GtkObject *___old = (GtkObject *)%s->%s; "
-                                             "GtkObject *___new = (GtkObject *)gtk_value_get_object (VAL); "
-                                             "if (___new != NULL) { "
-                                               "gtk_object_ref (GTK_OBJECT (___new)); "
-                                               "%s->%s = GTK_OBJECT (___new); "
-                                             "} else { "
-                                               "%s->%s = NULL; "
-                                             "} "
+                       char *cast;
+                       if (prop->extra_gtktype != NULL) {
+                               cast = remove_sep (prop->extra_gtktype);
+                       } else {
+                               cast = g_strdup ("void");
+                       }
+                       set = g_strdup_printf("{ GObject *___old = (GObject *)%s->%s; "
+                                             "%s->%s = (%s *)g_value_dup_object (VAL); "
                                              "if (___old != NULL) { "
-                                               "gtk_object_unref (GTK_OBJECT (___old)); "
+                                               "g_object_unref (G_OBJECT (___old)); "
                                              "} "
                                              "}",
                                              root, prop->name,
                                              root, prop->name,
-                                             root, prop->name);
-                       get = g_strdup_printf("g_value_set_object (VAL, %s->%s);",
-                                             root, prop->name);
+                                             cast);
+                       get = g_strdup_printf ("g_value_set_object (VAL, "
+                                              "(gpointer)%s->%s);",
+                                              root, prop->name);
+                       g_free (cast);
                } else if (strcmp (prop->gtktype, "BOXED") == 0) {
+                       char *type = make_me_type (prop->extra_gtktype,
+                                                  "G_TYPE_BOXED");
                        if (prop->extra_gtktype == NULL) {
                                error_print (GOB_ERROR, prop->line_no,
                                             _("Property linking requested for BOXED, but "
                                               "boxed_type not set"));
                        }
                        set = g_strdup_printf("{ gpointer ___old = (gpointer)%s->%s; "
-                                             "gpointer ___new = (gpointer)gtk_value_get_boxed (VAL); "
+                                             "gpointer ___new = (gpointer)g_value_get_boxed (VAL); "
                                              "if (___new != ___old) { "
                                                "if (___old != NULL) g_boxed_free (%s, ___old); "
                                                "if (___new != NULL) %s->%s = g_boxed_copy (%s, ___new); "
@@ -501,29 +575,53 @@ property_link_and_export (Node *node)
                                              "} "
                                              "}",
                                              root, prop->name,
-                                             prop->extra_gtktype,
+                                             type,
                                              root, prop->name,
-                                             prop->extra_gtktype,
+                                             type,
                                              root, prop->name);
-                       get = g_strdup_printf("g_value_set_object (VAL, %s->%s);",
+                       get = g_strdup_printf("g_value_set_boxed (VAL, %s->%s);",
                                              root, prop->name);
+                       g_free (type);
                } else {
                        char *set_func;
                        char *get_func;
+                       const char *getcast = "";
+                       const char *setcast = "";
+                       char *to_free = NULL;
                        set_func = g_strdup_printf ("g_value_set_%s", prop->gtktype);
                        g_strdown (set_func);
                        get_func = g_strdup_printf ("g_value_get_%s", prop->gtktype);
                        g_strdown (get_func);
 
-                       set = g_strdup_printf("%s->%s = %s (VAL);",
+                       if (for_cpp) {
+                               if (strcmp (prop->gtktype, "FLAGS") == 0) {
+                                       setcast = "(guint) ";
+                                       getcast = to_free =
+                                               get_prop_enum_flag_cast (prop);
+                               } else if (strcmp (prop->gtktype, "ENUM") == 0) {
+                                       setcast = "(gint) ";
+                                       getcast = to_free =
+                                               get_prop_enum_flag_cast (prop);
+                               }  else if (strcmp (prop->gtktype, "POINTER") == 0) {
+                                       setcast = "(gpointer) ";
+                                       getcast = g_strdup_printf ("(%s%s) ",
+                                                                 prop->ptype->name,
+                                                                 prop->ptype->pointer ? prop->ptype->pointer : "");
+                               }
+                       }
+
+                       set = g_strdup_printf("%s->%s = %s%s (VAL);",
                                              root, prop->name,
+                                             getcast,
                                              get_func);
-                       get = g_strdup_printf("%s (VAL, %s->%s);",
+                       get = g_strdup_printf("%s (VAL, %s%s->%s);",
                                              set_func,
+                                             setcast,  
                                              root, prop->name);
 
                        g_free (get_func);
                        g_free (set_func);
+                       g_free (to_free);
                }
 
                node_set (node,
@@ -537,7 +635,7 @@ property_link_and_export (Node *node)
        if (prop->export) {
                export_accessors (prop->name,
                                  prop->get != NULL, prop->get_line,
-                                 prop->set != NULL,  prop->get_line,
+                                 prop->set != NULL,  prop->set_line,
                                  prop->ptype,
                                  prop->gtktype,
                                  prop->line_no);
@@ -583,7 +681,7 @@ ensure_property (void)
 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING
 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE PROPERTY ARGUMENT
 %token <line> VIRTUAL SIGNAL OVERRIDE
-%token <line> NICK BLURB MAXIMUM MINIMUM DEFAULT_VALUE FLAGS TYPE
+%token <line> NICK BLURB MAXIMUM MINIMUM DEFAULT_VALUE ERROR FLAGS TYPE
 %token <line> FLAGS_TYPE ENUM_TYPE PARAM_TYPE BOXED_TYPE OBJECT_TYPE
 
 %%
@@ -651,7 +749,13 @@ ccode:             CCODE                   {
        ;
 
 ccodes:                ccodes ccode            { ; }
+       |       ccodes enumcode         { ; }
+       |       ccodes flagcode         { ; }
+       |       ccodes errorcode        { ; }
        |       ccode                   { ; }
+       |       enumcode                { ; }
+       |       flagcode                { ; }
+       |       errorcode               { ; }
        ;
 
 class:         classdec '{' classcode '}'      {
@@ -670,20 +774,44 @@ classdec: CLASS TYPETOKEN FROM TYPETOKEN  classflags {
                        class = node_new (CLASS_NODE,
                                          "otype:steal", $<id>2,
                                          "ptype:steal", $<id>4,
-                                         "bonobo_x_class:steal", bonobo_x_class,
+                                         "bonobo_object_class:steal", bonobo_object_class,
+                                         "glade_xml", glade_xml,
+                                         "interfaces:steal", interfaces,
                                          "chunk_size:steal", chunk_size,
+                                         "abstract", abstract,
                                          NULL);
+                       bonobo_object_class = NULL;
+                       glade_xml = FALSE;
+                       chunk_size = NULL;
+                       interfaces = NULL;
                                                }
        ;
 
 classflags:
+       | '(' TOKEN ')' classflags {
+                       if(strcmp($<id>2,"abstract") == 0) {
+                               abstract = TRUE;
+                       } else {
+                               yyerror(_("parse error"));
+                               YYERROR;
+                       }
+               }
        | '(' TOKEN TOKEN ')' classflags {
                        if(strcmp($<id>2,"chunks") == 0) {
                                g_free (chunk_size);
                                chunk_size = g_strdup($<id>3);
-                       } else if(strcmp($<id>2,"BonoboX") == 0) {
-                               g_free (bonobo_x_class);
-                               bonobo_x_class = g_strdup($<id>3);
+                       } else if(strcmp($<id>2,"BonoboObject") == 0) {
+                               g_free (bonobo_object_class);
+                               bonobo_object_class = g_strdup($<id>3);
+                       } else {
+                               yyerror(_("parse error"));
+                               YYERROR;
+                       }
+               }
+       | '(' TOKEN TYPETOKEN ')' classflags {
+                       if (strcmp ($<id>2, "interface") == 0) {
+                               interfaces = g_list_append (interfaces,
+                                                           g_strdup ($<id>3));
                        } else {
                                yyerror(_("parse error"));
                                YYERROR;
@@ -701,6 +829,42 @@ classflags:
                                YYERROR;
                        }
                }
+       | '(' TOKEN STRING STRING ')' classflags {
+                       if (strcmp ($<id>2, "GladeXML") == 0) {
+                               glade_xml = TRUE;
+                               add_construct_glade($<id>3, $<id>4, NULL);
+                       } else {
+                               yyerror(_("parse error"));
+                               YYERROR;
+                       }
+               }
+       | '(' TOKEN STRING STRING STRING ')' classflags {
+                       if (strcmp ($<id>2, "GladeXML") == 0) {
+                               glade_xml = TRUE;
+                               add_construct_glade($<id>3, $<id>4, $<id>5);
+                       } else {
+                               yyerror(_("parse error"));
+                               YYERROR;
+                       }
+               }
+       | '(' TOKEN TOKEN STRING ')' classflags {
+                       if (strcmp ($<id>2, "GladeXML") == 0) {
+                               glade_xml = TRUE;
+                               add_construct_glade($<id>3, $<id>4, NULL);
+                       } else {
+                               yyerror(_("parse error"));
+                               YYERROR;
+                       }
+               }
+       | '(' TOKEN TOKEN STRING STRING ')' classflags {
+                       if (strcmp ($<id>2, "GladeXML") == 0) {
+                               glade_xml = TRUE;
+                               add_construct_glade($<id>3, $<id>4, $<id>5);
+                       } else {
+                               yyerror(_("parse error"));
+                               YYERROR;
+                       }
+               }
        ;       
 
 classcode:     classcode thing                 { ; }
@@ -709,12 +873,25 @@ classcode:        classcode thing                 { ; }
 
 thing:                 method                          { ; }
        |       TOKEN method                    {
-                       if (strcmp ($<id>1, "BonoboX") != 0) {
-                               g_free($<id>1);
-                               yyerror(_("parse error"));
+                       if (strcmp ($<id>1, "BonoboObject") != 0) {
+                               g_free ($<id>1);
+                               yyerror (_("parse error"));
                                YYERROR;
                        }
-                       last_added_method->bonobo_x_func = TRUE;
+                       g_free ($<id>1);
+                       last_added_method->bonobo_object_func = TRUE;
+                                               }
+       |       TOKEN TYPETOKEN method                  {
+                       if (strcmp ($<id>1, "interface") != 0) {
+                               g_free ($<id>1);
+                               g_free ($<id>2);
+                               yyerror (_("parse error"));
+                               YYERROR;
+                       }
+                       g_free ($<id>1);
+                       node_set ((Node *)last_added_method,
+                                 "interface:steal", $<id>2,
+                                 NULL);
                                                }
        |       variable                        { ; }
        |       argument                        { ; }
@@ -788,6 +965,14 @@ varoptions:        destructor initializer  { ; }
        |       initializer destructor  { ; }
        |       initializer             { destructor = NULL; }
        |       destructor              { initializer = NULL; }
+       |       TOKEN                   {
+                       if (strcmp ($<id>1, "GladeXML") == 0) {
+                               glade_widget = TRUE;
+                       } else {
+                               yyerror(_("parse error"));
+                               YYERROR;
+                       }
+                                       }
        |                               {
                        destructor = NULL;
                        initializer = NULL;
@@ -929,7 +1114,7 @@ argument:  ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE TOKEN '{' CCODE ';
                        char *get, *set = NULL;
                        Variable *var;
                        Type *type;
-                       char *root;
+                       const char *root;
                        
                        if(strcmp($<id>6, "link")!=0 &&
                           strcmp($<id>6, "stringlink")!=0 && 
@@ -946,15 +1131,16 @@ argument:        ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE TOKEN '{' CCODE ';
                        type = pop_type();
 
                        var = find_var_or_die($<id>4, $<line>1);
-                       if(var->scope == PRIVATE_SCOPE)
+                       if(var->scope == PRIVATE_SCOPE) {
                                root = "self->_priv";
-                       else if(var->scope == CLASS_SCOPE) {
+                       else if(var->scope == CLASS_SCOPE) {
                                root = "SELF_GET_CLASS(self)";
                                if(no_self_alias)
                                        error_print(GOB_ERROR, $<line>1,
                                                    _("Self aliases needed when autolinking to a classwide member"));
-                       } else
+                       } else {
                                root = "self";
+                       }
 
                        if(strcmp($<id>6, "link")==0) {
                                set = g_strdup_printf("%s->%s = ARG;",
@@ -1193,30 +1379,60 @@ param_spec_value: NICK '=' string               {
                          "ptype:steal", type,
                          NULL);
                  }
+       |       FLAGS_TYPE '=' TYPETOKEN        {
+               ensure_property ();
+               node_set ((Node *)property,
+                         "extra_gtktype:steal", $<id>3,
+                         NULL);
+                 }
        |       FLAGS_TYPE '=' TOKEN            {
                ensure_property ();
                node_set ((Node *)property,
                          "extra_gtktype:steal", $<id>3,
                          NULL);
                  }
+       |       ENUM_TYPE '=' TYPETOKEN         {
+               ensure_property ();
+               node_set ((Node *)property,
+                         "extra_gtktype:steal", $<id>3,
+                         NULL);
+                 }
        |       ENUM_TYPE '=' TOKEN             {
                ensure_property ();
                node_set ((Node *)property,
                          "extra_gtktype:steal", $<id>3,
                          NULL);
                  }
+       |       PARAM_TYPE '=' TYPETOKEN        {
+               ensure_property ();
+               node_set ((Node *)property,
+                         "extra_gtktype:steal", $<id>3,
+                         NULL);
+                 }
        |       PARAM_TYPE '=' TOKEN            {
                ensure_property ();
                node_set ((Node *)property,
                          "extra_gtktype:steal", $<id>3,
                          NULL);
                  }
+       |       BOXED_TYPE '=' TYPETOKEN        {
+               ensure_property ();
+               node_set ((Node *)property,
+                         "extra_gtktype:steal", $<id>3,
+                         NULL);
+                 }
        |       BOXED_TYPE '=' TOKEN            {
                ensure_property ();
                node_set ((Node *)property,
                          "extra_gtktype:steal", $<id>3,
                          NULL);
                  }
+       |       OBJECT_TYPE '=' TYPETOKEN       {
+               ensure_property ();
+               node_set ((Node *)property,
+                         "extra_gtktype:steal", $<id>3,
+                         NULL);
+                 }
        |       OBJECT_TYPE '=' TOKEN           {
                ensure_property ();
                node_set ((Node *)property,
@@ -1225,7 +1441,12 @@ param_spec_value: NICK '=' string                {
                  }
        |       TOKEN           {
                ensure_property ();
-               if (strcmp ($<id>1, "link") == 0) {
+               if (strcmp ($<id>1, "override") == 0) {
+                       g_free($<id>1);
+                       node_set ((Node *)property,
+                                 "override", TRUE,
+                                 NULL);
+               } else if (strcmp ($<id>1, "link") == 0) {
                        g_free($<id>1);
                        node_set ((Node *)property,
                                  "link", TRUE,
@@ -1596,8 +1817,8 @@ returnvals:       TOKEN retcode           {
 
 retcode:       numtok                  { $<id>$ = $<id>1; }
        |       '{' CCODE               {
-                       $<id>$ = ($<cbuf>3)->str;
-                       g_string_free($<cbuf>3, FALSE);
+                       $<id>$ = ($<cbuf>2)->str;
+                       g_string_free($<cbuf>2, FALSE);
                                        }
        ;
        
@@ -1764,7 +1985,118 @@ check:          TOKEN                   {
                        checks = g_list_append(checks,node);
                                        }
        ;
-       
+
+enumcode:      ENUM TOKEN '{' enumvals '}' TYPETOKEN ';' {
+                       Node *node = node_new (ENUMDEF_NODE,
+                                              "etype:steal", $<id>6,
+                                              "prefix:steal", $<id>2,
+                                              "values:steal", enum_vals,
+                                              NULL);
+                       enum_vals = NULL;
+                       nodes = g_list_append (nodes, node);
+                       }
+       |       ENUM TOKEN '{' enumvals ',' '}' TYPETOKEN ';' {
+                       Node *node = node_new (ENUMDEF_NODE,
+                                              "etype:steal", $<id>7,
+                                              "prefix:steal", $<id>2,
+                                              "values:steal", enum_vals,
+                                              NULL);
+                       enum_vals = NULL;
+                       nodes = g_list_append (nodes, node);
+                       }
+       ;
+
+enumvals:      enumvals ',' enumval    {;}
+       |       enumval                 {;}
+       ;
+
+enumval:       TOKEN '=' numtok        {
+                       Node *node;
+                       char *num = $<id>3;
+
+                       /* A float value, that's a bad enum */
+                       if (num[0] >= '0' &&
+                           num[0] <= '9' &&
+                           strchr (num, '.') != NULL) {
+                               g_free ($<id>1);
+                               g_free (num);
+                               yyerror(_("parse error (enumerator value not integer constant)"));
+                               YYERROR;
+                       }
+                      
+                       node = node_new (ENUMVALUE_NODE,
+                                        "name:steal", $<id>1,
+                                        "value:steal", num,
+                                        NULL);
+                       enum_vals = g_list_append (enum_vals, node);
+                       }
+       |       TOKEN                   {
+                       Node *node;
+
+                       node = node_new (ENUMVALUE_NODE,
+                                        "name:steal", $<id>1,
+                                        NULL);
+                       enum_vals = g_list_append (enum_vals, node);
+       }
+       ;
+
+flagcode:      FLAGS TOKEN '{' flagvals '}' TYPETOKEN ';' {
+                       Node *node = node_new (FLAGS_NODE,
+                                              "ftype:steal", $<id>6,
+                                              "prefix:steal", $<id>2,
+                                              "values:steal", flag_vals,
+                                              NULL);
+                       flag_vals = NULL;
+                       nodes = g_list_append (nodes, node);
+                       }
+       |       FLAGS TOKEN '{' flagvals ',' '}' TYPETOKEN ';' {
+                       Node *node = node_new (FLAGS_NODE,
+                                              "ftype:steal", $<id>7,
+                                              "prefix:steal", $<id>2,
+                                              "values:steal", flag_vals,
+                                              NULL);
+                       flag_vals = NULL;
+                       nodes = g_list_append (nodes, node);
+                       }
+       ;
+
+flagvals:      flagvals ',' TOKEN      {
+                       flag_vals = g_list_append (flag_vals, $<id>3);
+               }
+       |       TOKEN                   {
+                       flag_vals = g_list_append (flag_vals, $<id>1);
+               }
+       ;
+
+errorcode:     ERROR TOKEN '{' errorvals '}' TYPETOKEN ';' {
+                       Node *node = node_new (ERROR_NODE,
+                                              "etype:steal", $<id>6,
+                                              "prefix:steal", $<id>2,
+                                              "values:steal", error_vals,
+                                              NULL);
+                       error_vals = NULL;
+                       nodes = g_list_append (nodes, node);
+                       }
+       |       ERROR TOKEN '{' errorvals ',' '}' TYPETOKEN ';' {
+                       Node *node = node_new (ERROR_NODE,
+                                              "etype:steal", $<id>7,
+                                              "prefix:steal", $<id>2,
+                                              "values:steal", error_vals,
+                                              NULL);
+                       error_vals = NULL;
+                       nodes = g_list_append (nodes, node);
+                       }
+       ;
+
+errorvals:     errorvals ',' TOKEN     {
+                       error_vals = g_list_append (error_vals, $<id>3);
+               }
+       |       TOKEN                   {
+                       error_vals = g_list_append (error_vals, $<id>1);
+               }
+       ;
+
+
 numtok:                NUMBER                  { $<id>$ = $<id>1; }
        |       '-' NUMBER              {
                        $<id>$ = g_strconcat("-",$<id>2,NULL);