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