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