]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
e6600bf5538b48e749206a78bbd69a340507b752
[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 = "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                         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                         if(strcmp($<id>6, "link")==0) {
1038                                 set = g_strdup_printf("%s->%s = ARG;",
1039                                                       root, $<id>4);
1040                         } else if(strcmp($<id>6, "stringlink")==0) {
1041                                 set = g_strdup_printf("g_free (%s->%s); "
1042                                                       "%s->%s = g_strdup (ARG);",
1043                                                       root, $<id>4,
1044                                                       root, $<id>4);
1045                         } else if(strcmp($<id>6, "objectlink")==0) {
1046                                 set = g_strdup_printf(
1047                                   "if (ARG != NULL) "
1048                                    "g_object_ref (G_OBJECT (ARG)); "
1049                                   "if (%s->%s != NULL) "
1050                                    "g_object_unref (G_OBJECT (%s->%s)); "
1051                                   "%s->%s = ARG;",
1052                                   root, $<id>4,
1053                                   root, $<id>4,
1054                                   root, $<id>4);
1055                         } else {
1056                                 g_assert_not_reached();
1057                         }
1058
1059                         get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
1060   
1061                         g_free ($<id>6);
1062
1063                         if (type == NULL)
1064                                 type = (Type *)node_copy ((Node *)var->vtype);
1065
1066                         node = node_new (ARGUMENT_NODE,
1067                                          "gtktype:steal", $<id>3,
1068                                          "atype:steal", type,
1069                                          "flags:steal", $<list>2,
1070                                          "name:steal", $<id>4,
1071                                          "get:steal", get,
1072                                          "get_line", $<line>1,
1073                                          "set:steal", set,
1074                                          "set_line", $<line>1,
1075                                          "line_no", $<line>1,
1076                                          NULL);
1077
1078                         if ($<id>5 != NULL) {
1079                                 Argument *arg = (Argument *)node;
1080                                 export_accessors (arg->name,
1081                                                   arg->get != NULL, arg->get_line,
1082                                                   arg->set != NULL, arg->set_line,
1083                                                   arg->atype,
1084                                                   arg->gtktype,
1085                                                   arg->line_no);
1086                                 g_free ($<id>5);
1087                         } 
1088
1089                         class_nodes = g_list_append (class_nodes, node);
1090                                                 }
1091         ;
1092
1093 export:         '(' TOKEN ')'                   {
1094                         if (strcmp ($<id>2, "export")!=0) {
1095                                 g_free ($<id>2); 
1096                                 yyerror (_("parse error"));
1097                                 YYERROR;
1098                         }
1099                         $<id>$ = $<id>2;
1100                                                 }
1101          |                                      {
1102                         $<id>$ = NULL;
1103                                                 }
1104          ;
1105
1106 property:       PROPERTY TOKEN TOKEN param_spec TOKEN '{' CCODE TOKEN '{' CCODE ';' {
1107                         ensure_property ();
1108                         node_set ((Node *)property,
1109                                   "line_no", $<line>1,
1110                                   "gtktype:steal", debool ($<id>2),
1111                                   "name:steal", $<id>3,
1112                                   NULL);
1113                         if (strcmp ($<id>5, "get") == 0 &&
1114                             strcmp ($<id>8, "set") == 0) {
1115                                 node_set ((Node *)property,
1116                                           "get:steal", ($<cbuf>7)->str,
1117                                           "get_line", $<line>6,
1118                                           "set:steal", ($<cbuf>10)->str,
1119                                           "set_line", $<line>9,
1120                                           NULL);
1121                                 g_string_free ($<cbuf>7, FALSE);
1122                                 g_string_free ($<cbuf>10, FALSE);
1123                                 g_free ($<id>5); 
1124                                 g_free ($<id>8);
1125                         } else if (strcmp ($<id>5, "set") == 0 &&
1126                                    strcmp ($<id>8, "get") == 0) {
1127                                 node_set ((Node *)property,
1128                                           "get:steal", ($<cbuf>10)->str,
1129                                           "get_line", $<line>9,
1130                                           "set:steal", ($<cbuf>7)->str,
1131                                           "set_line", $<line>6,
1132                                           NULL);
1133                                 g_string_free ($<cbuf>7, FALSE);
1134                                 g_string_free ($<cbuf>10, FALSE);
1135                                 g_free ($<id>5); 
1136                                 g_free ($<id>8);
1137                         } else {
1138                                 g_string_free ($<cbuf>7, TRUE);
1139                                 g_string_free ($<cbuf>10, TRUE);
1140                                 g_free ($<id>5); 
1141                                 g_free ($<id>8);
1142                                 node_free ((Node *)property);
1143                                 property = NULL;
1144                                 yyerror (_("parse error"));
1145                                 YYERROR;
1146                         }
1147                         property_link_and_export ((Node *)property);
1148                         if (property != NULL) {
1149                                 class_nodes = g_list_append (class_nodes,
1150                                                              property);
1151                                 property = NULL;
1152                         }
1153                 }
1154         |       PROPERTY TOKEN TOKEN param_spec TOKEN '{' CCODE ';' {
1155                         ensure_property ();
1156                         node_set ((Node *)property,
1157                                   "line_no", $<line>1,
1158                                   "gtktype:steal", debool ($<id>2),
1159                                   "name:steal", $<id>3,
1160                                   NULL);
1161                         if (strcmp ($<id>5, "get") == 0) {
1162                                 node_set ((Node *)property,
1163                                           "get:steal", ($<cbuf>7)->str,
1164                                           "get_line", $<line>6,
1165                                           NULL);
1166                                 g_string_free ($<cbuf>7, FALSE);
1167                                 g_free ($<id>5); 
1168                         } else if (strcmp ($<id>5, "set") == 0) {
1169                                 node_set ((Node *)property,
1170                                           "set:steal", ($<cbuf>7)->str,
1171                                           "set_line", $<line>6,
1172                                           NULL);
1173                                 g_string_free ($<cbuf>7, FALSE);
1174                                 g_free ($<id>5); 
1175                         } else {
1176                                 g_string_free ($<cbuf>7, TRUE);
1177                                 g_free ($<id>5); 
1178                                 node_free ((Node *)property);
1179                                 property = NULL;
1180                                 yyerror (_("parse error"));
1181                                 YYERROR;
1182                         }
1183                         property_link_and_export ((Node *)property);
1184                         if (property != NULL) {
1185                                 class_nodes = g_list_append (class_nodes,
1186                                                              property);
1187                                 property = NULL;
1188                         }
1189                 }
1190         |       PROPERTY TOKEN TOKEN param_spec ';' {
1191                         ensure_property ();
1192                         node_set ((Node *)property,
1193                                   "line_no", $<line>1,
1194                                   "gtktype:steal", debool ($<id>2),
1195                                   "name:steal", $<id>3,
1196                                   NULL);
1197                         property_link_and_export ((Node *)property);
1198                         if (property != NULL) {
1199                                 class_nodes = g_list_append (class_nodes,
1200                                                              property);
1201                                 property = NULL;
1202                         }
1203                 }
1204         ;
1205
1206 param_spec:     '(' param_spec_list ')' { ; }
1207         |                               { ; }
1208         ;
1209
1210 param_spec_list:        param_spec_list ',' param_spec_value    { ; }
1211         |               param_spec_value                        { ; }
1212         ;
1213
1214 string:         STRING                          { $<id>$ = $<id>1; }
1215         |       TOKEN '(' STRING ')'            {
1216                         if (strcmp ($<id>1, "_") != 0) {
1217                                 g_free ($<id>1);
1218                                 yyerror(_("parse error"));
1219                                 YYERROR;
1220                         }
1221                         g_free ($<id>1);
1222                         $<id>$ = g_strconcat ("_(", $<id>3, ")", NULL);
1223                         g_free ($<id>3);
1224                 }
1225         ;
1226
1227 anyval:         numtok          { $<id>$ = $<id>1; }
1228         |       string          { $<id>$ = $<id>1; }
1229         ;
1230
1231 param_spec_value: NICK '=' string               {
1232                 ensure_property ();
1233                 node_set ((Node *)property,
1234                           "nick:steal", $<id>3,
1235                           NULL);
1236                   }
1237         |       BLURB '=' string                {
1238                 ensure_property ();
1239                 node_set ((Node *)property,
1240                           "blurb:steal", $<id>3,
1241                           NULL);
1242                   }
1243         |       MAXIMUM '=' numtok              {
1244                 ensure_property ();
1245                 node_set ((Node *)property,
1246                           "maximum:steal", $<id>3,
1247                           NULL);
1248                   }
1249         |       MINIMUM '=' numtok              {
1250                 ensure_property ();
1251                 node_set ((Node *)property,
1252                           "minimum:steal", $<id>3,
1253                           NULL);
1254                   }
1255         |       DEFAULT_VALUE '=' anyval        {
1256                 ensure_property ();
1257                 node_set ((Node *)property,
1258                           "default_value:steal", $<id>3,
1259                           NULL);
1260                   }
1261         |       FLAGS '=' flaglist              {
1262                 ensure_property ();
1263                 node_set ((Node *)property,
1264                           "flags:steal", $<list>3,
1265                           NULL);
1266                   }
1267         |       TYPE '=' type                   {
1268                 Type *type = pop_type ();
1269                 ensure_property ();
1270                 node_set ((Node *)property,
1271                           "ptype:steal", type,
1272                           NULL);
1273                   }
1274         |       FLAGS_TYPE '=' TYPETOKEN        {
1275                 ensure_property ();
1276                 node_set ((Node *)property,
1277                           "extra_gtktype:steal", $<id>3,
1278                           NULL);
1279                   }
1280         |       FLAGS_TYPE '=' TOKEN            {
1281                 ensure_property ();
1282                 node_set ((Node *)property,
1283                           "extra_gtktype:steal", $<id>3,
1284                           NULL);
1285                   }
1286         |       ENUM_TYPE '=' TYPETOKEN         {
1287                 ensure_property ();
1288                 node_set ((Node *)property,
1289                           "extra_gtktype:steal", $<id>3,
1290                           NULL);
1291                   }
1292         |       ENUM_TYPE '=' TOKEN             {
1293                 ensure_property ();
1294                 node_set ((Node *)property,
1295                           "extra_gtktype:steal", $<id>3,
1296                           NULL);
1297                   }
1298         |       PARAM_TYPE '=' TYPETOKEN        {
1299                 ensure_property ();
1300                 node_set ((Node *)property,
1301                           "extra_gtktype:steal", $<id>3,
1302                           NULL);
1303                   }
1304         |       PARAM_TYPE '=' TOKEN            {
1305                 ensure_property ();
1306                 node_set ((Node *)property,
1307                           "extra_gtktype:steal", $<id>3,
1308                           NULL);
1309                   }
1310         |       BOXED_TYPE '=' TYPETOKEN        {
1311                 ensure_property ();
1312                 node_set ((Node *)property,
1313                           "extra_gtktype:steal", $<id>3,
1314                           NULL);
1315                   }
1316         |       BOXED_TYPE '=' TOKEN            {
1317                 ensure_property ();
1318                 node_set ((Node *)property,
1319                           "extra_gtktype:steal", $<id>3,
1320                           NULL);
1321                   }
1322         |       OBJECT_TYPE '=' TYPETOKEN       {
1323                 ensure_property ();
1324                 node_set ((Node *)property,
1325                           "extra_gtktype:steal", $<id>3,
1326                           NULL);
1327                   }
1328         |       OBJECT_TYPE '=' TOKEN           {
1329                 ensure_property ();
1330                 node_set ((Node *)property,
1331                           "extra_gtktype:steal", $<id>3,
1332                           NULL);
1333                   }
1334         |       TOKEN           {
1335                 ensure_property ();
1336                 if (strcmp ($<id>1, "link") == 0) {
1337                         g_free($<id>1);
1338                         node_set ((Node *)property,
1339                                   "link", TRUE,
1340                                   NULL);
1341                 } else if (strcmp ($<id>1, "export") == 0) {
1342                         g_free($<id>1);
1343                         node_set ((Node *)property,
1344                                   "export", TRUE,
1345                                   NULL);
1346                 } else {
1347                         g_free($<id>1);
1348                         yyerror(_("parse error"));
1349                         YYERROR;
1350                 }
1351                   }
1352         ;
1353
1354 argtype:        TOKEN '(' TOKEN type ')'        {
1355                         if(strcmp($<id>3,"type")!=0) {
1356                                 g_free($<id>1);
1357                                 g_free($<id>3);
1358                                 yyerror(_("parse error"));
1359                                 YYERROR;
1360                         }
1361                         $<id>$ = debool ($<id>1);
1362                                                 }
1363         |       TOKEN                           {
1364                         $<id>$ = debool ($<id>1);
1365                         typestack = g_list_prepend(typestack,NULL);
1366                                                 }
1367         ;
1368         
1369 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
1370         |                                       { $<list>$ = NULL; }
1371         ;
1372
1373 flaglist:       TOKEN '|' flaglist              {
1374                         $<list>$ = g_list_append($<list>3,$<id>1);
1375                                                 }
1376         |       TOKEN                           {
1377                         $<list>$ = g_list_append(NULL,$<id>1);
1378                                                 }
1379         ;
1380
1381
1382 type:           specifier_list pointer                          {
1383                         Node *node = node_new (TYPE_NODE, 
1384                                                "name:steal", $<id>1,
1385                                                "pointer:steal", $<id>2,
1386                                                NULL);
1387                         typestack = g_list_prepend(typestack,node);
1388                                                         }
1389         |       specifier_list                          {
1390                         Node *node = node_new (TYPE_NODE, 
1391                                                "name:steal", $<id>1,
1392                                                NULL);
1393                         typestack = g_list_prepend(typestack,node);
1394                                                         }
1395         ;
1396
1397 /* The special cases are neccessary to avoid conflicts */
1398 specifier_list: spec_list                               {
1399                         $<id>$ = $<id>1;
1400                                                         }
1401         |       TOKEN                                   {
1402                         $<id>$ = $<id>1;
1403                                                         }
1404         |       CONST TOKEN                             {
1405                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
1406                         g_free($<id>2);
1407                                                         }
1408         |       TOKEN CONST                             {
1409                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1410                         g_free($<id>1);
1411                                                         }
1412         |       strunionenum TOKEN                      {
1413                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1414                         g_free($<id>2);
1415                                                         }
1416         |       CONST strunionenum TOKEN                {
1417                         $<id>$ = g_strconcat("const ", $<id>2, " ",
1418                                              $<id>3, NULL);
1419                         g_free($<id>3);
1420                                                         }
1421         |       strunionenum TOKEN CONST                {
1422                         $<id>$ = g_strconcat($<id>1, " ",
1423                                              $<id>2, " const", NULL);
1424                         g_free($<id>2);
1425                                                         }
1426         ;
1427
1428 /* The special const cases take care of conflicts ! */
1429 spec_list:      specifier spec_list                     {
1430                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1431                         g_free($<id>2);
1432                                                         }
1433         |       TYPETOKEN spec_list                     {
1434                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1435                         g_free($<id>1);
1436                         g_free($<id>2);
1437                                                         }
1438         |       CONST spec_list                         {
1439                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
1440                         g_free($<id>2);
1441                                                         }
1442         |       TYPETOKEN                               {
1443                         $<id>$ = $<id>1;
1444                                                         }
1445         |       TYPETOKEN CONST                         {
1446                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1447                         g_free($<id>1);
1448                                                         }
1449         |       specifier                               {
1450                         $<id>$ = g_strdup($<id>1);
1451                                                         }
1452         |       specifier CONST                         {
1453                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1454                                                         }
1455         ;
1456
1457 specifier:      VOID                    { $<id>$ = "void"; }
1458         |       CHAR                    { $<id>$ = "char"; }
1459         |       SHORT                   { $<id>$ = "short"; }
1460         |       INT                     { $<id>$ = "int"; }
1461         |       LONG                    { $<id>$ = "long"; }
1462         |       FLOAT                   { $<id>$ = "float"; }
1463         |       DOUBLE                  { $<id>$ = "double"; }
1464         |       SIGNED                  { $<id>$ = "signed"; }
1465         |       UNSIGNED                { $<id>$ = "unsigned"; }
1466         ;
1467
1468 strunionenum:   STRUCT                  { $<id>$ = "struct"; }
1469         |       UNION                   { $<id>$ = "union"; }
1470         |       ENUM                    { $<id>$ = "enum"; }
1471         ;
1472
1473 pointer:        '*'                     { $<id>$ = g_strdup("*"); }
1474         |       '*' CONST               { $<id>$ = g_strdup("* const"); }
1475         |       '*' pointer             {
1476                                 $<id>$ = g_strconcat("*", $<id>2, NULL);
1477                                 g_free($<id>2);
1478                                         }
1479         |       '*' CONST pointer       {
1480                                 $<id>$ = g_strconcat("* const", $<id>3, NULL);
1481                                 g_free($<id>3);
1482                                         }
1483         ;
1484
1485 /* this never sets the_scope */
1486 simplesigtype:  TOKEN sigtype   {
1487                         if(strcmp($<id>1, "first")==0)
1488                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1489                         else if(strcmp($<id>1, "last")==0)
1490                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1491                         else {
1492                                 yyerror(_("signal must be 'first' or 'last'"));
1493                                 g_free($<id>1);
1494                                 YYERROR;
1495                         }
1496                         g_free($<id>1);
1497                                         }
1498         |       sigtype                 {
1499                         $<sigtype>$ = SIGNAL_LAST_METHOD;
1500                                         }
1501         ;
1502
1503 /* this always sets the_scope */
1504 fullsigtype:    scope TOKEN sigtype     {
1505                         if(strcmp($<id>2,"first")==0)
1506                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1507                         else if(strcmp($<id>2,"last")==0)
1508                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1509                         else {
1510                                 yyerror(_("signal must be 'first' or 'last'"));
1511                                 g_free($<id>2);
1512                                 YYERROR;
1513                         }
1514                         g_free($<id>2);
1515                                         }
1516         |       TOKEN scope sigtype     {
1517                         if(strcmp($<id>1,"first")==0)
1518                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1519                         else if(strcmp($<id>1,"last")==0)
1520                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1521                         else {
1522                                 yyerror(_("signal must be 'first' or 'last'"));
1523                                 g_free($<id>1);
1524                                 YYERROR;
1525                         }
1526                         g_free($<id>1);
1527                                         }
1528         |       scope sigtype           {
1529                         $<sigtype>$ = SIGNAL_LAST_METHOD;
1530                                         }
1531         |       simplesigtype           {
1532                         /* the_scope was default thus public */
1533                         the_scope = PUBLIC_SCOPE;
1534                                         }
1535         ;
1536         
1537 sigtype:        TOKEN '(' tokenlist ')'         {
1538                         gtktypes = g_list_prepend(gtktypes, debool ($<id>1));
1539                                                 }
1540         ;
1541
1542 tokenlist:      tokenlist ',' TOKEN             {
1543                         gtktypes = g_list_append(gtktypes, debool ($<id>3));
1544                                                 }
1545         |       TOKEN                           { 
1546                         gtktypes = g_list_append(gtktypes, debool ($<id>1));
1547                                                 }
1548         ;
1549
1550 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
1551         |       ';'                             { $<cbuf>$ = NULL; }
1552         ;
1553
1554 /*here CCODE will include the ending '}' */
1555 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
1556                         if(!has_self) {
1557                                 yyerror(_("signal without 'self' as "
1558                                           "first parameter"));
1559                                 free_all_global_state();
1560                                 YYERROR;
1561                         }
1562                         if(the_scope == CLASS_SCOPE) {
1563                                 yyerror(_("a method cannot be of class scope"));
1564                                 free_all_global_state();
1565                                 YYERROR;
1566                         }
1567                         push_function(the_scope, $<sigtype>3,NULL,
1568                                       $<id>5, $<cbuf>10,$<line>1,
1569                                       ccode_line, vararg, $<list>2);
1570                                                                         }
1571         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
1572                         if(!has_self) {
1573                                 yyerror(_("signal without 'self' as "
1574                                           "first parameter"));
1575                                 free_all_global_state();
1576                                 YYERROR;
1577                         }
1578                         if(the_scope == CLASS_SCOPE) {
1579                                 yyerror(_("a method cannot be of class scope"));
1580                                 free_all_global_state();
1581                                 YYERROR;
1582                         }
1583                         push_function(the_scope, $<sigtype>4, NULL,
1584                                       $<id>6, $<cbuf>11, $<line>2,
1585                                       ccode_line, vararg, $<list>3);
1586                                                                         }
1587         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
1588                         if(!has_self) {
1589                                 yyerror(_("virtual method without 'self' as "
1590                                           "first parameter"));
1591                                 free_all_global_state();
1592                                 YYERROR;
1593                         }
1594                         if(the_scope == CLASS_SCOPE) {
1595                                 yyerror(_("a method cannot be of class scope"));
1596                                 free_all_global_state();
1597                                 YYERROR;
1598                         }
1599                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1600                                       $<cbuf>9, $<line>1,
1601                                       ccode_line, vararg, NULL);
1602                                                                         }
1603         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
1604                         if(!has_self) {
1605                                 yyerror(_("virtual method without 'self' as "
1606                                           "first parameter"));
1607                                 free_all_global_state();
1608                                 YYERROR;
1609                         }
1610                         if(the_scope == CLASS_SCOPE) {
1611                                 yyerror(_("a method cannot be of class scope"));
1612                                 free_all_global_state();
1613                                 YYERROR;
1614                         }
1615                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1616                                       $<cbuf>9, $<line>2,
1617                                       ccode_line, vararg, NULL);
1618                                                                         }
1619         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
1620                         if(!has_self) {
1621                                 yyerror(_("virtual method without 'self' as "
1622                                           "first parameter"));
1623                                 free_all_global_state();
1624                                 YYERROR;
1625                         }
1626                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
1627                                       $<id>3, $<cbuf>8, $<line>1,
1628                                       ccode_line, vararg, NULL);
1629                                                                         }
1630         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
1631                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
1632                                       $<id>6, $<cbuf>11,
1633                                       $<line>1, ccode_line,
1634                                       vararg, NULL);
1635                                                                         }
1636         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
1637                         if(the_scope == CLASS_SCOPE) {
1638                                 yyerror(_("a method cannot be of class scope"));
1639                                 free_all_global_state();
1640                                 YYERROR;
1641                         }
1642                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
1643                                       $<cbuf>8, $<line>1, ccode_line,
1644                                       vararg, NULL);
1645                                                                 }
1646         |       TOKEN '(' TOKEN ')' codenocode  {
1647                         if(strcmp($<id>1, "init")==0) {
1648                                 push_init_arg($<id>3,FALSE);
1649                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
1650                                               $<id>1, $<cbuf>5, $<line>2,
1651                                               ccode_line, FALSE, NULL);
1652                         } else if(strcmp($<id>1, "class_init")==0) {
1653                                 push_init_arg($<id>3,TRUE);
1654                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
1655                                               $<id>1, $<cbuf>5, $<line>2,
1656                                               ccode_line, FALSE, NULL);
1657                         } else {
1658                                 g_free($<id>1);
1659                                 g_free($<id>3);
1660                                 g_string_free($<cbuf>5,TRUE);
1661                                 yyerror(_("parse error "
1662                                           "(untyped blocks must be init or "
1663                                           "class_init)"));
1664                                 YYERROR;
1665                         }
1666                                                 }
1667         ;
1668
1669 returnvals:     TOKEN retcode           {
1670                         g_free(onerror); onerror = NULL;
1671                         g_free(defreturn); defreturn = NULL;
1672                         if(!set_return_value($<id>1, $<id>2)) {
1673                                 g_free($<id>1);
1674                                 g_free($<id>2);
1675                                 yyerror(_("parse error"));
1676                                 YYERROR;
1677                         }
1678                         g_free($<id>1);
1679                                         }
1680         |       TOKEN retcode TOKEN retcode     {
1681                         g_free(onerror); onerror = NULL;
1682                         g_free(defreturn); defreturn = NULL;
1683                         if(!set_return_value($<id>1, $<id>2)) {
1684                                 g_free($<id>1); g_free($<id>2);
1685                                 g_free($<id>3); g_free($<id>4);
1686                                 yyerror(_("parse error"));
1687                                 YYERROR;
1688                         }
1689                         if(!set_return_value($<id>3, $<id>4)) {
1690                                 onerror = defreturn = NULL;
1691                                 g_free($<id>1); g_free($<id>2);
1692                                 g_free($<id>3); g_free($<id>4);
1693                                 yyerror(_("parse error"));
1694                                 YYERROR;
1695                         }
1696                         g_free($<id>1);
1697                         g_free($<id>3);
1698                                                 }
1699         |                               {
1700                         g_free(onerror); onerror = NULL;
1701                         g_free(defreturn); defreturn = NULL;
1702                                         }
1703         ;
1704
1705 retcode:        numtok                  { $<id>$ = $<id>1; }
1706         |       '{' CCODE               {
1707                         $<id>$ = ($<cbuf>3)->str;
1708                         g_string_free($<cbuf>3, FALSE);
1709                                         }
1710         ;
1711         
1712 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
1713         |       TOKEN                   {
1714                         vararg = FALSE;
1715                         has_self = TRUE;
1716                         if(strcmp($<id>1,"self")==0)
1717                                 push_self($<id>1, FALSE);
1718                         else {
1719                                 g_free($<id>1);
1720                                 yyerror(_("parse error"));
1721                                 YYERROR;
1722                         }
1723                                         }
1724         |       TOKEN CONST {
1725                         vararg = FALSE;
1726                         has_self = TRUE;
1727                         if(strcmp($<id>1,"self")==0)
1728                                 push_self($<id>1, TRUE);
1729                         else {
1730                                 g_free($<id>1);
1731                                 yyerror(_("parse error"));
1732                                 YYERROR;
1733                         }
1734                                         }
1735         |       CONST TOKEN {
1736                         vararg = FALSE;
1737                         has_self = TRUE;
1738                         if(strcmp($<id>2,"self")==0)
1739                                 push_self($<id>2, TRUE);
1740                         else {
1741                                 g_free($<id>2);
1742                                 yyerror(_("parse error"));
1743                                 YYERROR;
1744                         }
1745                                         }
1746         |       TOKEN ',' arglist       {
1747                         has_self = TRUE;
1748                         if(strcmp($<id>1,"self")==0)
1749                                 push_self($<id>1, FALSE);
1750                         else {
1751                                 g_free($<id>1);
1752                                 yyerror(_("parse error"));
1753                                 YYERROR;
1754                         }
1755                                         }
1756         |       TOKEN CONST ',' arglist {
1757                         has_self = TRUE;
1758                         if(strcmp($<id>1,"self")==0)
1759                                 push_self($<id>1, TRUE);
1760                         else {
1761                                 g_free($<id>1);
1762                                 yyerror(_("parse error"));
1763                                 YYERROR;
1764                         }
1765                                         }
1766         |       CONST TOKEN ',' arglist {
1767                         has_self = TRUE;
1768                         if(strcmp($<id>2,"self")==0)
1769                                 push_self($<id>2, TRUE);
1770                         else {
1771                                 g_free($<id>2);
1772                                 yyerror(_("parse error"));
1773                                 YYERROR;
1774                         }
1775                                         }
1776         |       arglist                 { has_self = FALSE; }
1777         ;
1778
1779 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
1780         |       arglist1                { vararg = FALSE; }
1781         ;
1782         
1783 arglist1:       arglist1 ',' arg        { ; }
1784         |       arg                     { ; }
1785         ;
1786
1787 arg:            type TOKEN                                      {
1788                         push_funcarg($<id>2,NULL);
1789                                                                 }
1790         |       type TOKEN ARRAY_DIM                            {
1791                         push_funcarg($<id>2,$<id>3);
1792                                                                 }
1793         |       type TOKEN '(' TOKEN checklist ')'              {
1794                         if(strcmp($<id>4,"check")!=0) {
1795                                 yyerror(_("parse error"));
1796                                 YYERROR;
1797                         }
1798                         g_free($<id>4);
1799                         push_funcarg($<id>2,NULL);
1800                                                                 }
1801         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
1802                         if(strcmp($<id>5,"check")!=0) {
1803                                 yyerror(_("parse error"));
1804                                 YYERROR;
1805                         }
1806                         g_free($<id>5);
1807                         push_funcarg($<id>2,$<id>3);
1808                                                                 }
1809         ;
1810         
1811 checklist:      checklist check         { ; }
1812         |       check                   { ; }
1813         ;
1814
1815 check:          TOKEN                   {
1816                         if(strcmp($<id>1,"type")==0) {
1817                                 Node *node = node_new (CHECK_NODE,
1818                                                        "chtype", TYPE_CHECK,
1819                                                        NULL);
1820                                 checks = g_list_append(checks,node);
1821                         } else if(strcmp($<id>1,"null")==0) {
1822                                 Node *node = node_new (CHECK_NODE,
1823                                                        "chtype", NULL_CHECK,
1824                                                        NULL);
1825                                 checks = g_list_append(checks,node);
1826                         } else {
1827                                 yyerror(_("parse error"));
1828                                 YYERROR;
1829                         }
1830                         g_free($<id>1);
1831                                         }
1832         |       '>' numtok              {
1833                         Node *node = node_new (CHECK_NODE,
1834                                                "chtype", GT_CHECK,
1835                                                "number:steal", $<id>2,
1836                                                NULL);
1837                         checks = g_list_append(checks,node);
1838                                         }
1839         |       '<' numtok              {
1840                         Node *node = node_new (CHECK_NODE,
1841                                                "chtype", LT_CHECK,
1842                                                "number:steal", $<id>2,
1843                                                NULL);
1844                         checks = g_list_append(checks,node);
1845                                         }
1846         |       '>' '=' numtok          {
1847                         Node *node = node_new (CHECK_NODE,
1848                                                "chtype", GE_CHECK,
1849                                                "number:steal", $<id>3,
1850                                                NULL);
1851                         checks = g_list_append(checks,node);
1852                                         }
1853         |       '<' '=' numtok          {
1854                         Node *node = node_new (CHECK_NODE,
1855                                                "chtype", LE_CHECK,
1856                                                "number:steal", $<id>3,
1857                                                NULL);
1858                         checks = g_list_append(checks,node);
1859                                         }
1860         |       '=' '=' numtok          {
1861                         Node *node = node_new (CHECK_NODE,
1862                                                "chtype", EQ_CHECK,
1863                                                "number:steal", $<id>3,
1864                                                NULL);
1865                         checks = g_list_append(checks,node);
1866                                         }
1867         |       '!' '=' numtok          {
1868                         Node *node = node_new (CHECK_NODE,
1869                                                "chtype", NE_CHECK,
1870                                                "number:steal", $<id>3,
1871                                                NULL);
1872                         checks = g_list_append(checks,node);
1873                                         }
1874         ;
1875
1876 enumcode:       ENUM TOKEN '{' enumvals '}' TYPETOKEN ';' {
1877                         Node *node = node_new (ENUMDEF_NODE,
1878                                                "etype:steal", $<id>6,
1879                                                "prefix:steal", $<id>2,
1880                                                "values:steal", enum_vals,
1881                                                NULL);
1882                         enum_vals = NULL;
1883                         nodes = g_list_append (nodes, node);
1884                         }
1885         |       ENUM TOKEN '{' enumvals ',' '}' TYPETOKEN ';' {
1886                         Node *node = node_new (ENUMDEF_NODE,
1887                                                "etype:steal", $<id>7,
1888                                                "prefix:steal", $<id>2,
1889                                                "values:steal", enum_vals,
1890                                                NULL);
1891                         enum_vals = NULL;
1892                         nodes = g_list_append (nodes, node);
1893                         }
1894         ;
1895
1896 enumvals:       enumvals ',' enumval    {;}
1897         |       enumval                 {;}
1898         ;
1899
1900 enumval:        TOKEN '=' numtok        {
1901                         Node *node;
1902                         char *num = $<id>3;
1903
1904                         /* A float value, that's a bad enum */
1905                         if (num[0] >= '0' &&
1906                             num[0] <= '9' &&
1907                             strchr (num, '.') != NULL) {
1908                                 g_free ($<id>1);
1909                                 g_free (num);
1910                                 yyerror(_("parse error (enumerator value not integer constant)"));
1911                                 YYERROR;
1912                         }
1913                        
1914                         node = node_new (ENUMVALUE_NODE,
1915                                          "name:steal", $<id>1,
1916                                          "value:steal", num,
1917                                          NULL);
1918                         enum_vals = g_list_append (enum_vals, node);
1919                         }
1920         |       TOKEN                   {
1921                         Node *node;
1922
1923                         node = node_new (ENUMVALUE_NODE,
1924                                          "name:steal", $<id>1,
1925                                          NULL);
1926                         enum_vals = g_list_append (enum_vals, node);
1927         }
1928         ;
1929
1930 flagcode:       FLAGS TOKEN '{' flagvals '}' TYPETOKEN ';' {
1931                         Node *node = node_new (FLAGS_NODE,
1932                                                "ftype:steal", $<id>6,
1933                                                "prefix:steal", $<id>2,
1934                                                "values:steal", flag_vals,
1935                                                NULL);
1936                         flag_vals = NULL;
1937                         nodes = g_list_append (nodes, node);
1938                         }
1939         |       FLAGS TOKEN '{' flagvals ',' '}' TYPETOKEN ';' {
1940                         Node *node = node_new (FLAGS_NODE,
1941                                                "ftype:steal", $<id>7,
1942                                                "prefix:steal", $<id>2,
1943                                                "values:steal", flag_vals,
1944                                                NULL);
1945                         flag_vals = NULL;
1946                         nodes = g_list_append (nodes, node);
1947                         }
1948         ;
1949
1950 flagvals:       flagvals ',' TOKEN      {
1951                         flag_vals = g_list_append (flag_vals, $<id>3);
1952                 }
1953         |       TOKEN                   {
1954                         flag_vals = g_list_append (flag_vals, $<id>1);
1955                 }
1956         ;
1957
1958 errorcode:      ERROR TOKEN '{' errorvals '}' TYPETOKEN ';' {
1959                         Node *node = node_new (ERROR_NODE,
1960                                                "etype:steal", $<id>6,
1961                                                "prefix:steal", $<id>2,
1962                                                "values:steal", error_vals,
1963                                                NULL);
1964                         error_vals = NULL;
1965                         nodes = g_list_append (nodes, node);
1966                         }
1967         |       ERROR TOKEN '{' errorvals ',' '}' TYPETOKEN ';' {
1968                         Node *node = node_new (ERROR_NODE,
1969                                                "etype:steal", $<id>7,
1970                                                "prefix:steal", $<id>2,
1971                                                "values:steal", error_vals,
1972                                                NULL);
1973                         error_vals = NULL;
1974                         nodes = g_list_append (nodes, node);
1975                         }
1976         ;
1977
1978 errorvals:      errorvals ',' TOKEN     {
1979                         error_vals = g_list_append (error_vals, $<id>3);
1980                 }
1981         |       TOKEN                   {
1982                         error_vals = g_list_append (error_vals, $<id>1);
1983                 }
1984         ;
1985
1986
1987 numtok:         NUMBER                  { $<id>$ = $<id>1; }
1988         |       '-' NUMBER              {
1989                         $<id>$ = g_strconcat("-",$<id>2,NULL);
1990                         g_free($<id>2);
1991                                         }
1992         |       SINGLE_CHAR             { $<id>$ = $<id>1; }
1993         |       TOKEN                   { $<id>$ = $<id>1; }
1994         ;
1995         
1996 %%