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