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