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