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