X-Git-Url: https://git.draconx.ca/gitweb/gob-dx.git/blobdiff_plain/3b10bbd3a88d6e16146414d91d06bb2f36347bfc..4f7cfa972623842e64e3a8468696f1f6f40fd202:/src/parse.y diff --git a/src/parse.y b/src/parse.y index d0b56fe..17ab264 100644 --- a/src/parse.y +++ b/src/parse.y @@ -25,7 +25,7 @@ #include #include -#include "tree.h" +#include "treefuncs.h" #include "main.h" #include "util.h" @@ -50,6 +50,9 @@ static gboolean destructor_simple = TRUE; static char *initializer = NULL; static int initializer_line = 0; +static char *onerror = NULL; +static char *defreturn = NULL; + static GList *gtktypes = NULL; /* this can be a global as we will only do one function at a time @@ -73,17 +76,17 @@ yyerror(char *str) if(strcmp(yytext,"\n")==0) { out=g_strconcat("Error: ",str," before newline",NULL); } else if(yytext[0]=='\0') { - out=g_strconcat("Error: ",str," at end of input",NULL); + out=g_strconcat("Error: ", str, " at end of input", NULL); } else { char *tmp = g_strdup(yytext); - while((p=strchr(tmp,'\n'))) + while((p=strchr(tmp, '\n'))) *p='.'; - out=g_strconcat("Error: ",str," before '",tmp,"'",NULL); + out=g_strconcat("Error: ", str, " before '", tmp, "'", NULL); g_free(tmp); } - fprintf(stderr,"%s:%d: %s\n",filename,line_no,out); + fprintf(stderr, "%s:%d: %s\n", filename, line_no, out); g_free(out); exit(1); @@ -113,13 +116,15 @@ push_variable(char *name, int scope, int line_no, char *postfix) } static void -push_function(int scope, int method, char *oid, char *id, char *onerror, - GString *cbuf, int line_no, int ccode_line, gboolean vararg, - GList *flags) +push_function(int scope, int method, char *oid, char *id, + GString *cbuf, int line_no, int ccode_line, + gboolean vararg, GList *flags) { Node *node; Type *type; char *c_cbuf; + + g_assert(scope != CLASS_SCOPE); if(method!=INIT_METHOD && method!=CLASS_INIT_METHOD) { type = pop_type(); @@ -134,10 +139,21 @@ push_function(int scope, int method, char *oid, char *id, char *onerror, g_list_length(gtktypes) != g_list_length(funcargs) && !(g_list_length(funcargs) == 1 && g_list_length(gtktypes) == 2 && - strcmp(gtktypes->next->data,"NONE")==0)) { + strcmp(gtktypes->next->data, "NONE")==0)) { print_error(TRUE, _("The number of GTK arguments and " "function arguments for a signal " - "don't seem to match"),line_no); + "don't seem to match"), line_no); + } + if(g_list_length(gtktypes) > 2) { + GList *li; + for(li = gtktypes->next; li; li = li->next) { + if(strcmp(li->data, "NONE")==0) { + print_error(FALSE, + _("NONE can only appear in an " + "argument list by itself"), + line_no); + } + } } if(cbuf) { char *p; @@ -150,7 +166,7 @@ push_function(int scope, int method, char *oid, char *id, char *onerror, c_cbuf = NULL; node = new_method(scope, method, type, oid, gtktypes, flags, - id, funcargs, onerror, c_cbuf, line_no, + id, funcargs, onerror, defreturn, c_cbuf, line_no, ccode_line, vararg); if(cbuf) @@ -161,9 +177,28 @@ push_function(int scope, int method, char *oid, char *id, char *onerror, gtktypes = NULL; funcargs = NULL; + onerror = NULL; + defreturn = NULL; + class_nodes = g_list_append(class_nodes, node); } +static void +free_all_global_state(void) +{ + g_free(onerror); + onerror = NULL; + g_free(defreturn); + defreturn = NULL; + + g_list_foreach(gtktypes, (GFunc)g_free, NULL); + g_list_free(gtktypes); + gtktypes = NULL; + + free_node_list(funcargs); + funcargs = NULL; +} + static void push_funcarg(char *name, char *postfix) { @@ -172,7 +207,7 @@ push_funcarg(char *name, char *postfix) type->postfix = postfix; - node = new_funcarg(type,name,checks); + node = new_funcarg(type, name, checks); checks = NULL; funcargs = g_list_append(funcargs, node); @@ -231,6 +266,25 @@ find_var_or_die(const char *id, int line) return NULL; } +static gboolean +set_return_value(char *type, char *val) +{ + if(strcmp(type, "onerror")==0) { + if(!onerror) { + onerror = val; + return TRUE; + } else + return FALSE; + } else if(strcmp(type, "defreturn")==0) { + if(!defreturn) { + defreturn = val; + return TRUE; + } else + return FALSE; + } + return FALSE; +} + %} %union { @@ -244,11 +298,10 @@ find_var_or_die(const char *id, int line) %token CLASS FROM %token CONST VOID STRUCT UNION ENUM THREEDOTS %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR -%token ONERROR %token TOKEN NUMBER TYPETOKEN ARRAY_DIM %token CCODE HTCODE PHCODE HCODE ACODE ATCODE -%token PUBLIC PRIVATE PROTECTED ARGUMENT VIRTUAL SIGNAL OVERRIDE +%token PUBLIC PRIVATE PROTECTED CLASSWIDE ARGUMENT VIRTUAL SIGNAL OVERRIDE %% @@ -330,13 +383,14 @@ thing: method { ; } scope: PUBLIC { the_scope = PUBLIC_SCOPE; } | PRIVATE { the_scope = PRIVATE_SCOPE; } | PROTECTED { the_scope = PROTECTED_SCOPE; } + | CLASSWIDE { the_scope = CLASS_SCOPE; } ; destructor: TOKEN TOKEN { if(strcmp($1, "destroywith")==0) { g_free($1); destructor = $2; - destructor_line = ccode_line; + destructor_line = line_no; destructor_simple = TRUE; } else { g_free($1); @@ -455,14 +509,14 @@ argument: ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { } | ARGUMENT flags argtype TOKEN TOKEN { Node *node; - char *get, *set; + char *get, *set = NULL; Variable *var; Type *type; char *root; - if(strcmp($5,"link")!=0 && - strcmp($5,"stringlink")!=0 && - strcmp($5,"objectlink")!=0) { + if(strcmp($5, "link")!=0 && + strcmp($5, "stringlink")!=0 && + strcmp($5, "objectlink")!=0) { g_free($5); g_free($3); g_free($4); g_list_foreach($2,(GFunc)g_free,NULL); @@ -475,24 +529,29 @@ argument: ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { var = find_var_or_die($4, $1); if(var->scope == PRIVATE_SCOPE) root = "self->_priv"; + else if(var->scope == CLASS_SCOPE) + root = "SELF_CLASS(GTK_OBJECT(self)->klass)"; else root = "self"; - if(strcmp($5,"link")==0) { + if(strcmp($5, "link")==0) { set = g_strdup_printf("%s->%s = ARG;", root, $4); - } else if(strcmp($5,"stringlink")==0) { + } else if(strcmp($5, "stringlink")==0) { set = g_strdup_printf("g_free(%s->%s); " "%s->%s = g_strdup(ARG);", root, $4, root, $4); - } else if(strcmp($5,"objectlink")==0) { + } else if(strcmp($5, "objectlink")==0) { set = g_strdup_printf( "if(%s->%s) " "gtk_object_unref(GTK_OBJECT(%s->%s)); " "%s->%s = ARG; " "if(%s->%s) " - "gtk_object_ref(GTK_OBJECT(%s->%s)); ", + "gtk_object_ref(GTK_OBJECT(%s->%s));", + root, $4, + root, $4, + root, $4, root, $4, root, $4, root, $4, @@ -639,9 +698,9 @@ stars: '*' stars { stars++; } /* this never sets the_scope */ simplesigtype: TOKEN sigtype { - if(strcmp($1,"first")==0) + if(strcmp($1, "first")==0) $$ = SIGNAL_FIRST_METHOD; - else if(strcmp($1,"last")==0) + else if(strcmp($1, "last")==0) $$ = SIGNAL_LAST_METHOD; else { yyerror(_("signal must be 'first' or 'last'")); @@ -690,15 +749,15 @@ fullsigtype: scope TOKEN sigtype { ; sigtype: TOKEN '(' tokenlist ')' { - gtktypes = g_list_prepend(gtktypes,$1); + gtktypes = g_list_prepend(gtktypes, $1); } ; tokenlist: tokenlist ',' TOKEN { - gtktypes = g_list_append(gtktypes,$3); + gtktypes = g_list_append(gtktypes, $3); } | TOKEN { - gtktypes = g_list_append(gtktypes,$1); + gtktypes = g_list_append(gtktypes, $1); } ; @@ -707,77 +766,107 @@ codenocode: '{' CCODE { $$ = $2; } ; /*here CCODE will include the ending '}' */ -method: SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' onerror codenocode { +method: SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode { if(!has_self) { yyerror(_("signal without 'self' as " "first parameter")); + free_all_global_state(); + YYERROR; + } + if(the_scope == CLASS_SCOPE) { + yyerror(_("a method cannot be of class scope")); + free_all_global_state(); YYERROR; } push_function(the_scope, $3,NULL, - $5, $9, $10,$1, + $5, $10,$1, ccode_line, vararg, $2); } - | scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' onerror codenocode { + | scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode { if(!has_self) { yyerror(_("signal without 'self' as " "first parameter")); + free_all_global_state(); + YYERROR; + } + if(the_scope == CLASS_SCOPE) { + yyerror(_("a method cannot be of class scope")); + free_all_global_state(); YYERROR; } push_function(the_scope, $4, NULL, - $6, $10, $11, $2, + $6, $11, $2, ccode_line, vararg, $3); } - | VIRTUAL scope type TOKEN '(' funcargs ')' onerror codenocode { + | VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode { if(!has_self) { yyerror(_("virtual method without 'self' as " "first parameter")); + free_all_global_state(); + YYERROR; + } + if(the_scope == CLASS_SCOPE) { + yyerror(_("a method cannot be of class scope")); + free_all_global_state(); YYERROR; } push_function(the_scope, VIRTUAL_METHOD, NULL, $4, - $8, $9, $1, + $9, $1, ccode_line, vararg, NULL); } - | scope VIRTUAL type TOKEN '(' funcargs ')' onerror codenocode { + | scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode { if(!has_self) { yyerror(_("virtual method without 'self' as " "first parameter")); + free_all_global_state(); + YYERROR; + } + if(the_scope == CLASS_SCOPE) { + yyerror(_("a method cannot be of class scope")); + free_all_global_state(); YYERROR; } push_function(the_scope, VIRTUAL_METHOD, NULL, $4, - $8, $9, $2, + $9, $2, ccode_line, vararg, NULL); } - | VIRTUAL type TOKEN '(' funcargs ')' onerror codenocode { + | VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode { if(!has_self) { yyerror(_("virtual method without 'self' as " "first parameter")); + free_all_global_state(); YYERROR; } push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL, - $3, $7, $8, $1, + $3, $8, $1, ccode_line, vararg, NULL); } - | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' onerror codenocode { + | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode { push_function(NO_SCOPE, OVERRIDE_METHOD, $3, - $6, $10, $11, + $6, $11, $1, ccode_line, vararg, NULL); } - | scope type TOKEN '(' funcargs ')' onerror codenocode { + | scope type TOKEN '(' funcargs ')' returnvals codenocode { + if(the_scope == CLASS_SCOPE) { + yyerror(_("a method cannot be of class scope")); + free_all_global_state(); + YYERROR; + } push_function(the_scope, REGULAR_METHOD, NULL, $3, - $7, $8, $1, ccode_line, + $8, $1, ccode_line, vararg, NULL); } | TOKEN '(' TOKEN ')' codenocode { - if(strcmp($1,"init")==0) { + if(strcmp($1, "init")==0) { push_init_arg($3,FALSE); push_function(NO_SCOPE, INIT_METHOD, NULL, - $1, NULL, $5, $2, + $1, $5, $2, ccode_line, FALSE, NULL); - } else if(strcmp($1,"class_init")==0) { + } else if(strcmp($1, "class_init")==0) { push_init_arg($3,TRUE); push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL, - $1, NULL, $5, $2, + $1, $5, $2, ccode_line, FALSE, NULL); } else { g_free($1); @@ -788,13 +877,48 @@ method: SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' onerror codenocode } } ; - -onerror: ONERROR numtok { $$ = $2; } - | ONERROR '{' CCODE { + +returnvals: TOKEN retcode { + g_free(onerror); onerror = NULL; + g_free(defreturn); defreturn = NULL; + if(!set_return_value($1, $2)) { + g_free($1); + g_free($2); + yyerror(_("parse error")); + YYERROR; + } + g_free($1); + } + | TOKEN retcode TOKEN retcode { + g_free(onerror); onerror = NULL; + g_free(defreturn); defreturn = NULL; + if(!set_return_value($1, $2)) { + g_free($1); g_free($2); + g_free($3); g_free($4); + yyerror(_("parse error")); + YYERROR; + } + if(!set_return_value($3, $4)) { + onerror = defreturn = NULL; + g_free($1); g_free($2); + g_free($3); g_free($4); + yyerror(_("parse error")); + YYERROR; + } + g_free($1); + g_free($3); + } + | { + g_free(onerror); onerror = NULL; + g_free(defreturn); defreturn = NULL; + } + ; + +retcode: numtok { $$ = $1; } + | '{' CCODE { $$ = ($3)->str; - g_string_free($3,FALSE); + g_string_free($3, FALSE); } - | { $$ = NULL; } ; funcargs: VOID { vararg = FALSE; has_self = FALSE; }