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