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