]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
Release 1.0.11
[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 (const char *var_name,
298                   const char *get_cbuf,
299                   int get_lineno,
300                   const char *set_cbuf,
301                   int set_lineno,
302                   Type *type,
303                   const char *gtktype,
304                   int lineno)
305 {       
306         if (type == NULL) {
307                 char *cast = g_strdup (get_cast (gtktype, FALSE));
308                 char *p = strchr (cast, ' ');
309                 if (p != NULL) {
310                         *p = '\0';
311                         p++;
312                 }
313                 /* leak, but we don't really care any more */
314                 type = (Type *)new_type (cast,
315                                          g_strdup (p),
316                                          NULL);
317         }
318
319         if (get_cbuf != NULL) {
320                 char *get_id = g_strdup_printf ("get_%s", var_name);
321                 GString *get_cbuf_copy = g_string_new (get_cbuf);
322                 char *tmp;
323                 Node *node1 = new_type (g_strdup (type->name),
324                                         g_strdup (type->pointer),
325                                         g_strdup (type->postfix));
326                 Node *node3 = new_type (g_strdup (class->class.otype),
327                                         g_strdup ("*"),
328                                         NULL);
329
330                 tmp = g_strdup_printf ("\t%s%s ARG;\n", 
331                                        type->name, 
332                                        type->pointer ? type->pointer : "");
333                 get_cbuf_copy = g_string_prepend (get_cbuf_copy, tmp);
334                 g_free (tmp);
335                 
336                 tmp = g_strdup_printf ("\n\t\treturn ARG;\n");
337                 get_cbuf_copy = g_string_append (get_cbuf_copy, tmp);
338                 g_free (tmp);
339                 
340                 typestack = g_list_prepend (typestack, node1);
341                 typestack = g_list_prepend (typestack, node3);
342                 
343                 push_funcarg ("self", FALSE);
344                 
345                 push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
346                                get_id, get_cbuf_copy, get_lineno,
347                                lineno, FALSE, NULL);
348         }
349         
350         if (set_cbuf != NULL) {
351                 char *set_id = g_strdup_printf ("set_%s", var_name);
352                 GString *set_cbuf_copy = g_string_new (set_cbuf);
353                 Node *node1 = new_type (g_strdup (type->name),
354                                         g_strdup (type->pointer),
355                                         g_strdup (type->postfix));
356                 Node *node2 = new_type (g_strdup ("void"),
357                                         NULL,
358                                         NULL);
359                 Node *node3 = new_type (g_strdup (class->class.otype),
360                                         g_strdup ("*"),
361                                         NULL);
362
363                 typestack = g_list_prepend (typestack, node2);
364                 typestack = g_list_prepend (typestack, node1);
365                 typestack = g_list_prepend (typestack, node3);
366                 
367                 push_funcarg ("self", FALSE);
368                 push_funcarg ("ARG", FALSE);
369         
370                 typestack = g_list_prepend (typestack, node2);
371                 push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
372                                set_id, set_cbuf_copy, set_lineno,
373                                lineno, FALSE, NULL);
374         }
375 }
376
377 %}
378
379 %union {
380         char *id;
381         GString *cbuf;
382         GList *list;
383         int line;
384         int sigtype;
385 }
386
387 %token CLASS FROM
388 %token CONST VOID STRUCT UNION ENUM THREEDOTS
389 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
390
391 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM
392 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE
393 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE ARGUMENT VIRTUAL SIGNAL OVERRIDE
394
395 %%
396
397 prog:           ccodes class ccodes     { ; }
398         |       class ccodes            { ; }
399         |       ccodes class            { ; }
400         |       class                   { ; }
401         ;
402
403 ccode:          CCODE                   {
404                         Node *node = new_ccode(C_CCODE,($<cbuf>1)->str,
405                                                ccode_line);
406                         nodes = g_list_append(nodes,node);
407                         g_string_free($<cbuf>1,FALSE);
408                                         }
409         |       HCODE                   {
410                         Node *node = new_ccode(H_CCODE,($<cbuf>1)->str,
411                                                ccode_line);
412                         nodes = g_list_append(nodes,node);
413                         g_string_free($<cbuf>1,FALSE);
414                                         }
415         |       HTCODE                  {
416                         Node *node = new_ccode(HT_CCODE,($<cbuf>1)->str,
417                                                ccode_line);
418                         nodes = g_list_append(nodes,node);
419                         g_string_free($<cbuf>1,FALSE);
420                                         }
421         |       PHCODE                  {
422                         Node *node = new_ccode(PH_CCODE,($<cbuf>1)->str,
423                                                ccode_line);
424                         nodes = g_list_append(nodes,node);
425                         g_string_free($<cbuf>1,FALSE);
426                                         }
427         |       ACODE                   {
428                         Node *node = new_ccode(A_CCODE,($<cbuf>1)->str,
429                                                ccode_line);
430                         nodes = g_list_append(nodes,node);
431                         g_string_free($<cbuf>1,FALSE);
432                                         }
433         |       ATCODE                  {
434                         Node *node = new_ccode(AT_CCODE,($<cbuf>1)->str,
435                                                ccode_line);
436                         nodes = g_list_append(nodes,node);
437                         g_string_free($<cbuf>1,FALSE);
438                                         }
439         ;
440
441 ccodes:         ccodes ccode            { ; }
442         |       ccode                   { ; }
443         ;
444
445 class:          classdec '{' classcode '}'      {
446                         ((Class *)class)->nodes = class_nodes;
447                         class_nodes = NULL;
448                         nodes = g_list_append(nodes,class);
449                                                 }
450         |       classdec '{' '}'                {
451                         ((Class *)class)->nodes = NULL;
452                         class_nodes = NULL;
453                         nodes = g_list_append(nodes,class);
454                                                 }
455         ;
456
457 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  classflags {
458                         class = new_class ($<id>2, $<id>4,
459                                            bonobo_x_class, chunk_size, NULL);
460                                                 }
461         ;
462
463 classflags:
464         | '(' TOKEN TOKEN ')' classflags {
465                         if(strcmp($<id>2,"chunks") == 0) {
466                                 g_free (chunk_size);
467                                 chunk_size = g_strdup($<id>3);
468                         } else if(strcmp($<id>2,"BonoboX") == 0) {
469                                 g_free (bonobo_x_class);
470                                 bonobo_x_class = g_strdup($<id>3);
471                         } else {
472                                 yyerror(_("parse error"));
473                                 YYERROR;
474                         }
475                 }
476         | '(' TOKEN NUMBER ')' classflags {
477                         if(strcmp($<id>2,"chunks") == 0) {
478                                 g_free (chunk_size);
479                                 if(atoi($<id>3) != 0)
480                                         chunk_size = g_strdup($<id>3);
481                                 else
482                                         chunk_size = NULL;
483                         } else {
484                                 yyerror(_("parse error"));
485                                 YYERROR;
486                         }
487                 }
488         ;       
489
490 classcode:      classcode thing                 { ; }
491         |       thing                           { ; }
492         ;
493
494 thing:          method                          { ; }
495         |       TOKEN method                    {
496                         if (strcmp ($<id>1, "BonoboX") != 0) {
497                                 g_free($<id>1);
498                                 yyerror(_("parse error"));
499                                 YYERROR;
500                         }
501                         last_added_method->bonobo_x_func = TRUE;
502                                                 }
503         |       variable                        { ; }
504         |       argument                        { ; }
505         |       ';'                             { ; }
506         ;
507
508 scope:          PUBLIC                  { the_scope = PUBLIC_SCOPE; }
509         |       PRIVATE                 { the_scope = PRIVATE_SCOPE; }
510         |       PROTECTED               { the_scope = PROTECTED_SCOPE; }
511         |       CLASSWIDE               { the_scope = CLASS_SCOPE; }
512         ;
513
514 destructor:     TOKEN TOKEN     {
515                         if(strcmp($<id>1, "destroywith")==0) {
516                                 g_free($<id>1);
517                                 destructor = $<id>2;
518                                 destructor_line = line_no;
519                                 destructor_simple = TRUE;
520                         } else {
521                                 g_free($<id>1);
522                                 g_free($<id>2);
523                                 yyerror(_("parse error"));
524                                 YYERROR;
525                         }
526                                 }
527         |       TOKEN '{' CCODE         {
528                         if(strcmp($<id>1, "destroy")==0) {
529                                 g_free($<id>1);
530                                 destructor = ($<cbuf>3)->str;
531                                 g_string_free($<cbuf>3, FALSE);
532                                 destructor_line = ccode_line;
533                                 destructor_simple = FALSE;
534                         } else {
535                                 g_free($<id>1);
536                                 g_string_free($<cbuf>3, TRUE);
537                                 yyerror(_("parse error"));
538                                 YYERROR;
539                         }
540                                         }
541         ;
542
543 initializer:    '=' numtok      {
544                         initializer = $<id>2;
545                         initializer_line = ccode_line;
546                                 }
547         |       '=' '{' CCODE   {
548                         initializer = ($<cbuf>3)->str;
549                         initializer_line = ccode_line;
550                         g_string_free($<cbuf>3, FALSE);
551                                 }
552         ;
553
554
555 varoptions:     destructor initializer  { ; }
556         |       initializer destructor  { ; }
557         |       initializer             { destructor = NULL; }
558         |       destructor              { initializer = NULL; }
559         |                               {
560                         destructor = NULL;
561                         initializer = NULL;
562                                         }
563         ;
564
565 variable:       scope type TOKEN varoptions ';'         {
566                         push_variable($<id>3, the_scope,$<line>1, NULL);
567                                                 }
568         |       scope type TOKEN ARRAY_DIM varoptions ';'       {
569                         push_variable($<id>3, the_scope, $<line>1, $<id>4);
570                                                 }
571         ;
572
573 argument:       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE TOKEN '{' CCODE ';' {
574                         if(strcmp($<id>6,"get")==0 &&
575                            strcmp($<id>9,"set")==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>8)->str, $<line>7,
582                                                      ($<cbuf>11)->str,$<line>10,
583                                                      $<line>1);
584
585                                 class_nodes = g_list_append(class_nodes,node);
586
587                                 if ($<id>5) {
588                                         export_accessors ($<id>4, 
589                                                           ($<cbuf>8)->str, $<line>7,
590                                                           ($<cbuf>11)->str, $<line>10,
591                                                           type,
592                                                           $<id>3,
593                                                           $<line>1);
594                                         g_free ($<id>5);
595                                 } 
596
597                                 g_string_free ($<cbuf>8, FALSE);
598                                 g_string_free ($<cbuf>11, FALSE);
599
600                         } else if(strcmp($<id>6,"set")==0 &&
601                                 strcmp($<id>9,"get")==0) {
602                                 Node *node;
603                                 Type *type = pop_type();
604                                 g_free ($<id>6); 
605                                 g_free ($<id>9);
606                                 node = new_argument ($<id>3, type, $<list>2, $<id>4,
607                                                      ($<cbuf>11)->str,$<line>10,
608                                                      ($<cbuf>8)->str,$<line>7,
609                                                      $<line>1);
610
611                                 if ($<id>5) {
612                                         export_accessors ($<id>4, 
613                                                           ($<cbuf>11)->str, $<line>10,
614                                                           ($<cbuf>8)->str, $<line>7,
615                                                           type,
616                                                           $<id>3,
617                                                           $<line>1);
618                                         g_free ($<id>5);
619                                 } 
620
621                                 g_string_free ($<cbuf>11, FALSE);
622                                 g_string_free ($<cbuf>8, FALSE);
623                                 class_nodes = g_list_append(class_nodes,node);
624                         } else {
625                                 g_free ($<id>3); 
626                                 g_free ($<id>4);
627                                 g_free ($<id>6); 
628                                 g_free ($<id>9);
629                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
630                                 g_list_free ($<list>2);
631                                 g_string_free ($<cbuf>11, TRUE);
632                                 g_string_free ($<cbuf>8, TRUE);
633                                 yyerror (_("parse error"));
634                                 YYERROR;
635                         }
636                                                 }
637         |       ARGUMENT flags argtype TOKEN export TOKEN '{' CCODE ';' {
638                         if(strcmp($<id>6, "get") == 0) {
639                                 Node *node;
640                                 Type *type = pop_type();
641                                 g_free ($<id>6);
642                                 node = new_argument ($<id>3, type, $<list>2, $<id>4,
643                                                      ($<cbuf>8)->str, $<line>7,
644                                                      NULL, 0, 
645                                                      $<line>1);
646                                 if ($<id>5) {
647                                         export_accessors ($<id>4, 
648                                                           ($<cbuf>8)->str, $<line>7,
649                                                           NULL, 0,
650                                                           type,
651                                                           $<id>3,
652                                                           $<line>1);
653                                         g_free ($<id>5);
654                                 } 
655
656                                 g_string_free ($<cbuf>8, FALSE);
657                                 class_nodes = g_list_append(class_nodes, node);
658                         } else if(strcmp($<id>6, "set") == 0) {
659                                 Node *node;
660                                 Type *type = pop_type();
661                                 g_free ($<id>6);
662                                 node = new_argument ($<id>3, type, $<list>2, $<id>4,
663                                                      NULL, 0, 
664                                                      ($<cbuf>8)->str, $<line>7, 
665                                                      $<line>1);
666                                 if ($<id>5) {
667                                         export_accessors ($<id>4, 
668                                                           NULL, 0,
669                                                           ($<cbuf>8)->str, $<line>7,
670                                                           type,
671                                                           $<id>3,
672                                                           $<line>1);
673                                         g_free ($<id>5);
674                                 } 
675
676                                 g_string_free ($<cbuf>8, FALSE);
677                                 class_nodes = g_list_append (class_nodes, node);
678                         } else {
679                                 g_free ($<id>6); 
680                                 g_free ($<id>3);
681                                 g_free ($<id>4);
682                                 g_list_foreach ($<list>2, (GFunc)g_free, NULL);
683                                 g_list_free ($<list>2);
684                                 g_string_free ($<cbuf>8, TRUE);
685                                 yyerror(_("parse error"));
686                                 YYERROR;
687                         }
688                                                 }
689         |       ARGUMENT flags argtype TOKEN export TOKEN {
690                         Node *node;
691                         char *get, *set = NULL;
692                         Variable *var;
693                         Type *type;
694                         char *root;
695                         
696                         if(strcmp($<id>6, "link")!=0 &&
697                            strcmp($<id>6, "stringlink")!=0 && 
698                            strcmp($<id>6, "objectlink")!=0) {
699                                 g_free($<id>6); 
700                                 g_free($<id>3);
701                                 g_free($<id>4);
702                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
703                                 g_list_free($<list>2);
704                                 yyerror(_("parse error"));
705                                 YYERROR;
706                         }
707
708                         type = pop_type();
709
710                         var = find_var_or_die($<id>4, $<line>1);
711                         if(var->scope == PRIVATE_SCOPE)
712                                 root = "self->_priv";
713                         else if(var->scope == CLASS_SCOPE) {
714                                 root = "SELF_GET_CLASS(self)";
715                                 if(no_self_alias)
716                                         error_print(GOB_ERROR, $<line>1,
717                                                     _("Self aliases needed when autolinking to a classwide member"));
718                         } else
719                                 root = "self";
720
721                         if(strcmp($<id>6, "link")==0) {
722                                 set = g_strdup_printf("%s->%s = ARG;",
723                                                       root, $<id>4);
724                         } else if(strcmp ($<id>6, "stringlink")==0) {
725                                 set = g_strdup_printf("g_free(%s->%s); "
726                                                       "%s->%s = g_strdup(ARG);",
727                                                       root, $<id>4,
728                                                       root, $<id>4);
729                         } else if(strcmp ($<id>6, "objectlink")==0) {
730                                 set = g_strdup_printf(
731                                   "if (ARG != NULL) "
732                                    "gtk_object_ref (GTK_OBJECT (ARG)); "
733                                   "if (%s->%s != NULL) "
734                                    "gtk_object_unref (GTK_OBJECT (%s->%s)); "
735                                   "%s->%s = ARG;",
736                                   root, $<id>4,
737                                   root, $<id>4,
738                                   root, $<id>4);
739                         } else {
740                                 g_assert_not_reached();
741                         }
742
743                         if (strcmp ($<id>6, "stringlink")==0) {
744                                 get = g_strdup_printf("ARG = g_strdup(%s->%s);", root, $<id>4);
745                         } else {
746                                 /* For everything else, get is just straight assignment */
747                                 get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
748                         }
749
750                         g_free ($<id>6);
751
752
753                         if(!type)
754                                 type = copy_type(var->vtype);
755
756                         node = new_argument ($<id>3, type, $<list>2,
757                                              $<id>4, 
758                                              get, $<line>1,
759                                              set, $<line>1, 
760                                              $<line>1);
761                         if ($<id>5) {
762                                 export_accessors ($<id>4, 
763                                                   get, $<line>1,
764                                                   set, $<line>1,
765                                                   type,
766                                                   $<id>3,
767                                                   $<line>1);
768                                 g_free ($<id>5);
769                         } 
770
771                         class_nodes = g_list_append(class_nodes,node);
772                                                 }
773         ;
774
775 export:         '(' TOKEN ')'                   {
776                                                   if (strcmp ($<id>2, "export")!=0) {
777                                                           g_free ($<id>2); 
778                                                           yyerror (_("parse error"));
779                                                           YYERROR;
780                                                   }
781                                                   $<id>$ = $<id>2;
782                                                 }
783          |                                      { $<id>$ = NULL; }
784                   
785 argtype:        TOKEN '(' TOKEN type ')'        {
786                         if(strcmp($<id>3,"type")!=0) {
787                                 g_free($<id>1);
788                                 g_free($<id>3);
789                                 yyerror(_("parse error"));
790                                 YYERROR;
791                         }
792                         $<id>$ = $<id>1;
793                                                 }
794         |       TOKEN                           {
795                         $<id>$ = $<id>1;
796                         typestack = g_list_prepend(typestack,NULL);
797                                                 }
798         ;
799         
800 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
801         |                                       { $<list>$ = NULL; }
802         ;
803
804 flaglist:       TOKEN '|' flaglist              {
805                         $<list>$ = g_list_append($<list>3,$<id>1);
806                                                 }
807         |       TOKEN                           {
808                         $<list>$ = g_list_append(NULL,$<id>1);
809                                                 }
810         ;
811
812
813 type:           specifier_list pointer                          {
814                         Node *node = new_type($<id>1, $<id>2, NULL);
815                         typestack = g_list_prepend(typestack,node);
816                                                         }
817         |       specifier_list                          {
818                         Node *node = new_type($<id>1, NULL, NULL);
819                         typestack = g_list_prepend(typestack,node);
820                                                         }
821         ;
822
823 /* The special cases are neccessary to avoid conflicts */
824 specifier_list: spec_list                               {
825                         $<id>$ = $<id>1;
826                                                         }
827         |       TOKEN                                   {
828                         $<id>$ = $<id>1;
829                                                         }
830         |       CONST TOKEN                             {
831                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
832                         g_free($<id>2);
833                                                         }
834         |       TOKEN CONST                             {
835                         $<id>$ = g_strconcat($<id>1, " const", NULL);
836                         g_free($<id>1);
837                                                         }
838         |       strunionenum TOKEN                      {
839                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
840                         g_free($<id>2);
841                                                         }
842         |       CONST strunionenum TOKEN                {
843                         $<id>$ = g_strconcat("const ", $<id>2, " ",
844                                              $<id>3, NULL);
845                         g_free($<id>3);
846                                                         }
847         |       strunionenum TOKEN CONST                {
848                         $<id>$ = g_strconcat($<id>1, " ",
849                                              $<id>2, " const", NULL);
850                         g_free($<id>2);
851                                                         }
852         ;
853
854 /* The special const cases take care of conflicts ! */
855 spec_list:      specifier spec_list                     {
856                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
857                         g_free($<id>2);
858                                                         }
859         |       TYPETOKEN spec_list                     {
860                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
861                         g_free($<id>1);
862                         g_free($<id>2);
863                                                         }
864         |       CONST spec_list                         {
865                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
866                         g_free($<id>2);
867                                                         }
868         |       TYPETOKEN                               {
869                         $<id>$ = $<id>1;
870                                                         }
871         |       TYPETOKEN CONST                         {
872                         $<id>$ = g_strconcat($<id>1, " const", NULL);
873                         g_free($<id>1);
874                                                         }
875         |       specifier                               {
876                         $<id>$ = g_strdup($<id>1);
877                                                         }
878         |       specifier CONST                         {
879                         $<id>$ = g_strconcat($<id>1, " const", NULL);
880                                                         }
881         ;
882
883 specifier:      VOID                    { $<id>$ = "void"; }
884         |       CHAR                    { $<id>$ = "char"; }
885         |       SHORT                   { $<id>$ = "short"; }
886         |       INT                     { $<id>$ = "int"; }
887         |       LONG                    { $<id>$ = "long"; }
888         |       FLOAT                   { $<id>$ = "float"; }
889         |       DOUBLE                  { $<id>$ = "double"; }
890         |       SIGNED                  { $<id>$ = "signed"; }
891         |       UNSIGNED                { $<id>$ = "unsigned"; }
892         ;
893
894 strunionenum:   STRUCT                  { $<id>$ = "struct"; }
895         |       UNION                   { $<id>$ = "union"; }
896         |       ENUM                    { $<id>$ = "enum"; }
897         ;
898
899 pointer:        '*'                     { $<id>$ = g_strdup("*"); }
900         |       '*' CONST               { $<id>$ = g_strdup("* const"); }
901         |       '*' pointer             {
902                                 $<id>$ = g_strconcat("*", $<id>2, NULL);
903                                 g_free($<id>2);
904                                         }
905         |       '*' CONST pointer       {
906                                 $<id>$ = g_strconcat("* const", $<id>3, NULL);
907                                 g_free($<id>3);
908                                         }
909         ;
910
911 /* this never sets the_scope */
912 simplesigtype:  TOKEN sigtype   {
913                         if(strcmp($<id>1, "first")==0)
914                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
915                         else if(strcmp($<id>1, "last")==0)
916                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
917                         else {
918                                 yyerror(_("signal must be 'first' or 'last'"));
919                                 g_free($<id>1);
920                                 YYERROR;
921                         }
922                         g_free($<id>1);
923                                         }
924         |       sigtype                 {
925                         $<sigtype>$ = SIGNAL_LAST_METHOD;
926                                         }
927         ;
928
929 /* this always sets the_scope */
930 fullsigtype:    scope TOKEN sigtype     {
931                         if(strcmp($<id>2,"first")==0)
932                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
933                         else if(strcmp($<id>2,"last")==0)
934                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
935                         else {
936                                 yyerror(_("signal must be 'first' or 'last'"));
937                                 g_free($<id>2);
938                                 YYERROR;
939                         }
940                         g_free($<id>2);
941                                         }
942         |       TOKEN scope sigtype     {
943                         if(strcmp($<id>1,"first")==0)
944                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
945                         else if(strcmp($<id>1,"last")==0)
946                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
947                         else {
948                                 yyerror(_("signal must be 'first' or 'last'"));
949                                 g_free($<id>1);
950                                 YYERROR;
951                         }
952                         g_free($<id>1);
953                                         }
954         |       scope sigtype           {
955                         $<sigtype>$ = SIGNAL_LAST_METHOD;
956                                         }
957         |       simplesigtype           {
958                         /* the_scope was default thus public */
959                         the_scope = PUBLIC_SCOPE;
960                                         }
961         ;
962         
963 sigtype:        TOKEN '(' tokenlist ')'         {
964                         gtktypes = g_list_prepend(gtktypes, $<id>1);
965                                                 }
966         ;
967
968 tokenlist:      tokenlist ',' TOKEN             {
969                         gtktypes = g_list_append(gtktypes, $<id>3);
970                                                 }
971         |       TOKEN                           { 
972                         gtktypes = g_list_append(gtktypes, $<id>1);
973                                                 }
974         ;
975
976 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
977         |       ';'                             { $<cbuf>$ = NULL; }
978         ;
979
980 /*here CCODE will include the ending '}' */
981 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
982                         if(!has_self) {
983                                 yyerror(_("signal without 'self' as "
984                                           "first parameter"));
985                                 free_all_global_state();
986                                 YYERROR;
987                         }
988                         if(the_scope == CLASS_SCOPE) {
989                                 yyerror(_("a method cannot be of class scope"));
990                                 free_all_global_state();
991                                 YYERROR;
992                         }
993                         push_function(the_scope, $<sigtype>3,NULL,
994                                       $<id>5, $<cbuf>10,$<line>1,
995                                       ccode_line, vararg, $<list>2);
996                                                                         }
997         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
998                         if(!has_self) {
999                                 yyerror(_("signal without 'self' as "
1000                                           "first parameter"));
1001                                 free_all_global_state();
1002                                 YYERROR;
1003                         }
1004                         if(the_scope == CLASS_SCOPE) {
1005                                 yyerror(_("a method cannot be of class scope"));
1006                                 free_all_global_state();
1007                                 YYERROR;
1008                         }
1009                         push_function(the_scope, $<sigtype>4, NULL,
1010                                       $<id>6, $<cbuf>11, $<line>2,
1011                                       ccode_line, vararg, $<list>3);
1012                                                                         }
1013         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
1014                         if(!has_self) {
1015                                 yyerror(_("virtual method without 'self' as "
1016                                           "first parameter"));
1017                                 free_all_global_state();
1018                                 YYERROR;
1019                         }
1020                         if(the_scope == CLASS_SCOPE) {
1021                                 yyerror(_("a method cannot be of class scope"));
1022                                 free_all_global_state();
1023                                 YYERROR;
1024                         }
1025                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1026                                       $<cbuf>9, $<line>1,
1027                                       ccode_line, vararg, NULL);
1028                                                                         }
1029         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
1030                         if(!has_self) {
1031                                 yyerror(_("virtual method without 'self' as "
1032                                           "first parameter"));
1033                                 free_all_global_state();
1034                                 YYERROR;
1035                         }
1036                         if(the_scope == CLASS_SCOPE) {
1037                                 yyerror(_("a method cannot be of class scope"));
1038                                 free_all_global_state();
1039                                 YYERROR;
1040                         }
1041                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
1042                                       $<cbuf>9, $<line>2,
1043                                       ccode_line, vararg, NULL);
1044                                                                         }
1045         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
1046                         if(!has_self) {
1047                                 yyerror(_("virtual method without 'self' as "
1048                                           "first parameter"));
1049                                 free_all_global_state();
1050                                 YYERROR;
1051                         }
1052                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
1053                                       $<id>3, $<cbuf>8, $<line>1,
1054                                       ccode_line, vararg, NULL);
1055                                                                         }
1056         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
1057                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
1058                                       $<id>6, $<cbuf>11,
1059                                       $<line>1, ccode_line,
1060                                       vararg, NULL);
1061                                                                         }
1062         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
1063                         if(the_scope == CLASS_SCOPE) {
1064                                 yyerror(_("a method cannot be of class scope"));
1065                                 free_all_global_state();
1066                                 YYERROR;
1067                         }
1068                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
1069                                       $<cbuf>8, $<line>1, ccode_line,
1070                                       vararg, NULL);
1071                                                                 }
1072         |       TOKEN '(' TOKEN ')' codenocode  {
1073                         if(strcmp($<id>1, "init")==0) {
1074                                 push_init_arg($<id>3,FALSE);
1075                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
1076                                               $<id>1, $<cbuf>5, $<line>2,
1077                                               ccode_line, FALSE, NULL);
1078                         } else if(strcmp($<id>1, "class_init")==0) {
1079                                 push_init_arg($<id>3,TRUE);
1080                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
1081                                               $<id>1, $<cbuf>5, $<line>2,
1082                                               ccode_line, FALSE, NULL);
1083                         } else {
1084                                 g_free($<id>1);
1085                                 g_free($<id>3);
1086                                 g_string_free($<cbuf>5,TRUE);
1087                                 yyerror(_("parse error "
1088                                           "(untyped blocks must be init or "
1089                                           "class_init)"));
1090                                 YYERROR;
1091                         }
1092                                                 }
1093         ;
1094
1095 returnvals:     TOKEN retcode           {
1096                         g_free(onerror); onerror = NULL;
1097                         g_free(defreturn); defreturn = NULL;
1098                         if(!set_return_value($<id>1, $<id>2)) {
1099                                 g_free($<id>1);
1100                                 g_free($<id>2);
1101                                 yyerror(_("parse error"));
1102                                 YYERROR;
1103                         }
1104                         g_free($<id>1);
1105                                         }
1106         |       TOKEN retcode TOKEN retcode     {
1107                         g_free(onerror); onerror = NULL;
1108                         g_free(defreturn); defreturn = NULL;
1109                         if(!set_return_value($<id>1, $<id>2)) {
1110                                 g_free($<id>1); g_free($<id>2);
1111                                 g_free($<id>3); g_free($<id>4);
1112                                 yyerror(_("parse error"));
1113                                 YYERROR;
1114                         }
1115                         if(!set_return_value($<id>3, $<id>4)) {
1116                                 onerror = defreturn = NULL;
1117                                 g_free($<id>1); g_free($<id>2);
1118                                 g_free($<id>3); g_free($<id>4);
1119                                 yyerror(_("parse error"));
1120                                 YYERROR;
1121                         }
1122                         g_free($<id>1);
1123                         g_free($<id>3);
1124                                                 }
1125         |                               {
1126                         g_free(onerror); onerror = NULL;
1127                         g_free(defreturn); defreturn = NULL;
1128                                         }
1129         ;
1130
1131 retcode:        numtok                  { $<id>$ = $<id>1; }
1132         |       '{' CCODE               {
1133                         $<id>$ = ($<cbuf>3)->str;
1134                         g_string_free($<cbuf>3, FALSE);
1135                                         }
1136         ;
1137         
1138 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
1139         |       TOKEN                   {
1140                         vararg = FALSE;
1141                         has_self = TRUE;
1142                         if(strcmp($<id>1,"self")==0)
1143                                 push_self($<id>1, FALSE);
1144                         else {
1145                                 g_free($<id>1);
1146                                 yyerror(_("parse error"));
1147                                 YYERROR;
1148                         }
1149                                         }
1150         |       TOKEN CONST {
1151                         vararg = FALSE;
1152                         has_self = TRUE;
1153                         if(strcmp($<id>1,"self")==0)
1154                                 push_self($<id>1, TRUE);
1155                         else {
1156                                 g_free($<id>1);
1157                                 yyerror(_("parse error"));
1158                                 YYERROR;
1159                         }
1160                                         }
1161         |       CONST TOKEN {
1162                         vararg = FALSE;
1163                         has_self = TRUE;
1164                         if(strcmp($<id>2,"self")==0)
1165                                 push_self($<id>2, TRUE);
1166                         else {
1167                                 g_free($<id>2);
1168                                 yyerror(_("parse error"));
1169                                 YYERROR;
1170                         }
1171                                         }
1172         |       TOKEN ',' arglist       {
1173                         has_self = TRUE;
1174                         if(strcmp($<id>1,"self")==0)
1175                                 push_self($<id>1, FALSE);
1176                         else {
1177                                 g_free($<id>1);
1178                                 yyerror(_("parse error"));
1179                                 YYERROR;
1180                         }
1181                                         }
1182         |       TOKEN CONST ',' arglist {
1183                         has_self = TRUE;
1184                         if(strcmp($<id>1,"self")==0)
1185                                 push_self($<id>1, TRUE);
1186                         else {
1187                                 g_free($<id>1);
1188                                 yyerror(_("parse error"));
1189                                 YYERROR;
1190                         }
1191                                         }
1192         |       CONST TOKEN ',' arglist {
1193                         has_self = TRUE;
1194                         if(strcmp($<id>2,"self")==0)
1195                                 push_self($<id>2, TRUE);
1196                         else {
1197                                 g_free($<id>2);
1198                                 yyerror(_("parse error"));
1199                                 YYERROR;
1200                         }
1201                                         }
1202         |       arglist                 { has_self = FALSE; }
1203         ;
1204
1205 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
1206         |       arglist1                { vararg = FALSE; }
1207         ;
1208         
1209 arglist1:       arglist1 ',' arg        { ; }
1210         |       arg                     { ; }
1211         ;
1212
1213 arg:            type TOKEN                                      {
1214                         push_funcarg($<id>2,NULL);
1215                                                                 }
1216         |       type TOKEN ARRAY_DIM                            {
1217                         push_funcarg($<id>2,$<id>3);
1218                                                                 }
1219         |       type TOKEN '(' TOKEN checklist ')'              {
1220                         if(strcmp($<id>4,"check")!=0) {
1221                                 yyerror(_("parse error"));
1222                                 YYERROR;
1223                         }
1224                         g_free($<id>4);
1225                         push_funcarg($<id>2,NULL);
1226                                                                 }
1227         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
1228                         if(strcmp($<id>5,"check")!=0) {
1229                                 yyerror(_("parse error"));
1230                                 YYERROR;
1231                         }
1232                         g_free($<id>5);
1233                         push_funcarg($<id>2,$<id>3);
1234                                                                 }
1235         ;
1236         
1237 checklist:      checklist check         { ; }
1238         |       check                   { ; }
1239         ;
1240
1241 check:          TOKEN                   {
1242                         if(strcmp($<id>1,"type")==0) {
1243                                 Node *node = new_check(TYPE_CHECK,NULL);
1244                                 checks = g_list_append(checks,node);
1245                         } else if(strcmp($<id>1,"null")==0) {
1246                                 Node *node = new_check(NULL_CHECK,NULL);
1247                                 checks = g_list_append(checks,node);
1248                         } else {
1249                                 yyerror(_("parse error"));
1250                                 YYERROR;
1251                         }
1252                         g_free($<id>1);
1253                                         }
1254         |       '>' numtok              {
1255                         Node *node = new_check(GT_CHECK,$<id>2);
1256                         checks = g_list_append(checks,node);
1257                                         }
1258         |       '<' numtok              {
1259                         Node *node = new_check(LT_CHECK,$<id>2);
1260                         checks = g_list_append(checks,node);
1261                                         }
1262         |       '>' '=' numtok          {
1263                         Node *node = new_check(GE_CHECK,$<id>3);
1264                         checks = g_list_append(checks,node);
1265                                         }
1266         |       '<' '=' numtok          {
1267                         Node *node = new_check(LE_CHECK,$<id>3);
1268                         checks = g_list_append(checks,node);
1269                                         }
1270         |       '=' '=' numtok          {
1271                         Node *node = new_check(EQ_CHECK,$<id>3);
1272                         checks = g_list_append(checks,node);
1273                                         }
1274         |       '!' '=' numtok          {
1275                         Node *node = new_check(NE_CHECK,$<id>3);
1276                         checks = g_list_append(checks,node);
1277                                         }
1278         ;
1279         
1280 numtok:         NUMBER                  { $<id>$ = $<id>1; }
1281         |       '-' NUMBER              {
1282                         $<id>$ = g_strconcat("-",$<id>2,NULL);
1283                         g_free($<id>2);
1284                                         }
1285         |       TOKEN                   { $<id>$ = $<id>1; }
1286         ;
1287         
1288 %%