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