2 * Copyright (C) 1999 the Free Software Foundation.
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.
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.
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,
33 extern char *filename;
37 static GList *class_nodes = NULL;
40 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;
47 static GList *gtktypes = NULL;
52 extern int ccode_line;
63 if(strcmp(yytext,"\n")==0) {
64 out=g_strconcat("Error: ",str," before newline",NULL);
65 } else if(yytext[0]=='\0') {
66 out=g_strconcat("Error: ",str," at end of input",NULL);
68 char *tmp = g_strdup(yytext);
69 while((p=strchr(tmp,'\n')))
72 out=g_strconcat("Error: ",str," before '",tmp,"'",NULL);
76 fprintf(stderr,"%s:%d: %s\n",filename,line_no,out);
83 push_variable(char *name, int scope, int line_no, char *postfix)
86 Type *type = typestack->data;
87 typestack = g_list_remove(typestack,typestack->data);
89 type->postfix = postfix;
91 var = new_variable(scope,type,name,line_no);
92 class_nodes = g_list_append(class_nodes, var);
96 push_function(int scope, char *oid, char *id, char *onerror,
97 GString *cbuf,int line_no, int ccode_line, int vararg)
102 if(scope!=INIT_METHOD && scope!=CLASS_INIT_METHOD) {
103 type = typestack->data;
104 typestack = g_list_remove(typestack,typestack->data);
106 type = (Type *)new_type(0,g_strdup("void"),NULL);
109 /* a complicated and ugly test to figure out if we have
110 the wrong number of types for a signal */
111 if((scope == SIGNAL_FIRST_METHOD ||
112 scope == SIGNAL_LAST_METHOD ||
113 scope == PRIVATE_SIGNAL_FIRST_METHOD ||
114 scope == PRIVATE_SIGNAL_LAST_METHOD) &&
115 g_list_length(gtktypes) != g_list_length(funcargs) &&
116 !(g_list_length(funcargs) == 1 &&
117 g_list_length(gtktypes) == 2 &&
118 strcmp(gtktypes->next->data,"NONE")==0)) {
119 print_error(TRUE, _("The number of GTK arguments and "
120 "function arguments for a signal "
121 "don't seem to match"),line_no);
123 node = new_method(scope,type,oid,gtktypes,id,funcargs,
124 onerror,cbuf,line_no,ccode_line,vararg);
128 class_nodes = g_list_append(class_nodes, node);
132 push_funcarg(char *name, char *postfix)
135 Type *type = typestack->data;
136 typestack = g_list_remove(typestack,typestack->data);
138 type->postfix = postfix;
140 node = new_funcarg(type,name,checks);
143 funcargs = g_list_append(funcargs, node);
147 push_init_arg(char *name, int is_class)
154 tn = g_strconcat(((Class *)class)->otype,":Class",NULL);
156 tn = g_strdup(((Class *)class)->otype);
158 type = new_type(1,tn,NULL);
159 node = new_funcarg((Type *)type,name,NULL);
160 funcargs = g_list_prepend(funcargs, node);
169 type = new_type(1,g_strdup(((Class *)class)->otype),NULL);
170 ch = g_list_append(ch,new_check(NULL_CHECK,NULL));
171 ch = g_list_append(ch,new_check(TYPE_CHECK,NULL));
172 node = new_funcarg((Type *)type,id,ch);
173 funcargs = g_list_prepend(funcargs, node);
187 %token CONST VOID STRUCT UNION ENUM THREEDOTS
188 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
191 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM
192 %token <cbuf> CCODE HCODE
193 %token <line> PUBLIC PRIVATE ARGUMENT VIRTUAL SIGNAL OVERRIDE
197 prog: ccodes class ccodes { ; }
203 ccodes: ccodes CCODE {
204 Node *node = new_ccode(FALSE,$<cbuf>2,ccode_line);
205 nodes = g_list_append(nodes,node);
208 Node *node = new_ccode(TRUE,$<cbuf>2,ccode_line);
209 nodes = g_list_append(nodes,node);
212 Node *node = new_ccode(FALSE,$<cbuf>1,ccode_line);
213 nodes = g_list_append(nodes,node);
216 Node *node = new_ccode(TRUE,$<cbuf>1,ccode_line);
217 nodes = g_list_append(nodes,node);
221 class: classdec '{' classcode '}' {
222 ((Class *)class)->nodes = class_nodes;
224 nodes = g_list_append(nodes,class);
227 ((Class *)class)->nodes = NULL;
229 nodes = g_list_append(nodes,class);
233 classdec: CLASS TYPETOKEN FROM TYPETOKEN {
234 class = new_class($<id>2,$<id>4,NULL);
238 classcode: classcode method { ; }
239 | classcode variable { ; }
240 | classcode argument { ; }
246 variable: PUBLIC type TOKEN ';' {
247 push_variable($<id>3,PUBLIC_SCOPE,$<line>1,NULL);
249 | PUBLIC type TOKEN ARRAY_DIM ';' {
250 push_variable($<id>3,PUBLIC_SCOPE,$<line>1,$<id>4);
252 | PRIVATE type TOKEN ';' {
253 push_variable($<id>3,PRIVATE_SCOPE,$<line>1,NULL);
255 | PRIVATE type TOKEN ARRAY_DIM ';' {
256 push_variable($<id>3,PRIVATE_SCOPE,$<line>1,$<id>4);
259 argument: ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' {
260 if(strcmp($<id>5,"get")==0 &&
261 strcmp($<id>8,"set")==0) {
263 g_free($<id>5); g_free($<id>8);
264 node = new_argument($<id>3,$<list>2,$<id>4,
268 class_nodes = g_list_append(class_nodes,node);
269 } else if(strcmp($<id>5,"set")==0 &&
270 strcmp($<id>8,"get")==0) {
272 g_free($<id>5); g_free($<id>8);
273 node = new_argument($<id>3,$<list>2,$<id>4,
277 class_nodes = g_list_append(class_nodes,node);
279 g_free($<id>3); g_free($<id>4);
280 g_free($<id>5); g_free($<id>8);
281 g_list_foreach($<list>2,(GFunc)g_free,NULL);
282 g_string_free($<cbuf>10,TRUE);
283 g_string_free($<cbuf>7,TRUE);
284 yyerror(_("parse error"));
288 | ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE ';' {
289 if(strcmp($<id>5,"get")==0) {
292 node = new_argument($<id>3,$<list>2,$<id>4,
293 $<cbuf>7,$<line>6,NULL,0,
295 class_nodes = g_list_append(class_nodes,node);
296 } else if(strcmp($<id>5,"set")==0) {
299 node = new_argument($<id>3,$<list>2,$<id>4,
300 NULL,0,$<cbuf>7,$<line>6,
302 class_nodes = g_list_append(class_nodes,node);
304 g_free($<id>5); g_free($<id>3);
306 g_list_foreach($<list>2,(GFunc)g_free,NULL);
307 g_string_free($<cbuf>7,TRUE);
308 yyerror(_("parse error"));
314 argflags: '(' flaglist ')' { $<list>$ = $<list>2; }
315 | { $<list>$ = NULL; }
318 flaglist: TOKEN '|' flaglist {
319 $<list>$ = g_list_append($<list>3,$<id>1);
322 $<list>$ = g_list_append(NULL,$<id>1);
329 Type *type = typestack->data;
330 char *oldname = type->name;
331 type->name = g_strconcat("const ",oldname,NULL);
337 Node *node = new_type(0,$<id>1,NULL);
338 typestack = g_list_prepend(typestack,node);
341 Node *node = new_type(stars,$<id>1,NULL);
343 typestack = g_list_prepend(typestack,node);
347 type2: UNSIGNED integer {
348 $<id>$ = g_strconcat("unsigned ",$<id>2,NULL);
351 $<id>$ = g_strconcat("signed ",$<id>2,NULL);
354 $<id>$ = g_strdup($<id>1);
357 $<id>$ = g_strdup("unsigned char");
360 $<id>$ = g_strdup("signed char");
363 $<id>$ = g_strdup("char");
366 $<id>$ = g_strdup("double");
369 $<id>$ = g_strdup("float");
375 $<id>$ = g_strconcat($<id>1,$<id>2,NULL);
382 $<id>$ = g_strdup("void");
393 $<id>$ = "short int";
414 stars: '*' stars { stars++; }
422 fullsigtype: PRIVATE TOKEN sigtype {
423 if(strcmp($<id>2,"first")==0)
424 $<sigtype>$ = PRIVATE_SIGNAL_FIRST_METHOD;
425 else if(strcmp($<id>2,"last")==0)
426 $<sigtype>$ = PRIVATE_SIGNAL_LAST_METHOD;
428 yyerror(_("signal must be 'first' or 'last'"));
434 | TOKEN PRIVATE sigtype {
435 if(strcmp($<id>1,"first")==0)
436 $<sigtype>$ = PRIVATE_SIGNAL_FIRST_METHOD;
437 else if(strcmp($<id>1,"last")==0)
438 $<sigtype>$ = PRIVATE_SIGNAL_LAST_METHOD;
440 yyerror(_("signal must be 'first' or 'last'"));
447 $<sigtype>$ = PRIVATE_SIGNAL_LAST_METHOD;
450 if(strcmp($<id>1,"first")==0)
451 $<sigtype>$ = SIGNAL_FIRST_METHOD;
452 else if(strcmp($<id>1,"last")==0)
453 $<sigtype>$ = SIGNAL_LAST_METHOD;
455 yyerror(_("signal must be 'first' or 'last'"));
461 | PUBLIC TOKEN sigtype {
462 if(strcmp($<id>2,"first")==0)
463 $<sigtype>$ = SIGNAL_FIRST_METHOD;
464 else if(strcmp($<id>2,"last")==0)
465 $<sigtype>$ = SIGNAL_LAST_METHOD;
467 yyerror(_("signal must be 'first' or 'last'"));
473 | TOKEN PUBLIC sigtype {
474 if(strcmp($<id>1,"first")==0)
475 $<sigtype>$ = SIGNAL_FIRST_METHOD;
476 else if(strcmp($<id>1,"last")==0)
477 $<sigtype>$ = SIGNAL_LAST_METHOD;
479 yyerror(_("signal must be 'first' or 'last'"));
486 $<sigtype>$ = SIGNAL_LAST_METHOD;
489 $<sigtype>$ = SIGNAL_LAST_METHOD;
493 sigtype: TOKEN '(' tokenlist ')' {
494 gtktypes = g_list_prepend(gtktypes,$<id>1);
498 tokenlist: tokenlist ',' TOKEN {
499 gtktypes = g_list_append(gtktypes,$<id>3);
502 gtktypes = g_list_append(gtktypes,$<id>1);
506 codenocode: '{' CCODE { $<cbuf>$=$<cbuf>2; }
507 | ';' { $<cbuf>$ = NULL; }
510 /*here CCODE will include the ending '}' */
511 method: SIGNAL fullsigtype type TOKEN '(' funcargs ')' onerror codenocode {
513 yyerror(_("signal without 'self' as "
517 push_function($<sigtype>2,NULL,
518 $<id>4, $<id>8, $<cbuf>9,$<line>1,
521 | VIRTUAL PRIVATE type TOKEN '(' funcargs ')' onerror codenocode {
523 yyerror(_("virtual method without 'self' as "
527 push_function(PRIVATE_VIRTUAL_METHOD, NULL, $<id>4,
528 $<id>8, $<cbuf>9,$<line>1,
531 | VIRTUAL optpublic type TOKEN '(' funcargs ')' onerror codenocode {
533 yyerror(_("virtual method without 'self' as "
537 push_function(VIRTUAL_METHOD, NULL, $<id>4,
538 $<id>8, $<cbuf>9,$<line>1,
541 | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' onerror '{' CCODE {
542 push_function(OVERRIDE_METHOD, $<id>3,
543 $<id>6, $<id>10, $<cbuf>12,
547 | PUBLIC type TOKEN '(' funcargs ')' onerror '{' CCODE {
548 push_function(PUBLIC_SCOPE, NULL, $<id>3,
549 $<id>7, $<cbuf>9,$<line>1,$<line>8,
552 | PRIVATE type TOKEN '(' funcargs ')' onerror '{' CCODE {
553 push_function(PRIVATE_SCOPE, NULL, $<id>3,
554 $<id>7, $<cbuf>9,$<line>1,$<line>8,
557 | TOKEN '(' TOKEN ')' codenocode {
558 if(strcmp($<id>1,"init")==0) {
559 push_init_arg($<id>3,FALSE);
560 push_function(INIT_METHOD, NULL,
561 $<id>1, NULL, $<cbuf>5,$<line>2,
563 } else if(strcmp($<id>1,"class_init")==0) {
564 push_init_arg($<id>3,TRUE);
565 push_function(CLASS_INIT_METHOD, NULL,
566 $<id>1, NULL, $<cbuf>5,$<line>2,
571 g_string_free($<cbuf>3,TRUE);
572 yyerror(_("parse error"));
578 onerror: ONERROR numtok { $<id>$ = $<id>2; }
579 | ONERROR '{' CCODE {
580 $<id>$ = ($<cbuf>3)->str;
581 g_string_free($<cbuf>3,FALSE);
587 funcargs: VOID { vararg = FALSE; has_self = FALSE; }
591 if(strcmp($<id>1,"self")==0)
595 yyerror(_("parse error"));
599 | TOKEN ',' arglist {
601 if(strcmp($<id>1,"self")==0)
605 yyerror(_("parse error"));
609 | arglist { has_self = FALSE; }
612 arglist: arglist1 ',' THREEDOTS { vararg = TRUE; }
613 | arglist1 { vararg = FALSE; }
616 arglist1: arglist1 ',' arg { ; }
621 push_funcarg($<id>2,NULL);
623 | type TOKEN ARRAY_DIM {
624 push_funcarg($<id>2,$<id>3);
626 | type TOKEN '(' TOKEN checklist ')' {
627 if(strcmp($<id>4,"check")!=0) {
628 yyerror(_("parse error"));
632 push_funcarg($<id>2,NULL);
634 | type TOKEN ARRAY_DIM '(' TOKEN checklist ')' {
635 if(strcmp($<id>5,"check")!=0) {
636 yyerror(_("parse error"));
640 push_funcarg($<id>2,$<id>3);
644 checklist: checklist check { ; }
649 if(strcmp($<id>1,"type")==0) {
650 Node *node = new_check(TYPE_CHECK,NULL);
651 checks = g_list_append(checks,node);
652 } else if(strcmp($<id>1,"null")==0) {
653 Node *node = new_check(NULL_CHECK,NULL);
654 checks = g_list_append(checks,node);
656 yyerror(_("parse error"));
662 Node *node = new_check(GT_CHECK,$<id>2);
663 checks = g_list_append(checks,node);
666 Node *node = new_check(LT_CHECK,$<id>2);
667 checks = g_list_append(checks,node);
670 Node *node = new_check(GE_CHECK,$<id>3);
671 checks = g_list_append(checks,node);
674 Node *node = new_check(LE_CHECK,$<id>3);
675 checks = g_list_append(checks,node);
678 Node *node = new_check(EQ_CHECK,$<id>3);
679 checks = g_list_append(checks,node);
682 Node *node = new_check(NE_CHECK,$<id>3);
683 checks = g_list_append(checks,node);
687 numtok: NUMBER { $<id>$ = $<id>1; }
689 $<id>$ = g_strconcat("-",$<id>2,NULL);
692 | TOKEN { $<id>$ = $<id>1; }