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