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