X-Git-Url: https://git.draconx.ca/gitweb/gob-dx.git/blobdiff_plain/64034bc2613afefb289d1450411e69a0de4bce4e..486240dc4c5d57b0afaddba60d87fe375112bed5:/src/parse.y diff --git a/src/parse.y b/src/parse.y index 449ef3c..9764b67 100644 --- a/src/parse.y +++ b/src/parse.y @@ -23,29 +23,43 @@ #include "config.h" #include #include +#include #include -#include "tree.h" +#include "treefuncs.h" #include "main.h" +#include "util.h" #define _(x) (x) -extern char *filename; - GList *nodes = NULL; static GList *class_nodes = NULL; Node *class = NULL; +char *chunk_size = NULL; static GList *typestack = NULL; -static int stars = 0; static GList *funcargs = NULL; 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 + anyway */ +static int the_scope = NO_SCOPE; + void free(void *ptr); int yylex(void); @@ -63,63 +77,141 @@ 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); } -static void -push_variable(char *name, int scope, int line_no) +static Type * +pop_type(void) { - Node *var; Type *type = typestack->data; typestack = g_list_remove(typestack,typestack->data); + return type; +} + +static void +push_variable(char *name, int scope, int line_no, char *postfix) +{ + Node *var; + Type *type = pop_type(); + + 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, char *oid, char *id, char *onerror, - GString *cbuf,int line_no, int ccode_line, int vararg) +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(scope!=INIT_METHOD && scope!=CLASS_INIT_METHOD) { - type = typestack->data; - typestack = g_list_remove(typestack,typestack->data); + if(method == INIT_METHOD || method == CLASS_INIT_METHOD) { + type = (Type *)new_type(g_strdup("void"), NULL, NULL); } else { - type = (Type *)new_type(0,g_strdup("void")); + type = pop_type(); } - node = new_method(scope,type,oid,gtktypes,id,funcargs, - onerror,cbuf,line_no,ccode_line,vararg); + /* a complicated and ugly test to figure out if we have + the wrong number of types for a signal */ + if((method == SIGNAL_FIRST_METHOD || + method == SIGNAL_LAST_METHOD) && + g_list_length(gtktypes) != g_list_length(funcargs) && + !(g_list_length(funcargs) == 1 && + g_list_length(gtktypes) == 2 && + 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); + } + 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; + c_cbuf = p = cbuf->str; + while(p && *p && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) + p++; + if(!p || !*p) + c_cbuf = NULL; + } else + c_cbuf = NULL; + + node = new_method(scope, method, type, oid, gtktypes, flags, + id, funcargs, onerror, defreturn, c_cbuf, line_no, + ccode_line, vararg, method_unique_id++); + + if(cbuf) + g_string_free(cbuf, + /*only free segment if we haven't passed it + above */ + c_cbuf?FALSE:TRUE); gtktypes = NULL; funcargs = NULL; + onerror = NULL; + defreturn = NULL; + class_nodes = g_list_append(class_nodes, node); } static void -push_funcarg(char *name) +free_all_global_state(void) +{ + g_free(onerror); + onerror = NULL; + g_free(defreturn); + defreturn = NULL; + + g_free(chunk_size); + chunk_size = 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) { Node *node; - Type *type = typestack->data; - typestack = g_list_remove(typestack,typestack->data); + Type *type = pop_type(); + + type->postfix = postfix; - node = new_funcarg(type,name,checks); + node = new_funcarg(type, name, checks); checks = NULL; funcargs = g_list_append(funcargs, node); @@ -137,7 +229,7 @@ push_init_arg(char *name, int is_class) else tn = g_strdup(((Class *)class)->otype); - type = new_type(1,tn); + type = new_type(tn, g_strdup("*"), NULL); node = new_funcarg((Type *)type,name,NULL); funcargs = g_list_prepend(funcargs, node); } @@ -148,13 +240,55 @@ push_self(char *id) Node *node; Node *type; GList *ch = NULL; - type = new_type(1,g_strdup(((Class *)class)->otype)); + type = new_type(g_strdup(((Class *)class)->otype), g_strdup("*"), NULL); ch = g_list_append(ch,new_check(NULL_CHECK,NULL)); ch = g_list_append(ch,new_check(TYPE_CHECK,NULL)); node = new_funcarg((Type *)type,id,ch); 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 { @@ -162,16 +296,16 @@ push_self(char *id) GString *cbuf; GList *list; int line; + int sigtype; } %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 -%token CCODE HCODE -%token PUBLIC PRIVATE ARGUMENT VIRTUAL SIGNAL OVERRIDE +%token TOKEN NUMBER TYPETOKEN ARRAY_DIM +%token CCODE HTCODE PHCODE HCODE ACODE ATCODE +%token PUBLIC PRIVATE PROTECTED CLASSWIDE ARGUMENT VIRTUAL SIGNAL OVERRIDE %% @@ -181,69 +315,183 @@ prog: ccodes class ccodes { ; } | class { ; } ; -ccodes: ccodes CCODE { - Node *node = new_ccode(FALSE,$2,ccode_line); +ccode: CCODE { + Node *node = new_ccode(C_CCODE,($1)->str, + ccode_line); nodes = g_list_append(nodes,node); + g_string_free($1,FALSE); } - | ccodes HCODE { - Node *node = new_ccode(TRUE,$2,ccode_line); + | HCODE { + Node *node = new_ccode(H_CCODE,($1)->str, + ccode_line); nodes = g_list_append(nodes,node); + g_string_free($1,FALSE); } - | CCODE { - Node *node = new_ccode(FALSE,$1,ccode_line); + | HTCODE { + Node *node = new_ccode(HT_CCODE,($1)->str, + ccode_line); nodes = g_list_append(nodes,node); + g_string_free($1,FALSE); } - | HCODE { - Node *node = new_ccode(TRUE,$1,ccode_line); + | PHCODE { + Node *node = new_ccode(PH_CCODE,($1)->str, + ccode_line); + nodes = g_list_append(nodes,node); + g_string_free($1,FALSE); + } + | ACODE { + Node *node = new_ccode(A_CCODE,($1)->str, + ccode_line); + nodes = g_list_append(nodes,node); + g_string_free($1,FALSE); + } + | ATCODE { + Node *node = new_ccode(AT_CCODE,($1)->str, + ccode_line); nodes = g_list_append(nodes,node); + g_string_free($1,FALSE); } ; +ccodes: ccodes ccode { ; } + | ccode { ; } + ; + class: classdec '{' classcode '}' { ((Class *)class)->nodes = class_nodes; class_nodes = NULL; nodes = g_list_append(nodes,class); } + | classdec '{' '}' { + ((Class *)class)->nodes = NULL; + class_nodes = NULL; + nodes = g_list_append(nodes,class); + } ; -classdec: CLASS TYPETOKEN FROM TYPETOKEN { - class = new_class($2,$4,NULL); +classdec: CLASS TYPETOKEN FROM TYPETOKEN chunk { + class = new_class($2,$4,chunk_size,NULL); } ; - -classcode: classcode method { ; } - | classcode variable { ; } - | classcode argument { ; } - | method { ; } + +chunk: + | '(' TOKEN TOKEN ')' { + if(strcmp($2,"chunks") == 0) { + chunk_size = g_strdup($4); + } else { + yyerror(_("parse error")); + YYERROR; + } + } + | '(' TOKEN NUMBER ')' { + if(strcmp($2,"chunks") == 0) { + if(atoi($4) != 0) + chunk_size = g_strdup($4); + } else { + yyerror(_("parse error")); + YYERROR; + } + } + ; + +classcode: classcode thing { ; } + | thing { ; } + ; + +thing: method { ; } | variable { ; } | argument { ; } + | ';' { ; } + ; + +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 = 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: PUBLIC type TOKEN ';' { - push_variable($3,PUBLIC_SCOPE,$1); +variable: scope type TOKEN varoptions ';' { + push_variable($3, the_scope,$1, NULL); } - | PRIVATE type TOKEN ';' { - push_variable($3,PRIVATE_SCOPE,$1); + | scope type TOKEN ARRAY_DIM varoptions ';' { + push_variable($3, the_scope, $1, $4); } ; -argument: ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { +argument: ARGUMENT flags argtype TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { if(strcmp($5,"get")==0 && strcmp($8,"set")==0) { Node *node; + Type *type = pop_type(); g_free($5); g_free($8); - node = new_argument($3,$2,$4, - $7,$6, - $10,$9, + node = new_argument($3,type,$2,$4, + ($7)->str,$6, + ($10)->str,$9, $1); + g_string_free($7,FALSE); + g_string_free($10,FALSE); class_nodes = g_list_append(class_nodes,node); } else if(strcmp($5,"set")==0 && strcmp($8,"get")==0) { Node *node; + Type *type = pop_type(); g_free($5); g_free($8); - node = new_argument($3,$2,$4, - $10,$9, - $7,$6, + node = new_argument($3,type,$2,$4, + ($10)->str,$9, + ($7)->str,$6, $1); + g_string_free($10,FALSE); + g_string_free($7,FALSE); class_nodes = g_list_append(class_nodes,node); } else { g_free($3); g_free($4); @@ -255,20 +503,24 @@ argument: ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { YYERROR; } } - | ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE ';' { + | ARGUMENT flags argtype TOKEN TOKEN '{' CCODE ';' { if(strcmp($5,"get")==0) { Node *node; + Type *type = pop_type(); g_free($5); - node = new_argument($3,$2,$4, - $7,$6,NULL,0, - $1); + node = new_argument($3,type,$2,$4, + ($7)->str,$6, + NULL,0, $1); + g_string_free($7,FALSE); class_nodes = g_list_append(class_nodes,node); } else if(strcmp($5,"set")==0) { Node *node; + Type *type = pop_type(); g_free($5); - node = new_argument($3,$2,$4, - NULL,0,$7,$6, - $1); + node = new_argument($3,type,$2,$4, + NULL,0,($7)->str, + $6, $1); + g_string_free($7,FALSE); class_nodes = g_list_append(class_nodes,node); } else { g_free($5); g_free($3); @@ -279,9 +531,92 @@ argument: ARGUMENT argflags TOKEN 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 if(var->scope == CLASS_SCOPE) + root = "SELF_CLASS(GTK_OBJECT(self)->klass)"; + 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(); + } + + if(strcmp($5, "stringlink")==0) { + get = g_strdup_printf("ARG = g_strdup(%s->%s);", root, $4); + } else + /* For everything else, get is just straight assignment */ + 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 ')' { + if(strcmp($3,"type")!=0) { + g_free($1); + g_free($3); + yyerror(_("parse error")); + YYERROR; + } + $$ = $1; + } + | TOKEN { + $$ = $1; + typestack = g_list_prepend(typestack,NULL); + } ; -argflags: '(' flaglist ')' { $$ = $2; } +flags: '(' flaglist ')' { $$ = $2; } | { $$ = NULL; } ; @@ -294,230 +629,336 @@ flaglist: TOKEN '|' flaglist { ; -type: type1 { ; } - | CONST type1 { - Type *type = typestack->data; - char *oldname = type->name; - type->name = g_strconcat("const ",oldname,NULL); - g_free(oldname); - } - ; - -type1: type2 { - Node *node = new_type(0,$1); +type: specifier_list pointer { + Node *node = new_type($1, $2, NULL); typestack = g_list_prepend(typestack,node); - } - | type2 stars { - Node *node = new_type(stars,$1); - stars = 0; + } + | specifier_list { + Node *node = new_type($1, NULL, NULL); typestack = g_list_prepend(typestack,node); - } + } ; -type2: UNSIGNED integer { - $$ = g_strconcat("unsigned ",$2,NULL); - } - | SIGNED integer { - $$ = g_strconcat("signed ",$2,NULL); - } - | integer { - $$ = g_strdup($1); - } - | UNSIGNED CHAR { - $$ = g_strdup("unsigned char"); - } - | SIGNED CHAR { - $$ = g_strdup("signed char"); - } - | CHAR { - $$ = g_strdup("char"); - } - | DOUBLE { - $$ = g_strdup("double"); - } - | FLOAT { - $$ = g_strdup("float"); - } - | TOKEN { +/* The special cases are neccessary to avoid conflicts */ +specifier_list: spec_list { $$ = $1; - } - | tspecifier TOKEN { - $$ = g_strconcat($1,$2,NULL); + } + | TOKEN { + $$ = $1; + } + | CONST TOKEN { + $$ = g_strconcat("const ", $2, NULL); g_free($2); - } - | TYPETOKEN { + } + | TOKEN CONST { + $$ = g_strconcat($1, " const", NULL); + g_free($1); + } + | strunionenum TOKEN { + $$ = g_strconcat($1, " ", $2, NULL); + g_free($2); + } + | CONST strunionenum TOKEN { + $$ = g_strconcat("const ", $2, " ", + $3, NULL); + g_free($3); + } + | strunionenum TOKEN CONST { + $$ = g_strconcat($1, " ", + $2, " const", NULL); + g_free($2); + } + ; + +/* The special const cases take care of conflicts ! */ +spec_list: specifier spec_list { + $$ = g_strconcat($1, " ", $2, NULL); + g_free($2); + } + | TYPETOKEN spec_list { + $$ = g_strconcat($1, " ", $2, NULL); + g_free($1); + g_free($2); + } + | CONST spec_list { + $$ = g_strconcat("const ", $2, NULL); + g_free($2); + } + | TYPETOKEN { $$ = $1; - } - | VOID { - $$ = g_strdup("void"); - } + } + | TYPETOKEN CONST { + $$ = g_strconcat($1, " const", NULL); + g_free($1); + } + | specifier { + $$ = g_strdup($1); + } + | specifier CONST { + $$ = g_strconcat($1, " const", NULL); + } ; -integer: LONG INT { - $$ = "long int"; - } - | LONG { - $$ = "long"; - } - | SHORT INT { - $$ = "short int"; - } - | SHORT { - $$ = "short"; - } - | INT { - $$ = "int"; - } +specifier: VOID { $$ = "void"; } + | CHAR { $$ = "char"; } + | SHORT { $$ = "short"; } + | INT { $$ = "int"; } + | LONG { $$ = "long"; } + | FLOAT { $$ = "float"; } + | DOUBLE { $$ = "double"; } + | SIGNED { $$ = "signed"; } + | UNSIGNED { $$ = "unsigned"; } + ; + +strunionenum: STRUCT { $$ = "struct"; } + | UNION { $$ = "union"; } + | ENUM { $$ = "enum"; } ; - -tspecifier: ENUM { - $$ = "enum "; - } - | UNION { - $$ = "union "; - } - | STRUCT { - $$ = "struct "; - } + +pointer: '*' { $$ = g_strdup("*"); } + | '*' CONST { $$ = g_strdup("* const"); } + | '*' pointer { + $$ = g_strconcat("*", $2, NULL); + g_free($2); + } + | '*' CONST pointer { + $$ = g_strconcat("* const", $3, NULL); + g_free($3); + } ; - -stars: '*' stars { stars++; } - | '*' { stars++; } + +/* this never sets the_scope */ +simplesigtype: TOKEN sigtype { + if(strcmp($1, "first")==0) + $$ = SIGNAL_FIRST_METHOD; + else if(strcmp($1, "last")==0) + $$ = SIGNAL_LAST_METHOD; + else { + yyerror(_("signal must be 'first' or 'last'")); + g_free($1); + YYERROR; + } + g_free($1); + } + | sigtype { + $$ = SIGNAL_LAST_METHOD; + } + ; + +/* this always sets the_scope */ +fullsigtype: scope TOKEN sigtype { + if(strcmp($2,"first")==0) + $$ = SIGNAL_FIRST_METHOD; + else if(strcmp($2,"last")==0) + $$ = SIGNAL_LAST_METHOD; + else { + yyerror(_("signal must be 'first' or 'last'")); + g_free($2); + YYERROR; + } + g_free($2); + } + | TOKEN scope sigtype { + if(strcmp($1,"first")==0) + $$ = SIGNAL_FIRST_METHOD; + else if(strcmp($1,"last")==0) + $$ = SIGNAL_LAST_METHOD; + else { + yyerror(_("signal must be 'first' or 'last'")); + g_free($1); + YYERROR; + } + g_free($1); + } + | scope sigtype { + $$ = SIGNAL_LAST_METHOD; + } + | simplesigtype { + /* the_scope was default thus public */ + the_scope = PUBLIC_SCOPE; + } ; 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); } ; -codenocode: '{' CCODE { $$=$2; } +codenocode: '{' CCODE { $$ = $2; } | ';' { $$ = NULL; } ; /*here CCODE will include the ending '}' */ -method: SIGNAL TOKEN sigtype type TOKEN '(' funcargs ')' onerror codenocode { - int sigtype = SIGNAL_LAST_METHOD; - if(strcmp($2,"first")==0) - sigtype = SIGNAL_FIRST_METHOD; - else if(strcmp($2,"last")==0) - sigtype = SIGNAL_LAST_METHOD; - else { - yyerror(_("signal must be 'first' or 'last'")); - g_free($2); +method: SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode { + if(!has_self) { + yyerror(_("signal without 'self' as " + "first parameter")); + free_all_global_state(); YYERROR; } - g_free($2); - + 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, $10,$1, + ccode_line, vararg, $2); + } + | 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(sigtype,NULL, - $5, $9, $10,$1, - ccode_line,vararg); + push_function(the_scope, $4, NULL, + $6, $11, $2, + ccode_line, vararg, $3); } - | SIGNAL sigtype type TOKEN '(' funcargs ')' onerror codenocode { + | VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode { if(!has_self) { - yyerror(_("signal without 'self' as " + 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(SIGNAL_LAST_METHOD, NULL, - $4, $8, $9,$1, - ccode_line,vararg); + push_function(the_scope, VIRTUAL_METHOD, NULL, $4, + $9, $1, + ccode_line, vararg, NULL); } - | 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(VIRTUAL_METHOD, NULL, $3, - $7, $8,$1, - ccode_line,vararg); + 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, + $9, $2, + ccode_line, vararg, NULL); } - | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' onerror '{' CCODE { - push_function(OVERRIDE_METHOD, $3, - $6, $10, $12, - $1,$11, - vararg); + | 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, $8, $1, + ccode_line, vararg, NULL); } - | PUBLIC type TOKEN '(' funcargs ')' onerror '{' CCODE { - push_function(PUBLIC_SCOPE, NULL, $3, - $7, $9,$1,$8, - vararg); - } - | PRIVATE type TOKEN '(' funcargs ')' onerror '{' CCODE { - push_function(PRIVATE_SCOPE, NULL, $3, - $7, $9,$1,$8, - vararg); + | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode { + push_function(NO_SCOPE, OVERRIDE_METHOD, $3, + $6, $11, + $1, ccode_line, + vararg, NULL); + } + | 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, + $8, $1, ccode_line, + vararg, NULL); } - | TOKEN '(' TOKEN ')' ';' { - if(strcmp($1,"init")==0) { + | TOKEN '(' TOKEN ')' codenocode { + if(strcmp($1, "init")==0) { push_init_arg($3,FALSE); - push_function(INIT_METHOD, NULL, $1, - NULL, NULL,$2,0, - FALSE); - } else if(strcmp($1,"class_init")==0) { + push_function(NO_SCOPE, INIT_METHOD, NULL, + $1, $5, $2, + ccode_line, FALSE, NULL); + } else if(strcmp($1, "class_init")==0) { push_init_arg($3,TRUE); - push_function(CLASS_INIT_METHOD, NULL, - $1, NULL, NULL,$2,0, - FALSE); + push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL, + $1, $5, $2, + ccode_line, FALSE, NULL); } else { g_free($1); g_free($3); - yyerror(_("parse error")); + g_string_free($5,TRUE); + yyerror(_("parse error " + "(untyped blocks must be init or " + "class_init)")); YYERROR; } } - | TOKEN '(' TOKEN ')' '{' CCODE { - if(strcmp($1,"init")==0) { - push_init_arg($3,FALSE); - push_function(INIT_METHOD, NULL, - $1, NULL, $6,$2, - $5,FALSE); - } else if(strcmp($1,"class_init")==0) { - push_init_arg($3,TRUE); - push_function(CLASS_INIT_METHOD, NULL, - $1, NULL, $6,$2, - $5,FALSE); - } else { + ; + +returnvals: TOKEN retcode { + g_free(onerror); onerror = NULL; + g_free(defreturn); defreturn = NULL; + if(!set_return_value($1, $2)) { g_free($1); - g_free($3); - g_string_free($3,TRUE); + 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; + } ; - -onerror: ONERROR numtok { $$ = $2; } - | ONERROR '{' CCODE { + +retcode: numtok { $$ = $1; } + | '{' CCODE { $$ = ($3)->str; - g_string_free($3,FALSE); + g_string_free($3, FALSE); } - | '=' '1' { ; } - | { $$ = NULL; } ; -funcargs: VOID { has_self = FALSE; } +funcargs: VOID { vararg = FALSE; has_self = FALSE; } | TOKEN { + vararg = FALSE; has_self = TRUE; - if(strcmp($1,"this")==0) { - push_self($1); - print_error(TRUE,_("Use of 'this' is " - "depreciated, use 'self' " - "instead"),line_no); - } else if(strcmp($1,"self")==0) + if(strcmp($1,"self")==0) push_self($1); else { g_free($1); @@ -527,12 +968,7 @@ funcargs: VOID { has_self = FALSE; } } | TOKEN ',' arglist { has_self = TRUE; - if(strcmp($1,"this")==0) { - push_self($1); - print_error(TRUE,_("Use of 'this' is " - "depreciated, use 'self' " - "instead"),line_no); - } else if(strcmp($1,"self")==0) + if(strcmp($1,"self")==0) push_self($1); else { g_free($1); @@ -552,7 +988,10 @@ arglist1: arglist1 ',' arg { ; } ; arg: type TOKEN { - push_funcarg($2); + push_funcarg($2,NULL); + } + | type TOKEN ARRAY_DIM { + push_funcarg($2,$3); } | type TOKEN '(' TOKEN checklist ')' { if(strcmp($4,"check")!=0) { @@ -560,7 +999,15 @@ arg: type TOKEN { YYERROR; } g_free($4); - push_funcarg($2); + push_funcarg($2,NULL); + } + | type TOKEN ARRAY_DIM '(' TOKEN checklist ')' { + if(strcmp($5,"check")!=0) { + yyerror(_("parse error")); + YYERROR; + } + g_free($5); + push_funcarg($2,$3); } ;