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