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