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