]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
0161aea5095fd9d5281eda665eba1b11ff6217cc
[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 <string.h>
27
28 #include "treefuncs.h"
29 #include "main.h"
30 #include "util.h"
31
32 #define _(x) (x)
33         
34 GList *nodes = NULL;
35
36 static GList *class_nodes = NULL;
37 Node *class = NULL;
38
39 static GList *typestack = NULL;
40 static int stars = 0;
41 static GList *funcargs = NULL;
42 static GList *checks = NULL;
43 static int has_self = FALSE;
44 static int vararg = FALSE;
45
46 /* destructor and initializer for variables */
47 static char *destructor = NULL;
48 static int destructor_line = 0;
49 static gboolean destructor_simple = TRUE;
50 static char *initializer = NULL;
51 static int initializer_line = 0;
52
53 static char *onerror = NULL;
54 static char *defreturn = NULL;
55
56 static GList *gtktypes = NULL;
57
58 /* this can be a global as we will only do one function at a time
59    anyway */
60 static int the_scope = NO_SCOPE;
61
62 void free(void *ptr);
63 int yylex(void);
64
65 extern int ccode_line;
66 extern int line_no;
67
68 extern char *yytext;
69
70 static void
71 yyerror(char *str)
72 {
73         char *out=NULL;
74         char *p;
75         
76         if(strcmp(yytext,"\n")==0) {
77                 out=g_strconcat("Error: ",str," before newline",NULL);
78         } else if(yytext[0]=='\0') {
79                 out=g_strconcat("Error: ", str, " at end of input", NULL);
80         } else {
81                 char *tmp = g_strdup(yytext);
82                 while((p=strchr(tmp, '\n')))
83                         *p='.';
84
85                 out=g_strconcat("Error: ", str, " before '", tmp, "'", NULL);
86                 g_free(tmp);
87         }
88
89         fprintf(stderr, "%s:%d: %s\n", filename, line_no, out);
90         g_free(out);
91         
92         exit(1);
93 }
94
95 static Type *
96 pop_type(void)
97 {
98         Type *type = typestack->data;
99         typestack = g_list_remove(typestack,typestack->data);
100         return type;
101 }
102
103 static void
104 push_variable(char *name, int scope, int line_no, char *postfix)
105 {
106         Node *var;
107         Type *type = pop_type();
108
109         type->postfix = postfix;
110         
111         var = new_variable(scope, type, name, line_no,
112                            destructor, destructor_line,
113                            destructor_simple,
114                            initializer, initializer_line);
115         class_nodes = g_list_append(class_nodes, var);
116 }
117
118 static void
119 push_function(int scope, int method, char *oid, char *id,
120               GString *cbuf, int line_no, int ccode_line,
121               gboolean vararg, GList *flags)
122 {
123         Node *node;
124         Type *type;
125         char *c_cbuf;
126        
127         if(method!=INIT_METHOD && method!=CLASS_INIT_METHOD) {
128                 type = pop_type();
129         } else {
130                 type = (Type *)new_type(0,g_strdup("void"),NULL);
131         }
132         
133         /* a complicated and ugly test to figure out if we have
134            the wrong number of types for a signal */
135         if((method == SIGNAL_FIRST_METHOD ||
136             method == SIGNAL_LAST_METHOD) &&
137            g_list_length(gtktypes) != g_list_length(funcargs) &&
138            !(g_list_length(funcargs) == 1 &&
139              g_list_length(gtktypes) == 2 &&
140              strcmp(gtktypes->next->data, "NONE")==0)) {
141                 print_error(TRUE, _("The number of GTK arguments and "
142                                     "function arguments for a signal "
143                                     "don't seem to match"), line_no);
144         }
145         if(g_list_length(gtktypes) > 2) {
146                 GList *li;
147                 for(li = gtktypes->next; li; li = li->next) {
148                         if(strcmp(li->data, "NONE")==0) {
149                                 print_error(FALSE,
150                                             _("NONE can only appear in an "
151                                               "argument list by itself"),
152                                             line_no);
153                         }
154                 }
155         }
156         if(cbuf) {
157                 char *p;
158                 c_cbuf = p = cbuf->str;
159                 while(p && *p && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
160                         p++;
161                 if(!p || !*p)
162                         c_cbuf = NULL;
163         } else
164                 c_cbuf = NULL;
165
166         node = new_method(scope, method, type, oid, gtktypes, flags,
167                           id, funcargs, onerror, defreturn, c_cbuf, line_no,
168                           ccode_line, vararg);
169
170         if(cbuf)
171                 g_string_free(cbuf,
172                               /*only free segment if we haven't passed it
173                                 above */
174                               c_cbuf?FALSE:TRUE);
175         gtktypes = NULL;
176         funcargs = NULL;
177
178         onerror = NULL;
179         defreturn = NULL;
180
181         class_nodes = g_list_append(class_nodes, node);
182 }
183
184 static void
185 free_all_global_state(void)
186 {
187         g_free(onerror);
188         onerror = NULL;
189         g_free(defreturn);
190         defreturn = NULL;
191
192         g_list_foreach(gtktypes, (GFunc)g_free, NULL);
193         g_list_free(gtktypes);
194         gtktypes = NULL;
195
196         free_node_list(funcargs);
197         funcargs = NULL;
198 }
199
200 static void
201 push_funcarg(char *name, char *postfix)
202 {
203         Node *node;
204         Type *type = pop_type();
205
206         type->postfix = postfix;
207         
208         node = new_funcarg(type, name, checks);
209         checks = NULL;
210         
211         funcargs = g_list_append(funcargs, node);
212 }
213
214 static void
215 push_init_arg(char *name, int is_class)
216 {
217         Node *node;
218         Node *type;
219         char *tn;
220         
221         if(is_class)
222                 tn = g_strconcat(((Class *)class)->otype,":Class",NULL);
223         else
224                 tn = g_strdup(((Class *)class)->otype);
225
226         type = new_type(1,tn,NULL);
227         node = new_funcarg((Type *)type,name,NULL);
228         funcargs = g_list_prepend(funcargs, node);
229 }
230
231 static void
232 push_self(char *id)
233 {
234         Node *node;
235         Node *type;
236         GList *ch = NULL;
237         type = new_type(1,g_strdup(((Class *)class)->otype),NULL);
238         ch = g_list_append(ch,new_check(NULL_CHECK,NULL));
239         ch = g_list_append(ch,new_check(TYPE_CHECK,NULL));
240         node = new_funcarg((Type *)type,id,ch);
241         funcargs = g_list_prepend(funcargs, node);
242 }
243
244 static Variable *
245 find_var_or_die(const char *id, int line)
246 {
247         GList *li;
248         char *s;
249
250         for(li = class_nodes; li != NULL; li = li->next) {
251                 Variable *var;
252                 Node *node = li->data;
253                 if(node->type != VARIABLE_NODE)
254                         continue;
255                 var = li->data;
256                 if(strcmp(var->id, id)==0)
257                         return var;
258         }
259
260         s = g_strdup_printf(_("Variable %s not defined here"), id);
261         print_error(FALSE, s, line);
262
263         g_assert_not_reached();
264         return NULL;
265 }
266
267 static gboolean
268 set_return_value(char *type, char *val)
269 {
270         if(strcmp(type, "onerror")==0) {
271                 if(!onerror) {
272                         onerror = val;
273                         return TRUE;
274                 } else
275                         return FALSE;
276         } else if(strcmp(type, "defreturn")==0) {
277                 if(!defreturn) {
278                         defreturn = val;
279                         return TRUE;
280                 } else
281                         return FALSE;
282         }
283         return FALSE;
284 }
285
286 %}
287
288 %union {
289         char *id;
290         GString *cbuf;
291         GList *list;
292         int line;
293         int sigtype;
294 }
295
296 %token CLASS FROM
297 %token CONST VOID STRUCT UNION ENUM THREEDOTS
298 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
299
300 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM
301 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE
302 %token <line> PUBLIC PRIVATE PROTECTED ARGUMENT VIRTUAL SIGNAL OVERRIDE
303
304 %%
305
306 prog:           ccodes class ccodes     { ; }
307         |       class ccodes            { ; }
308         |       ccodes class            { ; }
309         |       class                   { ; }
310         ;
311
312 ccode:          CCODE                   {
313                         Node *node = new_ccode(C_CCODE,($<cbuf>1)->str,
314                                                ccode_line);
315                         nodes = g_list_append(nodes,node);
316                         g_string_free($<cbuf>1,FALSE);
317                                         }
318         |       HCODE                   {
319                         Node *node = new_ccode(H_CCODE,($<cbuf>1)->str,
320                                                ccode_line);
321                         nodes = g_list_append(nodes,node);
322                         g_string_free($<cbuf>1,FALSE);
323                                         }
324         |       HTCODE                  {
325                         Node *node = new_ccode(HT_CCODE,($<cbuf>1)->str,
326                                                ccode_line);
327                         nodes = g_list_append(nodes,node);
328                         g_string_free($<cbuf>1,FALSE);
329                                         }
330         |       PHCODE                  {
331                         Node *node = new_ccode(PH_CCODE,($<cbuf>1)->str,
332                                                ccode_line);
333                         nodes = g_list_append(nodes,node);
334                         g_string_free($<cbuf>1,FALSE);
335                                         }
336         |       ACODE                   {
337                         Node *node = new_ccode(A_CCODE,($<cbuf>1)->str,
338                                                ccode_line);
339                         nodes = g_list_append(nodes,node);
340                         g_string_free($<cbuf>1,FALSE);
341                                         }
342         |       ATCODE                  {
343                         Node *node = new_ccode(AT_CCODE,($<cbuf>1)->str,
344                                                ccode_line);
345                         nodes = g_list_append(nodes,node);
346                         g_string_free($<cbuf>1,FALSE);
347                                         }
348         ;
349
350 ccodes:         ccodes ccode            { ; }
351         |       ccode                   { ; }
352         ;
353
354 class:          classdec '{' classcode '}'      {
355                         ((Class *)class)->nodes = class_nodes;
356                         class_nodes = NULL;
357                         nodes = g_list_append(nodes,class);
358                                                 }
359         |       classdec '{' '}'                {
360                         ((Class *)class)->nodes = NULL;
361                         class_nodes = NULL;
362                         nodes = g_list_append(nodes,class);
363                                                 }
364         ;
365
366 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  {
367                         class = new_class($<id>2,$<id>4,NULL);
368                                                 }
369         ;
370         
371 classcode:      classcode thing                 { ; }
372         |       thing                           { ; }
373         ;
374
375 thing:          method                          { ; }
376         |       variable                        { ; }
377         |       argument                        { ; }
378         |       ';'                             { ; }
379         ;
380
381 scope:          PUBLIC                  { the_scope = PUBLIC_SCOPE; }
382         |       PRIVATE                 { the_scope = PRIVATE_SCOPE; }
383         |       PROTECTED               { the_scope = PROTECTED_SCOPE; }
384         ;
385
386 destructor:     TOKEN TOKEN     {
387                         if(strcmp($<id>1, "destroywith")==0) {
388                                 g_free($<id>1);
389                                 destructor = $<id>2;
390                                 destructor_line = line_no;
391                                 destructor_simple = TRUE;
392                         } else {
393                                 g_free($<id>1);
394                                 g_free($<id>2);
395                                 yyerror(_("parse error"));
396                                 YYERROR;
397                         }
398                                 }
399         |       TOKEN '{' CCODE         {
400                         if(strcmp($<id>1, "destroy")==0) {
401                                 g_free($<id>1);
402                                 destructor = ($<cbuf>3)->str;
403                                 g_string_free($<cbuf>3, FALSE);
404                                 destructor_line = ccode_line;
405                                 destructor_simple = FALSE;
406                         } else {
407                                 g_free($<id>1);
408                                 g_string_free($<cbuf>3, TRUE);
409                                 yyerror(_("parse error"));
410                                 YYERROR;
411                         }
412                                         }
413         ;
414
415 initializer:    '=' numtok      {
416                         initializer = $<id>2;
417                         initializer_line = ccode_line;
418                                 }
419         |       '=' '{' CCODE   {
420                         initializer = ($<cbuf>3)->str;
421                         initializer_line = ccode_line;
422                         g_string_free($<cbuf>3, FALSE);
423                                 }
424         ;
425
426
427 varoptions:     destructor initializer  { ; }
428         |       initializer destructor  { ; }
429         |       initializer             { destructor = NULL; }
430         |       destructor              { initializer = NULL; }
431         |                               {
432                         destructor = NULL;
433                         initializer = NULL;
434                                         }
435         ;
436
437 variable:       scope type TOKEN varoptions ';'         {
438                         push_variable($<id>3, the_scope,$<line>1, NULL);
439                                                 }
440         |       scope type TOKEN ARRAY_DIM varoptions ';'       {
441                         push_variable($<id>3, the_scope, $<line>1, $<id>4);
442                                                 }
443         ;
444 argument:       ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' {
445                         if(strcmp($<id>5,"get")==0 &&
446                            strcmp($<id>8,"set")==0) {
447                                 Node *node;
448                                 Type *type = pop_type();
449                                 g_free($<id>5); g_free($<id>8);
450                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
451                                                     ($<cbuf>7)->str,$<line>6,
452                                                     ($<cbuf>10)->str,$<line>9,
453                                                     $<line>1);
454                                 g_string_free($<cbuf>7,FALSE);
455                                 g_string_free($<cbuf>10,FALSE);
456                                 class_nodes = g_list_append(class_nodes,node);
457                         } else if(strcmp($<id>5,"set")==0 &&
458                                 strcmp($<id>8,"get")==0) {
459                                 Node *node;
460                                 Type *type = pop_type();
461                                 g_free($<id>5); g_free($<id>8);
462                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
463                                                     ($<cbuf>10)->str,$<line>9,
464                                                     ($<cbuf>7)->str,$<line>6,
465                                                     $<line>1);
466                                 g_string_free($<cbuf>10,FALSE);
467                                 g_string_free($<cbuf>7,FALSE);
468                                 class_nodes = g_list_append(class_nodes,node);
469                         } else {
470                                 g_free($<id>3); g_free($<id>4);
471                                 g_free($<id>5); g_free($<id>8);
472                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
473                                 g_string_free($<cbuf>10,TRUE);
474                                 g_string_free($<cbuf>7,TRUE);
475                                 yyerror(_("parse error"));
476                                 YYERROR;
477                         }
478                                                 }
479         |       ARGUMENT flags argtype TOKEN TOKEN '{' CCODE ';' {
480                         if(strcmp($<id>5,"get")==0) {
481                                 Node *node;
482                                 Type *type = pop_type();
483                                 g_free($<id>5);
484                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
485                                                     ($<cbuf>7)->str,$<line>6,
486                                                     NULL,0, $<line>1);
487                                 g_string_free($<cbuf>7,FALSE);
488                                 class_nodes = g_list_append(class_nodes,node);
489                         } else if(strcmp($<id>5,"set")==0) {
490                                 Node *node;
491                                 Type *type = pop_type();
492                                 g_free($<id>5);
493                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
494                                                     NULL,0,($<cbuf>7)->str,
495                                                     $<line>6, $<line>1);
496                                 g_string_free($<cbuf>7,FALSE);
497                                 class_nodes = g_list_append(class_nodes,node);
498                         } else {
499                                 g_free($<id>5); g_free($<id>3);
500                                 g_free($<id>4);
501                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
502                                 g_string_free($<cbuf>7,TRUE);
503                                 yyerror(_("parse error"));
504                                 YYERROR;
505                         }
506                                                 }
507         |       ARGUMENT flags argtype TOKEN TOKEN {
508                         Node *node;
509                         char *get, *set = NULL;
510                         Variable *var;
511                         Type *type;
512                         char *root;
513                         
514                         if(strcmp($<id>5,"link")!=0 &&
515                            strcmp($<id>5,"stringlink")!=0 &&
516                            strcmp($<id>5,"objectlink")!=0) {
517                                 g_free($<id>5); g_free($<id>3);
518                                 g_free($<id>4);
519                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
520                                 yyerror(_("parse error"));
521                                 YYERROR;
522                         }
523
524                         type = pop_type();
525
526                         var = find_var_or_die($<id>4, $<line>1);
527                         if(var->scope == PRIVATE_SCOPE)
528                                 root = "self->_priv";
529                         else
530                                 root = "self";
531
532                         if(strcmp($<id>5,"link")==0) {
533                                 set = g_strdup_printf("%s->%s = ARG;",
534                                                       root, $<id>4);
535                         } else if(strcmp($<id>5,"stringlink")==0) {
536                                 set = g_strdup_printf("g_free(%s->%s); "
537                                                       "%s->%s = g_strdup(ARG);",
538                                                       root, $<id>4,
539                                                       root, $<id>4);
540                         } else if(strcmp($<id>5,"objectlink")==0) {
541                                 set = g_strdup_printf(
542                                   "if(%s->%s) "
543                                    "gtk_object_unref(GTK_OBJECT(%s->%s)); "
544                                   "%s->%s = ARG; "
545                                   "if(%s->%s) "
546                                    "gtk_object_ref(GTK_OBJECT(%s->%s)); ",
547                                   root, $<id>4,
548                                   root, $<id>4,
549                                   root, $<id>4,
550                                   root, $<id>4,
551                                   root, $<id>4);
552                         } else {
553                                 g_assert_not_reached();
554                         }
555
556                         /* get is the same for everything */
557                         get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
558
559                         g_free($<id>5);
560
561
562                         if(!type)
563                                 type = copy_type(var->vtype);
564
565                         node = new_argument($<id>3, type, $<list>2,
566                                             $<id>4, get, $<line>1,
567                                             set, $<line>1, $<line>1);
568                         class_nodes = g_list_append(class_nodes,node);
569                                                 }
570         ;
571
572 argtype:        TOKEN '(' TOKEN type ')'        {
573                         if(strcmp($<id>3,"type")!=0) {
574                                 g_free($<id>1);
575                                 g_free($<id>3);
576                                 yyerror(_("parse error"));
577                                 YYERROR;
578                         }
579                         $<id>$ = $<id>1;
580                                                 }
581         |       TOKEN                           {
582                         $<id>$ = $<id>1;
583                         typestack = g_list_prepend(typestack,NULL);
584                                                 }
585         ;
586         
587 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
588         |                                       { $<list>$ = NULL; }
589         ;
590
591 flaglist:       TOKEN '|' flaglist              {
592                         $<list>$ = g_list_append($<list>3,$<id>1);
593                                                 }
594         |       TOKEN                           {
595                         $<list>$ = g_list_append(NULL,$<id>1);
596                                                 }
597         ;
598
599
600 type:           type1                           { ; }
601         |       CONST type1                     {
602                         Type *type = typestack->data;
603                         char *oldname = type->name;
604                         type->name = g_strconcat("const ",oldname,NULL);
605                         g_free(oldname);
606                                                 }
607         ;
608
609 type1:          type2                           {
610                         Node *node = new_type(0,$<id>1,NULL);
611                         typestack = g_list_prepend(typestack,node);
612                                                 }
613         |       type2 stars                     {
614                         Node *node = new_type(stars,$<id>1,NULL);
615                         stars = 0;
616                         typestack = g_list_prepend(typestack,node);
617                                                 }
618         ;
619
620 type2:          UNSIGNED integer                {
621                         $<id>$ = g_strconcat("unsigned ",$<id>2,NULL);
622                                                 }
623         |       SIGNED integer                  {
624                         $<id>$ = g_strconcat("signed ",$<id>2,NULL);
625                                                 }
626         |       integer                         {
627                         $<id>$ = g_strdup($<id>1);
628                                                 }
629         |       UNSIGNED CHAR                   {
630                         $<id>$ = g_strdup("unsigned char");
631                                                 }
632         |       SIGNED CHAR                     {
633                         $<id>$ = g_strdup("signed char");
634                                                 }
635         |       CHAR                            {
636                         $<id>$ = g_strdup("char");
637                                                 }
638         |       DOUBLE                          {
639                         $<id>$ = g_strdup("double");
640                                                 }
641         |       FLOAT                           {
642                         $<id>$ = g_strdup("float");
643                                                 }
644         |       TOKEN                           {
645                         $<id>$ = $<id>1;
646                                                 }
647         |       tspecifier TOKEN                {
648                         $<id>$ = g_strconcat($<id>1,$<id>2,NULL);
649                         g_free($<id>2);
650                                                 }
651         |       TYPETOKEN                       {
652                         $<id>$ = $<id>1;
653                                                 }
654         |       VOID                            {
655                         $<id>$ = g_strdup("void");
656                                                 }
657         ;
658
659 integer:        LONG INT                        {
660                         $<id>$ = "long int";
661                                                 }
662         |       LONG                            {
663                         $<id>$ = "long";
664                                                 }
665         |       SHORT INT                       {
666                         $<id>$ = "short int";
667                                                 }
668         |       SHORT                           {
669                         $<id>$ = "short";
670                                                 }
671         |       INT                             {
672                         $<id>$ = "int";
673                                                 }
674         ;
675         
676 tspecifier:     ENUM                            {
677                         $<id>$ = "enum ";
678                                                 }
679         |       UNION                           {
680                         $<id>$ = "union ";
681                                                 }
682         |       STRUCT                          {
683                         $<id>$ = "struct ";
684                                                 }
685         ;
686         
687 stars:          '*' stars                       { stars++; }
688         |       '*'                             { stars++; }
689         ;
690
691 /* this never sets the_scope */
692 simplesigtype:  TOKEN sigtype   {
693                         if(strcmp($<id>1, "first")==0)
694                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
695                         else if(strcmp($<id>1, "last")==0)
696                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
697                         else {
698                                 yyerror(_("signal must be 'first' or 'last'"));
699                                 g_free($<id>1);
700                                 YYERROR;
701                         }
702                         g_free($<id>1);
703                                         }
704         |       sigtype                 {
705                         $<sigtype>$ = SIGNAL_LAST_METHOD;
706                                         }
707         ;
708
709 /* this always sets the_scope */
710 fullsigtype:    scope TOKEN sigtype     {
711                         if(strcmp($<id>2,"first")==0)
712                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
713                         else if(strcmp($<id>2,"last")==0)
714                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
715                         else {
716                                 yyerror(_("signal must be 'first' or 'last'"));
717                                 g_free($<id>2);
718                                 YYERROR;
719                         }
720                         g_free($<id>2);
721                                         }
722         |       TOKEN scope sigtype     {
723                         if(strcmp($<id>1,"first")==0)
724                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
725                         else if(strcmp($<id>1,"last")==0)
726                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
727                         else {
728                                 yyerror(_("signal must be 'first' or 'last'"));
729                                 g_free($<id>1);
730                                 YYERROR;
731                         }
732                         g_free($<id>1);
733                                         }
734         |       scope sigtype           {
735                         $<sigtype>$ = SIGNAL_LAST_METHOD;
736                                         }
737         |       simplesigtype           {
738                         /* the_scope was default thus public */
739                         the_scope = PUBLIC_SCOPE;
740                                         }
741         ;
742         
743 sigtype:        TOKEN '(' tokenlist ')'         {
744                         gtktypes = g_list_prepend(gtktypes, $<id>1);
745                                                 }
746         ;
747
748 tokenlist:      tokenlist ',' TOKEN             {
749                         gtktypes = g_list_append(gtktypes, $<id>3);
750                                                 }
751         |       TOKEN                           { 
752                         gtktypes = g_list_append(gtktypes, $<id>1);
753                                                 }
754         ;
755
756 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
757         |       ';'                             { $<cbuf>$ = NULL; }
758         ;
759
760 /*here CCODE will include the ending '}' */
761 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
762                         if(!has_self) {
763                                 yyerror(_("signal without 'self' as "
764                                           "first parameter"));
765                                 free_all_global_state();
766                                 YYERROR;
767                         }
768                         push_function(the_scope, $<sigtype>3,NULL,
769                                       $<id>5, $<cbuf>10,$<line>1,
770                                       ccode_line, vararg, $<list>2);
771                                                                         }
772         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
773                         if(!has_self) {
774                                 yyerror(_("signal without 'self' as "
775                                           "first parameter"));
776                                 free_all_global_state();
777                                 YYERROR;
778                         }
779                         push_function(the_scope, $<sigtype>4, NULL,
780                                       $<id>6, $<cbuf>11, $<line>2,
781                                       ccode_line, vararg, $<list>3);
782                                                                         }
783         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
784                         if(!has_self) {
785                                 yyerror(_("virtual method without 'self' as "
786                                           "first parameter"));
787                                 free_all_global_state();
788                                 YYERROR;
789                         }
790                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
791                                       $<cbuf>9, $<line>1,
792                                       ccode_line, vararg, NULL);
793                                                                         }
794         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
795                         if(!has_self) {
796                                 yyerror(_("virtual method without 'self' as "
797                                           "first parameter"));
798                                 free_all_global_state();
799                                 YYERROR;
800                         }
801                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
802                                       $<cbuf>9, $<line>2,
803                                       ccode_line, vararg, NULL);
804                                                                         }
805         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
806                         if(!has_self) {
807                                 yyerror(_("virtual method without 'self' as "
808                                           "first parameter"));
809                                 free_all_global_state();
810                                 YYERROR;
811                         }
812                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
813                                       $<id>3, $<cbuf>8, $<line>1,
814                                       ccode_line, vararg, NULL);
815                                                                         }
816         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
817                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
818                                       $<id>6, $<cbuf>11,
819                                       $<line>1, ccode_line,
820                                       vararg, NULL);
821                                                                         }
822         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
823                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
824                                       $<cbuf>8, $<line>1, ccode_line,
825                                       vararg, NULL);
826                                                                 }
827         |       TOKEN '(' TOKEN ')' codenocode  {
828                         if(strcmp($<id>1, "init")==0) {
829                                 push_init_arg($<id>3,FALSE);
830                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
831                                               $<id>1, $<cbuf>5, $<line>2,
832                                               ccode_line, FALSE, NULL);
833                         } else if(strcmp($<id>1, "class_init")==0) {
834                                 push_init_arg($<id>3,TRUE);
835                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
836                                               $<id>1, $<cbuf>5, $<line>2,
837                                               ccode_line, FALSE, NULL);
838                         } else {
839                                 g_free($<id>1);
840                                 g_free($<id>3);
841                                 g_string_free($<cbuf>3,TRUE);
842                                 yyerror(_("parse error"));
843                                 YYERROR;
844                         }
845                                                 }
846         ;
847
848 returnvals:     TOKEN retcode           {
849                         g_free(onerror); onerror = NULL;
850                         g_free(defreturn); defreturn = NULL;
851                         if(!set_return_value($<id>1, $<id>2)) {
852                                 g_free($<id>1);
853                                 g_free($<id>2);
854                                 yyerror(_("parse error"));
855                                 YYERROR;
856                         }
857                         g_free($<id>1);
858                                         }
859         |       TOKEN retcode TOKEN retcode     {
860                         g_free(onerror); onerror = NULL;
861                         g_free(defreturn); defreturn = NULL;
862                         if(!set_return_value($<id>1, $<id>2)) {
863                                 g_free($<id>1); g_free($<id>2);
864                                 g_free($<id>3); g_free($<id>4);
865                                 yyerror(_("parse error"));
866                                 YYERROR;
867                         }
868                         if(!set_return_value($<id>3, $<id>4)) {
869                                 onerror = defreturn = NULL;
870                                 g_free($<id>1); g_free($<id>2);
871                                 g_free($<id>3); g_free($<id>4);
872                                 yyerror(_("parse error"));
873                                 YYERROR;
874                         }
875                         g_free($<id>1);
876                         g_free($<id>3);
877                                                 }
878         |                               {
879                         g_free(onerror); onerror = NULL;
880                         g_free(defreturn); defreturn = NULL;
881                                         }
882         ;
883
884 retcode:        numtok                  { $<id>$ = $<id>1; }
885         |       '{' CCODE               {
886                         $<id>$ = ($<cbuf>3)->str;
887                         g_string_free($<cbuf>3, FALSE);
888                                         }
889         ;
890         
891 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
892         |       TOKEN                   {
893                         vararg = FALSE;
894                         has_self = TRUE;
895                         if(strcmp($<id>1,"self")==0)
896                                 push_self($<id>1);
897                         else {
898                                 g_free($<id>1);
899                                 yyerror(_("parse error"));
900                                 YYERROR;
901                         }
902                                         }
903         |       TOKEN ',' arglist       {
904                         has_self = TRUE;
905                         if(strcmp($<id>1,"self")==0)
906                                 push_self($<id>1);
907                         else {
908                                 g_free($<id>1);
909                                 yyerror(_("parse error"));
910                                 YYERROR;
911                         }
912                                         }
913         |       arglist                 { has_self = FALSE; }
914         ;
915
916 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
917         |       arglist1                { vararg = FALSE; }
918         ;
919         
920 arglist1:       arglist1 ',' arg        { ; }
921         |       arg                     { ; }
922         ;
923
924 arg:            type TOKEN                                      {
925                         push_funcarg($<id>2,NULL);
926                                                                 }
927         |       type TOKEN ARRAY_DIM                            {
928                         push_funcarg($<id>2,$<id>3);
929                                                                 }
930         |       type TOKEN '(' TOKEN checklist ')'              {
931                         if(strcmp($<id>4,"check")!=0) {
932                                 yyerror(_("parse error"));
933                                 YYERROR;
934                         }
935                         g_free($<id>4);
936                         push_funcarg($<id>2,NULL);
937                                                                 }
938         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
939                         if(strcmp($<id>5,"check")!=0) {
940                                 yyerror(_("parse error"));
941                                 YYERROR;
942                         }
943                         g_free($<id>5);
944                         push_funcarg($<id>2,$<id>3);
945                                                                 }
946         ;
947         
948 checklist:      checklist check         { ; }
949         |       check                   { ; }
950         ;
951
952 check:          TOKEN                   {
953                         if(strcmp($<id>1,"type")==0) {
954                                 Node *node = new_check(TYPE_CHECK,NULL);
955                                 checks = g_list_append(checks,node);
956                         } else if(strcmp($<id>1,"null")==0) {
957                                 Node *node = new_check(NULL_CHECK,NULL);
958                                 checks = g_list_append(checks,node);
959                         } else {
960                                 yyerror(_("parse error"));
961                                 YYERROR;
962                         }
963                         g_free($<id>1);
964                                         }
965         |       '>' numtok              {
966                         Node *node = new_check(GT_CHECK,$<id>2);
967                         checks = g_list_append(checks,node);
968                                         }
969         |       '<' numtok              {
970                         Node *node = new_check(LT_CHECK,$<id>2);
971                         checks = g_list_append(checks,node);
972                                         }
973         |       '>' '=' numtok          {
974                         Node *node = new_check(GE_CHECK,$<id>3);
975                         checks = g_list_append(checks,node);
976                                         }
977         |       '<' '=' numtok          {
978                         Node *node = new_check(LE_CHECK,$<id>3);
979                         checks = g_list_append(checks,node);
980                                         }
981         |       '=' '=' numtok          {
982                         Node *node = new_check(EQ_CHECK,$<id>3);
983                         checks = g_list_append(checks,node);
984                                         }
985         |       '!' '=' numtok          {
986                         Node *node = new_check(NE_CHECK,$<id>3);
987                         checks = g_list_append(checks,node);
988                                         }
989         ;
990         
991 numtok:         NUMBER                  { $<id>$ = $<id>1; }
992         |       '-' NUMBER              {
993                         $<id>$ = g_strconcat("-",$<id>2,NULL);
994                         g_free($<id>2);
995                                         }
996         |       TOKEN                   { $<id>$ = $<id>1; }
997         ;
998         
999 %%