]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
Release 2.0.13
[gob-dx.git] / src / parse.y
1 /* GOB C Preprocessor
2  * Copyright (C) 1999-2000 the Free Software Foundation.
3  * Copyright (C) 2000 Eazel, Inc.
4  * Copyright (C) 2001-2004 George (Jiri) Lebl
5  *
6  * Author: George Lebl
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the  Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21  * USA.
22  */
23 %{
24
25 #include "config.h"
26 #include <glib.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "treefuncs.h"
32 #include "main.h"
33 #include "util.h"
34
35 /* FIXME: add gettext support */
36 #define _(x) (x)
37         
38 GList *nodes = NULL;
39
40 static GList *class_nodes = NULL;
41 Node *class = NULL;
42 GList *enums = NULL;
43 static GList *enum_vals = NULL;
44 static GList *flag_vals = NULL;
45 static GList *error_vals = NULL;
46
47 static gboolean abstract = FALSE;
48 static char *chunk_size = NULL;
49 static char *bonobo_object_class = NULL;
50 static int glade_xml = FALSE;
51 static GList *interfaces = NULL;
52 static GList *typestack = NULL;
53 static GList *funcargs = NULL;
54 static GList *checks = NULL;
55 static int has_self = FALSE;
56 static int vararg = FALSE;
57 static Method *last_added_method = NULL;
58
59 /* destructor and initializer for variables */
60 static gboolean destructor_unref = FALSE;
61 static char *destructor = NULL;
62 static int destructor_line = 0;
63 static gboolean destructor_simple = TRUE;
64 static char *initializer = NULL;
65 static int initializer_line = 0;
66 static int glade_widget = FALSE;
67
68 static char *onerror = NULL;
69 static char *defreturn = NULL;
70
71 static GList *gtktypes = NULL;
72
73 static Property *property = NULL;
74
75 /* this can be a global as we will only do one function at a time
76    anyway */
77 static int the_scope = NO_SCOPE;
78
79 void free(void *ptr);
80 int yylex(void);
81
82 extern int ccode_line;
83 extern int line_no;
84 extern gboolean for_cpp;
85
86 extern char *yytext;
87
88 static void
89 yyerror(char *str)
90 {
91         char *out=NULL;
92         char *p;
93         
94         if(strcmp(yytext,"\n")==0) {
95                 out=g_strconcat("Error: ",str," before newline",NULL);
96         } else if(yytext[0]=='\0') {
97                 out=g_strconcat("Error: ", str, " at end of input", NULL);
98         } else {
99                 char *tmp = g_strdup(yytext);
100                 while((p=strchr(tmp, '\n')))
101                         *p='.';
102
103                 out=g_strconcat("Error: ", str, " before '", tmp, "'", NULL);
104                 g_free(tmp);
105         }
106
107         fprintf(stderr, "%s:%d: %s\n", filename, line_no, out);
108         g_free(out);
109         
110         exit(1);
111 }
112
113 static Type *
114 pop_type(void)
115 {
116         Type *type = typestack->data;
117         typestack = g_list_remove(typestack,typestack->data);
118         return type;
119 }
120
121 static void
122 push_variable (char *name, int scope, int line_no, char *postfix)
123 {
124         Node *var;
125         Type *type = pop_type ();
126
127         type->postfix = postfix;
128         
129         var = node_new (VARIABLE_NODE,
130                         "scope", scope,
131                         "vtype:steal", type,
132                         "glade_widget", glade_widget,
133                         "id:steal", name,
134                         "line_no", line_no,
135                         "destructor_unref", destructor_unref,
136                         "destructor:steal", destructor,
137                         "destructor_line", destructor_line,
138                         "destructor_simple", destructor_simple,
139                         "initializer:steal", initializer,
140                         "initializer_line", initializer_line,
141                         "initializer_simple", TRUE,
142                         NULL);
143         class_nodes = g_list_append(class_nodes, var);
144         glade_widget = FALSE;
145 }
146
147 static void
148 push_function (int scope, int method, char *oid, char *id,
149                GString *cbuf, int line_no, int ccode_line,
150                gboolean vararg, GList *flags)
151 {
152         Node *node;
153         Type *type;
154         char *c_cbuf;
155
156         g_assert(scope != CLASS_SCOPE);
157        
158         if(method == INIT_METHOD || method == CLASS_INIT_METHOD) {
159                 type = (Type *)node_new (TYPE_NODE,
160                                          "name", "void",
161                                          NULL);
162         } else {
163                 type = pop_type();
164         }
165         
166         /* a complicated and ugly test to figure out if we have
167            the wrong number of types for a signal */
168         if((method == SIGNAL_FIRST_METHOD ||
169             method == SIGNAL_LAST_METHOD) &&
170            g_list_length(gtktypes) != g_list_length(funcargs) &&
171            !(g_list_length(funcargs) == 1 &&
172              g_list_length(gtktypes) == 2 &&
173              strcmp(gtktypes->next->data, "NONE")==0)) {
174                 error_print(GOB_WARN, line_no,
175                             _("The number of GTK arguments and "
176                               "function arguments for a signal "
177                               "don't seem to match"));
178         }
179         if(g_list_length(gtktypes) > 2) {
180                 GList *li;
181                 for(li = gtktypes->next; li; li = li->next) {
182                         if(strcmp(li->data, "NONE")==0) {
183                                 error_print(GOB_ERROR, line_no,
184                                             _("NONE can only appear in an "
185                                               "argument list by itself"));
186                         }
187                 }
188         }
189         if(cbuf) {
190                 char *p;
191                 c_cbuf = p = cbuf->str;
192                 while(p && *p && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
193                         p++;
194                 if(!p || !*p)
195                         c_cbuf = NULL;
196         } else
197                 c_cbuf = NULL;
198
199         node = node_new (METHOD_NODE,
200                          "scope", scope,
201                          "method", method,
202                          "mtype:steal", type,
203                          "otype:steal", oid,
204                          "gtktypes:steal", gtktypes,
205                          "flags:steal", flags,
206                          "id:steal", id,
207                          "args:steal", funcargs,
208                          "onerror:steal", onerror,
209                          "defreturn:steal", defreturn,
210                          "cbuf:steal", c_cbuf,
211                          "line_no", line_no,
212                          "ccode_line", ccode_line,
213                          "vararg", vararg,
214                          "unique_id", method_unique_id++,
215                          NULL);
216
217         last_added_method = (Method *)node;
218
219         if(cbuf)
220                 g_string_free(cbuf,
221                               /*only free segment if we haven't passed it
222                                 above */
223                               c_cbuf?FALSE:TRUE);
224         gtktypes = NULL;
225         funcargs = NULL;
226
227         onerror = NULL;
228         defreturn = NULL;
229
230         class_nodes = g_list_append(class_nodes, node);
231 }
232
233 static void
234 free_all_global_state(void)
235 {
236         g_free(onerror);
237         onerror = NULL;
238         g_free(defreturn);
239         defreturn = NULL;
240
241         g_free(chunk_size);
242         chunk_size = NULL;
243         
244         g_list_foreach(gtktypes, (GFunc)g_free, NULL);
245         g_list_free(gtktypes);
246         gtktypes = NULL;
247
248         node_list_free (funcargs);
249         funcargs = NULL;
250 }
251
252 static void
253 push_funcarg(char *name, char *postfix)
254 {
255         Node *node;
256         Type *type = pop_type();
257
258         type->postfix = postfix;
259         
260         node = node_new (FUNCARG_NODE,
261                          "atype:steal", type,
262                          "name:steal", name,
263                          "checks:steal", checks,
264                          NULL);
265         checks = NULL;
266         
267         funcargs = g_list_append(funcargs, node);
268 }
269
270 static void
271 push_init_arg(char *name, int is_class)
272 {
273         Node *node;
274         Node *type;
275         char *tn;
276         
277         if(is_class)
278                 tn = g_strconcat(((Class *)class)->otype,":Class",NULL);
279         else
280                 tn = g_strdup(((Class *)class)->otype);
281
282         type = node_new (TYPE_NODE,
283                          "name:steal", tn,
284                          "pointer", "*",
285                          NULL);
286         node = node_new (FUNCARG_NODE,
287                          "atype:steal", (Type *)type,
288                          "name:steal", name,
289                          NULL);
290         funcargs = g_list_prepend(funcargs, node);
291 }
292
293 static void
294 push_self(char *id, gboolean constant)
295 {
296         Node *node;
297         Node *type;
298         GList *ch = NULL;
299         type = node_new (TYPE_NODE,
300                          "name", ((Class *)class)->otype,
301                          "pointer", constant ? "const *" : "*",
302                          NULL);
303         ch = g_list_append (ch, node_new (CHECK_NODE,
304                                           "chtype", NULL_CHECK,
305                                           NULL));
306         ch = g_list_append (ch, node_new (CHECK_NODE,
307                                           "chtype", TYPE_CHECK,
308                                           NULL));
309         node = node_new (FUNCARG_NODE,
310                          "atype:steal", (Type *)type,
311                          "name:steal", id,
312                          "checks:steal", ch,
313                          NULL);
314         funcargs = g_list_prepend(funcargs, node);
315 }
316
317 static Variable *
318 find_var_or_die(const char *id, int line)
319 {
320         GList *li;
321
322         for(li = class_nodes; li != NULL; li = li->next) {
323                 Variable *var;
324                 Node *node = li->data;
325                 if(node->type != VARIABLE_NODE)
326                         continue;
327                 var = li->data;
328                 if(strcmp(var->id, id)==0)
329                         return var;
330         }
331
332         error_printf(GOB_ERROR, line, _("Variable %s not defined here"), id);
333
334         g_assert_not_reached();
335         return NULL;
336 }
337
338 static gboolean
339 set_return_value(char *type, char *val)
340 {
341         if(strcmp(type, "onerror")==0) {
342                 if(!onerror) {
343                         onerror = val;
344                         return TRUE;
345                 } else
346                         return FALSE;
347         } else if(strcmp(type, "defreturn")==0) {
348                 if(!defreturn) {
349                         defreturn = val;
350                         return TRUE;
351                 } else
352                         return FALSE;
353         }
354         return FALSE;
355 }
356
357 static void
358 export_accessors (const char *var_name,
359                   gboolean do_get,
360                   int get_lineno,
361                   gboolean do_set,
362                   int set_lineno,
363                   Type *type,
364                   const char *gtktype,
365                   int lineno)
366 {       
367         Type *the_type;
368
369         if (type != NULL)
370                 the_type = (Type *)node_copy ((Node *)type);
371         else
372                 the_type = get_tree_type (gtktype, TRUE);
373
374         if (the_type == NULL) {
375                 error_print (GOB_ERROR, line_no,
376                              _("Cannot determine type of property or argument"));
377                 return;
378         }
379
380         if (do_get) {
381                 char *get_id = g_strdup_printf ("get_%s", var_name);
382                 GString *get_cbuf = g_string_new (NULL);
383                 Node *node1 = node_new (TYPE_NODE,
384                                         "name", the_type->name,
385                                         "pointer", the_type->pointer,
386                                         "postfix", the_type->postfix,
387                                         NULL);
388                 Node *node3 = node_new (TYPE_NODE,
389                                         "name", class->class.otype,
390                                         "pointer", "*",
391                                         NULL);
392
393                 g_string_sprintf (get_cbuf,
394                                   "\t%s%s val; "
395                                   "g_object_get (G_OBJECT (self), \"%s\", "
396                                   "&val, NULL); "
397                                   "return val;\n",
398                                   the_type->name, 
399                                   the_type->pointer ? the_type->pointer : "",
400                                   var_name);
401                 
402                 typestack = g_list_prepend (typestack, node1);
403                 typestack = g_list_prepend (typestack, node3);
404                 
405                 push_funcarg ("self", FALSE);
406                 
407                 push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
408                                get_id, get_cbuf, get_lineno,
409                                lineno, FALSE, NULL);
410         }
411         
412         if (do_set) {
413                 char *set_id = g_strdup_printf ("set_%s", var_name);
414                 GString *set_cbuf = g_string_new (NULL);
415                 Node *node1 = node_new (TYPE_NODE, 
416                                         "name", the_type->name,
417                                         "pointer", the_type->pointer,
418                                         "postfix", the_type->postfix,
419                                         NULL);
420                 Node *node2 = node_new (TYPE_NODE, 
421                                         "name", "void",
422                                         NULL);
423                 Node *node3 = node_new (TYPE_NODE, 
424                                         "name", class->class.otype,
425                                         "pointer", "*",
426                                         NULL);
427
428                 g_string_sprintf (set_cbuf,
429                                   "\tg_object_set (G_OBJECT (self), "
430                                   "\"%s\", val, NULL);\n",
431                                   var_name);
432
433                 typestack = g_list_prepend (typestack, node2);
434                 typestack = g_list_prepend (typestack, node1);
435                 typestack = g_list_prepend (typestack, node3);
436                 
437                 push_funcarg ("self", FALSE);
438                 push_funcarg ("val", FALSE);
439         
440                 typestack = g_list_prepend (typestack, node2);
441                 push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
442                                set_id, set_cbuf, set_lineno,
443                                lineno, FALSE, NULL);
444         }
445
446         node_free ((Node *)the_type);
447 }
448
449 static char *
450 get_prop_enum_flag_cast (Property *prop)
451 {
452         char *tmp, *ret;
453         if (prop->extra_gtktype == NULL ||
454         /* HACK!  just in case someone made this
455          * work with 2.0.0 by using the TYPE
456          * macro directly */
457             ((strstr (prop->extra_gtktype, "_TYPE_") != NULL ||
458               strstr (prop->extra_gtktype, "TYPE_") == prop->extra_gtktype) &&
459              strchr (prop->extra_gtktype, ':') == NULL)) {
460                 if (prop->ptype != NULL)
461                         return get_type (prop->ptype, TRUE);
462                 else
463                         return g_strdup ("");
464         }
465         tmp = remove_sep (prop->extra_gtktype);
466         ret = g_strdup_printf ("(%s) ", tmp);
467         g_free (tmp);
468         return ret;
469 }
470
471 static void
472 add_construct_glade (char * file, char * root, char * domain)
473 {
474         Node *var;
475         Type * type;
476         GList * flags = NULL;
477         
478         type = (Type *)node_new (TYPE_NODE,
479                                  "name", "GladeXML",
480                                  "pointer", "*",
481                                  NULL);
482         initializer = g_strdup_printf("\t{\n"
483                                       "\tGtkWidget * root;\n"
484                                       "\t%%1$s->_priv->_glade_xml = glade_xml_new(%s, %s, %s);\n"
485                                       "\troot = glade_xml_get_widget(%%1$s->_priv->_glade_xml, %s);\n"
486                                       "\tgtk_widget_show(root);\n"
487                                       "\tgtk_container_add(GTK_CONTAINER(%%1$s), root);\n"
488                                       "\tglade_xml_signal_autoconnect_full(%%1$s->_priv->_glade_xml, (GladeXMLConnectFunc)___glade_xml_connect_foreach, (gpointer)%%1$s);\n"
489                                       "}\n", file, root, domain ? domain : "NULL", root);
490         
491         var = node_new (VARIABLE_NODE,
492                         "scope", PRIVATE_SCOPE,
493                         "vtype:steal", type,
494                         "glade_widget", FALSE,
495                         "id:steal", "_glade_xml",
496                         "destructor_unref", FALSE,
497                         "destructor", "g_object_unref", 
498                         "destructor_simple", TRUE,
499                         "initializer", initializer,
500                         "initializer_simple", FALSE,
501                         NULL);
502         class_nodes = g_list_prepend(class_nodes, var);
503 }
504
505 static void
506 property_link_and_export (Node *node)
507 {
508         Property *prop = (Property *)node;
509
510         if (prop->link) {
511                 const char *root;
512                 char *get = NULL, *set = NULL;
513                 Variable *var;
514
515                 if (prop->set != NULL ||
516                     prop->get != NULL) {        
517                         error_print (GOB_ERROR, prop->line_no,
518                                      _("Property linking requested, but "
519                                        "getters and setters exist"));
520                 }
521
522                 var = find_var_or_die (prop->name, prop->line_no);
523                 if(var->scope == PRIVATE_SCOPE) {
524                         root = "self->_priv";
525                 } else if (var->scope == CLASS_SCOPE) {
526                         root = "SELF_GET_CLASS(self)";
527                         if (no_self_alias)
528                                 error_print (GOB_ERROR, prop->line_no,
529                                              _("Self aliases needed when autolinking to a classwide member"));
530                 } else {
531                         root = "self";
532                 }
533
534                 if (strcmp (prop->gtktype, "STRING") == 0) {
535                         set = g_strdup_printf("{ char *old = %s->%s; "
536                                               "%s->%s = g_value_dup_string (VAL); g_free (old); }",
537                                               root, prop->name,
538                                               root, prop->name);
539                         get = g_strdup_printf("g_value_set_string (VAL, %s->%s);",
540                                               root, prop->name);
541                 } else if (strcmp (prop->gtktype, "OBJECT") == 0) {
542                         char *cast;
543                         if (prop->extra_gtktype != NULL) {
544                                 cast = remove_sep (prop->extra_gtktype);
545                         } else {
546                                 cast = g_strdup ("void");
547                         }
548                         set = g_strdup_printf("{ GObject *___old = (GObject *)%s->%s; "
549                                               "%s->%s = (%s *)g_value_dup_object (VAL); "
550                                               "if (___old != NULL) { "
551                                                 "g_object_unref (G_OBJECT (___old)); "
552                                               "} "
553                                               "}",
554                                               root, prop->name,
555                                               root, prop->name,
556                                               cast);
557                         get = g_strdup_printf ("g_value_set_object (VAL, "
558                                                "(gpointer)%s->%s);",
559                                                root, prop->name);
560                         g_free (cast);
561                 } else if (strcmp (prop->gtktype, "BOXED") == 0) {
562                         char *type = make_me_type (prop->extra_gtktype,
563                                                    "G_TYPE_BOXED");
564                         if (prop->extra_gtktype == NULL) {
565                                 error_print (GOB_ERROR, prop->line_no,
566                                              _("Property linking requested for BOXED, but "
567                                                "boxed_type not set"));
568                         }
569                         set = g_strdup_printf("{ gpointer ___old = (gpointer)%s->%s; "
570                                               "gpointer ___new = (gpointer)g_value_get_boxed (VAL); "
571                                               "if (___new != ___old) { "
572                                                 "if (___old != NULL) g_boxed_free (%s, ___old); "
573                                                 "if (___new != NULL) %s->%s = g_boxed_copy (%s, ___new); "
574                                                 "else %s->%s = NULL;"
575                                               "} "
576                                               "}",
577                                               root, prop->name,
578                                               type,
579                                               root, prop->name,
580                                               type,
581                                               root, prop->name);
582                         get = g_strdup_printf("g_value_set_boxed (VAL, %s->%s);",
583                                               root, prop->name);
584                         g_free (type);
585                 } else {
586                         char *set_func;
587                         char *get_func;
588                         const char *getcast = "";
589                         const char *setcast = "";
590                         char *to_free = NULL;
591                         set_func = g_strdup_printf ("g_value_set_%s", prop->gtktype);
592                         g_strdown (set_func);
593                         get_func = g_strdup_printf ("g_value_get_%s", prop->gtktype);
594                         g_strdown (get_func);
595
596                         if (for_cpp) {
597                                 if (strcmp (prop->gtktype, "FLAGS") == 0) {
598                                         setcast = "(guint) ";
599                                         getcast = to_free =
600                                                 get_prop_enum_flag_cast (prop);
601                                 } else if (strcmp (prop->gtktype, "ENUM") == 0) {
602                                         setcast = "(gint) ";
603                                         getcast = to_free =
604                                                 get_prop_enum_flag_cast (prop);
605                                }  else if (strcmp (prop->gtktype, "POINTER") == 0) {
606                                        setcast = "(gpointer) ";
607                                        getcast = g_strdup_printf ("(%s%s) ",
608                                                                   prop->ptype->name,
609                                                                   prop->ptype->pointer ? prop->ptype->pointer : "");
610                                 }
611                         }
612
613                         set = g_strdup_printf("%s->%s = %s%s (VAL);",
614                                               root, prop->name,
615                                               getcast,
616                                               get_func);
617                         get = g_strdup_printf("%s (VAL, %s%s->%s);",
618                                               set_func,
619                                               setcast,  
620                                               root, prop->name);
621
622                         g_free (get_func);
623                         g_free (set_func);
624                         g_free (to_free);
625                 }
626
627                 node_set (node,
628                           "get:steal", get,
629                           "get_line", prop->line_no,
630                           "set:steal", set,
631                           "set_line", prop->line_no,
632                           NULL);
633         }
634
635         if (prop->export) {
636                 export_accessors (prop->name,
637                                   prop->get != NULL, prop->get_line,
638                                   prop->set != NULL,  prop->set_line,
639                                   prop->ptype,
640                                   prop->gtktype,
641                                   prop->line_no);
642         } 
643 }
644
645
646 static char *
647 debool (char *s)
648 {
649         if (strcmp (s, "BOOL") == 0) {
650                 error_print (GOB_WARN, line_no,
651                             _("BOOL type is deprecated, please use BOOLEAN"));
652                 g_free (s);
653                 return g_strdup ("BOOLEAN");
654         } else {
655                 return s;
656         }
657 }
658
659 static void
660 ensure_property (void)
661 {
662         if (property == NULL)
663                 property = (Property *)node_new (PROPERTY_NODE, NULL);
664 }
665
666 %}
667
668 %union {
669         char *id;
670         GString *cbuf;
671         GList *list;
672         int line;
673         int sigtype;
674 }
675
676 %token CLASS FROM
677 %token CONST VOID STRUCT UNION ENUM THREEDOTS
678 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
679
680 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM SINGLE_CHAR
681 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING
682 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE PROPERTY ARGUMENT
683 %token <line> VIRTUAL SIGNAL OVERRIDE
684 %token <line> NICK BLURB MAXIMUM MINIMUM DEFAULT_VALUE ERROR FLAGS TYPE
685 %token <line> FLAGS_TYPE ENUM_TYPE PARAM_TYPE BOXED_TYPE OBJECT_TYPE
686
687 %%
688
689 prog:           ccodes class ccodes     { ; }
690         |       class ccodes            { ; }
691         |       ccodes class            { ; }
692         |       class                   { ; }
693         ;
694
695 ccode:          CCODE                   {
696                         Node *node = node_new (CCODE_NODE,
697                                                "cctype", C_CCODE,
698                                                "cbuf:steal", ($<cbuf>1)->str,
699                                                "line_no", ccode_line,
700                                                NULL);
701                         nodes = g_list_append(nodes,node);
702                         g_string_free($<cbuf>1,FALSE);
703                                         }
704         |       HCODE                   {
705                         Node *node = node_new (CCODE_NODE,
706                                                "cctype", H_CCODE,
707                                                "cbuf:steal", ($<cbuf>1)->str,
708                                                "line_no", ccode_line,
709                                                NULL);
710                         nodes = g_list_append(nodes,node);
711                         g_string_free($<cbuf>1,FALSE);
712                                         }
713         |       HTCODE                  {
714                         Node *node = node_new (CCODE_NODE,
715                                                "cctype", HT_CCODE,
716                                                "cbuf:steal", ($<cbuf>1)->str,
717                                                "line_no", ccode_line,
718                                                NULL);
719                         nodes = g_list_append(nodes,node);
720                         g_string_free($<cbuf>1,FALSE);
721                                         }
722         |       PHCODE                  {
723                         Node *node = node_new (CCODE_NODE,
724                                                "cctype", PH_CCODE,
725                                                "cbuf:steal", ($<cbuf>1)->str,
726                                                "line_no", ccode_line,
727                                                NULL);
728                         nodes = g_list_append(nodes,node);
729                         g_string_free($<cbuf>1,FALSE);
730                                         }
731         |       ACODE                   {
732                         Node *node = node_new (CCODE_NODE,
733                                                "cctype", A_CCODE,
734                                                "cbuf:steal", ($<cbuf>1)->str,
735                                                "line_no", ccode_line,
736                                                NULL);
737                         nodes = g_list_append(nodes,node);
738                         g_string_free($<cbuf>1,FALSE);
739                                         }
740         |       ATCODE                  {
741                         Node *node = node_new (CCODE_NODE,
742                                                "cctype", AT_CCODE,
743                                                "cbuf:steal", ($<cbuf>1)->str,
744                                                "line_no", ccode_line,
745                                                NULL);
746                         nodes = g_list_append(nodes,node);
747                         g_string_free($<cbuf>1,FALSE);
748                                         }
749         ;
750
751 ccodes:         ccodes ccode            { ; }
752         |       ccodes enumcode         { ; }
753         |       ccodes flagcode         { ; }
754         |       ccodes errorcode        { ; }
755         |       ccode                   { ; }
756         |       enumcode                { ; }
757         |       flagcode                { ; }
758         |       errorcode               { ; }
759         ;
760
761 class:          classdec '{' classcode '}'      {
762                         ((Class *)class)->nodes = class_nodes;
763                         class_nodes = NULL;
764                         nodes = g_list_append(nodes,class);
765                                                 }
766         |       classdec '{' '}'                {
767                         ((Class *)class)->nodes = NULL;
768                         class_nodes = NULL;
769                         nodes = g_list_append(nodes,class);
770                                                 }
771         ;
772
773 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  classflags {
774                         class = node_new (CLASS_NODE,
775                                           "otype:steal", $<id>2,
776                                           "ptype:steal", $<id>4,
777                                           "bonobo_object_class:steal", bonobo_object_class,
778                                           "glade_xml", glade_xml,
779                                           "interfaces:steal", interfaces,
780                                           "chunk_size:steal", chunk_size,
781                                           "abstract", abstract,
782                                           NULL);
783                         bonobo_object_class = NULL;
784                         glade_xml = FALSE;
785                         chunk_size = NULL;
786                         interfaces = NULL;
787                                                 }
788         ;
789
790 classflags:
791         | '(' TOKEN ')' classflags {
792                         if(strcmp($<id>2,"abstract") == 0) {
793                                 abstract = TRUE;
794                         } else {
795                                 yyerror(_("parse error"));
796                                 YYERROR;
797                         }
798                 }
799         | '(' TOKEN TOKEN ')' classflags {
800                         if(strcmp($<id>2,"chunks") == 0) {
801                                 g_free (chunk_size);
802                                 chunk_size = g_strdup($<id>3);
803                         } else if(strcmp($<id>2,"BonoboObject") == 0) {
804                                 g_free (bonobo_object_class);
805                                 bonobo_object_class = g_strdup($<id>3);
806                         } else {
807                                 yyerror(_("parse error"));
808                                 YYERROR;
809                         }
810                 }
811         | '(' TOKEN TYPETOKEN ')' classflags {
812                         if (strcmp ($<id>2, "interface") == 0) {
813                                 interfaces = g_list_append (interfaces,
814                                                             g_strdup ($<id>3));
815                         } else {
816                                 yyerror(_("parse error"));
817                                 YYERROR;
818                         }
819                 }
820         | '(' TOKEN NUMBER ')' classflags {
821                         if(strcmp($<id>2,"chunks") == 0) {
822                                 g_free (chunk_size);
823                                 if(atoi($<id>3) != 0)
824                                         chunk_size = g_strdup($<id>3);
825                                 else
826                                         chunk_size = NULL;
827                         } else {
828                                 yyerror(_("parse error"));
829                                 YYERROR;
830                         }
831                 }
832         | '(' TOKEN STRING STRING ')' classflags {
833                         if (strcmp ($<id>2, "GladeXML") == 0) {
834                                 glade_xml = TRUE;
835                                 add_construct_glade($<id>3, $<id>4, NULL);
836                         } else {
837                                 yyerror(_("parse error"));
838                                 YYERROR;
839                         }
840                 }
841         | '(' TOKEN STRING STRING STRING ')' classflags {
842                         if (strcmp ($<id>2, "GladeXML") == 0) {
843                                 glade_xml = TRUE;
844                                 add_construct_glade($<id>3, $<id>4, $<id>5);
845                         } else {
846                                 yyerror(_("parse error"));
847                                 YYERROR;
848                         }
849                 }
850         | '(' TOKEN TOKEN STRING ')' classflags {
851                         if (strcmp ($<id>2, "GladeXML") == 0) {
852                                 glade_xml = TRUE;
853                                 add_construct_glade($<id>3, $<id>4, NULL);
854                         } else {
855                                 yyerror(_("parse error"));
856                                 YYERROR;
857                         }
858                 }
859         | '(' TOKEN TOKEN STRING STRING ')' classflags {
860                         if (strcmp ($<id>2, "GladeXML") == 0) {
861                                 glade_xml = TRUE;
862                                 add_construct_glade($<id>3, $<id>4, $<id>5);
863                         } else {
864                                 yyerror(_("parse error"));
865                                 YYERROR;
866                         }
867                 }
868         ;       
869
870 classcode:      classcode thing                 { ; }
871         |       thing                           { ; }
872         ;
873
874 thing:          method                          { ; }
875         |       TOKEN method                    {
876                         if (strcmp ($<id>1, "BonoboObject") != 0) {
877                                 g_free ($<id>1);
878                                 yyerror (_("parse error"));
879                                 YYERROR;
880                         }
881                         g_free ($<id>1);
882                         last_added_method->bonobo_object_func = TRUE;
883                                                 }
884         |       TOKEN TYPETOKEN method                  {
885                         if (strcmp ($<id>1, "interface") != 0) {
886                                 g_free ($<id>1);
887                                 g_free ($<id>2);
888                                 yyerror (_("parse error"));
889                                 YYERROR;
890                         }
891                         g_free ($<id>1);
892                         node_set ((Node *)last_added_method,
893                                   "interface:steal", $<id>2,
894                                   NULL);
895                                                 }
896         |       variable                        { ; }
897         |       argument                        { ; }
898         |       property                        { ; }
899         |       ';'                             { ; }
900         ;
901
902 scope:          PUBLIC                  { the_scope = PUBLIC_SCOPE; }
903         |       PRIVATE                 { the_scope = PRIVATE_SCOPE; }
904         |       PROTECTED               { the_scope = PROTECTED_SCOPE; }
905         |       CLASSWIDE               { the_scope = CLASS_SCOPE; }
906         ;
907
908 destructor:     TOKEN TOKEN     {
909                         if (strcmp ($<id>1, "destroywith") == 0) {
910                                 g_free ($<id>1);
911                                 destructor_unref = FALSE;
912                                 destructor = $<id>2;
913                                 destructor_line = line_no;
914                                 destructor_simple = TRUE;
915                         } else if (strcmp ($<id>1, "unrefwith") == 0) {
916                                 g_free ($<id>1);
917                                 destructor_unref = TRUE;
918                                 destructor = $<id>2;
919                                 destructor_line = line_no;
920                                 destructor_simple = TRUE;
921                         } else {
922                                 g_free ($<id>1);
923                                 g_free ($<id>2);
924                                 yyerror (_("parse error"));
925                                 YYERROR;
926                         }
927                                 }
928         |       TOKEN '{' CCODE         {
929                         if (strcmp ($<id>1, "destroy") == 0) {
930                                 g_free($<id>1);
931                                 destructor_unref = FALSE;
932                                 destructor = ($<cbuf>3)->str;
933                                 g_string_free($<cbuf>3, FALSE);
934                                 destructor_line = ccode_line;
935                                 destructor_simple = FALSE;
936                         } else if (strcmp ($<id>1, "unref") == 0) {
937                                 g_free ($<id>1);
938                                 destructor_unref = TRUE;
939                                 destructor = ($<cbuf>3)->str;
940                                 g_string_free ($<cbuf>3, FALSE);
941                                 destructor_line = ccode_line;
942                                 destructor_simple = FALSE;
943                         } else {
944                                 g_free ($<id>1);
945                                 g_string_free ($<cbuf>3, TRUE);
946                                 yyerror (_("parse error"));
947                                 YYERROR;
948                         }
949                                         }
950         ;
951
952 initializer:    '=' numtok      {
953                         initializer = $<id>2;
954                         initializer_line = ccode_line;
955                                 }
956         |       '=' '{' CCODE   {
957                         initializer = ($<cbuf>3)->str;
958                         initializer_line = ccode_line;
959                         g_string_free($<cbuf>3, FALSE);
960                                 }
961         ;
962
963
964 varoptions:     destructor initializer  { ; }
965         |       initializer destructor  { ; }
966         |       initializer             { destructor = NULL; }
967         |       destructor              { initializer = NULL; }
968         |       TOKEN                   {
969                         if (strcmp ($<id>1, "GladeXML") == 0) {
970                                 glade_widget = TRUE;
971                         } else {
972                                 yyerror(_("parse error"));
973                                 YYERROR;
974                         }
975                                         }
976         |                               {
977                         destructor = NULL;
978                         initializer = NULL;
979                                         }
980         ;
981
982 variable:       scope type TOKEN varoptions ';'         {
983                         push_variable($<id>3, the_scope,$<line>1, NULL);
984                                                 }
985         |       scope type TOKEN ARRAY_DIM varoptions ';'       {
986                         push_variable($<id>3, the_scope, $<line>1, $<id>4);
987                                                 }
988         ;
989
990 argument:       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE TOKEN '{' CCODE ';' {
991                         Node *node = NULL;
992                         if(strcmp($<id>6,"get")==0 &&
993                            strcmp($<id>9,"set")==0) {
994                                 Type *type = pop_type();
995                                 g_free ($<id>6); 
996                                 g_free ($<id>9);
997                                 node = node_new (ARGUMENT_NODE,
998                                                  "gtktype:steal", $<id>3,
999                                                  "atype:steal", type,
1000                                                  "flags:steal", $<list>2,
1001                                                  "name:steal", $<id>4,
1002                                                  "get:steal", ($<cbuf>8)->str,
1003                                                  "get_line", $<line>7,
1004                                                  "set:steal", ($<cbuf>11)->str,
1005                                                  "set_line", $<line>10,
1006                                                  "line_no", $<line>1,
1007                                                  NULL);
1008
1009                                 class_nodes = g_list_append(class_nodes,node);
1010
1011                                 g_string_free ($<cbuf>8, FALSE);
1012                                 g_string_free ($<cbuf>11, FALSE);
1013
1014                         } else if(strcmp($<id>6,"set")==0 &&
1015                                 strcmp($<id>9,"get")==0) {
1016                                 Type *type = pop_type();
1017                                 g_free ($<id>6); 
1018                                 g_free ($<id>9);
1019                                 node = node_new (ARGUMENT_NODE,
1020                                                  "gtktype:steal", $<id>3,
1021                                                  "atype:steal", type,
1022                                                  "flags:steal", $<list>2,
1023                                                  "name:steal", $<id>4,
1024                                                  "get:steal", ($<cbuf>11)->str,
1025                                                  "get_line", $<line>10,
1026                                                  "set:steal", ($<cbuf>8)->str,
1027                                                  "set_line", $<line>7,
1028                                                  "line_no", $<line>1,
1029                                                  NULL);
1030                                 g_string_free ($<cbuf>11, FALSE);
1031                                 g_string_free ($<cbuf>8, FALSE);
1032                                 class_nodes = g_list_append(class_nodes,node);
1033                         } else {
1034                                 g_free ($<id>3); 
1035                                 g_free ($<id>4);
1036                                 g_free ($<id>6); 
1037                                 g_free ($<id>9);
1038                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
1039                                 g_list_free ($<list>2);
1040                                 g_string_free ($<cbuf>11, TRUE);
1041                                 g_string_free ($<cbuf>8, TRUE);
1042                                 yyerror (_("parse error"));
1043                                 YYERROR;
1044                         }
1045
1046                         if ($<id>5 != NULL) {
1047                                 Argument *arg = (Argument *)node;
1048                                 export_accessors (arg->name,
1049                                                   arg->get != NULL, arg->get_line,
1050                                                   arg->set != NULL, arg->set_line,
1051                                                   arg->atype,
1052                                                   arg->gtktype,
1053                                                   arg->line_no);
1054                                 g_free ($<id>5);
1055                         } 
1056
1057                                                 }
1058         |       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE ';' {
1059                         Node *node = NULL;
1060                         if(strcmp($<id>6, "get") == 0) {
1061                                 Type *type = pop_type();
1062                                 g_free ($<id>6);
1063                                 node = node_new (ARGUMENT_NODE,
1064                                                  "gtktype:steal", $<id>3,
1065                                                  "atype:steal", type,
1066                                                  "flags:steal", $<list>2,
1067                                                  "name:steal", $<id>4,
1068                                                  "get:steal", ($<cbuf>8)->str,
1069                                                  "get_line", $<line>7,
1070                                                  "line_no", $<line>1,
1071                                                  NULL);
1072
1073                                 g_string_free ($<cbuf>8, FALSE);
1074                                 class_nodes = g_list_append(class_nodes, node);
1075                         } else if(strcmp($<id>6, "set") == 0) {
1076                                 Type *type = pop_type();
1077                                 g_free ($<id>6);
1078                                 node = node_new (ARGUMENT_NODE,
1079                                                  "gtktype:steal", $<id>3,
1080                                                  "atype:steal", type,
1081                                                  "flags:steal", $<list>2,
1082                                                  "name:steal", $<id>4,
1083                                                  "set:steal", ($<cbuf>8)->str,
1084                                                  "set_line", $<line>7,
1085                                                  "line_no", $<line>1,
1086                                                  NULL);
1087
1088                                 g_string_free ($<cbuf>8, FALSE);
1089                                 class_nodes = g_list_append (class_nodes, node);
1090                         } else {
1091                                 g_free ($<id>6); 
1092                                 g_free ($<id>3);
1093                                 g_free ($<id>4);
1094                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
1095                                 g_list_free ($<list>2);
1096                                 g_string_free ($<cbuf>8, TRUE);
1097                                 yyerror(_("parse error"));
1098                                 YYERROR;
1099                         }
1100
1101                         if ($<id>5 != NULL) {
1102                                 Argument *arg = (Argument *)node;
1103                                 export_accessors (arg->name,
1104                                                   arg->get != NULL, arg->get_line,
1105                                                   arg->set != NULL, arg->set_line,
1106                                                   arg->atype,
1107                                                   arg->gtktype,
1108                                                   arg->line_no);
1109                                 g_free ($<id>5);
1110                         } 
1111                                                 }
1112         |       ARGUMENT flags argtype TOKEN export TOKEN {
1113                         Node *node;
1114                         char *get, *set = NULL;
1115                         Variable *var;
1116                         Type *type;
1117                         const char *root;
1118                         
1119                         if(strcmp($<id>6, "link")!=0 &&
1120                            strcmp($<id>6, "stringlink")!=0 && 
1121                            strcmp($<id>6, "objectlink")!=0) {
1122                                 g_free($<id>6); 
1123                                 g_free($<id>3);
1124                                 g_free($<id>4);
1125                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
1126                                 g_list_free($<list>2);
1127                                 yyerror(_("parse error"));
1128                                 YYERROR;
1129                         }
1130
1131                         type = pop_type();
1132
1133                         var = find_var_or_die($<id>4, $<line>1);
1134                         if(var->scope == PRIVATE_SCOPE) {
1135                                 root = "self->_priv";
1136                         } else if(var->scope == CLASS_SCOPE) {
1137                                 root = "SELF_GET_CLASS(self)";
1138                                 if(no_self_alias)
1139                                         error_print(GOB_ERROR, $<line>1,
1140                                                     _("Self aliases needed when autolinking to a classwide member"));
1141                         } else {
1142                                 root = "self";
1143                         }
1144
1145                         if(strcmp($<id>6, "link")==0) {
1146                                 set = g_strdup_printf("%s->%s = ARG;",
1147                                                       root, $<id>4);
1148                         } else if(strcmp($<id>6, "stringlink")==0) {
1149                                 set = g_strdup_printf("g_free (%s->%s); "
1150                                                       "%s->%s = g_strdup (ARG);",
1151                                                       root, $<id>4,
1152                                                       root, $<id>4);
1153                         } else if(strcmp($<id>6, "objectlink")==0) {
1154                                 set = g_strdup_printf(
1155                                   "if (ARG != NULL) "
1156                                    "g_object_ref (G_OBJECT (ARG)); "
1157                                   "if (%s->%s != NULL) "
1158                                    "g_object_unref (G_OBJECT (%s->%s)); "
1159                                   "%s->%s = ARG;",
1160                                   root, $<id>4,
1161                                   root, $<id>4,
1162                                   root, $<id>4);
1163                         } else {
1164                                 g_assert_not_reached();
1165                         }
1166
1167                         get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
1168   
1169                         g_free ($<id>6);
1170
1171                         if (type == NULL)
1172                                 type = (Type *)node_copy ((Node *)var->vtype);
1173
1174                         node = node_new (ARGUMENT_NODE,
1175                                          "gtktype:steal", $<id>3,
1176                                          "atype:steal", type,
1177                                          "flags:steal", $<list>2,
1178                                          "name:steal", $<id>4,
1179                                          "get:steal", get,
1180                                          "get_line", $<line>1,
1181                                          "set:steal", set,
1182                                          "set_line", $<line>1,
1183                                          "line_no", $<line>1,
1184                                          NULL);
1185
1186                         if ($<id>5 != NULL) {
1187                                 Argument *arg = (Argument *)node;
1188                                 export_accessors (arg->name,
1189                                                   arg->get != NULL, arg->get_line,
1190                                                   arg->set != NULL, arg->set_line,
1191                                                   arg->atype,
1192                                                   arg->gtktype,
1193                                                   arg->line_no);
1194                                 g_free ($<id>5);
1195                         } 
1196
1197                         class_nodes = g_list_append (class_nodes, node);
1198                                                 }
1199         ;
1200
1201 export:         '(' TOKEN ')'                   {
1202                         if (strcmp ($<id>2, "export")!=0) {
1203                                 g_free ($<id>2); 
1204                                 yyerror (_("parse error"));
1205                                 YYERROR;
1206                         }
1207                         $<id>$ = $<id>2;
1208                                                 }
1209          |                                      {
1210                         $<id>$ = NULL;
1211                                                 }
1212          ;
1213
1214 property:       PROPERTY TOKEN TOKEN param_spec TOKEN '{' CCODE TOKEN '{' CCODE ';' {
1215                         ensure_property ();
1216                         node_set ((Node *)property,
1217                                   "line_no", $<line>1,
1218                                   "gtktype:steal", debool ($<id>2),
1219                                   "name:steal", $<id>3,
1220                                   NULL);
1221                         if (strcmp ($<id>5, "get") == 0 &&
1222                             strcmp ($<id>8, "set") == 0) {
1223                                 node_set ((Node *)property,
1224                                           "get:steal", ($<cbuf>7)->str,
1225                                           "get_line", $<line>6,
1226                                           "set:steal", ($<cbuf>10)->str,
1227                                           "set_line", $<line>9,
1228                                           NULL);
1229                                 g_string_free ($<cbuf>7, FALSE);
1230                                 g_string_free ($<cbuf>10, FALSE);
1231                                 g_free ($<id>5); 
1232                                 g_free ($<id>8);
1233                         } else if (strcmp ($<id>5, "set") == 0 &&
1234                                    strcmp ($<id>8, "get") == 0) {
1235                                 node_set ((Node *)property,
1236                                           "get:steal", ($<cbuf>10)->str,
1237                                           "get_line", $<line>9,
1238                                           "set:steal", ($<cbuf>7)->str,
1239                                           "set_line", $<line>6,
1240                                           NULL);
1241                                 g_string_free ($<cbuf>7, FALSE);
1242                                 g_string_free ($<cbuf>10, FALSE);
1243                                 g_free ($<id>5); 
1244                                 g_free ($<id>8);
1245                         } else {
1246                                 g_string_free ($<cbuf>7, TRUE);
1247                                 g_string_free ($<cbuf>10, TRUE);
1248                                 g_free ($<id>5); 
1249                                 g_free ($<id>8);
1250                                 node_free ((Node *)property);
1251                                 property = NULL;
1252                                 yyerror (_("parse error"));
1253                                 YYERROR;
1254                         }
1255                         property_link_and_export ((Node *)property);
1256                         if (property != NULL) {
1257                                 class_nodes = g_list_append (class_nodes,
1258                                                              property);
1259                                 property = NULL;
1260                         }
1261                 }
1262         |       PROPERTY TOKEN TOKEN param_spec TOKEN '{' CCODE ';' {
1263                         ensure_property ();
1264                         node_set ((Node *)property,
1265                                   "line_no", $<line>1,
1266                                   "gtktype:steal", debool ($<id>2),
1267                                   "name:steal", $<id>3,
1268                                   NULL);
1269                         if (strcmp ($<id>5, "get") == 0) {
1270                                 node_set ((Node *)property,
1271                                           "get:steal", ($<cbuf>7)->str,
1272                                           "get_line", $<line>6,
1273                                           NULL);
1274                                 g_string_free ($<cbuf>7, FALSE);
1275                                 g_free ($<id>5); 
1276                         } else if (strcmp ($<id>5, "set") == 0) {
1277                                 node_set ((Node *)property,
1278                                           "set:steal", ($<cbuf>7)->str,
1279                                           "set_line", $<line>6,
1280                                           NULL);
1281                                 g_string_free ($<cbuf>7, FALSE);
1282                                 g_free ($<id>5); 
1283                         } else {
1284                                 g_string_free ($<cbuf>7, TRUE);
1285                                 g_free ($<id>5); 
1286                                 node_free ((Node *)property);
1287                                 property = NULL;
1288                                 yyerror (_("parse error"));
1289                                 YYERROR;
1290                         }
1291                         property_link_and_export ((Node *)property);
1292                         if (property != NULL) {
1293                                 class_nodes = g_list_append (class_nodes,
1294                                                              property);
1295                                 property = NULL;
1296                         }
1297                 }
1298         |       PROPERTY TOKEN TOKEN param_spec ';' {
1299                         ensure_property ();
1300                         node_set ((Node *)property,
1301                                   "line_no", $<line>1,
1302                                   "gtktype:steal", debool ($<id>2),
1303                                   "name:steal", $<id>3,
1304                                   NULL);
1305                         property_link_and_export ((Node *)property);
1306                         if (property != NULL) {
1307                                 class_nodes = g_list_append (class_nodes,
1308                                                              property);
1309                                 property = NULL;
1310                         }
1311                 }
1312         ;
1313
1314 param_spec:     '(' param_spec_list ')' { ; }
1315         |                               { ; }
1316         ;
1317
1318 param_spec_list:        param_spec_list ',' param_spec_value    { ; }
1319         |               param_spec_value                        { ; }
1320         ;
1321
1322 string:         STRING                          { $<id>$ = $<id>1; }
1323         |       TOKEN '(' STRING ')'            {
1324                         if (strcmp ($<id>1, "_") != 0) {
1325                                 g_free ($<id>1);
1326                                 yyerror(_("parse error"));
1327                                 YYERROR;
1328                         }
1329                         g_free ($<id>1);
1330                         $<id>$ = g_strconcat ("_(", $<id>3, ")", NULL);
1331                         g_free ($<id>3);
1332                 }
1333         ;
1334
1335 anyval:         numtok          { $<id>$ = $<id>1; }
1336         |       string          { $<id>$ = $<id>1; }
1337         ;
1338
1339 param_spec_value: NICK '=' string               {
1340                 ensure_property ();
1341                 node_set ((Node *)property,
1342                           "nick:steal", $<id>3,
1343                           NULL);
1344                   }
1345         |       BLURB '=' string                {
1346                 ensure_property ();
1347                 node_set ((Node *)property,
1348                           "blurb:steal", $<id>3,
1349                           NULL);
1350                   }
1351         |       MAXIMUM '=' numtok              {
1352                 ensure_property ();
1353                 node_set ((Node *)property,
1354                           "maximum:steal", $<id>3,
1355                           NULL);
1356                   }
1357         |       MINIMUM '=' numtok              {
1358                 ensure_property ();
1359                 node_set ((Node *)property,
1360                           "minimum:steal", $<id>3,
1361                           NULL);
1362                   }
1363         |       DEFAULT_VALUE '=' anyval        {
1364                 ensure_property ();
1365                 node_set ((Node *)property,
1366                           "default_value:steal", $<id>3,
1367                           NULL);
1368                   }
1369         |       FLAGS '=' flaglist              {
1370                 ensure_property ();
1371                 node_set ((Node *)property,
1372                           "flags:steal", $<list>3,
1373                           NULL);
1374                   }
1375         |       TYPE '=' type                   {
1376                 Type *type = pop_type ();
1377                 ensure_property ();
1378                 node_set ((Node *)property,
1379                           "ptype:steal", type,
1380                           NULL);
1381                   }
1382         |       FLAGS_TYPE '=' TYPETOKEN        {
1383                 ensure_property ();
1384                 node_set ((Node *)property,
1385                           "extra_gtktype:steal", $<id>3,
1386                           NULL);
1387                   }
1388         |       FLAGS_TYPE '=' TOKEN            {
1389                 ensure_property ();
1390                 node_set ((Node *)property,
1391                           "extra_gtktype:steal", $<id>3,
1392                           NULL);
1393                   }
1394         |       ENUM_TYPE '=' TYPETOKEN         {
1395                 ensure_property ();
1396                 node_set ((Node *)property,
1397                           "extra_gtktype:steal", $<id>3,
1398                           NULL);
1399                   }
1400         |       ENUM_TYPE '=' TOKEN             {
1401                 ensure_property ();
1402                 node_set ((Node *)property,
1403                           "extra_gtktype:steal", $<id>3,
1404                           NULL);
1405                   }
1406         |       PARAM_TYPE '=' TYPETOKEN        {
1407                 ensure_property ();
1408                 node_set ((Node *)property,
1409                           "extra_gtktype:steal", $<id>3,
1410                           NULL);
1411                   }
1412         |       PARAM_TYPE '=' TOKEN            {
1413                 ensure_property ();
1414                 node_set ((Node *)property,
1415                           "extra_gtktype:steal", $<id>3,
1416                           NULL);
1417                   }
1418         |       BOXED_TYPE '=' TYPETOKEN        {
1419                 ensure_property ();
1420                 node_set ((Node *)property,
1421                           "extra_gtktype:steal", $<id>3,
1422                           NULL);
1423                   }
1424         |       BOXED_TYPE '=' TOKEN            {
1425                 ensure_property ();
1426                 node_set ((Node *)property,
1427                           "extra_gtktype:steal", $<id>3,
1428                           NULL);
1429                   }
1430         |       OBJECT_TYPE '=' TYPETOKEN       {
1431                 ensure_property ();
1432                 node_set ((Node *)property,
1433                           "extra_gtktype:steal", $<id>3,
1434                           NULL);
1435                   }
1436         |       OBJECT_TYPE '=' TOKEN           {
1437                 ensure_property ();
1438                 node_set ((Node *)property,
1439                           "extra_gtktype:steal", $<id>3,
1440                           NULL);
1441                   }
1442         |       TOKEN           {
1443                 ensure_property ();
1444                 if (strcmp ($<id>1, "override") == 0) {
1445                         g_free($<id>1);
1446                         node_set ((Node *)property,
1447                                   "override", TRUE,
1448                                   NULL);
1449                 } else if (strcmp ($<id>1, "link") == 0) {
1450                         g_free($<id>1);
1451                         node_set ((Node *)property,
1452                                   "link", TRUE,
1453                                   NULL);
1454                 } else if (strcmp ($<id>1, "export") == 0) {
1455                         g_free($<id>1);
1456                         node_set ((Node *)property,
1457                                   "export", TRUE,
1458                                   NULL);
1459                 } else {
1460                         g_free($<id>1);
1461                         yyerror(_("parse error"));
1462                         YYERROR;
1463                 }
1464                   }
1465         ;
1466
1467 argtype:        TOKEN '(' TOKEN type ')'        {
1468                         if(strcmp($<id>3,"type")!=0) {
1469                                 g_free($<id>1);
1470                                 g_free($<id>3);
1471                                 yyerror(_("parse error"));
1472                                 YYERROR;
1473                         }
1474                         $<id>$ = debool ($<id>1);
1475                                                 }
1476         |       TOKEN                           {
1477                         $<id>$ = debool ($<id>1);
1478                         typestack = g_list_prepend(typestack,NULL);
1479                                                 }
1480         ;
1481         
1482 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
1483         |                                       { $<list>$ = NULL; }
1484         ;
1485
1486 flaglist:       TOKEN '|' flaglist              {
1487                         $<list>$ = g_list_append($<list>3,$<id>1);
1488                                                 }
1489         |       TOKEN                           {
1490                         $<list>$ = g_list_append(NULL,$<id>1);
1491                                                 }
1492         ;
1493
1494
1495 type:           specifier_list pointer                          {
1496                         Node *node = node_new (TYPE_NODE, 
1497                                                "name:steal", $<id>1,
1498                                                "pointer:steal", $<id>2,
1499                                                NULL);
1500                         typestack = g_list_prepend(typestack,node);
1501                                                         }
1502         |       specifier_list                          {
1503                         Node *node = node_new (TYPE_NODE, 
1504                                                "name:steal", $<id>1,
1505                                                NULL);
1506                         typestack = g_list_prepend(typestack,node);
1507                                                         }
1508         ;
1509
1510 /* The special cases are neccessary to avoid conflicts */
1511 specifier_list: spec_list                               {
1512                         $<id>$ = $<id>1;
1513                                                         }
1514         |       TOKEN                                   {
1515                         $<id>$ = $<id>1;
1516                                                         }
1517         |       CONST TOKEN                             {
1518                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
1519                         g_free($<id>2);
1520                                                         }
1521         |       TOKEN CONST                             {
1522                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1523                         g_free($<id>1);
1524                                                         }
1525         |       strunionenum TOKEN                      {
1526                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1527                         g_free($<id>2);
1528                                                         }
1529         |       CONST strunionenum TOKEN                {
1530                         $<id>$ = g_strconcat("const ", $<id>2, " ",
1531                                              $<id>3, NULL);
1532                         g_free($<id>3);
1533                                                         }
1534         |       strunionenum TOKEN CONST                {
1535                         $<id>$ = g_strconcat($<id>1, " ",
1536                                              $<id>2, " const", NULL);
1537                         g_free($<id>2);
1538                                                         }
1539         ;
1540
1541 /* The special const cases take care of conflicts ! */
1542 spec_list:      specifier spec_list                     {
1543                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1544                         g_free($<id>2);
1545                                                         }
1546         |       TYPETOKEN spec_list                     {
1547                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1548                         g_free($<id>1);
1549                         g_free($<id>2);
1550                                                         }
1551         |       CONST spec_list                         {
1552                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
1553                         g_free($<id>2);
1554                                                         }
1555         |       TYPETOKEN                               {
1556                         $<id>$ = $<id>1;
1557                                                         }
1558         |       TYPETOKEN CONST                         {
1559                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1560                         g_free($<id>1);
1561                                                         }
1562         |       specifier                               {
1563                         $<id>$ = g_strdup($<id>1);
1564                                                         }
1565         |       specifier CONST                         {
1566                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1567                                                         }
1568         ;
1569
1570 specifier:      VOID                    { $<id>$ = "void"; }
1571         |       CHAR                    { $<id>$ = "char"; }
1572         |       SHORT                   { $<id>$ = "short"; }
1573         |       INT                     { $<id>$ = "int"; }
1574         |       LONG                    { $<id>$ = "long"; }
1575         |       FLOAT                   { $<id>$ = "float"; }
1576         |       DOUBLE                  { $<id>$ = "double"; }
1577         |       SIGNED                  { $<id>$ = "signed"; }
1578         |       UNSIGNED                { $<id>$ = "unsigned"; }
1579         ;
1580
1581 strunionenum:   STRUCT                  { $<id>$ = "struct"; }
1582         |       UNION                   { $<id>$ = "union"; }
1583         |       ENUM                    { $<id>$ = "enum"; }
1584         ;
1585
1586 pointer:        '*'                     { $<id>$ = g_strdup("*"); }
1587         |       '*' CONST               { $<id>$ = g_strdup("* const"); }
1588         |       '*' pointer             {
1589                                 $<id>$ = g_strconcat("*", $<id>2, NULL);
1590                                 g_free($<id>2);
1591                                         }
1592         |       '*' CONST pointer       {
1593                                 $<id>$ = g_strconcat("* const", $<id>3, NULL);
1594                                 g_free($<id>3);
1595                                         }
1596         ;
1597
1598 /* this never sets the_scope */
1599 simplesigtype:  TOKEN sigtype   {
1600                         if(strcmp($<id>1, "first")==0)
1601                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1602                         else if(strcmp($<id>1, "last")==0)
1603                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1604                         else {
1605                                 yyerror(_("signal must be 'first' or 'last'"));
1606                                 g_free($<id>1);
1607                                 YYERROR;
1608                         }
1609                         g_free($<id>1);
1610                                         }
1611         |       sigtype                 {
1612                         $<sigtype>$ = SIGNAL_LAST_METHOD;
1613                                         }
1614         ;
1615
1616 /* this always sets the_scope */
1617 fullsigtype:    scope TOKEN sigtype     {
1618                         if(strcmp($<id>2,"first")==0)
1619                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1620                         else if(strcmp($<id>2,"last")==0)
1621                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1622                         else {
1623                                 yyerror(_("signal must be 'first' or 'last'"));
1624                                 g_free($<id>2);
1625                                 YYERROR;
1626                         }
1627                         g_free($<id>2);
1628                                         }
1629         |       TOKEN scope sigtype     {
1630                         if(strcmp($<id>1,"first")==0)
1631                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1632                         else if(strcmp($<id>1,"last")==0)
1633                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1634                         else {
1635                                 yyerror(_("signal must be 'first' or 'last'"));
1636                                 g_free($<id>1);
1637                                 YYERROR;
1638                         }
1639                         g_free($<id>1);
1640                                         }
1641         |       scope sigtype           {
1642                         $<sigtype>$ = SIGNAL_LAST_METHOD;
1643                                         }
1644         |       simplesigtype           {
1645                         /* the_scope was default thus public */
1646                         the_scope = PUBLIC_SCOPE;
1647                                         }
1648         ;
1649         
1650 sigtype:        TOKEN '(' tokenlist ')'         {
1651                         gtktypes = g_list_prepend(gtktypes, debool ($<id>1));
1652                                                 }
1653         ;
1654
1655 tokenlist:      tokenlist ',' TOKEN             {
1656                         gtktypes = g_list_append(gtktypes, debool ($<id>3));
1657                                                 }
1658         |       TOKEN                           { 
1659                         gtktypes = g_list_append(gtktypes, debool ($<id>1));
1660                                                 }
1661         ;
1662
1663 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
1664         |       ';'                             { $<cbuf>$ = NULL; }
1665         ;
1666
1667 /*here CCODE will include the ending '}' */
1668 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
1669                         if(!has_self) {
1670                                 yyerror(_("signal without 'self' as "
1671                                           "first parameter"));
1672                                 free_all_global_state();
1673                                 YYERROR;
1674                         }
1675                         if(the_scope == CLASS_SCOPE) {
1676                                 yyerror(_("a method cannot be of class scope"));
1677                                 free_all_global_state();
1678                                 YYERROR;
1679                         }
1680                         push_function(the_scope, $<sigtype>3,NULL,
1681                                       $<id>5, $<cbuf>10,$<line>1,
1682                                       ccode_line, vararg, $<list>2);
1683                                                                         }
1684         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
1685                         if(!has_self) {
1686                                 yyerror(_("signal without 'self' as "
1687                                           "first parameter"));
1688                                 free_all_global_state();
1689                                 YYERROR;
1690                         }
1691                         if(the_scope == CLASS_SCOPE) {
1692                                 yyerror(_("a method cannot be of class scope"));
1693                                 free_all_global_state();
1694                                 YYERROR;
1695                         }
1696                         push_function(the_scope, $<sigtype>4, NULL,
1697                                       $<id>6, $<cbuf>11, $<line>2,
1698                                       ccode_line, vararg, $<list>3);
1699                                                                         }
1700         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
1701                         if(!has_self) {
1702                                 yyerror(_("virtual method without 'self' as "
1703                                           "first parameter"));
1704                                 free_all_global_state();
1705                                 YYERROR;
1706                         }
1707                         if(the_scope == CLASS_SCOPE) {
1708                                 yyerror(_("a method cannot be of class scope"));
1709                                 free_all_global_state();
1710                                 YYERROR;
1711                         }
1712                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1713                                       $<cbuf>9, $<line>1,
1714                                       ccode_line, vararg, NULL);
1715                                                                         }
1716         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
1717                         if(!has_self) {
1718                                 yyerror(_("virtual method without 'self' as "
1719                                           "first parameter"));
1720                                 free_all_global_state();
1721                                 YYERROR;
1722                         }
1723                         if(the_scope == CLASS_SCOPE) {
1724                                 yyerror(_("a method cannot be of class scope"));
1725                                 free_all_global_state();
1726                                 YYERROR;
1727                         }
1728                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1729                                       $<cbuf>9, $<line>2,
1730                                       ccode_line, vararg, NULL);
1731                                                                         }
1732         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
1733                         if(!has_self) {
1734                                 yyerror(_("virtual method without 'self' as "
1735                                           "first parameter"));
1736                                 free_all_global_state();
1737                                 YYERROR;
1738                         }
1739                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
1740                                       $<id>3, $<cbuf>8, $<line>1,
1741                                       ccode_line, vararg, NULL);
1742                                                                         }
1743         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
1744                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
1745                                       $<id>6, $<cbuf>11,
1746                                       $<line>1, ccode_line,
1747                                       vararg, NULL);
1748                                                                         }
1749         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
1750                         if(the_scope == CLASS_SCOPE) {
1751                                 yyerror(_("a method cannot be of class scope"));
1752                                 free_all_global_state();
1753                                 YYERROR;
1754                         }
1755                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
1756                                       $<cbuf>8, $<line>1, ccode_line,
1757                                       vararg, NULL);
1758                                                                 }
1759         |       TOKEN '(' TOKEN ')' codenocode  {
1760                         if(strcmp($<id>1, "init")==0) {
1761                                 push_init_arg($<id>3,FALSE);
1762                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
1763                                               $<id>1, $<cbuf>5, $<line>2,
1764                                               ccode_line, FALSE, NULL);
1765                         } else if(strcmp($<id>1, "class_init")==0) {
1766                                 push_init_arg($<id>3,TRUE);
1767                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
1768                                               $<id>1, $<cbuf>5, $<line>2,
1769                                               ccode_line, FALSE, NULL);
1770                         } else {
1771                                 g_free($<id>1);
1772                                 g_free($<id>3);
1773                                 g_string_free($<cbuf>5,TRUE);
1774                                 yyerror(_("parse error "
1775                                           "(untyped blocks must be init or "
1776                                           "class_init)"));
1777                                 YYERROR;
1778                         }
1779                                                 }
1780         ;
1781
1782 returnvals:     TOKEN retcode           {
1783                         g_free(onerror); onerror = NULL;
1784                         g_free(defreturn); defreturn = NULL;
1785                         if(!set_return_value($<id>1, $<id>2)) {
1786                                 g_free($<id>1);
1787                                 g_free($<id>2);
1788                                 yyerror(_("parse error"));
1789                                 YYERROR;
1790                         }
1791                         g_free($<id>1);
1792                                         }
1793         |       TOKEN retcode TOKEN retcode     {
1794                         g_free(onerror); onerror = NULL;
1795                         g_free(defreturn); defreturn = NULL;
1796                         if(!set_return_value($<id>1, $<id>2)) {
1797                                 g_free($<id>1); g_free($<id>2);
1798                                 g_free($<id>3); g_free($<id>4);
1799                                 yyerror(_("parse error"));
1800                                 YYERROR;
1801                         }
1802                         if(!set_return_value($<id>3, $<id>4)) {
1803                                 onerror = defreturn = NULL;
1804                                 g_free($<id>1); g_free($<id>2);
1805                                 g_free($<id>3); g_free($<id>4);
1806                                 yyerror(_("parse error"));
1807                                 YYERROR;
1808                         }
1809                         g_free($<id>1);
1810                         g_free($<id>3);
1811                                                 }
1812         |                               {
1813                         g_free(onerror); onerror = NULL;
1814                         g_free(defreturn); defreturn = NULL;
1815                                         }
1816         ;
1817
1818 retcode:        numtok                  { $<id>$ = $<id>1; }
1819         |       '{' CCODE               {
1820                         $<id>$ = ($<cbuf>2)->str;
1821                         g_string_free($<cbuf>2, FALSE);
1822                                         }
1823         ;
1824         
1825 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
1826         |       TOKEN                   {
1827                         vararg = FALSE;
1828                         has_self = TRUE;
1829                         if(strcmp($<id>1,"self")==0)
1830                                 push_self($<id>1, FALSE);
1831                         else {
1832                                 g_free($<id>1);
1833                                 yyerror(_("parse error"));
1834                                 YYERROR;
1835                         }
1836                                         }
1837         |       TOKEN CONST {
1838                         vararg = FALSE;
1839                         has_self = TRUE;
1840                         if(strcmp($<id>1,"self")==0)
1841                                 push_self($<id>1, TRUE);
1842                         else {
1843                                 g_free($<id>1);
1844                                 yyerror(_("parse error"));
1845                                 YYERROR;
1846                         }
1847                                         }
1848         |       CONST TOKEN {
1849                         vararg = FALSE;
1850                         has_self = TRUE;
1851                         if(strcmp($<id>2,"self")==0)
1852                                 push_self($<id>2, TRUE);
1853                         else {
1854                                 g_free($<id>2);
1855                                 yyerror(_("parse error"));
1856                                 YYERROR;
1857                         }
1858                                         }
1859         |       TOKEN ',' arglist       {
1860                         has_self = TRUE;
1861                         if(strcmp($<id>1,"self")==0)
1862                                 push_self($<id>1, FALSE);
1863                         else {
1864                                 g_free($<id>1);
1865                                 yyerror(_("parse error"));
1866                                 YYERROR;
1867                         }
1868                                         }
1869         |       TOKEN CONST ',' arglist {
1870                         has_self = TRUE;
1871                         if(strcmp($<id>1,"self")==0)
1872                                 push_self($<id>1, TRUE);
1873                         else {
1874                                 g_free($<id>1);
1875                                 yyerror(_("parse error"));
1876                                 YYERROR;
1877                         }
1878                                         }
1879         |       CONST TOKEN ',' arglist {
1880                         has_self = TRUE;
1881                         if(strcmp($<id>2,"self")==0)
1882                                 push_self($<id>2, TRUE);
1883                         else {
1884                                 g_free($<id>2);
1885                                 yyerror(_("parse error"));
1886                                 YYERROR;
1887                         }
1888                                         }
1889         |       arglist                 { has_self = FALSE; }
1890         ;
1891
1892 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
1893         |       arglist1                { vararg = FALSE; }
1894         ;
1895         
1896 arglist1:       arglist1 ',' arg        { ; }
1897         |       arg                     { ; }
1898         ;
1899
1900 arg:            type TOKEN                                      {
1901                         push_funcarg($<id>2,NULL);
1902                                                                 }
1903         |       type TOKEN ARRAY_DIM                            {
1904                         push_funcarg($<id>2,$<id>3);
1905                                                                 }
1906         |       type TOKEN '(' TOKEN checklist ')'              {
1907                         if(strcmp($<id>4,"check")!=0) {
1908                                 yyerror(_("parse error"));
1909                                 YYERROR;
1910                         }
1911                         g_free($<id>4);
1912                         push_funcarg($<id>2,NULL);
1913                                                                 }
1914         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
1915                         if(strcmp($<id>5,"check")!=0) {
1916                                 yyerror(_("parse error"));
1917                                 YYERROR;
1918                         }
1919                         g_free($<id>5);
1920                         push_funcarg($<id>2,$<id>3);
1921                                                                 }
1922         ;
1923         
1924 checklist:      checklist check         { ; }
1925         |       check                   { ; }
1926         ;
1927
1928 check:          TOKEN                   {
1929                         if(strcmp($<id>1,"type")==0) {
1930                                 Node *node = node_new (CHECK_NODE,
1931                                                        "chtype", TYPE_CHECK,
1932                                                        NULL);
1933                                 checks = g_list_append(checks,node);
1934                         } else if(strcmp($<id>1,"null")==0) {
1935                                 Node *node = node_new (CHECK_NODE,
1936                                                        "chtype", NULL_CHECK,
1937                                                        NULL);
1938                                 checks = g_list_append(checks,node);
1939                         } else {
1940                                 yyerror(_("parse error"));
1941                                 YYERROR;
1942                         }
1943                         g_free($<id>1);
1944                                         }
1945         |       '>' numtok              {
1946                         Node *node = node_new (CHECK_NODE,
1947                                                "chtype", GT_CHECK,
1948                                                "number:steal", $<id>2,
1949                                                NULL);
1950                         checks = g_list_append(checks,node);
1951                                         }
1952         |       '<' numtok              {
1953                         Node *node = node_new (CHECK_NODE,
1954                                                "chtype", LT_CHECK,
1955                                                "number:steal", $<id>2,
1956                                                NULL);
1957                         checks = g_list_append(checks,node);
1958                                         }
1959         |       '>' '=' numtok          {
1960                         Node *node = node_new (CHECK_NODE,
1961                                                "chtype", GE_CHECK,
1962                                                "number:steal", $<id>3,
1963                                                NULL);
1964                         checks = g_list_append(checks,node);
1965                                         }
1966         |       '<' '=' numtok          {
1967                         Node *node = node_new (CHECK_NODE,
1968                                                "chtype", LE_CHECK,
1969                                                "number:steal", $<id>3,
1970                                                NULL);
1971                         checks = g_list_append(checks,node);
1972                                         }
1973         |       '=' '=' numtok          {
1974                         Node *node = node_new (CHECK_NODE,
1975                                                "chtype", EQ_CHECK,
1976                                                "number:steal", $<id>3,
1977                                                NULL);
1978                         checks = g_list_append(checks,node);
1979                                         }
1980         |       '!' '=' numtok          {
1981                         Node *node = node_new (CHECK_NODE,
1982                                                "chtype", NE_CHECK,
1983                                                "number:steal", $<id>3,
1984                                                NULL);
1985                         checks = g_list_append(checks,node);
1986                                         }
1987         ;
1988
1989 enumcode:       ENUM TOKEN '{' enumvals '}' TYPETOKEN ';' {
1990                         Node *node = node_new (ENUMDEF_NODE,
1991                                                "etype:steal", $<id>6,
1992                                                "prefix:steal", $<id>2,
1993                                                "values:steal", enum_vals,
1994                                                NULL);
1995                         enum_vals = NULL;
1996                         nodes = g_list_append (nodes, node);
1997                         }
1998         |       ENUM TOKEN '{' enumvals ',' '}' TYPETOKEN ';' {
1999                         Node *node = node_new (ENUMDEF_NODE,
2000                                                "etype:steal", $<id>7,
2001                                                "prefix:steal", $<id>2,
2002                                                "values:steal", enum_vals,
2003                                                NULL);
2004                         enum_vals = NULL;
2005                         nodes = g_list_append (nodes, node);
2006                         }
2007         ;
2008
2009 enumvals:       enumvals ',' enumval    {;}
2010         |       enumval                 {;}
2011         ;
2012
2013 enumval:        TOKEN '=' numtok        {
2014                         Node *node;
2015                         char *num = $<id>3;
2016
2017                         /* A float value, that's a bad enum */
2018                         if (num[0] >= '0' &&
2019                             num[0] <= '9' &&
2020                             strchr (num, '.') != NULL) {
2021                                 g_free ($<id>1);
2022                                 g_free (num);
2023                                 yyerror(_("parse error (enumerator value not integer constant)"));
2024                                 YYERROR;
2025                         }
2026                        
2027                         node = node_new (ENUMVALUE_NODE,
2028                                          "name:steal", $<id>1,
2029                                          "value:steal", num,
2030                                          NULL);
2031                         enum_vals = g_list_append (enum_vals, node);
2032                         }
2033         |       TOKEN                   {
2034                         Node *node;
2035
2036                         node = node_new (ENUMVALUE_NODE,
2037                                          "name:steal", $<id>1,
2038                                          NULL);
2039                         enum_vals = g_list_append (enum_vals, node);
2040         }
2041         ;
2042
2043 flagcode:       FLAGS TOKEN '{' flagvals '}' TYPETOKEN ';' {
2044                         Node *node = node_new (FLAGS_NODE,
2045                                                "ftype:steal", $<id>6,
2046                                                "prefix:steal", $<id>2,
2047                                                "values:steal", flag_vals,
2048                                                NULL);
2049                         flag_vals = NULL;
2050                         nodes = g_list_append (nodes, node);
2051                         }
2052         |       FLAGS TOKEN '{' flagvals ',' '}' TYPETOKEN ';' {
2053                         Node *node = node_new (FLAGS_NODE,
2054                                                "ftype:steal", $<id>7,
2055                                                "prefix:steal", $<id>2,
2056                                                "values:steal", flag_vals,
2057                                                NULL);
2058                         flag_vals = NULL;
2059                         nodes = g_list_append (nodes, node);
2060                         }
2061         ;
2062
2063 flagvals:       flagvals ',' TOKEN      {
2064                         flag_vals = g_list_append (flag_vals, $<id>3);
2065                 }
2066         |       TOKEN                   {
2067                         flag_vals = g_list_append (flag_vals, $<id>1);
2068                 }
2069         ;
2070
2071 errorcode:      ERROR TOKEN '{' errorvals '}' TYPETOKEN ';' {
2072                         Node *node = node_new (ERROR_NODE,
2073                                                "etype:steal", $<id>6,
2074                                                "prefix:steal", $<id>2,
2075                                                "values:steal", error_vals,
2076                                                NULL);
2077                         error_vals = NULL;
2078                         nodes = g_list_append (nodes, node);
2079                         }
2080         |       ERROR TOKEN '{' errorvals ',' '}' TYPETOKEN ';' {
2081                         Node *node = node_new (ERROR_NODE,
2082                                                "etype:steal", $<id>7,
2083                                                "prefix:steal", $<id>2,
2084                                                "values:steal", error_vals,
2085                                                NULL);
2086                         error_vals = NULL;
2087                         nodes = g_list_append (nodes, node);
2088                         }
2089         ;
2090
2091 errorvals:      errorvals ',' TOKEN     {
2092                         error_vals = g_list_append (error_vals, $<id>3);
2093                 }
2094         |       TOKEN                   {
2095                         error_vals = g_list_append (error_vals, $<id>1);
2096                 }
2097         ;
2098
2099
2100 numtok:         NUMBER                  { $<id>$ = $<id>1; }
2101         |       '-' NUMBER              {
2102                         $<id>$ = g_strconcat("-",$<id>2,NULL);
2103                         g_free($<id>2);
2104                                         }
2105         |       SINGLE_CHAR             { $<id>$ = $<id>1; }
2106         |       TOKEN                   { $<id>$ = $<id>1; }
2107         ;
2108         
2109 %%