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