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