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