]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
Release 1.0.2
[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 <stdlib.h>
27 #include <string.h>
28
29 #include "treefuncs.h"
30 #include "main.h"
31 #include "util.h"
32
33 #define _(x) (x)
34         
35 GList *nodes = NULL;
36
37 static GList *class_nodes = NULL;
38 Node *class = NULL;
39 char *chunk_size = NULL;
40
41 static GList *typestack = NULL;
42 static GList *funcargs = NULL;
43 static GList *checks = NULL;
44 static int has_self = FALSE;
45 static int vararg = FALSE;
46
47 /* destructor and initializer for variables */
48 static char *destructor = NULL;
49 static int destructor_line = 0;
50 static gboolean destructor_simple = TRUE;
51 static char *initializer = NULL;
52 static int initializer_line = 0;
53
54 static char *onerror = NULL;
55 static char *defreturn = NULL;
56
57 static GList *gtktypes = NULL;
58
59 /* this can be a global as we will only do one function at a time
60    anyway */
61 static int the_scope = NO_SCOPE;
62
63 void free(void *ptr);
64 int yylex(void);
65
66 extern int ccode_line;
67 extern int line_no;
68
69 extern char *yytext;
70
71 static void
72 yyerror(char *str)
73 {
74         char *out=NULL;
75         char *p;
76         
77         if(strcmp(yytext,"\n")==0) {
78                 out=g_strconcat("Error: ",str," before newline",NULL);
79         } else if(yytext[0]=='\0') {
80                 out=g_strconcat("Error: ", str, " at end of input", NULL);
81         } else {
82                 char *tmp = g_strdup(yytext);
83                 while((p=strchr(tmp, '\n')))
84                         *p='.';
85
86                 out=g_strconcat("Error: ", str, " before '", tmp, "'", NULL);
87                 g_free(tmp);
88         }
89
90         fprintf(stderr, "%s:%d: %s\n", filename, line_no, out);
91         g_free(out);
92         
93         exit(1);
94 }
95
96 static Type *
97 pop_type(void)
98 {
99         Type *type = typestack->data;
100         typestack = g_list_remove(typestack,typestack->data);
101         return type;
102 }
103
104 static void
105 push_variable(char *name, int scope, int line_no, char *postfix)
106 {
107         Node *var;
108         Type *type = pop_type();
109
110         type->postfix = postfix;
111         
112         var = new_variable(scope, type, name, line_no,
113                            destructor, destructor_line,
114                            destructor_simple,
115                            initializer, initializer_line);
116         class_nodes = g_list_append(class_nodes, var);
117 }
118
119 static void
120 push_function(int scope, int method, char *oid, char *id,
121               GString *cbuf, int line_no, int ccode_line,
122               gboolean vararg, GList *flags)
123 {
124         Node *node;
125         Type *type;
126         char *c_cbuf;
127
128         g_assert(scope != CLASS_SCOPE);
129        
130         if(method == INIT_METHOD || method == CLASS_INIT_METHOD) {
131                 type = (Type *)new_type(g_strdup("void"), NULL, NULL);
132         } else {
133                 type = pop_type();
134         }
135         
136         /* a complicated and ugly test to figure out if we have
137            the wrong number of types for a signal */
138         if((method == SIGNAL_FIRST_METHOD ||
139             method == SIGNAL_LAST_METHOD) &&
140            g_list_length(gtktypes) != g_list_length(funcargs) &&
141            !(g_list_length(funcargs) == 1 &&
142              g_list_length(gtktypes) == 2 &&
143              strcmp(gtktypes->next->data, "NONE")==0)) {
144                 print_error(TRUE, _("The number of GTK arguments and "
145                                     "function arguments for a signal "
146                                     "don't seem to match"), line_no);
147         }
148         if(g_list_length(gtktypes) > 2) {
149                 GList *li;
150                 for(li = gtktypes->next; li; li = li->next) {
151                         if(strcmp(li->data, "NONE")==0) {
152                                 print_error(FALSE,
153                                             _("NONE can only appear in an "
154                                               "argument list by itself"),
155                                             line_no);
156                         }
157                 }
158         }
159         if(cbuf) {
160                 char *p;
161                 c_cbuf = p = cbuf->str;
162                 while(p && *p && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
163                         p++;
164                 if(!p || !*p)
165                         c_cbuf = NULL;
166         } else
167                 c_cbuf = NULL;
168
169         node = new_method(scope, method, type, oid, gtktypes, flags,
170                           id, funcargs, onerror, defreturn, c_cbuf, line_no,
171                           ccode_line, vararg, method_unique_id++);
172
173         if(cbuf)
174                 g_string_free(cbuf,
175                               /*only free segment if we haven't passed it
176                                 above */
177                               c_cbuf?FALSE:TRUE);
178         gtktypes = NULL;
179         funcargs = NULL;
180
181         onerror = NULL;
182         defreturn = NULL;
183
184         class_nodes = g_list_append(class_nodes, node);
185 }
186
187 static void
188 free_all_global_state(void)
189 {
190         g_free(onerror);
191         onerror = NULL;
192         g_free(defreturn);
193         defreturn = NULL;
194
195         g_free(chunk_size);
196         chunk_size = NULL;
197         
198         g_list_foreach(gtktypes, (GFunc)g_free, NULL);
199         g_list_free(gtktypes);
200         gtktypes = NULL;
201
202         free_node_list(funcargs);
203         funcargs = NULL;
204 }
205
206 static void
207 push_funcarg(char *name, char *postfix)
208 {
209         Node *node;
210         Type *type = pop_type();
211
212         type->postfix = postfix;
213         
214         node = new_funcarg(type, name, checks);
215         checks = NULL;
216         
217         funcargs = g_list_append(funcargs, node);
218 }
219
220 static void
221 push_init_arg(char *name, int is_class)
222 {
223         Node *node;
224         Node *type;
225         char *tn;
226         
227         if(is_class)
228                 tn = g_strconcat(((Class *)class)->otype,":Class",NULL);
229         else
230                 tn = g_strdup(((Class *)class)->otype);
231
232         type = new_type(tn, g_strdup("*"), NULL);
233         node = new_funcarg((Type *)type,name,NULL);
234         funcargs = g_list_prepend(funcargs, node);
235 }
236
237 static void
238 push_self(char *id)
239 {
240         Node *node;
241         Node *type;
242         GList *ch = NULL;
243         type = new_type(g_strdup(((Class *)class)->otype), g_strdup("*"), NULL);
244         ch = g_list_append(ch,new_check(NULL_CHECK,NULL));
245         ch = g_list_append(ch,new_check(TYPE_CHECK,NULL));
246         node = new_funcarg((Type *)type,id,ch);
247         funcargs = g_list_prepend(funcargs, node);
248 }
249
250 static Variable *
251 find_var_or_die(const char *id, int line)
252 {
253         GList *li;
254         char *s;
255
256         for(li = class_nodes; li != NULL; li = li->next) {
257                 Variable *var;
258                 Node *node = li->data;
259                 if(node->type != VARIABLE_NODE)
260                         continue;
261                 var = li->data;
262                 if(strcmp(var->id, id)==0)
263                         return var;
264         }
265
266         s = g_strdup_printf(_("Variable %s not defined here"), id);
267         print_error(FALSE, s, line);
268
269         g_assert_not_reached();
270         return NULL;
271 }
272
273 static gboolean
274 set_return_value(char *type, char *val)
275 {
276         if(strcmp(type, "onerror")==0) {
277                 if(!onerror) {
278                         onerror = val;
279                         return TRUE;
280                 } else
281                         return FALSE;
282         } else if(strcmp(type, "defreturn")==0) {
283                 if(!defreturn) {
284                         defreturn = val;
285                         return TRUE;
286                 } else
287                         return FALSE;
288         }
289         return FALSE;
290 }
291
292 %}
293
294 %union {
295         char *id;
296         GString *cbuf;
297         GList *list;
298         int line;
299         int sigtype;
300 }
301
302 %token CLASS FROM
303 %token CONST VOID STRUCT UNION ENUM THREEDOTS
304 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
305
306 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM
307 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE
308 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE ARGUMENT VIRTUAL SIGNAL OVERRIDE
309
310 %%
311
312 prog:           ccodes class ccodes     { ; }
313         |       class ccodes            { ; }
314         |       ccodes class            { ; }
315         |       class                   { ; }
316         ;
317
318 ccode:          CCODE                   {
319                         Node *node = new_ccode(C_CCODE,($<cbuf>1)->str,
320                                                ccode_line);
321                         nodes = g_list_append(nodes,node);
322                         g_string_free($<cbuf>1,FALSE);
323                                         }
324         |       HCODE                   {
325                         Node *node = new_ccode(H_CCODE,($<cbuf>1)->str,
326                                                ccode_line);
327                         nodes = g_list_append(nodes,node);
328                         g_string_free($<cbuf>1,FALSE);
329                                         }
330         |       HTCODE                  {
331                         Node *node = new_ccode(HT_CCODE,($<cbuf>1)->str,
332                                                ccode_line);
333                         nodes = g_list_append(nodes,node);
334                         g_string_free($<cbuf>1,FALSE);
335                                         }
336         |       PHCODE                  {
337                         Node *node = new_ccode(PH_CCODE,($<cbuf>1)->str,
338                                                ccode_line);
339                         nodes = g_list_append(nodes,node);
340                         g_string_free($<cbuf>1,FALSE);
341                                         }
342         |       ACODE                   {
343                         Node *node = new_ccode(A_CCODE,($<cbuf>1)->str,
344                                                ccode_line);
345                         nodes = g_list_append(nodes,node);
346                         g_string_free($<cbuf>1,FALSE);
347                                         }
348         |       ATCODE                  {
349                         Node *node = new_ccode(AT_CCODE,($<cbuf>1)->str,
350                                                ccode_line);
351                         nodes = g_list_append(nodes,node);
352                         g_string_free($<cbuf>1,FALSE);
353                                         }
354         ;
355
356 ccodes:         ccodes ccode            { ; }
357         |       ccode                   { ; }
358         ;
359
360 class:          classdec '{' classcode '}'      {
361                         ((Class *)class)->nodes = class_nodes;
362                         class_nodes = NULL;
363                         nodes = g_list_append(nodes,class);
364                                                 }
365         |       classdec '{' '}'                {
366                         ((Class *)class)->nodes = NULL;
367                         class_nodes = NULL;
368                         nodes = g_list_append(nodes,class);
369                                                 }
370         ;
371
372 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  chunk {
373                         class = new_class($<id>2,$<id>4,chunk_size,NULL);
374                                                 }
375         ;
376
377 chunk:
378         | '(' TOKEN TOKEN ')' {
379                         if(strcmp($<id>2,"chunks") == 0) {
380                                         chunk_size = g_strdup($<id>4);
381                         } else {
382                                 yyerror(_("parse error"));
383                                 YYERROR;
384                         }
385                 }
386         | '(' TOKEN NUMBER ')' {
387                         if(strcmp($<id>2,"chunks") == 0) {
388                                 if(atoi($<id>4) != 0)
389                                         chunk_size = g_strdup($<id>4);
390                         } else {
391                                 yyerror(_("parse error"));
392                                 YYERROR;
393                         }
394                 }
395         ;       
396
397 classcode:      classcode thing                 { ; }
398         |       thing                           { ; }
399         ;
400
401 thing:          method                          { ; }
402         |       variable                        { ; }
403         |       argument                        { ; }
404         |       ';'                             { ; }
405         ;
406
407 scope:          PUBLIC                  { the_scope = PUBLIC_SCOPE; }
408         |       PRIVATE                 { the_scope = PRIVATE_SCOPE; }
409         |       PROTECTED               { the_scope = PROTECTED_SCOPE; }
410         |       CLASSWIDE               { the_scope = CLASS_SCOPE; }
411         ;
412
413 destructor:     TOKEN TOKEN     {
414                         if(strcmp($<id>1, "destroywith")==0) {
415                                 g_free($<id>1);
416                                 destructor = $<id>2;
417                                 destructor_line = line_no;
418                                 destructor_simple = TRUE;
419                         } else {
420                                 g_free($<id>1);
421                                 g_free($<id>2);
422                                 yyerror(_("parse error"));
423                                 YYERROR;
424                         }
425                                 }
426         |       TOKEN '{' CCODE         {
427                         if(strcmp($<id>1, "destroy")==0) {
428                                 g_free($<id>1);
429                                 destructor = ($<cbuf>3)->str;
430                                 g_string_free($<cbuf>3, FALSE);
431                                 destructor_line = ccode_line;
432                                 destructor_simple = FALSE;
433                         } else {
434                                 g_free($<id>1);
435                                 g_string_free($<cbuf>3, TRUE);
436                                 yyerror(_("parse error"));
437                                 YYERROR;
438                         }
439                                         }
440         ;
441
442 initializer:    '=' numtok      {
443                         initializer = $<id>2;
444                         initializer_line = ccode_line;
445                                 }
446         |       '=' '{' CCODE   {
447                         initializer = ($<cbuf>3)->str;
448                         initializer_line = ccode_line;
449                         g_string_free($<cbuf>3, FALSE);
450                                 }
451         ;
452
453
454 varoptions:     destructor initializer  { ; }
455         |       initializer destructor  { ; }
456         |       initializer             { destructor = NULL; }
457         |       destructor              { initializer = NULL; }
458         |                               {
459                         destructor = NULL;
460                         initializer = NULL;
461                                         }
462         ;
463
464 variable:       scope type TOKEN varoptions ';'         {
465                         push_variable($<id>3, the_scope,$<line>1, NULL);
466                                                 }
467         |       scope type TOKEN ARRAY_DIM varoptions ';'       {
468                         push_variable($<id>3, the_scope, $<line>1, $<id>4);
469                                                 }
470         ;
471 argument:       ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' {
472                         if(strcmp($<id>5,"get")==0 &&
473                            strcmp($<id>8,"set")==0) {
474                                 Node *node;
475                                 Type *type = pop_type();
476                                 g_free($<id>5); g_free($<id>8);
477                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
478                                                     ($<cbuf>7)->str,$<line>6,
479                                                     ($<cbuf>10)->str,$<line>9,
480                                                     $<line>1);
481                                 g_string_free($<cbuf>7,FALSE);
482                                 g_string_free($<cbuf>10,FALSE);
483                                 class_nodes = g_list_append(class_nodes,node);
484                         } else if(strcmp($<id>5,"set")==0 &&
485                                 strcmp($<id>8,"get")==0) {
486                                 Node *node;
487                                 Type *type = pop_type();
488                                 g_free($<id>5); g_free($<id>8);
489                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
490                                                     ($<cbuf>10)->str,$<line>9,
491                                                     ($<cbuf>7)->str,$<line>6,
492                                                     $<line>1);
493                                 g_string_free($<cbuf>10,FALSE);
494                                 g_string_free($<cbuf>7,FALSE);
495                                 class_nodes = g_list_append(class_nodes,node);
496                         } else {
497                                 g_free($<id>3); g_free($<id>4);
498                                 g_free($<id>5); g_free($<id>8);
499                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
500                                 g_string_free($<cbuf>10,TRUE);
501                                 g_string_free($<cbuf>7,TRUE);
502                                 yyerror(_("parse error"));
503                                 YYERROR;
504                         }
505                                                 }
506         |       ARGUMENT flags argtype TOKEN TOKEN '{' CCODE ';' {
507                         if(strcmp($<id>5,"get")==0) {
508                                 Node *node;
509                                 Type *type = pop_type();
510                                 g_free($<id>5);
511                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
512                                                     ($<cbuf>7)->str,$<line>6,
513                                                     NULL,0, $<line>1);
514                                 g_string_free($<cbuf>7,FALSE);
515                                 class_nodes = g_list_append(class_nodes,node);
516                         } else if(strcmp($<id>5,"set")==0) {
517                                 Node *node;
518                                 Type *type = pop_type();
519                                 g_free($<id>5);
520                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
521                                                     NULL,0,($<cbuf>7)->str,
522                                                     $<line>6, $<line>1);
523                                 g_string_free($<cbuf>7,FALSE);
524                                 class_nodes = g_list_append(class_nodes,node);
525                         } else {
526                                 g_free($<id>5); g_free($<id>3);
527                                 g_free($<id>4);
528                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
529                                 g_string_free($<cbuf>7,TRUE);
530                                 yyerror(_("parse error"));
531                                 YYERROR;
532                         }
533                                                 }
534         |       ARGUMENT flags argtype TOKEN TOKEN {
535                         Node *node;
536                         char *get, *set = NULL;
537                         Variable *var;
538                         Type *type;
539                         char *root;
540                         
541                         if(strcmp($<id>5, "link")!=0 &&
542                            strcmp($<id>5, "stringlink")!=0 &&
543                            strcmp($<id>5, "objectlink")!=0) {
544                                 g_free($<id>5); g_free($<id>3);
545                                 g_free($<id>4);
546                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
547                                 yyerror(_("parse error"));
548                                 YYERROR;
549                         }
550
551                         type = pop_type();
552
553                         var = find_var_or_die($<id>4, $<line>1);
554                         if(var->scope == PRIVATE_SCOPE)
555                                 root = "self->_priv";
556                         else if(var->scope == CLASS_SCOPE)
557                                 root = "SELF_CLASS(GTK_OBJECT(self)->klass)";
558                         else
559                                 root = "self";
560
561                         if(strcmp($<id>5, "link")==0) {
562                                 set = g_strdup_printf("%s->%s = ARG;",
563                                                       root, $<id>4);
564                         } else if(strcmp($<id>5, "stringlink")==0) {
565                                 set = g_strdup_printf("g_free(%s->%s); "
566                                                       "%s->%s = g_strdup(ARG);",
567                                                       root, $<id>4,
568                                                       root, $<id>4);
569                         } else if(strcmp($<id>5, "objectlink")==0) {
570                                 set = g_strdup_printf(
571                                   "if(%s->%s) "
572                                    "gtk_object_unref(GTK_OBJECT(%s->%s)); "
573                                   "%s->%s = ARG; "
574                                   "if(%s->%s) "
575                                    "gtk_object_ref(GTK_OBJECT(%s->%s));",
576                                   root, $<id>4,
577                                   root, $<id>4,
578                                   root, $<id>4,
579                                   root, $<id>4,
580                                   root, $<id>4);
581                         } else {
582                                 g_assert_not_reached();
583                         }
584
585                         if(strcmp($<id>5, "stringlink")==0) {
586                                 get = g_strdup_printf("ARG = g_strdup(%s->%s);", root, $<id>4);
587                         } else
588                                 /* For everything else, get is just straight assignment */
589                                 get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
590
591                         g_free($<id>5);
592
593
594                         if(!type)
595                                 type = copy_type(var->vtype);
596
597                         node = new_argument($<id>3, type, $<list>2,
598                                             $<id>4, get, $<line>1,
599                                             set, $<line>1, $<line>1);
600                         class_nodes = g_list_append(class_nodes,node);
601                                                 }
602         ;
603
604 argtype:        TOKEN '(' TOKEN type ')'        {
605                         if(strcmp($<id>3,"type")!=0) {
606                                 g_free($<id>1);
607                                 g_free($<id>3);
608                                 yyerror(_("parse error"));
609                                 YYERROR;
610                         }
611                         $<id>$ = $<id>1;
612                                                 }
613         |       TOKEN                           {
614                         $<id>$ = $<id>1;
615                         typestack = g_list_prepend(typestack,NULL);
616                                                 }
617         ;
618         
619 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
620         |                                       { $<list>$ = NULL; }
621         ;
622
623 flaglist:       TOKEN '|' flaglist              {
624                         $<list>$ = g_list_append($<list>3,$<id>1);
625                                                 }
626         |       TOKEN                           {
627                         $<list>$ = g_list_append(NULL,$<id>1);
628                                                 }
629         ;
630
631
632 type:           specifier_list pointer                          {
633                         Node *node = new_type($<id>1, $<id>2, NULL);
634                         typestack = g_list_prepend(typestack,node);
635                                                         }
636         |       specifier_list                          {
637                         Node *node = new_type($<id>1, NULL, NULL);
638                         typestack = g_list_prepend(typestack,node);
639                                                         }
640         ;
641
642 /* The special cases are neccessary to avoid conflicts */
643 specifier_list: spec_list                               {
644                         $<id>$ = $<id>1;
645                                                         }
646         |       TOKEN                                   {
647                         $<id>$ = $<id>1;
648                                                         }
649         |       CONST TOKEN                             {
650                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
651                         g_free($<id>2);
652                                                         }
653         |       TOKEN CONST                             {
654                         $<id>$ = g_strconcat($<id>1, " const", NULL);
655                         g_free($<id>1);
656                                                         }
657         |       strunionenum TOKEN                      {
658                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
659                         g_free($<id>2);
660                                                         }
661         |       CONST strunionenum TOKEN                {
662                         $<id>$ = g_strconcat("const ", $<id>2, " ",
663                                              $<id>3, NULL);
664                         g_free($<id>3);
665                                                         }
666         |       strunionenum TOKEN CONST                {
667                         $<id>$ = g_strconcat($<id>1, " ",
668                                              $<id>2, " const", NULL);
669                         g_free($<id>2);
670                                                         }
671         ;
672
673 /* The special const cases take care of conflicts ! */
674 spec_list:      specifier spec_list                     {
675                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
676                         g_free($<id>2);
677                                                         }
678         |       TYPETOKEN spec_list                     {
679                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
680                         g_free($<id>1);
681                         g_free($<id>2);
682                                                         }
683         |       CONST spec_list                         {
684                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
685                         g_free($<id>2);
686                                                         }
687         |       TYPETOKEN                               {
688                         $<id>$ = $<id>1;
689                                                         }
690         |       TYPETOKEN CONST                         {
691                         $<id>$ = g_strconcat($<id>1, " const", NULL);
692                         g_free($<id>1);
693                                                         }
694         |       specifier                               {
695                         $<id>$ = g_strdup($<id>1);
696                                                         }
697         |       specifier CONST                         {
698                         $<id>$ = g_strconcat($<id>1, " const", NULL);
699                                                         }
700         ;
701
702 specifier:      VOID                    { $<id>$ = "void"; }
703         |       CHAR                    { $<id>$ = "char"; }
704         |       SHORT                   { $<id>$ = "short"; }
705         |       INT                     { $<id>$ = "int"; }
706         |       LONG                    { $<id>$ = "long"; }
707         |       FLOAT                   { $<id>$ = "float"; }
708         |       DOUBLE                  { $<id>$ = "double"; }
709         |       SIGNED                  { $<id>$ = "signed"; }
710         |       UNSIGNED                { $<id>$ = "unsigned"; }
711         ;
712
713 strunionenum:   STRUCT                  { $<id>$ = "struct"; }
714         |       UNION                   { $<id>$ = "union"; }
715         |       ENUM                    { $<id>$ = "enum"; }
716         ;
717
718 pointer:        '*'                     { $<id>$ = g_strdup("*"); }
719         |       '*' CONST               { $<id>$ = g_strdup("* const"); }
720         |       '*' pointer             {
721                                 $<id>$ = g_strconcat("*", $<id>2, NULL);
722                                 g_free($<id>2);
723                                         }
724         |       '*' CONST pointer       {
725                                 $<id>$ = g_strconcat("* const", $<id>3, NULL);
726                                 g_free($<id>3);
727                                         }
728         ;
729
730 /* this never sets the_scope */
731 simplesigtype:  TOKEN sigtype   {
732                         if(strcmp($<id>1, "first")==0)
733                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
734                         else if(strcmp($<id>1, "last")==0)
735                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
736                         else {
737                                 yyerror(_("signal must be 'first' or 'last'"));
738                                 g_free($<id>1);
739                                 YYERROR;
740                         }
741                         g_free($<id>1);
742                                         }
743         |       sigtype                 {
744                         $<sigtype>$ = SIGNAL_LAST_METHOD;
745                                         }
746         ;
747
748 /* this always sets the_scope */
749 fullsigtype:    scope TOKEN sigtype     {
750                         if(strcmp($<id>2,"first")==0)
751                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
752                         else if(strcmp($<id>2,"last")==0)
753                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
754                         else {
755                                 yyerror(_("signal must be 'first' or 'last'"));
756                                 g_free($<id>2);
757                                 YYERROR;
758                         }
759                         g_free($<id>2);
760                                         }
761         |       TOKEN scope sigtype     {
762                         if(strcmp($<id>1,"first")==0)
763                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
764                         else if(strcmp($<id>1,"last")==0)
765                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
766                         else {
767                                 yyerror(_("signal must be 'first' or 'last'"));
768                                 g_free($<id>1);
769                                 YYERROR;
770                         }
771                         g_free($<id>1);
772                                         }
773         |       scope sigtype           {
774                         $<sigtype>$ = SIGNAL_LAST_METHOD;
775                                         }
776         |       simplesigtype           {
777                         /* the_scope was default thus public */
778                         the_scope = PUBLIC_SCOPE;
779                                         }
780         ;
781         
782 sigtype:        TOKEN '(' tokenlist ')'         {
783                         gtktypes = g_list_prepend(gtktypes, $<id>1);
784                                                 }
785         ;
786
787 tokenlist:      tokenlist ',' TOKEN             {
788                         gtktypes = g_list_append(gtktypes, $<id>3);
789                                                 }
790         |       TOKEN                           { 
791                         gtktypes = g_list_append(gtktypes, $<id>1);
792                                                 }
793         ;
794
795 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
796         |       ';'                             { $<cbuf>$ = NULL; }
797         ;
798
799 /*here CCODE will include the ending '}' */
800 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
801                         if(!has_self) {
802                                 yyerror(_("signal without 'self' as "
803                                           "first parameter"));
804                                 free_all_global_state();
805                                 YYERROR;
806                         }
807                         if(the_scope == CLASS_SCOPE) {
808                                 yyerror(_("a method cannot be of class scope"));
809                                 free_all_global_state();
810                                 YYERROR;
811                         }
812                         push_function(the_scope, $<sigtype>3,NULL,
813                                       $<id>5, $<cbuf>10,$<line>1,
814                                       ccode_line, vararg, $<list>2);
815                                                                         }
816         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
817                         if(!has_self) {
818                                 yyerror(_("signal without 'self' as "
819                                           "first parameter"));
820                                 free_all_global_state();
821                                 YYERROR;
822                         }
823                         if(the_scope == CLASS_SCOPE) {
824                                 yyerror(_("a method cannot be of class scope"));
825                                 free_all_global_state();
826                                 YYERROR;
827                         }
828                         push_function(the_scope, $<sigtype>4, NULL,
829                                       $<id>6, $<cbuf>11, $<line>2,
830                                       ccode_line, vararg, $<list>3);
831                                                                         }
832         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
833                         if(!has_self) {
834                                 yyerror(_("virtual method without 'self' as "
835                                           "first parameter"));
836                                 free_all_global_state();
837                                 YYERROR;
838                         }
839                         if(the_scope == CLASS_SCOPE) {
840                                 yyerror(_("a method cannot be of class scope"));
841                                 free_all_global_state();
842                                 YYERROR;
843                         }
844                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
845                                       $<cbuf>9, $<line>1,
846                                       ccode_line, vararg, NULL);
847                                                                         }
848         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
849                         if(!has_self) {
850                                 yyerror(_("virtual method without 'self' as "
851                                           "first parameter"));
852                                 free_all_global_state();
853                                 YYERROR;
854                         }
855                         if(the_scope == CLASS_SCOPE) {
856                                 yyerror(_("a method cannot be of class scope"));
857                                 free_all_global_state();
858                                 YYERROR;
859                         }
860                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
861                                       $<cbuf>9, $<line>2,
862                                       ccode_line, vararg, NULL);
863                                                                         }
864         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
865                         if(!has_self) {
866                                 yyerror(_("virtual method without 'self' as "
867                                           "first parameter"));
868                                 free_all_global_state();
869                                 YYERROR;
870                         }
871                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
872                                       $<id>3, $<cbuf>8, $<line>1,
873                                       ccode_line, vararg, NULL);
874                                                                         }
875         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
876                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
877                                       $<id>6, $<cbuf>11,
878                                       $<line>1, ccode_line,
879                                       vararg, NULL);
880                                                                         }
881         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
882                         if(the_scope == CLASS_SCOPE) {
883                                 yyerror(_("a method cannot be of class scope"));
884                                 free_all_global_state();
885                                 YYERROR;
886                         }
887                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
888                                       $<cbuf>8, $<line>1, ccode_line,
889                                       vararg, NULL);
890                                                                 }
891         |       TOKEN '(' TOKEN ')' codenocode  {
892                         if(strcmp($<id>1, "init")==0) {
893                                 push_init_arg($<id>3,FALSE);
894                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
895                                               $<id>1, $<cbuf>5, $<line>2,
896                                               ccode_line, FALSE, NULL);
897                         } else if(strcmp($<id>1, "class_init")==0) {
898                                 push_init_arg($<id>3,TRUE);
899                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
900                                               $<id>1, $<cbuf>5, $<line>2,
901                                               ccode_line, FALSE, NULL);
902                         } else {
903                                 g_free($<id>1);
904                                 g_free($<id>3);
905                                 g_string_free($<cbuf>5,TRUE);
906                                 yyerror(_("parse error "
907                                           "(untyped blocks must be init or "
908                                           "class_init)"));
909                                 YYERROR;
910                         }
911                                                 }
912         ;
913
914 returnvals:     TOKEN retcode           {
915                         g_free(onerror); onerror = NULL;
916                         g_free(defreturn); defreturn = NULL;
917                         if(!set_return_value($<id>1, $<id>2)) {
918                                 g_free($<id>1);
919                                 g_free($<id>2);
920                                 yyerror(_("parse error"));
921                                 YYERROR;
922                         }
923                         g_free($<id>1);
924                                         }
925         |       TOKEN retcode TOKEN retcode     {
926                         g_free(onerror); onerror = NULL;
927                         g_free(defreturn); defreturn = NULL;
928                         if(!set_return_value($<id>1, $<id>2)) {
929                                 g_free($<id>1); g_free($<id>2);
930                                 g_free($<id>3); g_free($<id>4);
931                                 yyerror(_("parse error"));
932                                 YYERROR;
933                         }
934                         if(!set_return_value($<id>3, $<id>4)) {
935                                 onerror = defreturn = NULL;
936                                 g_free($<id>1); g_free($<id>2);
937                                 g_free($<id>3); g_free($<id>4);
938                                 yyerror(_("parse error"));
939                                 YYERROR;
940                         }
941                         g_free($<id>1);
942                         g_free($<id>3);
943                                                 }
944         |                               {
945                         g_free(onerror); onerror = NULL;
946                         g_free(defreturn); defreturn = NULL;
947                                         }
948         ;
949
950 retcode:        numtok                  { $<id>$ = $<id>1; }
951         |       '{' CCODE               {
952                         $<id>$ = ($<cbuf>3)->str;
953                         g_string_free($<cbuf>3, FALSE);
954                                         }
955         ;
956         
957 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
958         |       TOKEN                   {
959                         vararg = FALSE;
960                         has_self = TRUE;
961                         if(strcmp($<id>1,"self")==0)
962                                 push_self($<id>1);
963                         else {
964                                 g_free($<id>1);
965                                 yyerror(_("parse error"));
966                                 YYERROR;
967                         }
968                                         }
969         |       TOKEN ',' arglist       {
970                         has_self = TRUE;
971                         if(strcmp($<id>1,"self")==0)
972                                 push_self($<id>1);
973                         else {
974                                 g_free($<id>1);
975                                 yyerror(_("parse error"));
976                                 YYERROR;
977                         }
978                                         }
979         |       arglist                 { has_self = FALSE; }
980         ;
981
982 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
983         |       arglist1                { vararg = FALSE; }
984         ;
985         
986 arglist1:       arglist1 ',' arg        { ; }
987         |       arg                     { ; }
988         ;
989
990 arg:            type TOKEN                                      {
991                         push_funcarg($<id>2,NULL);
992                                                                 }
993         |       type TOKEN ARRAY_DIM                            {
994                         push_funcarg($<id>2,$<id>3);
995                                                                 }
996         |       type TOKEN '(' TOKEN checklist ')'              {
997                         if(strcmp($<id>4,"check")!=0) {
998                                 yyerror(_("parse error"));
999                                 YYERROR;
1000                         }
1001                         g_free($<id>4);
1002                         push_funcarg($<id>2,NULL);
1003                                                                 }
1004         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
1005                         if(strcmp($<id>5,"check")!=0) {
1006                                 yyerror(_("parse error"));
1007                                 YYERROR;
1008                         }
1009                         g_free($<id>5);
1010                         push_funcarg($<id>2,$<id>3);
1011                                                                 }
1012         ;
1013         
1014 checklist:      checklist check         { ; }
1015         |       check                   { ; }
1016         ;
1017
1018 check:          TOKEN                   {
1019                         if(strcmp($<id>1,"type")==0) {
1020                                 Node *node = new_check(TYPE_CHECK,NULL);
1021                                 checks = g_list_append(checks,node);
1022                         } else if(strcmp($<id>1,"null")==0) {
1023                                 Node *node = new_check(NULL_CHECK,NULL);
1024                                 checks = g_list_append(checks,node);
1025                         } else {
1026                                 yyerror(_("parse error"));
1027                                 YYERROR;
1028                         }
1029                         g_free($<id>1);
1030                                         }
1031         |       '>' numtok              {
1032                         Node *node = new_check(GT_CHECK,$<id>2);
1033                         checks = g_list_append(checks,node);
1034                                         }
1035         |       '<' numtok              {
1036                         Node *node = new_check(LT_CHECK,$<id>2);
1037                         checks = g_list_append(checks,node);
1038                                         }
1039         |       '>' '=' numtok          {
1040                         Node *node = new_check(GE_CHECK,$<id>3);
1041                         checks = g_list_append(checks,node);
1042                                         }
1043         |       '<' '=' numtok          {
1044                         Node *node = new_check(LE_CHECK,$<id>3);
1045                         checks = g_list_append(checks,node);
1046                                         }
1047         |       '=' '=' numtok          {
1048                         Node *node = new_check(EQ_CHECK,$<id>3);
1049                         checks = g_list_append(checks,node);
1050                                         }
1051         |       '!' '=' numtok          {
1052                         Node *node = new_check(NE_CHECK,$<id>3);
1053                         checks = g_list_append(checks,node);
1054                                         }
1055         ;
1056         
1057 numtok:         NUMBER                  { $<id>$ = $<id>1; }
1058         |       '-' NUMBER              {
1059                         $<id>$ = g_strconcat("-",$<id>2,NULL);
1060                         g_free($<id>2);
1061                                         }
1062         |       TOKEN                   { $<id>$ = $<id>1; }
1063         ;
1064         
1065 %%