]> git.draconx.ca Git - gob-dx.git/blob - src/parse.y
Release 1.0.4
[gob-dx.git] / src / parse.y
1 /* GOB C Preprocessor
2  * Copyright (C) 1999 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the  Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  * USA.
20  */
21 %{
22
23 #include "config.h"
24 #include <glib.h>
25 #include <stdio.h>
26 #include <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                 error_print(GOB_WARN, line_no,
145                             _("The number of GTK arguments and "
146                               "function arguments for a signal "
147                               "don't seem to match"));
148         }
149         if(g_list_length(gtktypes) > 2) {
150                 GList *li;
151                 for(li = gtktypes->next; li; li = li->next) {
152                         if(strcmp(li->data, "NONE")==0) {
153                                 error_print(GOB_ERROR, line_no,
154                                             _("NONE can only appear in an "
155                                               "argument list by itself"));
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, gboolean constant)
239 {
240         Node *node;
241         Node *type;
242         GList *ch = NULL;
243         type = new_type(g_strdup(((Class *)class)->otype),
244                         g_strdup(constant ? "const *" : "*"), NULL);
245         ch = g_list_append(ch,new_check(NULL_CHECK,NULL));
246         ch = g_list_append(ch,new_check(TYPE_CHECK,NULL));
247         node = new_funcarg((Type *)type,id,ch);
248         funcargs = g_list_prepend(funcargs, node);
249 }
250
251 static Variable *
252 find_var_or_die(const char *id, int line)
253 {
254         GList *li;
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         error_printf(GOB_ERROR, line, _("Variable %s not defined here"), id);
267
268         g_assert_not_reached();
269         return NULL;
270 }
271
272 static gboolean
273 set_return_value(char *type, char *val)
274 {
275         if(strcmp(type, "onerror")==0) {
276                 if(!onerror) {
277                         onerror = val;
278                         return TRUE;
279                 } else
280                         return FALSE;
281         } else if(strcmp(type, "defreturn")==0) {
282                 if(!defreturn) {
283                         defreturn = val;
284                         return TRUE;
285                 } else
286                         return FALSE;
287         }
288         return FALSE;
289 }
290
291 %}
292
293 %union {
294         char *id;
295         GString *cbuf;
296         GList *list;
297         int line;
298         int sigtype;
299 }
300
301 %token CLASS FROM
302 %token CONST VOID STRUCT UNION ENUM THREEDOTS
303 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
304
305 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM
306 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE
307 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE ARGUMENT VIRTUAL SIGNAL OVERRIDE
308
309 %%
310
311 prog:           ccodes class ccodes     { ; }
312         |       class ccodes            { ; }
313         |       ccodes class            { ; }
314         |       class                   { ; }
315         ;
316
317 ccode:          CCODE                   {
318                         Node *node = new_ccode(C_CCODE,($<cbuf>1)->str,
319                                                ccode_line);
320                         nodes = g_list_append(nodes,node);
321                         g_string_free($<cbuf>1,FALSE);
322                                         }
323         |       HCODE                   {
324                         Node *node = new_ccode(H_CCODE,($<cbuf>1)->str,
325                                                ccode_line);
326                         nodes = g_list_append(nodes,node);
327                         g_string_free($<cbuf>1,FALSE);
328                                         }
329         |       HTCODE                  {
330                         Node *node = new_ccode(HT_CCODE,($<cbuf>1)->str,
331                                                ccode_line);
332                         nodes = g_list_append(nodes,node);
333                         g_string_free($<cbuf>1,FALSE);
334                                         }
335         |       PHCODE                  {
336                         Node *node = new_ccode(PH_CCODE,($<cbuf>1)->str,
337                                                ccode_line);
338                         nodes = g_list_append(nodes,node);
339                         g_string_free($<cbuf>1,FALSE);
340                                         }
341         |       ACODE                   {
342                         Node *node = new_ccode(A_CCODE,($<cbuf>1)->str,
343                                                ccode_line);
344                         nodes = g_list_append(nodes,node);
345                         g_string_free($<cbuf>1,FALSE);
346                                         }
347         |       ATCODE                  {
348                         Node *node = new_ccode(AT_CCODE,($<cbuf>1)->str,
349                                                ccode_line);
350                         nodes = g_list_append(nodes,node);
351                         g_string_free($<cbuf>1,FALSE);
352                                         }
353         ;
354
355 ccodes:         ccodes ccode            { ; }
356         |       ccode                   { ; }
357         ;
358
359 class:          classdec '{' classcode '}'      {
360                         ((Class *)class)->nodes = class_nodes;
361                         class_nodes = NULL;
362                         nodes = g_list_append(nodes,class);
363                                                 }
364         |       classdec '{' '}'                {
365                         ((Class *)class)->nodes = NULL;
366                         class_nodes = NULL;
367                         nodes = g_list_append(nodes,class);
368                                                 }
369         ;
370
371 classdec:       CLASS TYPETOKEN FROM TYPETOKEN  chunk {
372                         class = new_class($<id>2,$<id>4,chunk_size,NULL);
373                                                 }
374         ;
375
376 chunk:
377         | '(' TOKEN TOKEN ')' {
378                         if(strcmp($<id>2,"chunks") == 0) {
379                                         chunk_size = g_strdup($<id>4);
380                         } else {
381                                 yyerror(_("parse error"));
382                                 YYERROR;
383                         }
384                 }
385         | '(' TOKEN NUMBER ')' {
386                         if(strcmp($<id>2,"chunks") == 0) {
387                                 if(atoi($<id>4) != 0)
388                                         chunk_size = g_strdup($<id>4);
389                         } else {
390                                 yyerror(_("parse error"));
391                                 YYERROR;
392                         }
393                 }
394         ;       
395
396 classcode:      classcode thing                 { ; }
397         |       thing                           { ; }
398         ;
399
400 thing:          method                          { ; }
401         |       variable                        { ; }
402         |       argument                        { ; }
403         |       ';'                             { ; }
404         ;
405
406 scope:          PUBLIC                  { the_scope = PUBLIC_SCOPE; }
407         |       PRIVATE                 { the_scope = PRIVATE_SCOPE; }
408         |       PROTECTED               { the_scope = PROTECTED_SCOPE; }
409         |       CLASSWIDE               { the_scope = CLASS_SCOPE; }
410         ;
411
412 destructor:     TOKEN TOKEN     {
413                         if(strcmp($<id>1, "destroywith")==0) {
414                                 g_free($<id>1);
415                                 destructor = $<id>2;
416                                 destructor_line = line_no;
417                                 destructor_simple = TRUE;
418                         } else {
419                                 g_free($<id>1);
420                                 g_free($<id>2);
421                                 yyerror(_("parse error"));
422                                 YYERROR;
423                         }
424                                 }
425         |       TOKEN '{' CCODE         {
426                         if(strcmp($<id>1, "destroy")==0) {
427                                 g_free($<id>1);
428                                 destructor = ($<cbuf>3)->str;
429                                 g_string_free($<cbuf>3, FALSE);
430                                 destructor_line = ccode_line;
431                                 destructor_simple = FALSE;
432                         } else {
433                                 g_free($<id>1);
434                                 g_string_free($<cbuf>3, TRUE);
435                                 yyerror(_("parse error"));
436                                 YYERROR;
437                         }
438                                         }
439         ;
440
441 initializer:    '=' numtok      {
442                         initializer = $<id>2;
443                         initializer_line = ccode_line;
444                                 }
445         |       '=' '{' CCODE   {
446                         initializer = ($<cbuf>3)->str;
447                         initializer_line = ccode_line;
448                         g_string_free($<cbuf>3, FALSE);
449                                 }
450         ;
451
452
453 varoptions:     destructor initializer  { ; }
454         |       initializer destructor  { ; }
455         |       initializer             { destructor = NULL; }
456         |       destructor              { initializer = NULL; }
457         |                               {
458                         destructor = NULL;
459                         initializer = NULL;
460                                         }
461         ;
462
463 variable:       scope type TOKEN varoptions ';'         {
464                         push_variable($<id>3, the_scope,$<line>1, NULL);
465                                                 }
466         |       scope type TOKEN ARRAY_DIM varoptions ';'       {
467                         push_variable($<id>3, the_scope, $<line>1, $<id>4);
468                                                 }
469         ;
470 argument:       ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' {
471                         if(strcmp($<id>5,"get")==0 &&
472                            strcmp($<id>8,"set")==0) {
473                                 Node *node;
474                                 Type *type = pop_type();
475                                 g_free($<id>5); g_free($<id>8);
476                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
477                                                     ($<cbuf>7)->str,$<line>6,
478                                                     ($<cbuf>10)->str,$<line>9,
479                                                     $<line>1);
480                                 g_string_free($<cbuf>7,FALSE);
481                                 g_string_free($<cbuf>10,FALSE);
482                                 class_nodes = g_list_append(class_nodes,node);
483                         } else if(strcmp($<id>5,"set")==0 &&
484                                 strcmp($<id>8,"get")==0) {
485                                 Node *node;
486                                 Type *type = pop_type();
487                                 g_free($<id>5); g_free($<id>8);
488                                 node = new_argument($<id>3,type,$<list>2,$<id>4,
489                                                     ($<cbuf>10)->str,$<line>9,
490                                                     ($<cbuf>7)->str,$<line>6,
491                                                     $<line>1);
492                                 g_string_free($<cbuf>10,FALSE);
493                                 g_string_free($<cbuf>7,FALSE);
494                                 class_nodes = g_list_append(class_nodes,node);
495                         } else {
496                                 g_free($<id>3); g_free($<id>4);
497                                 g_free($<id>5); g_free($<id>8);
498                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
499                                 g_list_free($<list>2);
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_list_free($<list>2);
530                                 g_string_free($<cbuf>7, TRUE);
531                                 yyerror(_("parse error"));
532                                 YYERROR;
533                         }
534                                                 }
535         |       ARGUMENT flags argtype TOKEN TOKEN {
536                         Node *node;
537                         char *get, *set = NULL;
538                         Variable *var;
539                         Type *type;
540                         char *root;
541                         
542                         if(strcmp($<id>5, "link")!=0 &&
543                            strcmp($<id>5, "stringlink")!=0 &&
544                            strcmp($<id>5, "objectlink")!=0) {
545                                 g_free($<id>5); g_free($<id>3);
546                                 g_free($<id>4);
547                                 g_list_foreach($<list>2,(GFunc)g_free,NULL);
548                                 g_list_free($<list>2);
549                                 yyerror(_("parse error"));
550                                 YYERROR;
551                         }
552
553                         type = pop_type();
554
555                         var = find_var_or_die($<id>4, $<line>1);
556                         if(var->scope == PRIVATE_SCOPE)
557                                 root = "self->_priv";
558                         else if(var->scope == CLASS_SCOPE) {
559                                 root = "SELF_GET_CLASS(self)";
560                                 if(no_self_alias)
561                                         error_print(GOB_ERROR, $<line>1,
562                                                     _("Self aliases needed when autolinking to a classwide member"));
563                         } else
564                                 root = "self";
565
566                         if(strcmp($<id>5, "link")==0) {
567                                 set = g_strdup_printf("%s->%s = ARG;",
568                                                       root, $<id>4);
569                         } else if(strcmp($<id>5, "stringlink")==0) {
570                                 set = g_strdup_printf("g_free(%s->%s); "
571                                                       "%s->%s = g_strdup(ARG);",
572                                                       root, $<id>4,
573                                                       root, $<id>4);
574                         } else if(strcmp($<id>5, "objectlink")==0) {
575                                 set = g_strdup_printf(
576                                   "if(%s->%s) "
577                                    "gtk_object_unref(GTK_OBJECT(%s->%s)); "
578                                   "%s->%s = ARG; "
579                                   "if(%s->%s) "
580                                    "gtk_object_ref(GTK_OBJECT(%s->%s));",
581                                   root, $<id>4,
582                                   root, $<id>4,
583                                   root, $<id>4,
584                                   root, $<id>4,
585                                   root, $<id>4);
586                         } else {
587                                 g_assert_not_reached();
588                         }
589
590                         if(strcmp($<id>5, "stringlink")==0) {
591                                 get = g_strdup_printf("ARG = g_strdup(%s->%s);", root, $<id>4);
592                         } else
593                                 /* For everything else, get is just straight assignment */
594                                 get = g_strdup_printf("ARG = %s->%s;", root, $<id>4);
595
596                         g_free($<id>5);
597
598
599                         if(!type)
600                                 type = copy_type(var->vtype);
601
602                         node = new_argument($<id>3, type, $<list>2,
603                                             $<id>4, get, $<line>1,
604                                             set, $<line>1, $<line>1);
605                         class_nodes = g_list_append(class_nodes,node);
606                                                 }
607         ;
608
609 argtype:        TOKEN '(' TOKEN type ')'        {
610                         if(strcmp($<id>3,"type")!=0) {
611                                 g_free($<id>1);
612                                 g_free($<id>3);
613                                 yyerror(_("parse error"));
614                                 YYERROR;
615                         }
616                         $<id>$ = $<id>1;
617                                                 }
618         |       TOKEN                           {
619                         $<id>$ = $<id>1;
620                         typestack = g_list_prepend(typestack,NULL);
621                                                 }
622         ;
623         
624 flags:          '(' flaglist ')'                { $<list>$ = $<list>2; }
625         |                                       { $<list>$ = NULL; }
626         ;
627
628 flaglist:       TOKEN '|' flaglist              {
629                         $<list>$ = g_list_append($<list>3,$<id>1);
630                                                 }
631         |       TOKEN                           {
632                         $<list>$ = g_list_append(NULL,$<id>1);
633                                                 }
634         ;
635
636
637 type:           specifier_list pointer                          {
638                         Node *node = new_type($<id>1, $<id>2, NULL);
639                         typestack = g_list_prepend(typestack,node);
640                                                         }
641         |       specifier_list                          {
642                         Node *node = new_type($<id>1, NULL, NULL);
643                         typestack = g_list_prepend(typestack,node);
644                                                         }
645         ;
646
647 /* The special cases are neccessary to avoid conflicts */
648 specifier_list: spec_list                               {
649                         $<id>$ = $<id>1;
650                                                         }
651         |       TOKEN                                   {
652                         $<id>$ = $<id>1;
653                                                         }
654         |       CONST TOKEN                             {
655                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
656                         g_free($<id>2);
657                                                         }
658         |       TOKEN CONST                             {
659                         $<id>$ = g_strconcat($<id>1, " const", NULL);
660                         g_free($<id>1);
661                                                         }
662         |       strunionenum TOKEN                      {
663                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
664                         g_free($<id>2);
665                                                         }
666         |       CONST strunionenum TOKEN                {
667                         $<id>$ = g_strconcat("const ", $<id>2, " ",
668                                              $<id>3, NULL);
669                         g_free($<id>3);
670                                                         }
671         |       strunionenum TOKEN CONST                {
672                         $<id>$ = g_strconcat($<id>1, " ",
673                                              $<id>2, " const", NULL);
674                         g_free($<id>2);
675                                                         }
676         ;
677
678 /* The special const cases take care of conflicts ! */
679 spec_list:      specifier spec_list                     {
680                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
681                         g_free($<id>2);
682                                                         }
683         |       TYPETOKEN spec_list                     {
684                         $<id>$ = g_strconcat($<id>1, " ", $<id>2, NULL);
685                         g_free($<id>1);
686                         g_free($<id>2);
687                                                         }
688         |       CONST spec_list                         {
689                         $<id>$ = g_strconcat("const ", $<id>2, NULL);
690                         g_free($<id>2);
691                                                         }
692         |       TYPETOKEN                               {
693                         $<id>$ = $<id>1;
694                                                         }
695         |       TYPETOKEN CONST                         {
696                         $<id>$ = g_strconcat($<id>1, " const", NULL);
697                         g_free($<id>1);
698                                                         }
699         |       specifier                               {
700                         $<id>$ = g_strdup($<id>1);
701                                                         }
702         |       specifier CONST                         {
703                         $<id>$ = g_strconcat($<id>1, " const", NULL);
704                                                         }
705         ;
706
707 specifier:      VOID                    { $<id>$ = "void"; }
708         |       CHAR                    { $<id>$ = "char"; }
709         |       SHORT                   { $<id>$ = "short"; }
710         |       INT                     { $<id>$ = "int"; }
711         |       LONG                    { $<id>$ = "long"; }
712         |       FLOAT                   { $<id>$ = "float"; }
713         |       DOUBLE                  { $<id>$ = "double"; }
714         |       SIGNED                  { $<id>$ = "signed"; }
715         |       UNSIGNED                { $<id>$ = "unsigned"; }
716         ;
717
718 strunionenum:   STRUCT                  { $<id>$ = "struct"; }
719         |       UNION                   { $<id>$ = "union"; }
720         |       ENUM                    { $<id>$ = "enum"; }
721         ;
722
723 pointer:        '*'                     { $<id>$ = g_strdup("*"); }
724         |       '*' CONST               { $<id>$ = g_strdup("* const"); }
725         |       '*' pointer             {
726                                 $<id>$ = g_strconcat("*", $<id>2, NULL);
727                                 g_free($<id>2);
728                                         }
729         |       '*' CONST pointer       {
730                                 $<id>$ = g_strconcat("* const", $<id>3, NULL);
731                                 g_free($<id>3);
732                                         }
733         ;
734
735 /* this never sets the_scope */
736 simplesigtype:  TOKEN sigtype   {
737                         if(strcmp($<id>1, "first")==0)
738                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
739                         else if(strcmp($<id>1, "last")==0)
740                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
741                         else {
742                                 yyerror(_("signal must be 'first' or 'last'"));
743                                 g_free($<id>1);
744                                 YYERROR;
745                         }
746                         g_free($<id>1);
747                                         }
748         |       sigtype                 {
749                         $<sigtype>$ = SIGNAL_LAST_METHOD;
750                                         }
751         ;
752
753 /* this always sets the_scope */
754 fullsigtype:    scope TOKEN sigtype     {
755                         if(strcmp($<id>2,"first")==0)
756                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
757                         else if(strcmp($<id>2,"last")==0)
758                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
759                         else {
760                                 yyerror(_("signal must be 'first' or 'last'"));
761                                 g_free($<id>2);
762                                 YYERROR;
763                         }
764                         g_free($<id>2);
765                                         }
766         |       TOKEN scope sigtype     {
767                         if(strcmp($<id>1,"first")==0)
768                                 $<sigtype>$ = SIGNAL_FIRST_METHOD;
769                         else if(strcmp($<id>1,"last")==0)
770                                 $<sigtype>$ = SIGNAL_LAST_METHOD;
771                         else {
772                                 yyerror(_("signal must be 'first' or 'last'"));
773                                 g_free($<id>1);
774                                 YYERROR;
775                         }
776                         g_free($<id>1);
777                                         }
778         |       scope sigtype           {
779                         $<sigtype>$ = SIGNAL_LAST_METHOD;
780                                         }
781         |       simplesigtype           {
782                         /* the_scope was default thus public */
783                         the_scope = PUBLIC_SCOPE;
784                                         }
785         ;
786         
787 sigtype:        TOKEN '(' tokenlist ')'         {
788                         gtktypes = g_list_prepend(gtktypes, $<id>1);
789                                                 }
790         ;
791
792 tokenlist:      tokenlist ',' TOKEN             {
793                         gtktypes = g_list_append(gtktypes, $<id>3);
794                                                 }
795         |       TOKEN                           { 
796                         gtktypes = g_list_append(gtktypes, $<id>1);
797                                                 }
798         ;
799
800 codenocode:     '{' CCODE                       { $<cbuf>$ = $<cbuf>2; }
801         |       ';'                             { $<cbuf>$ = NULL; }
802         ;
803
804 /*here CCODE will include the ending '}' */
805 method:         SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
806                         if(!has_self) {
807                                 yyerror(_("signal without 'self' as "
808                                           "first parameter"));
809                                 free_all_global_state();
810                                 YYERROR;
811                         }
812                         if(the_scope == CLASS_SCOPE) {
813                                 yyerror(_("a method cannot be of class scope"));
814                                 free_all_global_state();
815                                 YYERROR;
816                         }
817                         push_function(the_scope, $<sigtype>3,NULL,
818                                       $<id>5, $<cbuf>10,$<line>1,
819                                       ccode_line, vararg, $<list>2);
820                                                                         }
821         |       scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
822                         if(!has_self) {
823                                 yyerror(_("signal without 'self' as "
824                                           "first parameter"));
825                                 free_all_global_state();
826                                 YYERROR;
827                         }
828                         if(the_scope == CLASS_SCOPE) {
829                                 yyerror(_("a method cannot be of class scope"));
830                                 free_all_global_state();
831                                 YYERROR;
832                         }
833                         push_function(the_scope, $<sigtype>4, NULL,
834                                       $<id>6, $<cbuf>11, $<line>2,
835                                       ccode_line, vararg, $<list>3);
836                                                                         }
837         |       VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
838                         if(!has_self) {
839                                 yyerror(_("virtual method without 'self' as "
840                                           "first parameter"));
841                                 free_all_global_state();
842                                 YYERROR;
843                         }
844                         if(the_scope == CLASS_SCOPE) {
845                                 yyerror(_("a method cannot be of class scope"));
846                                 free_all_global_state();
847                                 YYERROR;
848                         }
849                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
850                                       $<cbuf>9, $<line>1,
851                                       ccode_line, vararg, NULL);
852                                                                         }
853         |       scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
854                         if(!has_self) {
855                                 yyerror(_("virtual method without 'self' as "
856                                           "first parameter"));
857                                 free_all_global_state();
858                                 YYERROR;
859                         }
860                         if(the_scope == CLASS_SCOPE) {
861                                 yyerror(_("a method cannot be of class scope"));
862                                 free_all_global_state();
863                                 YYERROR;
864                         }
865                         push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
866                                       $<cbuf>9, $<line>2,
867                                       ccode_line, vararg, NULL);
868                                                                         }
869         |       VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode       {
870                         if(!has_self) {
871                                 yyerror(_("virtual method without 'self' as "
872                                           "first parameter"));
873                                 free_all_global_state();
874                                 YYERROR;
875                         }
876                         push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
877                                       $<id>3, $<cbuf>8, $<line>1,
878                                       ccode_line, vararg, NULL);
879                                                                         }
880         |       OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode    {
881                         push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
882                                       $<id>6, $<cbuf>11,
883                                       $<line>1, ccode_line,
884                                       vararg, NULL);
885                                                                         }
886         |       scope type TOKEN '(' funcargs ')' returnvals codenocode {
887                         if(the_scope == CLASS_SCOPE) {
888                                 yyerror(_("a method cannot be of class scope"));
889                                 free_all_global_state();
890                                 YYERROR;
891                         }
892                         push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
893                                       $<cbuf>8, $<line>1, ccode_line,
894                                       vararg, NULL);
895                                                                 }
896         |       TOKEN '(' TOKEN ')' codenocode  {
897                         if(strcmp($<id>1, "init")==0) {
898                                 push_init_arg($<id>3,FALSE);
899                                 push_function(NO_SCOPE, INIT_METHOD, NULL,
900                                               $<id>1, $<cbuf>5, $<line>2,
901                                               ccode_line, FALSE, NULL);
902                         } else if(strcmp($<id>1, "class_init")==0) {
903                                 push_init_arg($<id>3,TRUE);
904                                 push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
905                                               $<id>1, $<cbuf>5, $<line>2,
906                                               ccode_line, FALSE, NULL);
907                         } else {
908                                 g_free($<id>1);
909                                 g_free($<id>3);
910                                 g_string_free($<cbuf>5,TRUE);
911                                 yyerror(_("parse error "
912                                           "(untyped blocks must be init or "
913                                           "class_init)"));
914                                 YYERROR;
915                         }
916                                                 }
917         ;
918
919 returnvals:     TOKEN retcode           {
920                         g_free(onerror); onerror = NULL;
921                         g_free(defreturn); defreturn = NULL;
922                         if(!set_return_value($<id>1, $<id>2)) {
923                                 g_free($<id>1);
924                                 g_free($<id>2);
925                                 yyerror(_("parse error"));
926                                 YYERROR;
927                         }
928                         g_free($<id>1);
929                                         }
930         |       TOKEN retcode TOKEN retcode     {
931                         g_free(onerror); onerror = NULL;
932                         g_free(defreturn); defreturn = NULL;
933                         if(!set_return_value($<id>1, $<id>2)) {
934                                 g_free($<id>1); g_free($<id>2);
935                                 g_free($<id>3); g_free($<id>4);
936                                 yyerror(_("parse error"));
937                                 YYERROR;
938                         }
939                         if(!set_return_value($<id>3, $<id>4)) {
940                                 onerror = defreturn = NULL;
941                                 g_free($<id>1); g_free($<id>2);
942                                 g_free($<id>3); g_free($<id>4);
943                                 yyerror(_("parse error"));
944                                 YYERROR;
945                         }
946                         g_free($<id>1);
947                         g_free($<id>3);
948                                                 }
949         |                               {
950                         g_free(onerror); onerror = NULL;
951                         g_free(defreturn); defreturn = NULL;
952                                         }
953         ;
954
955 retcode:        numtok                  { $<id>$ = $<id>1; }
956         |       '{' CCODE               {
957                         $<id>$ = ($<cbuf>3)->str;
958                         g_string_free($<cbuf>3, FALSE);
959                                         }
960         ;
961         
962 funcargs:       VOID                    { vararg = FALSE; has_self = FALSE; }
963         |       TOKEN                   {
964                         vararg = FALSE;
965                         has_self = TRUE;
966                         if(strcmp($<id>1,"self")==0)
967                                 push_self($<id>1, FALSE);
968                         else {
969                                 g_free($<id>1);
970                                 yyerror(_("parse error"));
971                                 YYERROR;
972                         }
973                                         }
974         |       TOKEN CONST {
975                         vararg = FALSE;
976                         has_self = TRUE;
977                         if(strcmp($<id>1,"self")==0)
978                                 push_self($<id>1, TRUE);
979                         else {
980                                 g_free($<id>1);
981                                 yyerror(_("parse error"));
982                                 YYERROR;
983                         }
984                                         }
985         |       CONST TOKEN {
986                         vararg = FALSE;
987                         has_self = TRUE;
988                         if(strcmp($<id>2,"self")==0)
989                                 push_self($<id>2, TRUE);
990                         else {
991                                 g_free($<id>2);
992                                 yyerror(_("parse error"));
993                                 YYERROR;
994                         }
995                                         }
996         |       TOKEN ',' arglist       {
997                         has_self = TRUE;
998                         if(strcmp($<id>1,"self")==0)
999                                 push_self($<id>1, FALSE);
1000                         else {
1001                                 g_free($<id>1);
1002                                 yyerror(_("parse error"));
1003                                 YYERROR;
1004                         }
1005                                         }
1006         |       TOKEN CONST ',' arglist {
1007                         has_self = TRUE;
1008                         if(strcmp($<id>1,"self")==0)
1009                                 push_self($<id>1, TRUE);
1010                         else {
1011                                 g_free($<id>1);
1012                                 yyerror(_("parse error"));
1013                                 YYERROR;
1014                         }
1015                                         }
1016         |       CONST TOKEN ',' arglist {
1017                         has_self = TRUE;
1018                         if(strcmp($<id>2,"self")==0)
1019                                 push_self($<id>2, TRUE);
1020                         else {
1021                                 g_free($<id>2);
1022                                 yyerror(_("parse error"));
1023                                 YYERROR;
1024                         }
1025                                         }
1026         |       arglist                 { has_self = FALSE; }
1027         ;
1028
1029 arglist:        arglist1 ',' THREEDOTS  { vararg = TRUE; }
1030         |       arglist1                { vararg = FALSE; }
1031         ;
1032         
1033 arglist1:       arglist1 ',' arg        { ; }
1034         |       arg                     { ; }
1035         ;
1036
1037 arg:            type TOKEN                                      {
1038                         push_funcarg($<id>2,NULL);
1039                                                                 }
1040         |       type TOKEN ARRAY_DIM                            {
1041                         push_funcarg($<id>2,$<id>3);
1042                                                                 }
1043         |       type TOKEN '(' TOKEN checklist ')'              {
1044                         if(strcmp($<id>4,"check")!=0) {
1045                                 yyerror(_("parse error"));
1046                                 YYERROR;
1047                         }
1048                         g_free($<id>4);
1049                         push_funcarg($<id>2,NULL);
1050                                                                 }
1051         |       type TOKEN ARRAY_DIM '(' TOKEN checklist ')'    {
1052                         if(strcmp($<id>5,"check")!=0) {
1053                                 yyerror(_("parse error"));
1054                                 YYERROR;
1055                         }
1056                         g_free($<id>5);
1057                         push_funcarg($<id>2,$<id>3);
1058                                                                 }
1059         ;
1060         
1061 checklist:      checklist check         { ; }
1062         |       check                   { ; }
1063         ;
1064
1065 check:          TOKEN                   {
1066                         if(strcmp($<id>1,"type")==0) {
1067                                 Node *node = new_check(TYPE_CHECK,NULL);
1068                                 checks = g_list_append(checks,node);
1069                         } else if(strcmp($<id>1,"null")==0) {
1070                                 Node *node = new_check(NULL_CHECK,NULL);
1071                                 checks = g_list_append(checks,node);
1072                         } else {
1073                                 yyerror(_("parse error"));
1074                                 YYERROR;
1075                         }
1076                         g_free($<id>1);
1077                                         }
1078         |       '>' numtok              {
1079                         Node *node = new_check(GT_CHECK,$<id>2);
1080                         checks = g_list_append(checks,node);
1081                                         }
1082         |       '<' numtok              {
1083                         Node *node = new_check(LT_CHECK,$<id>2);
1084                         checks = g_list_append(checks,node);
1085                                         }
1086         |       '>' '=' numtok          {
1087                         Node *node = new_check(GE_CHECK,$<id>3);
1088                         checks = g_list_append(checks,node);
1089                                         }
1090         |       '<' '=' numtok          {
1091                         Node *node = new_check(LE_CHECK,$<id>3);
1092                         checks = g_list_append(checks,node);
1093                                         }
1094         |       '=' '=' numtok          {
1095                         Node *node = new_check(EQ_CHECK,$<id>3);
1096                         checks = g_list_append(checks,node);
1097                                         }
1098         |       '!' '=' numtok          {
1099                         Node *node = new_check(NE_CHECK,$<id>3);
1100                         checks = g_list_append(checks,node);
1101                                         }
1102         ;
1103         
1104 numtok:         NUMBER                  { $<id>$ = $<id>1; }
1105         |       '-' NUMBER              {
1106                         $<id>$ = g_strconcat("-",$<id>2,NULL);
1107                         g_free($<id>2);
1108                                         }
1109         |       TOKEN                   { $<id>$ = $<id>1; }
1110         ;
1111         
1112 %%