X-Git-Url: http://git.draconx.ca/gitweb/gob-dx.git/blobdiff_plain/b17287deb56775a49030d738d8c8c0e9cd15f9fe..3379dcdfd0872947d761053c61d773add94d38c2:/src/parse.y diff --git a/src/parse.y b/src/parse.y index 63f0a7a..192e4c4 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" @@ -43,6 +43,16 @@ static GList *checks = NULL; static int has_self = FALSE; static int vararg = FALSE; +/* destructor and initializer for variables */ +static char *destructor = NULL; +static int destructor_line = 0; +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 @@ -66,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); @@ -98,14 +108,17 @@ push_variable(char *name, int scope, int line_no, char *postfix) type->postfix = postfix; - var = new_variable(scope,type,name,line_no); + var = new_variable(scope, type, name, line_no, + destructor, destructor_line, + destructor_simple, + initializer, initializer_line); class_nodes = g_list_append(class_nodes, var); } 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; @@ -127,7 +140,7 @@ push_function(int scope, int method, char *oid, char *id, char *onerror, 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(cbuf) { char *p; @@ -140,7 +153,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) @@ -151,9 +164,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) { @@ -162,7 +194,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); @@ -198,6 +230,48 @@ push_self(char *id) funcargs = g_list_prepend(funcargs, node); } +static Variable * +find_var_or_die(const char *id, int line) +{ + GList *li; + char *s; + + for(li = class_nodes; li != NULL; li = li->next) { + Variable *var; + Node *node = li->data; + if(node->type != VARIABLE_NODE) + continue; + var = li->data; + if(strcmp(var->id, id)==0) + return var; + } + + s = g_strdup_printf(_("Variable %s not defined here"), id); + print_error(FALSE, s, line); + + g_assert_not_reached(); + 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 { @@ -211,7 +285,6 @@ push_self(char *id) %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 @@ -284,12 +357,14 @@ classdec: CLASS TYPETOKEN FROM TYPETOKEN { } ; -classcode: classcode method { ; } - | classcode variable { ; } - | classcode argument { ; } - | method { ; } +classcode: classcode thing { ; } + | thing { ; } + ; + +thing: method { ; } | variable { ; } | argument { ; } + | ';' { ; } ; scope: PUBLIC { the_scope = PUBLIC_SCOPE; } @@ -297,11 +372,62 @@ scope: PUBLIC { the_scope = PUBLIC_SCOPE; } | PROTECTED { the_scope = PROTECTED_SCOPE; } ; -variable: scope type TOKEN ';' { - push_variable($3,the_scope,$1,NULL); +destructor: TOKEN TOKEN { + if(strcmp($1, "destroywith")==0) { + g_free($1); + destructor = $2; + destructor_line = line_no; + destructor_simple = TRUE; + } else { + g_free($1); + g_free($2); + yyerror(_("parse error")); + YYERROR; + } + } + | TOKEN '{' CCODE { + if(strcmp($1, "destroy")==0) { + g_free($1); + destructor = ($3)->str; + g_string_free($3, FALSE); + destructor_line = ccode_line; + destructor_simple = FALSE; + } else { + g_free($1); + g_string_free($3, TRUE); + yyerror(_("parse error")); + YYERROR; + } + } + ; + +initializer: '=' numtok { + initializer = $2; + initializer_line = ccode_line; + } + | '=' '{' CCODE { + initializer = ($3)->str; + initializer_line = ccode_line; + g_string_free($3, FALSE); + } + ; + + +varoptions: destructor initializer { ; } + | initializer destructor { ; } + | initializer { destructor = NULL; } + | destructor { initializer = NULL; } + | { + destructor = NULL; + initializer = NULL; + } + ; + +variable: scope type TOKEN varoptions ';' { + push_variable($3, the_scope,$1, NULL); } - | scope type TOKEN ARRAY_DIM ';' { - push_variable($3,the_scope,$1,$4); + | scope type TOKEN ARRAY_DIM varoptions ';' { + push_variable($3, the_scope, $1, $4); } ; argument: ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { @@ -367,6 +493,69 @@ argument: ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { YYERROR; } } + | ARGUMENT flags argtype TOKEN TOKEN { + Node *node; + char *get, *set = NULL; + Variable *var; + Type *type; + char *root; + + 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); + yyerror(_("parse error")); + YYERROR; + } + + type = pop_type(); + + var = find_var_or_die($4, $1); + if(var->scope == PRIVATE_SCOPE) + root = "self->_priv"; + else + root = "self"; + + if(strcmp($5,"link")==0) { + set = g_strdup_printf("%s->%s = ARG;", + root, $4); + } 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) { + 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)); ", + root, $4, + root, $4, + root, $4, + root, $4, + root, $4); + } else { + g_assert_not_reached(); + } + + /* get is the same for everything */ + get = g_strdup_printf("ARG = %s->%s;", root, $4); + + g_free($5); + + + if(!type) + type = copy_type(var->vtype); + + node = new_argument($3, type, $2, + $4, get, $1, + set, $1, $1); + class_nodes = g_list_append(class_nodes,node); + } ; argtype: TOKEN '(' TOKEN type ')' { @@ -490,9 +679,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'")); @@ -541,15 +730,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); } ; @@ -558,77 +747,82 @@ 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; } 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; } 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; } 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; } 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 { 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); @@ -639,13 +833,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; }