]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
Release 0.91.1
[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         ;
227
228 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  {
229                         class = new_class($<id>2,$<id>4,NULL);
230                                                 }
231         ;
232         
233 classcode:      classcode method                { ; }
234         |       classcode variable              { ; }
235         |       classcode argument              { ; }
236         |       method                          { ; }
237         |       variable                        { ; }
238         |       argument                        { ; }
239         ;
240
241 variable:       PUBLIC type TOKEN ';'           {
242                         push_variable($<id>3,PUBLIC_SCOPE,$<line>1,NULL);
243                                                 }
244         |       PUBLIC type TOKEN ARRAY_DIM ';' {
245                         push_variable($<id>3,PUBLIC_SCOPE,$<line>1,$<id>4);
246                                                 }
247         |       PRIVATE type TOKEN ';'          {
248                         push_variable($<id>3,PRIVATE_SCOPE,$<line>1,NULL);
249                                                 }
250         |       PRIVATE type TOKEN ARRAY_DIM ';' {
251                         push_variable($<id>3,PRIVATE_SCOPE,$<line>1,$<id>4);
252                                                  }
253         ;
254 argument:       ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' {
255                         if(strcmp($<id>5,"get")==0 &&
256                            strcmp($<id>8,"set")==0) {
257                                 Node *node;
258                                 g_free($<id>5); g_free($<id>8);
259                                 node = new_argument($<id>3,$<list>2,$<id>4,
260                                                     $<cbuf>7,$<line>6,
261                                                     $<cbuf>10,$<line>9,
262                                                     $<line>1);
263                                 class_nodes = g_list_append(class_nodes,node);
264                         } else if(strcmp($<id>5,"set")==0 &&
265                                 strcmp($<id>8,"get")==0) {
266                                 Node *node;
267                                 g_free($<id>5); g_free($<id>8);
268                                 node = new_argument($<id>3,$<list>2,$<id>4,
269                                                     $<cbuf>10,$<line>9,
270                                                     $<cbuf>7,$<line>6,
271                                                     $<line>1);
272                                 class_nodes = g_list_append(class_nodes,node);
273                         } else {
274                                 g_free($<id>3); g_free($<id>4);
275                                 g_free($<id>5); g_free($<id>8);
276                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
277                                 g_string_free($<cbuf>10,TRUE);
278                                 g_string_free($<cbuf>7,TRUE);
279                                 yyerror(_("parse error"));
280                                 YYERROR;
281                         }
282                                                 }
283         |       ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE ';' {
284                         if(strcmp($<id>5,"get")==0) {
285                                 Node *node;
286                                 g_free($<id>5);
287                                 node = new_argument($<id>3,$<list>2,$<id>4,
288                                                     $<cbuf>7,$<line>6,NULL,0,
289                                                     $<line>1);
290                                 class_nodes = g_list_append(class_nodes,node);
291                         } else if(strcmp($<id>5,"set")==0) {
292                                 Node *node;
293                                 g_free($<id>5);
294                                 node = new_argument($<id>3,$<list>2,$<id>4,
295                                                     NULL,0,$<cbuf>7,$<line>6,
296                                                     $<line>1);
297                                 class_nodes = g_list_append(class_nodes,node);
298                         } else {
299                                 g_free($<id>5); g_free($<id>3);
300                                 g_free($<id>4);
301                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
302                                 g_string_free($<cbuf>7,TRUE);
303                                 yyerror(_("parse error"));
304                                 YYERROR;
305                         }
306                                                 }
307         ;
308         
309 argflags:       '(' flaglist ')'                { $<list>$ = $<list>2; }
310         |                                       { $<list>$ = NULL; }
311         ;
312
313 flaglist:       TOKEN '|' flaglist              {
314                         $<list>$ = g_list_append($<list>3,$<id>1);
315                                                 }
316         |       TOKEN                           {
317                         $<list>$ = g_list_append(NULL,$<id>1);
318                                                 }
319         ;
320
321
322 type:           type1                           { ; }
323         |       CONST type1                     {
324                         Type *type = typestack->data;
325                         char *oldname = type->name;
326                         type->name = g_strconcat("const ",oldname,NULL);
327                         g_free(oldname);
328                                                 }
329         ;
330
331 type1:          type2                           {
332                         Node *node = new_type(0,$<id>1,NULL);
333                         typestack = g_list_prepend(typestack,node);
334                                                 }
335         |       type2 stars                     {
336                         Node *node = new_type(stars,$<id>1,NULL);
337                         stars = 0;
338                         typestack = g_list_prepend(typestack,node);
339                                                 }
340         ;
341
342 type2:          UNSIGNED integer                {
343                         $<id>$ = g_strconcat("unsigned ",$<id>2,NULL);
344                                                 }
345         |       SIGNED integer                  {
346                         $<id>$ = g_strconcat("signed ",$<id>2,NULL);
347                                                 }
348         |       integer                         {
349                         $<id>$ = g_strdup($<id>1);
350                                                 }
351         |       UNSIGNED CHAR                   {
352                         $<id>$ = g_strdup("unsigned char");
353                                                 }
354         |       SIGNED CHAR                     {
355                         $<id>$ = g_strdup("signed char");
356                                                 }
357         |       CHAR                            {
358                         $<id>$ = g_strdup("char");
359                                                 }
360         |       DOUBLE                          {
361                         $<id>$ = g_strdup("double");
362                                                 }
363         |       FLOAT                           {
364                         $<id>$ = g_strdup("float");
365                                                 }
366         |       TOKEN                           {
367                         $<id>$ = $<id>1;
368                                                 }
369         |       tspecifier TOKEN                {
370                         $<id>$ = g_strconcat($<id>1,$<id>2,NULL);
371                         g_free($<id>2);
372                                                 }
373         |       TYPETOKEN                       {
374                         $<id>$ = $<id>1;
375                                                 }
376         |       VOID                            {
377                         $<id>$ = g_strdup("void");
378                                                 }
379         ;
380
381 integer:        LONG INT                        {
382                         $<id>$ = "long int";
383                                                 }
384         |       LONG                            {
385                         $<id>$ = "long";
386                                                 }
387         |       SHORT INT                       {
388                         $<id>$ = "short int";
389                                                 }
390         |       SHORT                           {
391                         $<id>$ = "short";
392                                                 }
393         |       INT                             {
394                         $<id>$ = "int";
395                                                 }
396         ;
397         
398 tspecifier:     ENUM                            {
399                         $<id>$ = "enum ";
400                                                 }
401         |       UNION                           {
402                         $<id>$ = "union ";
403                                                 }
404         |       STRUCT                          {
405                         $<id>$ = "struct ";
406                                                 }
407         ;
408         
409 stars:          '*' stars                       { stars++; }
410         |       '*'                             { stars++; }
411         ;
412
413 fullsigtype:    PRIVATE TOKEN sigtype   {
414                         if(strcmp($<id>2,"first")==0)
415                                 $<sigtype>$ = PRIVATE_SIGNAL_FIRST_METHOD;
416                         else if(strcmp($<id>2,"last")==0)
417                                 $<sigtype>$ = PRIVATE_SIGNAL_LAST_METHOD;
418                         else {
419                                 yyerror(_("signal must be 'first' or 'last'"));
420                                 g_free($<id>2);
421                                 YYERROR;
422                         }
423                         g_free($<id>2);
424                                         }
425         |       TOKEN PRIVATE sigtype   {
426                         if(strcmp($<id>1,"first")==0)
427                                 $<sigtype>$ = PRIVATE_SIGNAL_FIRST_METHOD;
428                         else if(strcmp($<id>1,"last")==0)
429                                 $<sigtype>$ = PRIVATE_SIGNAL_LAST_METHOD;
430                         else {
431                                 yyerror(_("signal must be 'first' or 'last'"));
432                                 g_free($<id>1);
433                                 YYERROR;
434                         }
435                         g_free($<id>1);
436                                         }
437         |       PRIVATE sigtype         {
438                         $<sigtype>$ = PRIVATE_SIGNAL_LAST_METHOD;
439                                         }
440         |       TOKEN sigtype           {
441                         if(strcmp($<id>1,"first")==0)
442                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
443                         else if(strcmp($<id>1,"last")==0)
444                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
445                         else {
446                                 yyerror(_("signal must be 'first' or 'last'"));
447                                 g_free($<id>1);
448                                 YYERROR;
449                         }
450                         g_free($<id>1);
451                                         }
452         |       sigtype                 {
453                         $<sigtype>$ = SIGNAL_LAST_METHOD;
454                                         }
455         ;
456         
457 sigtype:        TOKEN '(' tokenlist ')'         {
458                         gtktypes = g_list_prepend(gtktypes,$<id>1);
459                                                 }
460         ;
461
462 tokenlist:      tokenlist ',' TOKEN             {
463                         gtktypes = g_list_append(gtktypes,$<id>3);
464                                                 }
465         |       TOKEN                           { 
466                         gtktypes = g_list_append(gtktypes,$<id>1);
467                                                 }
468         ;
469
470 codenocode:     '{' CCODE                       { $<cbuf>$=$<cbuf>2; }
471         |       ';'                             { $<cbuf>$ = NULL; }
472         ;
473
474 /*here CCODE will include the ending '}' */
475 method:         SIGNAL fullsigtype type TOKEN '(' funcargs ')' onerror codenocode {
476                         if(!has_self) {
477                                 yyerror(_("signal without 'self' as "
478                                           "first parameter"));
479                                 YYERROR;
480                         }
481                         push_function($<sigtype>2,NULL,
482                                       $<id>4, $<id>8, $<cbuf>9,$<line>1,
483                                       ccode_line,vararg);
484                                                                         }
485         |       VIRTUAL PRIVATE type TOKEN '(' funcargs ')' onerror codenocode  {
486                         if(!has_self) {
487                                 yyerror(_("virtual method without 'self' as "
488                                           "first parameter"));
489                                 YYERROR;
490                         }
491                         push_function(PRIVATE_VIRTUAL_METHOD, NULL, $<id>4,
492                                       $<id>8, $<cbuf>9,$<line>1,
493                                       ccode_line,vararg);
494                                                                         }
495         |       VIRTUAL type TOKEN '(' funcargs ')' onerror codenocode  {
496                         if(!has_self) {
497                                 yyerror(_("virtual method without 'self' as "
498                                           "first parameter"));
499                                 YYERROR;
500                         }
501                         push_function(VIRTUAL_METHOD, NULL, $<id>3,
502                                       $<id>7, $<cbuf>8,$<line>1,
503                                       ccode_line,vararg);
504                                                                         }
505         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' onerror '{' CCODE        {
506                         push_function(OVERRIDE_METHOD, $<id>3,
507                                       $<id>6, $<id>10, $<cbuf>12,
508                                       $<line>1,$<line>11,
509                                       vararg);
510                                                                         }
511         |       PUBLIC type TOKEN '(' funcargs ')' onerror '{' CCODE    {
512                         push_function(PUBLIC_SCOPE, NULL, $<id>3,
513                                       $<id>7, $<cbuf>9,$<line>1,$<line>8,
514                                       vararg);
515                                                                 }
516         |       PRIVATE type TOKEN '(' funcargs ')' onerror '{' CCODE   {
517                         push_function(PRIVATE_SCOPE, NULL, $<id>3,
518                                       $<id>7, $<cbuf>9,$<line>1,$<line>8,
519                                       vararg);
520                                                                 }
521         |       TOKEN '(' TOKEN ')' codenocode  {
522                         if(strcmp($<id>1,"init")==0) {
523                                 push_init_arg($<id>3,FALSE);
524                                 push_function(INIT_METHOD, NULL,
525                                               $<id>1, NULL, $<cbuf>5,$<line>2,
526                                               ccode_line,FALSE);
527                         } else if(strcmp($<id>1,"class_init")==0) {
528                                 push_init_arg($<id>3,TRUE);
529                                 push_function(CLASS_INIT_METHOD, NULL, 
530                                               $<id>1, NULL, $<cbuf>5,$<line>2,
531                                               ccode_line,FALSE);
532                         } else {
533                                 g_free($<id>1);
534                                 g_free($<id>3);
535                                 g_string_free($<cbuf>3,TRUE);
536                                 yyerror(_("parse error"));
537                                 YYERROR;
538                         }
539                                                 }
540         ;
541         
542 onerror:        ONERROR numtok          { $<id>$ = $<id>2; }
543         |       ONERROR '{' CCODE       {
544                         $<id>$ = ($<cbuf>3)->str;
545                         g_string_free($<cbuf>3,FALSE);
546                                         }
547         |       '=' '1'                 { ; }
548         |                               { $<id>$ = NULL; }
549         ;
550         
551 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
552         |       TOKEN                   {
553                         vararg = FALSE;
554                         has_self = TRUE;
555                         if(strcmp($<id>1,"self")==0)
556                                 push_self($<id>1);
557                         else {
558                                 g_free($<id>1);
559                                 yyerror(_("parse error"));
560                                 YYERROR;
561                         }
562                                         }
563         |       TOKEN ',' arglist       {
564                         has_self = TRUE;
565                         if(strcmp($<id>1,"self")==0)
566                                 push_self($<id>1);
567                         else {
568                                 g_free($<id>1);
569                                 yyerror(_("parse error"));
570                                 YYERROR;
571                         }
572                                         }
573         |       arglist                 { has_self = FALSE; }
574         ;
575
576 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
577         |       arglist1                { vararg = FALSE; }
578         ;
579         
580 arglist1:       arglist1 ',' arg        { ; }
581         |       arg                     { ; }
582         ;
583
584 arg:            type TOKEN                                      {
585                         push_funcarg($<id>2,NULL);
586                                                                 }
587         |       type TOKEN ARRAY_DIM                            {
588                         push_funcarg($<id>2,$<id>3);
589                                                                 }
590         |       type TOKEN '(' TOKEN checklist ')'              {
591                         if(strcmp($<id>4,"check")!=0) {
592                                 yyerror(_("parse error"));
593                                 YYERROR;
594                         }
595                         g_free($<id>4);
596                         push_funcarg($<id>2,NULL);
597                                                                 }
598         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
599                         if(strcmp($<id>5,"check")!=0) {
600                                 yyerror(_("parse error"));
601                                 YYERROR;
602                         }
603                         g_free($<id>5);
604                         push_funcarg($<id>2,$<id>3);
605                                                                 }
606         ;
607         
608 checklist:      checklist check         { ; }
609         |       check                   { ; }
610         ;
611
612 check:          TOKEN                   {
613                         if(strcmp($<id>1,"type")==0) {
614                                 Node *node = new_check(TYPE_CHECK,NULL);
615                                 checks = g_list_append(checks,node);
616                         } else if(strcmp($<id>1,"null")==0) {
617                                 Node *node = new_check(NULL_CHECK,NULL);
618                                 checks = g_list_append(checks,node);
619                         } else {
620                                 yyerror(_("parse error"));
621                                 YYERROR;
622                         }
623                         g_free($<id>1);
624                                         }
625         |       '>' numtok              {
626                         Node *node = new_check(GT_CHECK,$<id>2);
627                         checks = g_list_append(checks,node);
628                                         }
629         |       '<' numtok              {
630                         Node *node = new_check(LT_CHECK,$<id>2);
631                         checks = g_list_append(checks,node);
632                                         }
633         |       '>' '=' numtok          {
634                         Node *node = new_check(GE_CHECK,$<id>3);
635                         checks = g_list_append(checks,node);
636                                         }
637         |       '<' '=' numtok          {
638                         Node *node = new_check(LE_CHECK,$<id>3);
639                         checks = g_list_append(checks,node);
640                                         }
641         |       '=' '=' numtok          {
642                         Node *node = new_check(EQ_CHECK,$<id>3);
643                         checks = g_list_append(checks,node);
644                                         }
645         |       '!' '=' numtok          {
646                         Node *node = new_check(NE_CHECK,$<id>3);
647                         checks = g_list_append(checks,node);
648                                         }
649         ;
650         
651 numtok:         NUMBER                  { $<id>$ = $<id>1; }
652         |       '-' NUMBER              {
653                         $<id>$ = g_strconcat("-",$<id>2,NULL);
654                         g_free($<id>2);
655                                         }
656         |       TOKEN                   { $<id>$ = $<id>1; }
657         ;
658         
659 %%