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