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