]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
Release 1.0.10
[gob-dx.git] / src / parse.y
1 /* GOB C Preprocessor
2  * Copyright (C) 1999 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the  Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  * USA.
20  */
21 %{
22
23 #include "config.h"
24 #include <glib.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "treefuncs.h"
30 #include "main.h"
31 #include "util.h"
32
33 #define _(x) (x)
34         
35 GList *nodes = NULL;
36
37 static GList *class_nodes = NULL;
38 Node *class = NULL;
39
40 static char *chunk_size = NULL;
41 static char *bonobo_x_class = NULL;
42 static GList *typestack = NULL;
43 static GList *funcargs = NULL;
44 static GList *checks = NULL;
45 static int has_self = FALSE;
46 static int vararg = FALSE;
47 static Method *last_added_method = NULL;
48
49 /* destructor and initializer for variables */
50 static char *destructor = NULL;
51 static int destructor_line = 0;
52 static gboolean destructor_simple = TRUE;
53 static char *initializer = NULL;
54 static int initializer_line = 0;
55
56 static char *onerror = NULL;
57 static char *defreturn = NULL;
58
59 static GList *gtktypes = NULL;
60
61 /* this can be a global as we will only do one function at a time
62    anyway */
63 static int the_scope = NO_SCOPE;
64
65 void free(void *ptr);
66 int yylex(void);
67
68 extern int ccode_line;
69 extern int line_no;
70
71 extern char *yytext;
72
73 static void
74 yyerror(char *str)
75 {
76         char *out=NULL;
77         char *p;
78         
79         if(strcmp(yytext,"\n")==0) {
80                 out=g_strconcat("Error: ",str," before newline",NULL);
81         } else if(yytext[0]=='\0') {
82                 out=g_strconcat("Error: ", str, " at end of input", NULL);
83         } else {
84                 char *tmp = g_strdup(yytext);
85                 while((p=strchr(tmp, '\n')))
86                         *p='.';
87
88                 out=g_strconcat("Error: ", str, " before '", tmp, "'", NULL);
89                 g_free(tmp);
90         }
91
92         fprintf(stderr, "%s:%d: %s\n", filename, line_no, out);
93         g_free(out);
94         
95         exit(1);
96 }
97
98 static Type *
99 pop_type(void)
100 {
101         Type *type = typestack->data;
102         typestack = g_list_remove(typestack,typestack->data);
103         return type;
104 }
105
106 static void
107 push_variable(char *name, int scope, int line_no, char *postfix)
108 {
109         Node *var;
110         Type *type = pop_type();
111
112         type->postfix = postfix;
113         
114         var = new_variable(scope, type, name, line_no,
115                            destructor, destructor_line,
116                            destructor_simple,
117                            initializer, initializer_line);
118         class_nodes = g_list_append(class_nodes, var);
119 }
120
121 static void
122 push_function(int scope, int method, char *oid, char *id,
123               GString *cbuf, int line_no, int ccode_line,
124               gboolean vararg, GList *flags)
125 {
126         Node *node;
127         Type *type;
128         char *c_cbuf;
129
130         g_assert(scope != CLASS_SCOPE);
131        
132         if(method == INIT_METHOD || method == CLASS_INIT_METHOD) {
133                 type = (Type *)new_type(g_strdup("void"), NULL, NULL);
134         } else {
135                 type = pop_type();
136         }
137         
138         /* a complicated and ugly test to figure out if we have
139            the wrong number of types for a signal */
140         if((method == SIGNAL_FIRST_METHOD ||
141             method == SIGNAL_LAST_METHOD) &&
142            g_list_length(gtktypes) != g_list_length(funcargs) &&
143            !(g_list_length(funcargs) == 1 &&
144              g_list_length(gtktypes) == 2 &&
145              strcmp(gtktypes->next->data, "NONE")==0)) {
146                 error_print(GOB_WARN, line_no,
147                             _("The number of GTK arguments and "
148                               "function arguments for a signal "
149                               "don't seem to match"));
150         }
151         if(g_list_length(gtktypes) > 2) {
152                 GList *li;
153                 for(li = gtktypes->next; li; li = li->next) {
154                         if(strcmp(li->data, "NONE")==0) {
155                                 error_print(GOB_ERROR, line_no,
156                                             _("NONE can only appear in an "
157                                               "argument list by itself"));
158                         }
159                 }
160         }
161         if(cbuf) {
162                 char *p;
163                 c_cbuf = p = cbuf->str;
164                 while(p && *p && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
165                         p++;
166                 if(!p || !*p)
167                         c_cbuf = NULL;
168         } else
169                 c_cbuf = NULL;
170
171         node = new_method(scope, method, type, oid, gtktypes, flags,
172                           id, funcargs, onerror, defreturn, c_cbuf, line_no,
173                           ccode_line, vararg, method_unique_id++,
174                           FALSE);
175
176         last_added_method = (Method *)node;
177
178         if(cbuf)
179                 g_string_free(cbuf,
180                               /*only free segment if we haven't passed it
181                                 above */
182                               c_cbuf?FALSE:TRUE);
183         gtktypes = NULL;
184         funcargs = NULL;
185
186         onerror = NULL;
187         defreturn = NULL;
188
189         class_nodes = g_list_append(class_nodes, node);
190 }
191
192 static void
193 free_all_global_state(void)
194 {
195         g_free(onerror);
196         onerror = NULL;
197         g_free(defreturn);
198         defreturn = NULL;
199
200         g_free(chunk_size);
201         chunk_size = NULL;
202         
203         g_list_foreach(gtktypes, (GFunc)g_free, NULL);
204         g_list_free(gtktypes);
205         gtktypes = NULL;
206
207         free_node_list(funcargs);
208         funcargs = NULL;
209 }
210
211 static void
212 push_funcarg(char *name, char *postfix)
213 {
214         Node *node;
215         Type *type = pop_type();
216
217         type->postfix = postfix;
218         
219         node = new_funcarg(type, name, checks);
220         checks = NULL;
221         
222         funcargs = g_list_append(funcargs, node);
223 }
224
225 static void
226 push_init_arg(char *name, int is_class)
227 {
228         Node *node;
229         Node *type;
230         char *tn;
231         
232         if(is_class)
233                 tn = g_strconcat(((Class *)class)->otype,":Class",NULL);
234         else
235                 tn = g_strdup(((Class *)class)->otype);
236
237         type = new_type(tn, g_strdup("*"), NULL);
238         node = new_funcarg((Type *)type,name,NULL);
239         funcargs = g_list_prepend(funcargs, node);
240 }
241
242 static void
243 push_self(char *id, gboolean constant)
244 {
245         Node *node;
246         Node *type;
247         GList *ch = NULL;
248         type = new_type(g_strdup(((Class *)class)->otype),
249                         g_strdup(constant ? "const *" : "*"), NULL);
250         ch = g_list_append(ch,new_check(NULL_CHECK,NULL));
251         ch = g_list_append(ch,new_check(TYPE_CHECK,NULL));
252         node = new_funcarg((Type *)type,id,ch);
253         funcargs = g_list_prepend(funcargs, node);
254 }
255
256 static Variable *
257 find_var_or_die(const char *id, int line)
258 {
259         GList *li;
260
261         for(li = class_nodes; li != NULL; li = li->next) {
262                 Variable *var;
263                 Node *node = li->data;
264                 if(node->type != VARIABLE_NODE)
265                         continue;
266                 var = li->data;
267                 if(strcmp(var->id, id)==0)
268                         return var;
269         }
270
271         error_printf(GOB_ERROR, line, _("Variable %s not defined here"), id);
272
273         g_assert_not_reached();
274         return NULL;
275 }
276
277 static gboolean
278 set_return_value(char *type, char *val)
279 {
280         if(strcmp(type, "onerror")==0) {
281                 if(!onerror) {
282                         onerror = val;
283                         return TRUE;
284                 } else
285                         return FALSE;
286         } else if(strcmp(type, "defreturn")==0) {
287                 if(!defreturn) {
288                         defreturn = val;
289                         return TRUE;
290                 } else
291                         return FALSE;
292         }
293         return FALSE;
294 }
295
296 static void
297 export_accessors (char *var_name,
298                   GString *get_cbuf,
299                   int get_lineno,
300                   GString *set_cbuf,
301                   int set_lineno,
302                   Type *type,
303                   int lineno)
304 {       
305         if (get_cbuf) {
306                 char *get_id = g_strdup_printf ("get_%s", var_name);
307                 GString *get_cbuf_copy = g_string_new (get_cbuf->str);
308                 char *tmp;
309                 Node *node1 = new_type (type->name, type->pointer, type->postfix);
310                 Node *node3 = new_type (class->class.otype, "*", NULL);
311
312                 tmp = g_strdup_printf ("\t%s%s ARG;\n", 
313                                        type->name, 
314                                        type->pointer ? type->pointer : "");
315                 get_cbuf_copy = g_string_prepend (get_cbuf_copy, tmp);
316                 g_free (tmp);
317                 
318                 tmp = g_strdup_printf ("\n\t\treturn ARG;\n");
319                 get_cbuf_copy = g_string_append (get_cbuf_copy, tmp);
320                 g_free (tmp);
321                 
322                 typestack = g_list_prepend (typestack, node1);
323                 typestack = g_list_prepend (typestack, node3);
324                 
325                 push_funcarg ("self", FALSE);
326                 
327                 push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
328                                get_id, get_cbuf_copy, get_lineno,
329                                lineno, FALSE, NULL);
330         }
331         
332         if (set_cbuf) {
333                 char *set_id = g_strdup_printf ("set_%s", var_name);
334                 GString *set_cbuf_copy = g_string_new (set_cbuf->str);
335                 Node *node1 = new_type (type->name, type->pointer, type->postfix);
336                 Node *node2 = new_type ("void", NULL, NULL);
337                 Node *node3 = new_type (class->class.otype, "*", NULL);
338
339                 typestack = g_list_prepend (typestack, node2);
340                 typestack = g_list_prepend (typestack, node1);
341                 typestack = g_list_prepend (typestack, node3);
342                 
343                 push_funcarg ("self", FALSE);
344                 push_funcarg ("ARG", FALSE);
345         
346                 typestack = g_list_prepend (typestack, node2);
347                 push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
348                                set_id, set_cbuf_copy, set_lineno,
349                                lineno, FALSE, NULL);
350         }
351 }
352
353 %}
354
355 %union {
356         char *id;
357         GString *cbuf;
358         GList *list;
359         int line;
360         int sigtype;
361 }
362
363 %token CLASS FROM
364 %token CONST VOID STRUCT UNION ENUM THREEDOTS
365 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
366
367 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM
368 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE
369 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE ARGUMENT VIRTUAL SIGNAL OVERRIDE
370
371 %%
372
373 prog:           ccodes class ccodes     { ; }
374         |       class ccodes            { ; }
375         |       ccodes class            { ; }
376         |       class                   { ; }
377         ;
378
379 ccode:          CCODE                   {
380                         Node *node = new_ccode(C_CCODE,($<cbuf>1)->str,
381                                                ccode_line);
382                         nodes = g_list_append(nodes,node);
383                         g_string_free($<cbuf>1,FALSE);
384                                         }
385         |       HCODE                   {
386                         Node *node = new_ccode(H_CCODE,($<cbuf>1)->str,
387                                                ccode_line);
388                         nodes = g_list_append(nodes,node);
389                         g_string_free($<cbuf>1,FALSE);
390                                         }
391         |       HTCODE                  {
392                         Node *node = new_ccode(HT_CCODE,($<cbuf>1)->str,
393                                                ccode_line);
394                         nodes = g_list_append(nodes,node);
395                         g_string_free($<cbuf>1,FALSE);
396                                         }
397         |       PHCODE                  {
398                         Node *node = new_ccode(PH_CCODE,($<cbuf>1)->str,
399                                                ccode_line);
400                         nodes = g_list_append(nodes,node);
401                         g_string_free($<cbuf>1,FALSE);
402                                         }
403         |       ACODE                   {
404                         Node *node = new_ccode(A_CCODE,($<cbuf>1)->str,
405                                                ccode_line);
406                         nodes = g_list_append(nodes,node);
407                         g_string_free($<cbuf>1,FALSE);
408                                         }
409         |       ATCODE                  {
410                         Node *node = new_ccode(AT_CCODE,($<cbuf>1)->str,
411                                                ccode_line);
412                         nodes = g_list_append(nodes,node);
413                         g_string_free($<cbuf>1,FALSE);
414                                         }
415         ;
416
417 ccodes:         ccodes ccode            { ; }
418         |       ccode                   { ; }
419         ;
420
421 class:          classdec '{' classcode '}'      {
422                         ((Class *)class)->nodes = class_nodes;
423                         class_nodes = NULL;
424                         nodes = g_list_append(nodes,class);
425                                                 }
426         |       classdec '{' '}'                {
427                         ((Class *)class)->nodes = NULL;
428                         class_nodes = NULL;
429                         nodes = g_list_append(nodes,class);
430                                                 }
431         ;
432
433 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  classflags {
434                         class = new_class ($<id>2, $<id>4,
435                                            bonobo_x_class, chunk_size, NULL);
436                                                 }
437         ;
438
439 classflags:
440         | '(' TOKEN TOKEN ')' classflags {
441                         if(strcmp($<id>2,"chunks") == 0) {
442                                 g_free (chunk_size);
443                                 chunk_size = g_strdup($<id>3);
444                         } else if(strcmp($<id>2,"BonoboX") == 0) {
445                                 g_free (bonobo_x_class);
446                                 bonobo_x_class = g_strdup($<id>3);
447                         } else {
448                                 yyerror(_("parse error"));
449                                 YYERROR;
450                         }
451                 }
452         | '(' TOKEN NUMBER ')' classflags {
453                         if(strcmp($<id>2,"chunks") == 0) {
454                                 g_free (chunk_size);
455                                 if(atoi($<id>3) != 0)
456                                         chunk_size = g_strdup($<id>3);
457                                 else
458                                         chunk_size = NULL;
459                         } else {
460                                 yyerror(_("parse error"));
461                                 YYERROR;
462                         }
463                 }
464         ;       
465
466 classcode:      classcode thing                 { ; }
467         |       thing                           { ; }
468         ;
469
470 thing:          method                          { ; }
471         |       TOKEN method                    {
472                         if (strcmp ($<id>1, "BonoboX") != 0) {
473                                 g_free($<id>1);
474                                 yyerror(_("parse error"));
475                                 YYERROR;
476                         }
477                         last_added_method->bonobo_x_func = TRUE;
478                                                 }
479         |       variable                        { ; }
480         |       argument                        { ; }
481         |       ';'                             { ; }
482         ;
483
484 scope:          PUBLIC                  { the_scope = PUBLIC_SCOPE; }
485         |       PRIVATE                 { the_scope = PRIVATE_SCOPE; }
486         |       PROTECTED               { the_scope = PROTECTED_SCOPE; }
487         |       CLASSWIDE               { the_scope = CLASS_SCOPE; }
488         ;
489
490 destructor:     TOKEN TOKEN     {
491                         if(strcmp($<id>1, "destroywith")==0) {
492                                 g_free($<id>1);
493                                 destructor = $<id>2;
494                                 destructor_line = line_no;
495                                 destructor_simple = TRUE;
496                         } else {
497                                 g_free($<id>1);
498                                 g_free($<id>2);
499                                 yyerror(_("parse error"));
500                                 YYERROR;
501                         }
502                                 }
503         |       TOKEN '{' CCODE         {
504                         if(strcmp($<id>1, "destroy")==0) {
505                                 g_free($<id>1);
506                                 destructor = ($<cbuf>3)->str;
507                                 g_string_free($<cbuf>3, FALSE);
508                                 destructor_line = ccode_line;
509                                 destructor_simple = FALSE;
510                         } else {
511                                 g_free($<id>1);
512                                 g_string_free($<cbuf>3, TRUE);
513                                 yyerror(_("parse error"));
514                                 YYERROR;
515                         }
516                                         }
517         ;
518
519 initializer:    '=' numtok      {
520                         initializer = $<id>2;
521                         initializer_line = ccode_line;
522                                 }
523         |       '=' '{' CCODE   {
524                         initializer = ($<cbuf>3)->str;
525                         initializer_line = ccode_line;
526                         g_string_free($<cbuf>3, FALSE);
527                                 }
528         ;
529
530
531 varoptions:     destructor initializer  { ; }
532         |       initializer destructor  { ; }
533         |       initializer             { destructor = NULL; }
534         |       destructor              { initializer = NULL; }
535         |                               {
536                         destructor = NULL;
537                         initializer = NULL;
538                                         }
539         ;
540
541 variable:       scope type TOKEN varoptions ';'         {
542                         push_variable($<id>3, the_scope,$<line>1, NULL);
543                                                 }
544         |       scope type TOKEN ARRAY_DIM varoptions ';'       {
545                         push_variable($<id>3, the_scope, $<line>1, $<id>4);
546                                                 }
547         ;
548
549 argument:       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE TOKEN '{' CCODE ';' {
550                         if(strcmp($<id>6,"get")==0 &&
551                            strcmp($<id>9,"set")==0) {
552                                 Node *node;
553                                 Type *type = pop_type();
554                                 g_free ($<id>6); 
555                                 g_free ($<id>9);
556                                 node = new_argument ($<id>3, type, $<list>2, $<id>4,
557                                                      ($<cbuf>8)->str, $<line>7,
558                                                      ($<cbuf>11)->str,$<line>10,
559                                                      $<line>1);
560
561                                 class_nodes = g_list_append(class_nodes,node);
562
563                                 if ($<id>5) {
564                                         export_accessors ($<id>4, 
565                                                           $<cbuf>8, $<line>7,
566                                                           $<cbuf>11, $<line>10,
567                                                           type,
568                                                           $<line>1);
569                                 } 
570
571                                 g_string_free ($<cbuf>8, FALSE);
572                                 g_string_free ($<cbuf>11, FALSE);
573
574                         } else if(strcmp($<id>6,"set")==0 &&
575                                 strcmp($<id>9,"get")==0) {
576                                 Node *node;
577                                 Type *type = pop_type();
578                                 g_free ($<id>6); 
579                                 g_free ($<id>9);
580                                 node = new_argument ($<id>3, type, $<list>2, $<id>4,
581                                                      ($<cbuf>11)->str,$<line>10,
582                                                      ($<cbuf>8)->str,$<line>7,
583                                                      $<line>1);
584                                 g_string_free ($<cbuf>11, FALSE);
585                                 g_string_free ($<cbuf>8, FALSE);
586                                 class_nodes = g_list_append(class_nodes,node);
587                         } else {
588                                 g_free ($<id>3); 
589                                 g_free ($<id>4);
590                                 g_free ($<id>6); 
591                                 g_free ($<id>9);
592                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
593                                 g_list_free ($<list>2);
594                                 g_string_free ($<cbuf>11, TRUE);
595                                 g_string_free ($<cbuf>8, TRUE);
596                                 yyerror (_("parse error"));
597                                 YYERROR;
598                         }
599                                                 }
600         |       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE ';' {
601                         if(strcmp($<id>6, "get") == 0) {
602                                 Node *node;
603                                 Type *type = pop_type();
604                                 g_free ($<id>6);
605                                 node = new_argument ($<id>3, type, $<list>2, $<id>4,
606                                                      ($<cbuf>8)->str, $<line>7,
607                                                      NULL, 0, 
608                                                      $<line>1);
609                                 if ($<id>5) {
610                                         export_accessors ($<id>4, 
611                                                           $<cbuf>8, $<line>7,
612                                                           NULL, 0,
613                                                           type,
614                                                           $<line>1);
615                                 } 
616
617                                 g_string_free ($<cbuf>8, FALSE);
618                                 class_nodes = g_list_append(class_nodes, node);
619                         } else if(strcmp($<id>6, "set") == 0) {
620                                 Node *node;
621                                 Type *type = pop_type();
622                                 g_free ($<id>6);
623                                 node = new_argument ($<id>3, type, $<list>2, $<id>4,
624                                                      NULL, 0, 
625                                                      ($<cbuf>8)->str, $<line>7, 
626                                                      $<line>1);
627                                 if ($<id>5) {
628                                         export_accessors ($<id>4, 
629                                                           NULL, 0,
630                                                           $<cbuf>8, $<line>7,
631                                                           type,
632                                                           $<line>1);
633                                 } 
634
635                                 g_string_free ($<cbuf>8, FALSE);
636                                 class_nodes = g_list_append (class_nodes, node);
637                         } else {
638                                 g_free ($<id>6); 
639                                 g_free ($<id>3);
640                                 g_free ($<id>4);
641                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
642                                 g_list_free ($<list>2);
643                                 g_string_free ($<cbuf>8, TRUE);
644                                 yyerror(_("parse error"));
645                                 YYERROR;
646                         }
647                                                 }
648         |       ARGUMENT flags argtype TOKEN export TOKEN {
649                         Node *node;
650                         char *get, *set = NULL;
651                         Variable *var;
652                         Type *type;
653                         char *root;
654                         
655                         if(strcmp($<id>6, "link")!=0 &&
656                            strcmp($<id>6, "stringlink")!=0 && 
657                            strcmp($<id>6, "objectlink")!=0) {
658                                 g_free($<id>6); 
659                                 g_free($<id>3);
660                                 g_free($<id>4);
661                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
662                                 g_list_free($<list>2);
663                                 yyerror(_("parse error"));
664                                 YYERROR;
665                         }
666
667                         type = pop_type();
668
669                         var = find_var_or_die($<id>4, $<line>1);
670                         if(var->scope == PRIVATE_SCOPE)
671                                 root = "self->_priv";
672                         else if(var->scope == CLASS_SCOPE) {
673                                 root = "SELF_GET_CLASS(self)";
674                                 if(no_self_alias)
675                                         error_print(GOB_ERROR, $<line>1,
676                                                     _("Self aliases needed when autolinking to a classwide member"));
677                         } else
678                                 root = "self";
679
680                         if(strcmp($<id>6, "link")==0) {
681                                 set = g_strdup_printf("%s->%s = ARG;",
682                                                       root, $<id>4);
683                         } else if(strcmp ($<id>6, "stringlink")==0) {
684                                 set = g_strdup_printf("g_free(%s->%s); "
685                                                       "%s->%s = g_strdup(ARG);",
686                                                       root, $<id>4,
687                                                       root, $<id>4);
688                         } else if(strcmp ($<id>6, "objectlink")==0) {
689                                 set = g_strdup_printf(
690                                   "if (ARG != NULL) "
691                                    "gtk_object_ref (GTK_OBJECT (ARG)); "
692                                   "if (%s->%s != NULL) "
693                                    "gtk_object_unref (GTK_OBJECT (%s->%s)); "
694                                   "%s->%s = ARG;",
695                                   root, $<id>4,
696                                   root, $<id>4,
697                                   root, $<id>4);
698                         } else {
699                                 g_assert_not_reached();
700                         }
701
702                         if(strcmp ($<id>6, "stringlink")==0) {
703                                 get = g_strdup_printf("ARG = g_strdup(%s->%s);", root, $<id>4);
704                         } else
705                                 /* For everything else, get is just straight assignment */
706                                 get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
707
708                         g_free ($<id>6);
709
710
711                         if(!type)
712                                 type = copy_type(var->vtype);
713
714                         node = new_argument ($<id>3, type, $<list>2,
715                                              $<id>4, 
716                                              get, $<line>1,
717                                              set, $<line>1, 
718                                              $<line>1);
719                         if ($<id>5) {
720                                 export_accessors ($<id>4, 
721                                                   g_string_new (get), $<line>1,
722                                                   g_string_new (set), $<line>1,
723                                                   type,
724                                                   $<line>1);
725                         } 
726
727                         class_nodes = g_list_append(class_nodes,node);
728                                                 }
729         ;
730
731 export:         '(' TOKEN ')'                   {
732                                                   if (strcmp ($<id>2, "export")!=0) {
733                                                           g_free ($<id>2); 
734                                                           yyerror (_("parse error"));
735                                                           YYERROR;
736                                                   }
737                                                   $<id>$ = $<id>2;
738                                                 }
739          |                                      { $<id>$ = NULL; }
740                   
741 argtype:        TOKEN '(' TOKEN type ')'        {
742                         if(strcmp($<id>3,"type")!=0) {
743                                 g_free($<id>1);
744                                 g_free($<id>3);
745                                 yyerror(_("parse error"));
746                                 YYERROR;
747                         }
748                         $<id>$ = $<id>1;
749                                                 }
750         |       TOKEN                           {
751                         $<id>$ = $<id>1;
752                         typestack = g_list_prepend(typestack,NULL);
753                                                 }
754         ;
755         
756 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
757         |                                       { $<list>$ = NULL; }
758         ;
759
760 flaglist:       TOKEN '|' flaglist              {
761                         $<list>$ = g_list_append($<list>3,$<id>1);
762                                                 }
763         |       TOKEN                           {
764                         $<list>$ = g_list_append(NULL,$<id>1);
765                                                 }
766         ;
767
768
769 type:           specifier_list pointer                          {
770                         Node *node = new_type($<id>1, $<id>2, NULL);
771                         typestack = g_list_prepend(typestack,node);
772                                                         }
773         |       specifier_list                          {
774                         Node *node = new_type($<id>1, NULL, NULL);
775                         typestack = g_list_prepend(typestack,node);
776                                                         }
777         ;
778
779 /* The special cases are neccessary to avoid conflicts */
780 specifier_list: spec_list                               {
781                         $<id>$ = $<id>1;
782                                                         }
783         |       TOKEN                                   {
784                         $<id>$ = $<id>1;
785                                                         }
786         |       CONST TOKEN                             {
787                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
788                         g_free($<id>2);
789                                                         }
790         |       TOKEN CONST                             {
791                         $<id>$ = g_strconcat($<id>1, " const", NULL);
792                         g_free($<id>1);
793                                                         }
794         |       strunionenum TOKEN                      {
795                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
796                         g_free($<id>2);
797                                                         }
798         |       CONST strunionenum TOKEN                {
799                         $<id>$ = g_strconcat("const ", $<id>2, " ",
800                                              $<id>3, NULL);
801                         g_free($<id>3);
802                                                         }
803         |       strunionenum TOKEN CONST                {
804                         $<id>$ = g_strconcat($<id>1, " ",
805                                              $<id>2, " const", NULL);
806                         g_free($<id>2);
807                                                         }
808         ;
809
810 /* The special const cases take care of conflicts ! */
811 spec_list:      specifier spec_list                     {
812                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
813                         g_free($<id>2);
814                                                         }
815         |       TYPETOKEN spec_list                     {
816                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
817                         g_free($<id>1);
818                         g_free($<id>2);
819                                                         }
820         |       CONST spec_list                         {
821                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
822                         g_free($<id>2);
823                                                         }
824         |       TYPETOKEN                               {
825                         $<id>$ = $<id>1;
826                                                         }
827         |       TYPETOKEN CONST                         {
828                         $<id>$ = g_strconcat($<id>1, " const", NULL);
829                         g_free($<id>1);
830                                                         }
831         |       specifier                               {
832                         $<id>$ = g_strdup($<id>1);
833                                                         }
834         |       specifier CONST                         {
835                         $<id>$ = g_strconcat($<id>1, " const", NULL);
836                                                         }
837         ;
838
839 specifier:      VOID                    { $<id>$ = "void"; }
840         |       CHAR                    { $<id>$ = "char"; }
841         |       SHORT                   { $<id>$ = "short"; }
842         |       INT                     { $<id>$ = "int"; }
843         |       LONG                    { $<id>$ = "long"; }
844         |       FLOAT                   { $<id>$ = "float"; }
845         |       DOUBLE                  { $<id>$ = "double"; }
846         |       SIGNED                  { $<id>$ = "signed"; }
847         |       UNSIGNED                { $<id>$ = "unsigned"; }
848         ;
849
850 strunionenum:   STRUCT                  { $<id>$ = "struct"; }
851         |       UNION                   { $<id>$ = "union"; }
852         |       ENUM                    { $<id>$ = "enum"; }
853         ;
854
855 pointer:        '*'                     { $<id>$ = g_strdup("*"); }
856         |       '*' CONST               { $<id>$ = g_strdup("* const"); }
857         |       '*' pointer             {
858                                 $<id>$ = g_strconcat("*", $<id>2, NULL);
859                                 g_free($<id>2);
860                                         }
861         |       '*' CONST pointer       {
862                                 $<id>$ = g_strconcat("* const", $<id>3, NULL);
863                                 g_free($<id>3);
864                                         }
865         ;
866
867 /* this never sets the_scope */
868 simplesigtype:  TOKEN sigtype   {
869                         if(strcmp($<id>1, "first")==0)
870                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
871                         else if(strcmp($<id>1, "last")==0)
872                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
873                         else {
874                                 yyerror(_("signal must be 'first' or 'last'"));
875                                 g_free($<id>1);
876                                 YYERROR;
877                         }
878                         g_free($<id>1);
879                                         }
880         |       sigtype                 {
881                         $<sigtype>$ = SIGNAL_LAST_METHOD;
882                                         }
883         ;
884
885 /* this always sets the_scope */
886 fullsigtype:    scope TOKEN sigtype     {
887                         if(strcmp($<id>2,"first")==0)
888                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
889                         else if(strcmp($<id>2,"last")==0)
890                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
891                         else {
892                                 yyerror(_("signal must be 'first' or 'last'"));
893                                 g_free($<id>2);
894                                 YYERROR;
895                         }
896                         g_free($<id>2);
897                                         }
898         |       TOKEN scope sigtype     {
899                         if(strcmp($<id>1,"first")==0)
900                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
901                         else if(strcmp($<id>1,"last")==0)
902                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
903                         else {
904                                 yyerror(_("signal must be 'first' or 'last'"));
905                                 g_free($<id>1);
906                                 YYERROR;
907                         }
908                         g_free($<id>1);
909                                         }
910         |       scope sigtype           {
911                         $<sigtype>$ = SIGNAL_LAST_METHOD;
912                                         }
913         |       simplesigtype           {
914                         /* the_scope was default thus public */
915                         the_scope = PUBLIC_SCOPE;
916                                         }
917         ;
918         
919 sigtype:        TOKEN '(' tokenlist ')'         {
920                         gtktypes = g_list_prepend(gtktypes, $<id>1);
921                                                 }
922         ;
923
924 tokenlist:      tokenlist ',' TOKEN             {
925                         gtktypes = g_list_append(gtktypes, $<id>3);
926                                                 }
927         |       TOKEN                           { 
928                         gtktypes = g_list_append(gtktypes, $<id>1);
929                                                 }
930         ;
931
932 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
933         |       ';'                             { $<cbuf>$ = NULL; }
934         ;
935
936 /*here CCODE will include the ending '}' */
937 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
938                         if(!has_self) {
939                                 yyerror(_("signal without 'self' as "
940                                           "first parameter"));
941                                 free_all_global_state();
942                                 YYERROR;
943                         }
944                         if(the_scope == CLASS_SCOPE) {
945                                 yyerror(_("a method cannot be of class scope"));
946                                 free_all_global_state();
947                                 YYERROR;
948                         }
949                         push_function(the_scope, $<sigtype>3,NULL,
950                                       $<id>5, $<cbuf>10,$<line>1,
951                                       ccode_line, vararg, $<list>2);
952                                                                         }
953         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
954                         if(!has_self) {
955                                 yyerror(_("signal without 'self' as "
956                                           "first parameter"));
957                                 free_all_global_state();
958                                 YYERROR;
959                         }
960                         if(the_scope == CLASS_SCOPE) {
961                                 yyerror(_("a method cannot be of class scope"));
962                                 free_all_global_state();
963                                 YYERROR;
964                         }
965                         push_function(the_scope, $<sigtype>4, NULL,
966                                       $<id>6, $<cbuf>11, $<line>2,
967                                       ccode_line, vararg, $<list>3);
968                                                                         }
969         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
970                         if(!has_self) {
971                                 yyerror(_("virtual method without 'self' as "
972                                           "first parameter"));
973                                 free_all_global_state();
974                                 YYERROR;
975                         }
976                         if(the_scope == CLASS_SCOPE) {
977                                 yyerror(_("a method cannot be of class scope"));
978                                 free_all_global_state();
979                                 YYERROR;
980                         }
981                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
982                                       $<cbuf>9, $<line>1,
983                                       ccode_line, vararg, NULL);
984                                                                         }
985         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
986                         if(!has_self) {
987                                 yyerror(_("virtual method without 'self' as "
988                                           "first parameter"));
989                                 free_all_global_state();
990                                 YYERROR;
991                         }
992                         if(the_scope == CLASS_SCOPE) {
993                                 yyerror(_("a method cannot be of class scope"));
994                                 free_all_global_state();
995                                 YYERROR;
996                         }
997                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
998                                       $<cbuf>9, $<line>2,
999                                       ccode_line, vararg, NULL);
1000                                                                         }
1001         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
1002                         if(!has_self) {
1003                                 yyerror(_("virtual method without 'self' as "
1004                                           "first parameter"));
1005                                 free_all_global_state();
1006                                 YYERROR;
1007                         }
1008                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
1009                                       $<id>3, $<cbuf>8, $<line>1,
1010                                       ccode_line, vararg, NULL);
1011                                                                         }
1012         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
1013                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
1014                                       $<id>6, $<cbuf>11,
1015                                       $<line>1, ccode_line,
1016                                       vararg, NULL);
1017                                                                         }
1018         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
1019                         if(the_scope == CLASS_SCOPE) {
1020                                 yyerror(_("a method cannot be of class scope"));
1021                                 free_all_global_state();
1022                                 YYERROR;
1023                         }
1024                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
1025                                       $<cbuf>8, $<line>1, ccode_line,
1026                                       vararg, NULL);
1027                                                                 }
1028         |       TOKEN '(' TOKEN ')' codenocode  {
1029                         if(strcmp($<id>1, "init")==0) {
1030                                 push_init_arg($<id>3,FALSE);
1031                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
1032                                               $<id>1, $<cbuf>5, $<line>2,
1033                                               ccode_line, FALSE, NULL);
1034                         } else if(strcmp($<id>1, "class_init")==0) {
1035                                 push_init_arg($<id>3,TRUE);
1036                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
1037                                               $<id>1, $<cbuf>5, $<line>2,
1038                                               ccode_line, FALSE, NULL);
1039                         } else {
1040                                 g_free($<id>1);
1041                                 g_free($<id>3);
1042                                 g_string_free($<cbuf>5,TRUE);
1043                                 yyerror(_("parse error "
1044                                           "(untyped blocks must be init or "
1045                                           "class_init)"));
1046                                 YYERROR;
1047                         }
1048                                                 }
1049         ;
1050
1051 returnvals:     TOKEN retcode           {
1052                         g_free(onerror); onerror = NULL;
1053                         g_free(defreturn); defreturn = NULL;
1054                         if(!set_return_value($<id>1, $<id>2)) {
1055                                 g_free($<id>1);
1056                                 g_free($<id>2);
1057                                 yyerror(_("parse error"));
1058                                 YYERROR;
1059                         }
1060                         g_free($<id>1);
1061                                         }
1062         |       TOKEN retcode TOKEN retcode     {
1063                         g_free(onerror); onerror = NULL;
1064                         g_free(defreturn); defreturn = NULL;
1065                         if(!set_return_value($<id>1, $<id>2)) {
1066                                 g_free($<id>1); g_free($<id>2);
1067                                 g_free($<id>3); g_free($<id>4);
1068                                 yyerror(_("parse error"));
1069                                 YYERROR;
1070                         }
1071                         if(!set_return_value($<id>3, $<id>4)) {
1072                                 onerror = defreturn = NULL;
1073                                 g_free($<id>1); g_free($<id>2);
1074                                 g_free($<id>3); g_free($<id>4);
1075                                 yyerror(_("parse error"));
1076                                 YYERROR;
1077                         }
1078                         g_free($<id>1);
1079                         g_free($<id>3);
1080                                                 }
1081         |                               {
1082                         g_free(onerror); onerror = NULL;
1083                         g_free(defreturn); defreturn = NULL;
1084                                         }
1085         ;
1086
1087 retcode:        numtok                  { $<id>$ = $<id>1; }
1088         |       '{' CCODE               {
1089                         $<id>$ = ($<cbuf>3)->str;
1090                         g_string_free($<cbuf>3, FALSE);
1091                                         }
1092         ;
1093         
1094 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
1095         |       TOKEN                   {
1096                         vararg = FALSE;
1097                         has_self = TRUE;
1098                         if(strcmp($<id>1,"self")==0)
1099                                 push_self($<id>1, FALSE);
1100                         else {
1101                                 g_free($<id>1);
1102                                 yyerror(_("parse error"));
1103                                 YYERROR;
1104                         }
1105                                         }
1106         |       TOKEN CONST {
1107                         vararg = FALSE;
1108                         has_self = TRUE;
1109                         if(strcmp($<id>1,"self")==0)
1110                                 push_self($<id>1, TRUE);
1111                         else {
1112                                 g_free($<id>1);
1113                                 yyerror(_("parse error"));
1114                                 YYERROR;
1115                         }
1116                                         }
1117         |       CONST TOKEN {
1118                         vararg = FALSE;
1119                         has_self = TRUE;
1120                         if(strcmp($<id>2,"self")==0)
1121                                 push_self($<id>2, TRUE);
1122                         else {
1123                                 g_free($<id>2);
1124                                 yyerror(_("parse error"));
1125                                 YYERROR;
1126                         }
1127                                         }
1128         |       TOKEN ',' arglist       {
1129                         has_self = TRUE;
1130                         if(strcmp($<id>1,"self")==0)
1131                                 push_self($<id>1, FALSE);
1132                         else {
1133                                 g_free($<id>1);
1134                                 yyerror(_("parse error"));
1135                                 YYERROR;
1136                         }
1137                                         }
1138         |       TOKEN CONST ',' arglist {
1139                         has_self = TRUE;
1140                         if(strcmp($<id>1,"self")==0)
1141                                 push_self($<id>1, TRUE);
1142                         else {
1143                                 g_free($<id>1);
1144                                 yyerror(_("parse error"));
1145                                 YYERROR;
1146                         }
1147                                         }
1148         |       CONST TOKEN ',' arglist {
1149                         has_self = TRUE;
1150                         if(strcmp($<id>2,"self")==0)
1151                                 push_self($<id>2, TRUE);
1152                         else {
1153                                 g_free($<id>2);
1154                                 yyerror(_("parse error"));
1155                                 YYERROR;
1156                         }
1157                                         }
1158         |       arglist                 { has_self = FALSE; }
1159         ;
1160
1161 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
1162         |       arglist1                { vararg = FALSE; }
1163         ;
1164         
1165 arglist1:       arglist1 ',' arg        { ; }
1166         |       arg                     { ; }
1167         ;
1168
1169 arg:            type TOKEN                                      {
1170                         push_funcarg($<id>2,NULL);
1171                                                                 }
1172         |       type TOKEN ARRAY_DIM                            {
1173                         push_funcarg($<id>2,$<id>3);
1174                                                                 }
1175         |       type TOKEN '(' TOKEN checklist ')'              {
1176                         if(strcmp($<id>4,"check")!=0) {
1177                                 yyerror(_("parse error"));
1178                                 YYERROR;
1179                         }
1180                         g_free($<id>4);
1181                         push_funcarg($<id>2,NULL);
1182                                                                 }
1183         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
1184                         if(strcmp($<id>5,"check")!=0) {
1185                                 yyerror(_("parse error"));
1186                                 YYERROR;
1187                         }
1188                         g_free($<id>5);
1189                         push_funcarg($<id>2,$<id>3);
1190                                                                 }
1191         ;
1192         
1193 checklist:      checklist check         { ; }
1194         |       check                   { ; }
1195         ;
1196
1197 check:          TOKEN                   {
1198                         if(strcmp($<id>1,"type")==0) {
1199                                 Node *node = new_check(TYPE_CHECK,NULL);
1200                                 checks = g_list_append(checks,node);
1201                         } else if(strcmp($<id>1,"null")==0) {
1202                                 Node *node = new_check(NULL_CHECK,NULL);
1203                                 checks = g_list_append(checks,node);
1204                         } else {
1205                                 yyerror(_("parse error"));
1206                                 YYERROR;
1207                         }
1208                         g_free($<id>1);
1209                                         }
1210         |       '>' numtok              {
1211                         Node *node = new_check(GT_CHECK,$<id>2);
1212                         checks = g_list_append(checks,node);
1213                                         }
1214         |       '<' numtok              {
1215                         Node *node = new_check(LT_CHECK,$<id>2);
1216                         checks = g_list_append(checks,node);
1217                                         }
1218         |       '>' '=' numtok          {
1219                         Node *node = new_check(GE_CHECK,$<id>3);
1220                         checks = g_list_append(checks,node);
1221                                         }
1222         |       '<' '=' numtok          {
1223                         Node *node = new_check(LE_CHECK,$<id>3);
1224                         checks = g_list_append(checks,node);
1225                                         }
1226         |       '=' '=' numtok          {
1227                         Node *node = new_check(EQ_CHECK,$<id>3);
1228                         checks = g_list_append(checks,node);
1229                                         }
1230         |       '!' '=' numtok          {
1231                         Node *node = new_check(NE_CHECK,$<id>3);
1232                         checks = g_list_append(checks,node);
1233                                         }
1234         ;
1235         
1236 numtok:         NUMBER                  { $<id>$ = $<id>1; }
1237         |       '-' NUMBER              {
1238                         $<id>$ = g_strconcat("-",$<id>2,NULL);
1239                         g_free($<id>2);
1240                                         }
1241         |       TOKEN                   { $<id>$ = $<id>1; }
1242         ;
1243         
1244 %%