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