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