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