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