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