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