]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
a8d3341f07d56ca14b105f3d0b589bb30ca3af40
[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                   gboolean do_set,
353                   int get_lineno,
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 void
442 property_link_and_export (Node *node)
443 {
444         Property *prop = (Property *)node;
445
446         if (prop->link) {
447                 const char *root;
448                 char *get = NULL, *set = NULL;
449                 Variable *var;
450
451                 if (prop->set != NULL ||
452                     prop->get != NULL) {        
453                         error_print (GOB_ERROR, prop->line_no,
454                                      _("Property linking requested, but "
455                                        "getters and setters exist"));
456                 }
457
458                 var = find_var_or_die (prop->name, prop->line_no);
459                 if(var->scope == PRIVATE_SCOPE) {
460                         root = "self->_priv";
461                 } else if (var->scope == CLASS_SCOPE) {
462                         root = "SELF_GET_CLASS(self)";
463                         if (no_self_alias)
464                                 error_print (GOB_ERROR, prop->line_no,
465                                              _("Self aliases needed when autolinking to a classwide member"));
466                 } else {
467                         root = "self";
468                 }
469
470                 if (strcmp (prop->gtktype, "STRING") == 0) {
471                         set = g_strdup_printf("{ char *old = %s->%s; "
472                                               "%s->%s = g_value_dup_string (VAL); g_free (old); }",
473                                               root, prop->name,
474                                               root, prop->name);
475                         get = g_strdup_printf("g_value_set_string (VAL, %s->%s);",
476                                               root, prop->name);
477                 } else if (strcmp (prop->gtktype, "OBJECT") == 0) {
478                         set = g_strdup_printf("{ GtkObject *___old = (GtkObject *)%s->%s; "
479                                               "GtkObject *___new = (GtkObject *)gtk_value_get_object (VAL); "
480                                               "if (___new != NULL) { "
481                                                 "gtk_object_ref (GTK_OBJECT (___new)); "
482                                                 "%s->%s = GTK_OBJECT (___new); "
483                                               "} else { "
484                                                 "%s->%s = NULL; "
485                                               "} "
486                                               "if (___old != NULL) { "
487                                                 "gtk_object_unref (GTK_OBJECT (___old)); "
488                                               "} "
489                                               "}",
490                                               root, prop->name,
491                                               root, prop->name,
492                                               root, prop->name);
493                         get = g_strdup_printf("g_value_set_object (VAL, %s->%s);",
494                                               root, prop->name);
495                 } else if (strcmp (prop->gtktype, "BOXED") == 0) {
496                         if (prop->extra_gtktype == NULL) {
497                                 error_print (GOB_ERROR, prop->line_no,
498                                              _("Property linking requested for BOXED, but "
499                                                "boxed_type not set"));
500                         }
501                         set = g_strdup_printf("{ gpointer ___old = (gpointer)%s->%s; "
502                                               "gpointer ___new = (gpointer)gtk_value_get_boxed (VAL); "
503                                               "if (___new != ___old) { "
504                                                 "if (___old != NULL) g_boxed_free (%s, ___old); "
505                                                 "if (___new != NULL) %s->%s = g_boxed_copy (%s, ___new); "
506                                                 "else %s->%s = NULL;"
507                                               "} "
508                                               "}",
509                                               root, prop->name,
510                                               prop->extra_gtktype,
511                                               root, prop->name,
512                                               prop->extra_gtktype,
513                                               root, prop->name);
514                         get = g_strdup_printf("g_value_set_object (VAL, %s->%s);",
515                                               root, prop->name);
516                 } else {
517                         char *set_func;
518                         char *get_func;
519                         set_func = g_strdup_printf ("g_value_set_%s", prop->gtktype);
520                         g_strdown (set_func);
521                         get_func = g_strdup_printf ("g_value_get_%s", prop->gtktype);
522                         g_strdown (get_func);
523
524                         set = g_strdup_printf("%s->%s = %s (VAL);",
525                                               root, prop->name,
526                                               get_func);
527                         get = g_strdup_printf("%s (VAL, %s->%s);",
528                                               set_func,
529                                               root, prop->name);
530
531                         g_free (get_func);
532                         g_free (set_func);
533                 }
534
535                 node_set (node,
536                           "get:steal", get,
537                           "get_line", prop->line_no,
538                           "set:steal", set,
539                           "set_line", prop->line_no,
540                           NULL);
541         }
542
543         if (prop->export) {
544                 export_accessors (prop->name,
545                                   prop->get != NULL, prop->get_line,
546                                   prop->set != NULL,  prop->get_line,
547                                   prop->ptype,
548                                   prop->gtktype,
549                                   prop->line_no);
550         } 
551 }
552
553
554 static char *
555 debool (char *s)
556 {
557         if (strcmp (s, "BOOL") == 0) {
558                 error_print (GOB_WARN, line_no,
559                             _("BOOL type is deprecated, please use BOOLEAN"));
560                 g_free (s);
561                 return g_strdup ("BOOLEAN");
562         } else {
563                 return s;
564         }
565 }
566
567 static void
568 ensure_property (void)
569 {
570         if (property == NULL)
571                 property = (Property *)node_new (PROPERTY_NODE, NULL);
572 }
573
574 %}
575
576 %union {
577         char *id;
578         GString *cbuf;
579         GList *list;
580         int line;
581         int sigtype;
582 }
583
584 %token CLASS FROM
585 %token CONST VOID STRUCT UNION ENUM THREEDOTS
586 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
587
588 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM SINGLE_CHAR
589 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING
590 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE PROPERTY ARGUMENT
591 %token <line> VIRTUAL SIGNAL OVERRIDE
592 %token <line> NICK BLURB MAXIMUM MINIMUM DEFAULT_VALUE ERROR FLAGS TYPE
593 %token <line> FLAGS_TYPE ENUM_TYPE PARAM_TYPE BOXED_TYPE OBJECT_TYPE
594
595 %%
596
597 prog:           ccodes class ccodes     { ; }
598         |       class ccodes            { ; }
599         |       ccodes class            { ; }
600         |       class                   { ; }
601         ;
602
603 ccode:          CCODE                   {
604                         Node *node = node_new (CCODE_NODE,
605                                                "cctype", C_CCODE,
606                                                "cbuf:steal", ($<cbuf>1)->str,
607                                                "line_no", ccode_line,
608                                                NULL);
609                         nodes = g_list_append(nodes,node);
610                         g_string_free($<cbuf>1,FALSE);
611                                         }
612         |       HCODE                   {
613                         Node *node = node_new (CCODE_NODE,
614                                                "cctype", H_CCODE,
615                                                "cbuf:steal", ($<cbuf>1)->str,
616                                                "line_no", ccode_line,
617                                                NULL);
618                         nodes = g_list_append(nodes,node);
619                         g_string_free($<cbuf>1,FALSE);
620                                         }
621         |       HTCODE                  {
622                         Node *node = node_new (CCODE_NODE,
623                                                "cctype", HT_CCODE,
624                                                "cbuf:steal", ($<cbuf>1)->str,
625                                                "line_no", ccode_line,
626                                                NULL);
627                         nodes = g_list_append(nodes,node);
628                         g_string_free($<cbuf>1,FALSE);
629                                         }
630         |       PHCODE                  {
631                         Node *node = node_new (CCODE_NODE,
632                                                "cctype", PH_CCODE,
633                                                "cbuf:steal", ($<cbuf>1)->str,
634                                                "line_no", ccode_line,
635                                                NULL);
636                         nodes = g_list_append(nodes,node);
637                         g_string_free($<cbuf>1,FALSE);
638                                         }
639         |       ACODE                   {
640                         Node *node = node_new (CCODE_NODE,
641                                                "cctype", A_CCODE,
642                                                "cbuf:steal", ($<cbuf>1)->str,
643                                                "line_no", ccode_line,
644                                                NULL);
645                         nodes = g_list_append(nodes,node);
646                         g_string_free($<cbuf>1,FALSE);
647                                         }
648         |       ATCODE                  {
649                         Node *node = node_new (CCODE_NODE,
650                                                "cctype", AT_CCODE,
651                                                "cbuf:steal", ($<cbuf>1)->str,
652                                                "line_no", ccode_line,
653                                                NULL);
654                         nodes = g_list_append(nodes,node);
655                         g_string_free($<cbuf>1,FALSE);
656                                         }
657         ;
658
659 ccodes:         ccodes ccode            { ; }
660         |       ccodes enumcode         { ; }
661         |       ccodes flagcode         { ; }
662         |       ccodes errorcode        { ; }
663         |       ccode                   { ; }
664         |       enumcode                { ; }
665         |       flagcode                { ; }
666         |       errorcode               { ; }
667         ;
668
669 class:          classdec '{' classcode '}'      {
670                         ((Class *)class)->nodes = class_nodes;
671                         class_nodes = NULL;
672                         nodes = g_list_append(nodes,class);
673                                                 }
674         |       classdec '{' '}'                {
675                         ((Class *)class)->nodes = NULL;
676                         class_nodes = NULL;
677                         nodes = g_list_append(nodes,class);
678                                                 }
679         ;
680
681 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  classflags {
682                         class = node_new (CLASS_NODE,
683                                           "otype:steal", $<id>2,
684                                           "ptype:steal", $<id>4,
685                                           "bonobo_object_class:steal", bonobo_object_class,
686                                           "interfaces:steal", interfaces,
687                                           "chunk_size:steal", chunk_size,
688                                           NULL);
689                         bonobo_object_class = NULL;
690                         chunk_size = NULL;
691                         interfaces = NULL;
692                                                 }
693         ;
694
695 classflags:
696         | '(' TOKEN TOKEN ')' classflags {
697                         if(strcmp($<id>2,"chunks") == 0) {
698                                 g_free (chunk_size);
699                                 chunk_size = g_strdup($<id>3);
700                         } else if(strcmp($<id>2,"BonoboObject") == 0) {
701                                 g_free (bonobo_object_class);
702                                 bonobo_object_class = g_strdup($<id>3);
703                         } else {
704                                 yyerror(_("parse error"));
705                                 YYERROR;
706                         }
707                 }
708         | '(' TOKEN TYPETOKEN ')' classflags {
709                         if (strcmp ($<id>2, "interface") == 0) {
710                                 interfaces = g_list_append (interfaces,
711                                                             g_strdup ($<id>3));
712                         } else {
713                                 yyerror(_("parse error"));
714                                 YYERROR;
715                         }
716                 }
717         | '(' TOKEN NUMBER ')' classflags {
718                         if(strcmp($<id>2,"chunks") == 0) {
719                                 g_free (chunk_size);
720                                 if(atoi($<id>3) != 0)
721                                         chunk_size = g_strdup($<id>3);
722                                 else
723                                         chunk_size = NULL;
724                         } else {
725                                 yyerror(_("parse error"));
726                                 YYERROR;
727                         }
728                 }
729         ;       
730
731 classcode:      classcode thing                 { ; }
732         |       thing                           { ; }
733         ;
734
735 thing:          method                          { ; }
736         |       TOKEN method                    {
737                         if (strcmp ($<id>1, "BonoboObject") != 0) {
738                                 g_free ($<id>1);
739                                 yyerror (_("parse error"));
740                                 YYERROR;
741                         }
742                         g_free ($<id>1);
743                         last_added_method->bonobo_object_func = TRUE;
744                                                 }
745         |       TOKEN TYPETOKEN method                  {
746                         if (strcmp ($<id>1, "interface") != 0) {
747                                 g_free ($<id>1);
748                                 g_free ($<id>2);
749                                 yyerror (_("parse error"));
750                                 YYERROR;
751                         }
752                         g_free ($<id>1);
753                         node_set ((Node *)last_added_method,
754                                   "interface:steal", $<id>2,
755                                   NULL);
756                                                 }
757         |       variable                        { ; }
758         |       argument                        { ; }
759         |       property                        { ; }
760         |       ';'                             { ; }
761         ;
762
763 scope:          PUBLIC                  { the_scope = PUBLIC_SCOPE; }
764         |       PRIVATE                 { the_scope = PRIVATE_SCOPE; }
765         |       PROTECTED               { the_scope = PROTECTED_SCOPE; }
766         |       CLASSWIDE               { the_scope = CLASS_SCOPE; }
767         ;
768
769 destructor:     TOKEN TOKEN     {
770                         if (strcmp ($<id>1, "destroywith") == 0) {
771                                 g_free ($<id>1);
772                                 destructor_unref = FALSE;
773                                 destructor = $<id>2;
774                                 destructor_line = line_no;
775                                 destructor_simple = TRUE;
776                         } else if (strcmp ($<id>1, "unrefwith") == 0) {
777                                 g_free ($<id>1);
778                                 destructor_unref = TRUE;
779                                 destructor = $<id>2;
780                                 destructor_line = line_no;
781                                 destructor_simple = TRUE;
782                         } else {
783                                 g_free ($<id>1);
784                                 g_free ($<id>2);
785                                 yyerror (_("parse error"));
786                                 YYERROR;
787                         }
788                                 }
789         |       TOKEN '{' CCODE         {
790                         if (strcmp ($<id>1, "destroy") == 0) {
791                                 g_free($<id>1);
792                                 destructor_unref = FALSE;
793                                 destructor = ($<cbuf>3)->str;
794                                 g_string_free($<cbuf>3, FALSE);
795                                 destructor_line = ccode_line;
796                                 destructor_simple = FALSE;
797                         } else if (strcmp ($<id>1, "unref") == 0) {
798                                 g_free ($<id>1);
799                                 destructor_unref = TRUE;
800                                 destructor = ($<cbuf>3)->str;
801                                 g_string_free ($<cbuf>3, FALSE);
802                                 destructor_line = ccode_line;
803                                 destructor_simple = FALSE;
804                         } else {
805                                 g_free ($<id>1);
806                                 g_string_free ($<cbuf>3, TRUE);
807                                 yyerror (_("parse error"));
808                                 YYERROR;
809                         }
810                                         }
811         ;
812
813 initializer:    '=' numtok      {
814                         initializer = $<id>2;
815                         initializer_line = ccode_line;
816                                 }
817         |       '=' '{' CCODE   {
818                         initializer = ($<cbuf>3)->str;
819                         initializer_line = ccode_line;
820                         g_string_free($<cbuf>3, FALSE);
821                                 }
822         ;
823
824
825 varoptions:     destructor initializer  { ; }
826         |       initializer destructor  { ; }
827         |       initializer             { destructor = NULL; }
828         |       destructor              { initializer = NULL; }
829         |                               {
830                         destructor = NULL;
831                         initializer = NULL;
832                                         }
833         ;
834
835 variable:       scope type TOKEN varoptions ';'         {
836                         push_variable($<id>3, the_scope,$<line>1, NULL);
837                                                 }
838         |       scope type TOKEN ARRAY_DIM varoptions ';'       {
839                         push_variable($<id>3, the_scope, $<line>1, $<id>4);
840                                                 }
841         ;
842
843 argument:       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE TOKEN '{' CCODE ';' {
844                         Node *node = NULL;
845                         if(strcmp($<id>6,"get")==0 &&
846                            strcmp($<id>9,"set")==0) {
847                                 Type *type = pop_type();
848                                 g_free ($<id>6); 
849                                 g_free ($<id>9);
850                                 node = node_new (ARGUMENT_NODE,
851                                                  "gtktype:steal", $<id>3,
852                                                  "atype:steal", type,
853                                                  "flags:steal", $<list>2,
854                                                  "name:steal", $<id>4,
855                                                  "get:steal", ($<cbuf>8)->str,
856                                                  "get_line", $<line>7,
857                                                  "set:steal", ($<cbuf>11)->str,
858                                                  "set_line", $<line>10,
859                                                  "line_no", $<line>1,
860                                                  NULL);
861
862                                 class_nodes = g_list_append(class_nodes,node);
863
864                                 g_string_free ($<cbuf>8, FALSE);
865                                 g_string_free ($<cbuf>11, FALSE);
866
867                         } else if(strcmp($<id>6,"set")==0 &&
868                                 strcmp($<id>9,"get")==0) {
869                                 Type *type = pop_type();
870                                 g_free ($<id>6); 
871                                 g_free ($<id>9);
872                                 node = node_new (ARGUMENT_NODE,
873                                                  "gtktype:steal", $<id>3,
874                                                  "atype:steal", type,
875                                                  "flags:steal", $<list>2,
876                                                  "name:steal", $<id>4,
877                                                  "get:steal", ($<cbuf>11)->str,
878                                                  "get_line", $<line>10,
879                                                  "set:steal", ($<cbuf>8)->str,
880                                                  "set_line", $<line>7,
881                                                  "line_no", $<line>1,
882                                                  NULL);
883                                 g_string_free ($<cbuf>11, FALSE);
884                                 g_string_free ($<cbuf>8, FALSE);
885                                 class_nodes = g_list_append(class_nodes,node);
886                         } else {
887                                 g_free ($<id>3); 
888                                 g_free ($<id>4);
889                                 g_free ($<id>6); 
890                                 g_free ($<id>9);
891                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
892                                 g_list_free ($<list>2);
893                                 g_string_free ($<cbuf>11, TRUE);
894                                 g_string_free ($<cbuf>8, TRUE);
895                                 yyerror (_("parse error"));
896                                 YYERROR;
897                         }
898
899                         if ($<id>5 != NULL) {
900                                 Argument *arg = (Argument *)node;
901                                 export_accessors (arg->name,
902                                                   arg->get != NULL, arg->get_line,
903                                                   arg->set != NULL, arg->set_line,
904                                                   arg->atype,
905                                                   arg->gtktype,
906                                                   arg->line_no);
907                                 g_free ($<id>5);
908                         } 
909
910                                                 }
911         |       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE ';' {
912                         Node *node = NULL;
913                         if(strcmp($<id>6, "get") == 0) {
914                                 Type *type = pop_type();
915                                 g_free ($<id>6);
916                                 node = node_new (ARGUMENT_NODE,
917                                                  "gtktype:steal", $<id>3,
918                                                  "atype:steal", type,
919                                                  "flags:steal", $<list>2,
920                                                  "name:steal", $<id>4,
921                                                  "get:steal", ($<cbuf>8)->str,
922                                                  "get_line", $<line>7,
923                                                  "line_no", $<line>1,
924                                                  NULL);
925
926                                 g_string_free ($<cbuf>8, FALSE);
927                                 class_nodes = g_list_append(class_nodes, node);
928                         } else if(strcmp($<id>6, "set") == 0) {
929                                 Type *type = pop_type();
930                                 g_free ($<id>6);
931                                 node = node_new (ARGUMENT_NODE,
932                                                  "gtktype:steal", $<id>3,
933                                                  "atype:steal", type,
934                                                  "flags:steal", $<list>2,
935                                                  "name:steal", $<id>4,
936                                                  "set:steal", ($<cbuf>8)->str,
937                                                  "set_line", $<line>7,
938                                                  "line_no", $<line>1,
939                                                  NULL);
940
941                                 g_string_free ($<cbuf>8, FALSE);
942                                 class_nodes = g_list_append (class_nodes, node);
943                         } else {
944                                 g_free ($<id>6); 
945                                 g_free ($<id>3);
946                                 g_free ($<id>4);
947                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
948                                 g_list_free ($<list>2);
949                                 g_string_free ($<cbuf>8, TRUE);
950                                 yyerror(_("parse error"));
951                                 YYERROR;
952                         }
953
954                         if ($<id>5 != NULL) {
955                                 Argument *arg = (Argument *)node;
956                                 export_accessors (arg->name,
957                                                   arg->get != NULL, arg->get_line,
958                                                   arg->set != NULL, arg->set_line,
959                                                   arg->atype,
960                                                   arg->gtktype,
961                                                   arg->line_no);
962                                 g_free ($<id>5);
963                         } 
964                                                 }
965         |       ARGUMENT flags argtype TOKEN export TOKEN {
966                         Node *node;
967                         char *get, *set = NULL;
968                         Variable *var;
969                         Type *type;
970                         char *root;
971                         
972                         if(strcmp($<id>6, "link")!=0 &&
973                            strcmp($<id>6, "stringlink")!=0 && 
974                            strcmp($<id>6, "objectlink")!=0) {
975                                 g_free($<id>6); 
976                                 g_free($<id>3);
977                                 g_free($<id>4);
978                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
979                                 g_list_free($<list>2);
980                                 yyerror(_("parse error"));
981                                 YYERROR;
982                         }
983
984                         type = pop_type();
985
986                         var = find_var_or_die($<id>4, $<line>1);
987                         if(var->scope == PRIVATE_SCOPE)
988                                 root = "self->_priv";
989                         else if(var->scope == CLASS_SCOPE) {
990                                 root = "SELF_GET_CLASS(self)";
991                                 if(no_self_alias)
992                                         error_print(GOB_ERROR, $<line>1,
993                                                     _("Self aliases needed when autolinking to a classwide member"));
994                         } else
995                                 root = "self";
996
997                         if(strcmp($<id>6, "link")==0) {
998                                 set = g_strdup_printf("%s->%s = ARG;",
999                                                       root, $<id>4);
1000                         } else if(strcmp($<id>6, "stringlink")==0) {
1001                                 set = g_strdup_printf("g_free (%s->%s); "
1002                                                       "%s->%s = g_strdup (ARG);",
1003                                                       root, $<id>4,
1004                                                       root, $<id>4);
1005                         } else if(strcmp($<id>6, "objectlink")==0) {
1006                                 set = g_strdup_printf(
1007                                   "if (ARG != NULL) "
1008                                    "g_object_ref (G_OBJECT (ARG)); "
1009                                   "if (%s->%s != NULL) "
1010                                    "g_object_unref (G_OBJECT (%s->%s)); "
1011                                   "%s->%s = ARG;",
1012                                   root, $<id>4,
1013                                   root, $<id>4,
1014                                   root, $<id>4);
1015                         } else {
1016                                 g_assert_not_reached();
1017                         }
1018
1019                         get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
1020   
1021                         g_free ($<id>6);
1022
1023                         if (type == NULL)
1024                                 type = (Type *)node_copy ((Node *)var->vtype);
1025
1026                         node = node_new (ARGUMENT_NODE,
1027                                          "gtktype:steal", $<id>3,
1028                                          "atype:steal", type,
1029                                          "flags:steal", $<list>2,
1030                                          "name:steal", $<id>4,
1031                                          "get:steal", get,
1032                                          "get_line", $<line>1,
1033                                          "set:steal", set,
1034                                          "set_line", $<line>1,
1035                                          "line_no", $<line>1,
1036                                          NULL);
1037
1038                         if ($<id>5 != NULL) {
1039                                 Argument *arg = (Argument *)node;
1040                                 export_accessors (arg->name,
1041                                                   arg->get != NULL, arg->get_line,
1042                                                   arg->set != NULL, arg->set_line,
1043                                                   arg->atype,
1044                                                   arg->gtktype,
1045                                                   arg->line_no);
1046                                 g_free ($<id>5);
1047                         } 
1048
1049                         class_nodes = g_list_append (class_nodes, node);
1050                                                 }
1051         ;
1052
1053 export:         '(' TOKEN ')'                   {
1054                         if (strcmp ($<id>2, "export")!=0) {
1055                                 g_free ($<id>2); 
1056                                 yyerror (_("parse error"));
1057                                 YYERROR;
1058                         }
1059                         $<id>$ = $<id>2;
1060                                                 }
1061          |                                      {
1062                         $<id>$ = NULL;
1063                                                 }
1064          ;
1065
1066 property:       PROPERTY TOKEN TOKEN param_spec TOKEN '{' CCODE TOKEN '{' CCODE ';' {
1067                         ensure_property ();
1068                         node_set ((Node *)property,
1069                                   "line_no", $<line>1,
1070                                   "gtktype:steal", debool ($<id>2),
1071                                   "name:steal", $<id>3,
1072                                   NULL);
1073                         if (strcmp ($<id>5, "get") == 0 &&
1074                             strcmp ($<id>8, "set") == 0) {
1075                                 node_set ((Node *)property,
1076                                           "get:steal", ($<cbuf>7)->str,
1077                                           "get_line", $<line>6,
1078                                           "set:steal", ($<cbuf>10)->str,
1079                                           "set_line", $<line>9,
1080                                           NULL);
1081                                 g_string_free ($<cbuf>7, FALSE);
1082                                 g_string_free ($<cbuf>10, FALSE);
1083                                 g_free ($<id>5); 
1084                                 g_free ($<id>8);
1085                         } else if (strcmp ($<id>5, "set") == 0 &&
1086                                    strcmp ($<id>8, "get") == 0) {
1087                                 node_set ((Node *)property,
1088                                           "get:steal", ($<cbuf>10)->str,
1089                                           "get_line", $<line>9,
1090                                           "set:steal", ($<cbuf>7)->str,
1091                                           "set_line", $<line>6,
1092                                           NULL);
1093                                 g_string_free ($<cbuf>7, FALSE);
1094                                 g_string_free ($<cbuf>10, FALSE);
1095                                 g_free ($<id>5); 
1096                                 g_free ($<id>8);
1097                         } else {
1098                                 g_string_free ($<cbuf>7, TRUE);
1099                                 g_string_free ($<cbuf>10, TRUE);
1100                                 g_free ($<id>5); 
1101                                 g_free ($<id>8);
1102                                 node_free ((Node *)property);
1103                                 property = NULL;
1104                                 yyerror (_("parse error"));
1105                                 YYERROR;
1106                         }
1107                         property_link_and_export ((Node *)property);
1108                         if (property != NULL) {
1109                                 class_nodes = g_list_append (class_nodes,
1110                                                              property);
1111                                 property = NULL;
1112                         }
1113                 }
1114         |       PROPERTY TOKEN TOKEN param_spec TOKEN '{' CCODE ';' {
1115                         ensure_property ();
1116                         node_set ((Node *)property,
1117                                   "line_no", $<line>1,
1118                                   "gtktype:steal", debool ($<id>2),
1119                                   "name:steal", $<id>3,
1120                                   NULL);
1121                         if (strcmp ($<id>5, "get") == 0) {
1122                                 node_set ((Node *)property,
1123                                           "get:steal", ($<cbuf>7)->str,
1124                                           "get_line", $<line>6,
1125                                           NULL);
1126                                 g_string_free ($<cbuf>7, FALSE);
1127                                 g_free ($<id>5); 
1128                         } else if (strcmp ($<id>5, "set") == 0) {
1129                                 node_set ((Node *)property,
1130                                           "set:steal", ($<cbuf>7)->str,
1131                                           "set_line", $<line>6,
1132                                           NULL);
1133                                 g_string_free ($<cbuf>7, FALSE);
1134                                 g_free ($<id>5); 
1135                         } else {
1136                                 g_string_free ($<cbuf>7, TRUE);
1137                                 g_free ($<id>5); 
1138                                 node_free ((Node *)property);
1139                                 property = NULL;
1140                                 yyerror (_("parse error"));
1141                                 YYERROR;
1142                         }
1143                         property_link_and_export ((Node *)property);
1144                         if (property != NULL) {
1145                                 class_nodes = g_list_append (class_nodes,
1146                                                              property);
1147                                 property = NULL;
1148                         }
1149                 }
1150         |       PROPERTY TOKEN TOKEN param_spec ';' {
1151                         ensure_property ();
1152                         node_set ((Node *)property,
1153                                   "line_no", $<line>1,
1154                                   "gtktype:steal", debool ($<id>2),
1155                                   "name:steal", $<id>3,
1156                                   NULL);
1157                         property_link_and_export ((Node *)property);
1158                         if (property != NULL) {
1159                                 class_nodes = g_list_append (class_nodes,
1160                                                              property);
1161                                 property = NULL;
1162                         }
1163                 }
1164         ;
1165
1166 param_spec:     '(' param_spec_list ')' { ; }
1167         |                               { ; }
1168         ;
1169
1170 param_spec_list:        param_spec_list ',' param_spec_value    { ; }
1171         |               param_spec_value                        { ; }
1172         ;
1173
1174 string:         STRING                          { $<id>$ = $<id>1; }
1175         |       TOKEN '(' STRING ')'            {
1176                         if (strcmp ($<id>1, "_") != 0) {
1177                                 g_free ($<id>1);
1178                                 yyerror(_("parse error"));
1179                                 YYERROR;
1180                         }
1181                         g_free ($<id>1);
1182                         $<id>$ = g_strconcat ("_(", $<id>3, ")", NULL);
1183                         g_free ($<id>3);
1184                 }
1185         ;
1186
1187 anyval:         numtok          { $<id>$ = $<id>1; }
1188         |       string          { $<id>$ = $<id>1; }
1189         ;
1190
1191 param_spec_value: NICK '=' string               {
1192                 ensure_property ();
1193                 node_set ((Node *)property,
1194                           "nick:steal", $<id>3,
1195                           NULL);
1196                   }
1197         |       BLURB '=' string                {
1198                 ensure_property ();
1199                 node_set ((Node *)property,
1200                           "blurb:steal", $<id>3,
1201                           NULL);
1202                   }
1203         |       MAXIMUM '=' numtok              {
1204                 ensure_property ();
1205                 node_set ((Node *)property,
1206                           "maximum:steal", $<id>3,
1207                           NULL);
1208                   }
1209         |       MINIMUM '=' numtok              {
1210                 ensure_property ();
1211                 node_set ((Node *)property,
1212                           "minimum:steal", $<id>3,
1213                           NULL);
1214                   }
1215         |       DEFAULT_VALUE '=' anyval        {
1216                 ensure_property ();
1217                 node_set ((Node *)property,
1218                           "default_value:steal", $<id>3,
1219                           NULL);
1220                   }
1221         |       FLAGS '=' flaglist              {
1222                 ensure_property ();
1223                 node_set ((Node *)property,
1224                           "flags:steal", $<list>3,
1225                           NULL);
1226                   }
1227         |       TYPE '=' type                   {
1228                 Type *type = pop_type ();
1229                 ensure_property ();
1230                 node_set ((Node *)property,
1231                           "ptype:steal", type,
1232                           NULL);
1233                   }
1234         |       FLAGS_TYPE '=' TOKEN            {
1235                 ensure_property ();
1236                 node_set ((Node *)property,
1237                           "extra_gtktype:steal", $<id>3,
1238                           NULL);
1239                   }
1240         |       ENUM_TYPE '=' TOKEN             {
1241                 ensure_property ();
1242                 node_set ((Node *)property,
1243                           "extra_gtktype:steal", $<id>3,
1244                           NULL);
1245                   }
1246         |       PARAM_TYPE '=' TOKEN            {
1247                 ensure_property ();
1248                 node_set ((Node *)property,
1249                           "extra_gtktype:steal", $<id>3,
1250                           NULL);
1251                   }
1252         |       BOXED_TYPE '=' TOKEN            {
1253                 ensure_property ();
1254                 node_set ((Node *)property,
1255                           "extra_gtktype:steal", $<id>3,
1256                           NULL);
1257                   }
1258         |       OBJECT_TYPE '=' TOKEN           {
1259                 ensure_property ();
1260                 node_set ((Node *)property,
1261                           "extra_gtktype:steal", $<id>3,
1262                           NULL);
1263                   }
1264         |       TOKEN           {
1265                 ensure_property ();
1266                 if (strcmp ($<id>1, "link") == 0) {
1267                         g_free($<id>1);
1268                         node_set ((Node *)property,
1269                                   "link", TRUE,
1270                                   NULL);
1271                 } else if (strcmp ($<id>1, "export") == 0) {
1272                         g_free($<id>1);
1273                         node_set ((Node *)property,
1274                                   "export", TRUE,
1275                                   NULL);
1276                 } else {
1277                         g_free($<id>1);
1278                         yyerror(_("parse error"));
1279                         YYERROR;
1280                 }
1281                   }
1282         ;
1283
1284 argtype:        TOKEN '(' TOKEN type ')'        {
1285                         if(strcmp($<id>3,"type")!=0) {
1286                                 g_free($<id>1);
1287                                 g_free($<id>3);
1288                                 yyerror(_("parse error"));
1289                                 YYERROR;
1290                         }
1291                         $<id>$ = debool ($<id>1);
1292                                                 }
1293         |       TOKEN                           {
1294                         $<id>$ = debool ($<id>1);
1295                         typestack = g_list_prepend(typestack,NULL);
1296                                                 }
1297         ;
1298         
1299 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
1300         |                                       { $<list>$ = NULL; }
1301         ;
1302
1303 flaglist:       TOKEN '|' flaglist              {
1304                         $<list>$ = g_list_append($<list>3,$<id>1);
1305                                                 }
1306         |       TOKEN                           {
1307                         $<list>$ = g_list_append(NULL,$<id>1);
1308                                                 }
1309         ;
1310
1311
1312 type:           specifier_list pointer                          {
1313                         Node *node = node_new (TYPE_NODE, 
1314                                                "name:steal", $<id>1,
1315                                                "pointer:steal", $<id>2,
1316                                                NULL);
1317                         typestack = g_list_prepend(typestack,node);
1318                                                         }
1319         |       specifier_list                          {
1320                         Node *node = node_new (TYPE_NODE, 
1321                                                "name:steal", $<id>1,
1322                                                NULL);
1323                         typestack = g_list_prepend(typestack,node);
1324                                                         }
1325         ;
1326
1327 /* The special cases are neccessary to avoid conflicts */
1328 specifier_list: spec_list                               {
1329                         $<id>$ = $<id>1;
1330                                                         }
1331         |       TOKEN                                   {
1332                         $<id>$ = $<id>1;
1333                                                         }
1334         |       CONST TOKEN                             {
1335                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
1336                         g_free($<id>2);
1337                                                         }
1338         |       TOKEN CONST                             {
1339                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1340                         g_free($<id>1);
1341                                                         }
1342         |       strunionenum TOKEN                      {
1343                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1344                         g_free($<id>2);
1345                                                         }
1346         |       CONST strunionenum TOKEN                {
1347                         $<id>$ = g_strconcat("const ", $<id>2, " ",
1348                                              $<id>3, NULL);
1349                         g_free($<id>3);
1350                                                         }
1351         |       strunionenum TOKEN CONST                {
1352                         $<id>$ = g_strconcat($<id>1, " ",
1353                                              $<id>2, " const", NULL);
1354                         g_free($<id>2);
1355                                                         }
1356         ;
1357
1358 /* The special const cases take care of conflicts ! */
1359 spec_list:      specifier spec_list                     {
1360                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1361                         g_free($<id>2);
1362                                                         }
1363         |       TYPETOKEN spec_list                     {
1364                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
1365                         g_free($<id>1);
1366                         g_free($<id>2);
1367                                                         }
1368         |       CONST spec_list                         {
1369                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
1370                         g_free($<id>2);
1371                                                         }
1372         |       TYPETOKEN                               {
1373                         $<id>$ = $<id>1;
1374                                                         }
1375         |       TYPETOKEN CONST                         {
1376                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1377                         g_free($<id>1);
1378                                                         }
1379         |       specifier                               {
1380                         $<id>$ = g_strdup($<id>1);
1381                                                         }
1382         |       specifier CONST                         {
1383                         $<id>$ = g_strconcat($<id>1, " const", NULL);
1384                                                         }
1385         ;
1386
1387 specifier:      VOID                    { $<id>$ = "void"; }
1388         |       CHAR                    { $<id>$ = "char"; }
1389         |       SHORT                   { $<id>$ = "short"; }
1390         |       INT                     { $<id>$ = "int"; }
1391         |       LONG                    { $<id>$ = "long"; }
1392         |       FLOAT                   { $<id>$ = "float"; }
1393         |       DOUBLE                  { $<id>$ = "double"; }
1394         |       SIGNED                  { $<id>$ = "signed"; }
1395         |       UNSIGNED                { $<id>$ = "unsigned"; }
1396         ;
1397
1398 strunionenum:   STRUCT                  { $<id>$ = "struct"; }
1399         |       UNION                   { $<id>$ = "union"; }
1400         |       ENUM                    { $<id>$ = "enum"; }
1401         ;
1402
1403 pointer:        '*'                     { $<id>$ = g_strdup("*"); }
1404         |       '*' CONST               { $<id>$ = g_strdup("* const"); }
1405         |       '*' pointer             {
1406                                 $<id>$ = g_strconcat("*", $<id>2, NULL);
1407                                 g_free($<id>2);
1408                                         }
1409         |       '*' CONST pointer       {
1410                                 $<id>$ = g_strconcat("* const", $<id>3, NULL);
1411                                 g_free($<id>3);
1412                                         }
1413         ;
1414
1415 /* this never sets the_scope */
1416 simplesigtype:  TOKEN sigtype   {
1417                         if(strcmp($<id>1, "first")==0)
1418                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1419                         else if(strcmp($<id>1, "last")==0)
1420                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1421                         else {
1422                                 yyerror(_("signal must be 'first' or 'last'"));
1423                                 g_free($<id>1);
1424                                 YYERROR;
1425                         }
1426                         g_free($<id>1);
1427                                         }
1428         |       sigtype                 {
1429                         $<sigtype>$ = SIGNAL_LAST_METHOD;
1430                                         }
1431         ;
1432
1433 /* this always sets the_scope */
1434 fullsigtype:    scope TOKEN sigtype     {
1435                         if(strcmp($<id>2,"first")==0)
1436                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1437                         else if(strcmp($<id>2,"last")==0)
1438                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1439                         else {
1440                                 yyerror(_("signal must be 'first' or 'last'"));
1441                                 g_free($<id>2);
1442                                 YYERROR;
1443                         }
1444                         g_free($<id>2);
1445                                         }
1446         |       TOKEN scope sigtype     {
1447                         if(strcmp($<id>1,"first")==0)
1448                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
1449                         else if(strcmp($<id>1,"last")==0)
1450                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
1451                         else {
1452                                 yyerror(_("signal must be 'first' or 'last'"));
1453                                 g_free($<id>1);
1454                                 YYERROR;
1455                         }
1456                         g_free($<id>1);
1457                                         }
1458         |       scope sigtype           {
1459                         $<sigtype>$ = SIGNAL_LAST_METHOD;
1460                                         }
1461         |       simplesigtype           {
1462                         /* the_scope was default thus public */
1463                         the_scope = PUBLIC_SCOPE;
1464                                         }
1465         ;
1466         
1467 sigtype:        TOKEN '(' tokenlist ')'         {
1468                         gtktypes = g_list_prepend(gtktypes, debool ($<id>1));
1469                                                 }
1470         ;
1471
1472 tokenlist:      tokenlist ',' TOKEN             {
1473                         gtktypes = g_list_append(gtktypes, debool ($<id>3));
1474                                                 }
1475         |       TOKEN                           { 
1476                         gtktypes = g_list_append(gtktypes, debool ($<id>1));
1477                                                 }
1478         ;
1479
1480 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
1481         |       ';'                             { $<cbuf>$ = NULL; }
1482         ;
1483
1484 /*here CCODE will include the ending '}' */
1485 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
1486                         if(!has_self) {
1487                                 yyerror(_("signal without 'self' as "
1488                                           "first parameter"));
1489                                 free_all_global_state();
1490                                 YYERROR;
1491                         }
1492                         if(the_scope == CLASS_SCOPE) {
1493                                 yyerror(_("a method cannot be of class scope"));
1494                                 free_all_global_state();
1495                                 YYERROR;
1496                         }
1497                         push_function(the_scope, $<sigtype>3,NULL,
1498                                       $<id>5, $<cbuf>10,$<line>1,
1499                                       ccode_line, vararg, $<list>2);
1500                                                                         }
1501         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
1502                         if(!has_self) {
1503                                 yyerror(_("signal without 'self' as "
1504                                           "first parameter"));
1505                                 free_all_global_state();
1506                                 YYERROR;
1507                         }
1508                         if(the_scope == CLASS_SCOPE) {
1509                                 yyerror(_("a method cannot be of class scope"));
1510                                 free_all_global_state();
1511                                 YYERROR;
1512                         }
1513                         push_function(the_scope, $<sigtype>4, NULL,
1514                                       $<id>6, $<cbuf>11, $<line>2,
1515                                       ccode_line, vararg, $<list>3);
1516                                                                         }
1517         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
1518                         if(!has_self) {
1519                                 yyerror(_("virtual method without 'self' as "
1520                                           "first parameter"));
1521                                 free_all_global_state();
1522                                 YYERROR;
1523                         }
1524                         if(the_scope == CLASS_SCOPE) {
1525                                 yyerror(_("a method cannot be of class scope"));
1526                                 free_all_global_state();
1527                                 YYERROR;
1528                         }
1529                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1530                                       $<cbuf>9, $<line>1,
1531                                       ccode_line, vararg, NULL);
1532                                                                         }
1533         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
1534                         if(!has_self) {
1535                                 yyerror(_("virtual method without 'self' as "
1536                                           "first parameter"));
1537                                 free_all_global_state();
1538                                 YYERROR;
1539                         }
1540                         if(the_scope == CLASS_SCOPE) {
1541                                 yyerror(_("a method cannot be of class scope"));
1542                                 free_all_global_state();
1543                                 YYERROR;
1544                         }
1545                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1546                                       $<cbuf>9, $<line>2,
1547                                       ccode_line, vararg, NULL);
1548                                                                         }
1549         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
1550                         if(!has_self) {
1551                                 yyerror(_("virtual method without 'self' as "
1552                                           "first parameter"));
1553                                 free_all_global_state();
1554                                 YYERROR;
1555                         }
1556                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
1557                                       $<id>3, $<cbuf>8, $<line>1,
1558                                       ccode_line, vararg, NULL);
1559                                                                         }
1560         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
1561                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
1562                                       $<id>6, $<cbuf>11,
1563                                       $<line>1, ccode_line,
1564                                       vararg, NULL);
1565                                                                         }
1566         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
1567                         if(the_scope == CLASS_SCOPE) {
1568                                 yyerror(_("a method cannot be of class scope"));
1569                                 free_all_global_state();
1570                                 YYERROR;
1571                         }
1572                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
1573                                       $<cbuf>8, $<line>1, ccode_line,
1574                                       vararg, NULL);
1575                                                                 }
1576         |       TOKEN '(' TOKEN ')' codenocode  {
1577                         if(strcmp($<id>1, "init")==0) {
1578                                 push_init_arg($<id>3,FALSE);
1579                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
1580                                               $<id>1, $<cbuf>5, $<line>2,
1581                                               ccode_line, FALSE, NULL);
1582                         } else if(strcmp($<id>1, "class_init")==0) {
1583                                 push_init_arg($<id>3,TRUE);
1584                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
1585                                               $<id>1, $<cbuf>5, $<line>2,
1586                                               ccode_line, FALSE, NULL);
1587                         } else {
1588                                 g_free($<id>1);
1589                                 g_free($<id>3);
1590                                 g_string_free($<cbuf>5,TRUE);
1591                                 yyerror(_("parse error "
1592                                           "(untyped blocks must be init or "
1593                                           "class_init)"));
1594                                 YYERROR;
1595                         }
1596                                                 }
1597         ;
1598
1599 returnvals:     TOKEN retcode           {
1600                         g_free(onerror); onerror = NULL;
1601                         g_free(defreturn); defreturn = NULL;
1602                         if(!set_return_value($<id>1, $<id>2)) {
1603                                 g_free($<id>1);
1604                                 g_free($<id>2);
1605                                 yyerror(_("parse error"));
1606                                 YYERROR;
1607                         }
1608                         g_free($<id>1);
1609                                         }
1610         |       TOKEN retcode TOKEN retcode     {
1611                         g_free(onerror); onerror = NULL;
1612                         g_free(defreturn); defreturn = NULL;
1613                         if(!set_return_value($<id>1, $<id>2)) {
1614                                 g_free($<id>1); g_free($<id>2);
1615                                 g_free($<id>3); g_free($<id>4);
1616                                 yyerror(_("parse error"));
1617                                 YYERROR;
1618                         }
1619                         if(!set_return_value($<id>3, $<id>4)) {
1620                                 onerror = defreturn = NULL;
1621                                 g_free($<id>1); g_free($<id>2);
1622                                 g_free($<id>3); g_free($<id>4);
1623                                 yyerror(_("parse error"));
1624                                 YYERROR;
1625                         }
1626                         g_free($<id>1);
1627                         g_free($<id>3);
1628                                                 }
1629         |                               {
1630                         g_free(onerror); onerror = NULL;
1631                         g_free(defreturn); defreturn = NULL;
1632                                         }
1633         ;
1634
1635 retcode:        numtok                  { $<id>$ = $<id>1; }
1636         |       '{' CCODE               {
1637                         $<id>$ = ($<cbuf>3)->str;
1638                         g_string_free($<cbuf>3, FALSE);
1639                                         }
1640         ;
1641         
1642 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
1643         |       TOKEN                   {
1644                         vararg = FALSE;
1645                         has_self = TRUE;
1646                         if(strcmp($<id>1,"self")==0)
1647                                 push_self($<id>1, FALSE);
1648                         else {
1649                                 g_free($<id>1);
1650                                 yyerror(_("parse error"));
1651                                 YYERROR;
1652                         }
1653                                         }
1654         |       TOKEN CONST {
1655                         vararg = FALSE;
1656                         has_self = TRUE;
1657                         if(strcmp($<id>1,"self")==0)
1658                                 push_self($<id>1, TRUE);
1659                         else {
1660                                 g_free($<id>1);
1661                                 yyerror(_("parse error"));
1662                                 YYERROR;
1663                         }
1664                                         }
1665         |       CONST TOKEN {
1666                         vararg = FALSE;
1667                         has_self = TRUE;
1668                         if(strcmp($<id>2,"self")==0)
1669                                 push_self($<id>2, TRUE);
1670                         else {
1671                                 g_free($<id>2);
1672                                 yyerror(_("parse error"));
1673                                 YYERROR;
1674                         }
1675                                         }
1676         |       TOKEN ',' arglist       {
1677                         has_self = TRUE;
1678                         if(strcmp($<id>1,"self")==0)
1679                                 push_self($<id>1, FALSE);
1680                         else {
1681                                 g_free($<id>1);
1682                                 yyerror(_("parse error"));
1683                                 YYERROR;
1684                         }
1685                                         }
1686         |       TOKEN CONST ',' arglist {
1687                         has_self = TRUE;
1688                         if(strcmp($<id>1,"self")==0)
1689                                 push_self($<id>1, TRUE);
1690                         else {
1691                                 g_free($<id>1);
1692                                 yyerror(_("parse error"));
1693                                 YYERROR;
1694                         }
1695                                         }
1696         |       CONST TOKEN ',' arglist {
1697                         has_self = TRUE;
1698                         if(strcmp($<id>2,"self")==0)
1699                                 push_self($<id>2, TRUE);
1700                         else {
1701                                 g_free($<id>2);
1702                                 yyerror(_("parse error"));
1703                                 YYERROR;
1704                         }
1705                                         }
1706         |       arglist                 { has_self = FALSE; }
1707         ;
1708
1709 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
1710         |       arglist1                { vararg = FALSE; }
1711         ;
1712         
1713 arglist1:       arglist1 ',' arg        { ; }
1714         |       arg                     { ; }
1715         ;
1716
1717 arg:            type TOKEN                                      {
1718                         push_funcarg($<id>2,NULL);
1719                                                                 }
1720         |       type TOKEN ARRAY_DIM                            {
1721                         push_funcarg($<id>2,$<id>3);
1722                                                                 }
1723         |       type TOKEN '(' TOKEN checklist ')'              {
1724                         if(strcmp($<id>4,"check")!=0) {
1725                                 yyerror(_("parse error"));
1726                                 YYERROR;
1727                         }
1728                         g_free($<id>4);
1729                         push_funcarg($<id>2,NULL);
1730                                                                 }
1731         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
1732                         if(strcmp($<id>5,"check")!=0) {
1733                                 yyerror(_("parse error"));
1734                                 YYERROR;
1735                         }
1736                         g_free($<id>5);
1737                         push_funcarg($<id>2,$<id>3);
1738                                                                 }
1739         ;
1740         
1741 checklist:      checklist check         { ; }
1742         |       check                   { ; }
1743         ;
1744
1745 check:          TOKEN                   {
1746                         if(strcmp($<id>1,"type")==0) {
1747                                 Node *node = node_new (CHECK_NODE,
1748                                                        "chtype", TYPE_CHECK,
1749                                                        NULL);
1750                                 checks = g_list_append(checks,node);
1751                         } else if(strcmp($<id>1,"null")==0) {
1752                                 Node *node = node_new (CHECK_NODE,
1753                                                        "chtype", NULL_CHECK,
1754                                                        NULL);
1755                                 checks = g_list_append(checks,node);
1756                         } else {
1757                                 yyerror(_("parse error"));
1758                                 YYERROR;
1759                         }
1760                         g_free($<id>1);
1761                                         }
1762         |       '>' numtok              {
1763                         Node *node = node_new (CHECK_NODE,
1764                                                "chtype", GT_CHECK,
1765                                                "number:steal", $<id>2,
1766                                                NULL);
1767                         checks = g_list_append(checks,node);
1768                                         }
1769         |       '<' numtok              {
1770                         Node *node = node_new (CHECK_NODE,
1771                                                "chtype", LT_CHECK,
1772                                                "number:steal", $<id>2,
1773                                                NULL);
1774                         checks = g_list_append(checks,node);
1775                                         }
1776         |       '>' '=' numtok          {
1777                         Node *node = node_new (CHECK_NODE,
1778                                                "chtype", GE_CHECK,
1779                                                "number:steal", $<id>3,
1780                                                NULL);
1781                         checks = g_list_append(checks,node);
1782                                         }
1783         |       '<' '=' numtok          {
1784                         Node *node = node_new (CHECK_NODE,
1785                                                "chtype", LE_CHECK,
1786                                                "number:steal", $<id>3,
1787                                                NULL);
1788                         checks = g_list_append(checks,node);
1789                                         }
1790         |       '=' '=' numtok          {
1791                         Node *node = node_new (CHECK_NODE,
1792                                                "chtype", EQ_CHECK,
1793                                                "number:steal", $<id>3,
1794                                                NULL);
1795                         checks = g_list_append(checks,node);
1796                                         }
1797         |       '!' '=' numtok          {
1798                         Node *node = node_new (CHECK_NODE,
1799                                                "chtype", NE_CHECK,
1800                                                "number:steal", $<id>3,
1801                                                NULL);
1802                         checks = g_list_append(checks,node);
1803                                         }
1804         ;
1805
1806 enumcode:       ENUM TOKEN '{' enumvals '}' TYPETOKEN ';' {
1807                         Node *node = node_new (ENUMDEF_NODE,
1808                                                "etype:steal", $<id>6,
1809                                                "prefix:steal", $<id>2,
1810                                                "values:steal", enum_vals,
1811                                                NULL);
1812                         enum_vals = NULL;
1813                         nodes = g_list_append (nodes, node);
1814                         }
1815         |       ENUM TOKEN '{' enumvals ',' '}' TYPETOKEN ';' {
1816                         Node *node = node_new (ENUMDEF_NODE,
1817                                                "etype:steal", $<id>7,
1818                                                "prefix:steal", $<id>2,
1819                                                "values:steal", enum_vals,
1820                                                NULL);
1821                         enum_vals = NULL;
1822                         nodes = g_list_append (nodes, node);
1823                         }
1824         ;
1825
1826 enumvals:       enumvals ',' enumval    {;}
1827         |       enumval                 {;}
1828         ;
1829
1830 enumval:        TOKEN '=' numtok        {
1831                         Node *node;
1832                         char *num = $<id>3;
1833
1834                         /* A float value, that's a bad enum */
1835                         if (num[0] >= '0' &&
1836                             num[0] <= '9' &&
1837                             strchr (num, '.') != NULL) {
1838                                 g_free ($<id>1);
1839                                 g_free (num);
1840                                 yyerror(_("parse error (enumerator value not integer constant)"));
1841                                 YYERROR;
1842                         }
1843                        
1844                         node = node_new (ENUMVALUE_NODE,
1845                                          "name:steal", $<id>1,
1846                                          "value:steal", num,
1847                                          NULL);
1848                         enum_vals = g_list_append (enum_vals, node);
1849                         }
1850         |       TOKEN                   {
1851                         Node *node;
1852
1853                         node = node_new (ENUMVALUE_NODE,
1854                                          "name:steal", $<id>1,
1855                                          NULL);
1856                         enum_vals = g_list_append (enum_vals, node);
1857         }
1858         ;
1859
1860 flagcode:       FLAGS TOKEN '{' flagvals '}' TYPETOKEN ';' {
1861                         Node *node = node_new (FLAGS_NODE,
1862                                                "ftype:steal", $<id>6,
1863                                                "prefix:steal", $<id>2,
1864                                                "values:steal", flag_vals,
1865                                                NULL);
1866                         flag_vals = NULL;
1867                         nodes = g_list_append (nodes, node);
1868                         }
1869         |       FLAGS TOKEN '{' flagvals ',' '}' TYPETOKEN ';' {
1870                         Node *node = node_new (FLAGS_NODE,
1871                                                "ftype:steal", $<id>7,
1872                                                "prefix:steal", $<id>2,
1873                                                "values:steal", flag_vals,
1874                                                NULL);
1875                         flag_vals = NULL;
1876                         nodes = g_list_append (nodes, node);
1877                         }
1878         ;
1879
1880 flagvals:       flagvals ',' TOKEN      {
1881                         flag_vals = g_list_append (flag_vals, $<id>3);
1882                 }
1883         |       TOKEN                   {
1884                         flag_vals = g_list_append (flag_vals, $<id>1);
1885                 }
1886         ;
1887
1888 errorcode:      ERROR TOKEN '{' errorvals '}' TYPETOKEN ';' {
1889                         Node *node = node_new (ERROR_NODE,
1890                                                "etype:steal", $<id>6,
1891                                                "prefix:steal", $<id>2,
1892                                                "values:steal", error_vals,
1893                                                NULL);
1894                         error_vals = NULL;
1895                         nodes = g_list_append (nodes, node);
1896                         }
1897         |       ERROR TOKEN '{' errorvals ',' '}' TYPETOKEN ';' {
1898                         Node *node = node_new (ERROR_NODE,
1899                                                "etype:steal", $<id>7,
1900                                                "prefix:steal", $<id>2,
1901                                                "values:steal", error_vals,
1902                                                NULL);
1903                         error_vals = NULL;
1904                         nodes = g_list_append (nodes, node);
1905                         }
1906         ;
1907
1908 errorvals:      errorvals ',' TOKEN     {
1909                         error_vals = g_list_append (error_vals, $<id>3);
1910                 }
1911         |       TOKEN                   {
1912                         error_vals = g_list_append (error_vals, $<id>1);
1913                 }
1914         ;
1915
1916
1917 numtok:         NUMBER                  { $<id>$ = $<id>1; }
1918         |       '-' NUMBER              {
1919                         $<id>$ = g_strconcat("-",$<id>2,NULL);
1920                         g_free($<id>2);
1921                                         }
1922         |       SINGLE_CHAR             { $<id>$ = $<id>1; }
1923         |       TOKEN                   { $<id>$ = $<id>1; }
1924         ;
1925         
1926 %%