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