X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=8c99eca25f0350f1e0e858b478c8ba21f797e772;hb=d9fc7aab1efc946d04f0e8cde52c88ffd4598943;hp=b11c5eae6c2c6c5fe1bd4e1e69499657b5319578;hpb=fe0554f343c5f4d4bd9affdab418b3db2f7eb949;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index b11c5ea..8c99eca 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -69,6 +69,11 @@ %token T_SHORT %token T_FLOAT +%token T_FOR "for" +%token T_WHILE "while" +%token T_DO "do" +%token T_SWITCH "switch" + %token KW_IMPLEMENTS %token KW_NAMESPACE "namespace" %token KW_PACKAGE "package" @@ -81,9 +86,11 @@ %token KW_NATIVE %token KW_FUNCTION "function" %token KW_UNDEFINED "undefined" -%token KW_FOR "for" +%token KW_CONTINUE "continue" %token KW_CLASS "class" %token KW_CONST "const" +%token KW_CATCH "catch" +%token KW_CASE "case" %token KW_SET "set" %token KW_VOID "void" %token KW_STATIC @@ -94,10 +101,11 @@ %token KW_INTERFACE "interface" %token KW_NULL "null" %token KW_VAR "var" -%token KW_DYNAMIC +%token KW_DYNAMIC "dynamic" %token KW_OVERRIDE %token KW_FINAL %token KW_GET "get" +%token KW_TRY "try" %token KW_SUPER "super" %token KW_EXTENDS %token KW_FALSE "false" @@ -105,9 +113,9 @@ %token KW_BOOLEAN "Boolean" %token KW_UINT "uint" %token KW_INT "int" -%token KW_WHILE "while" %token KW_NUMBER "Number" %token KW_STRING "String" +%token KW_DEFAULT "default" %token KW_DELETE "delete" %token KW_IF "if" %token KW_ELSE "else" @@ -144,7 +152,7 @@ %type VARCONST %type CODE %type CODEPIECE -%type CODEBLOCK MAYBECODE +%type CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH %type PACKAGE_DECLARATION %type FUNCTION_DECLARATION %type VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST @@ -156,7 +164,7 @@ %type MAYBEEXPRESSION %type E DELETE %type CONSTANT -%type FOR IF WHILE MAYBEELSE BREAK RETURN +%type FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE %type USE_NAMESPACE %type FOR_INIT %type IMPORT @@ -181,7 +189,7 @@ //%type T_IDENTIFIER %type MODIFIER %type FUNCTIONCALL -%type MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES +%type MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST // precedence: from low to high @@ -207,6 +215,7 @@ %left '/' '*' '%' %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too %left "--" "++" +%nonassoc below_curly %left '[' ']' '{' "new" '.' ".." "::" %nonassoc T_IDENTIFIER %left below_else @@ -218,6 +227,7 @@ %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT %nonassoc "false" "true" "null" "undefined" "super" + %{ @@ -482,7 +492,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo printf("\n"); */ - if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL)) + if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC)) syntaxerror("invalid modifier(s)"); if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL)) @@ -707,6 +717,21 @@ code_t* killvars(code_t*c) return c; } +void check_code_for_break(code_t*c) +{ + while(c) { + if(c->opcode == OPCODE___BREAK__) { + char*name = string_cstr(c->data[0]); + syntaxerror("Unresolved \"break %s\"", name); + } + if(c->opcode == OPCODE___CONTINUE__) { + char*name = string_cstr(c->data[0]); + syntaxerror("Unresolved \"continue %s\"", name); + } + c=c->prev; + } +} + static void check_constant_against_type(classinfo_t*t, constant_t*c) { @@ -858,7 +883,13 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam syntaxerror("non-optional parameter not allowed after optional parameters"); } } - f->body->code = body; + check_code_for_break(body); + + if(f->body) + f->body->code = body; + else //interface + if(body) + syntaxerror("interface methods can't have a method body"); old_state(); } @@ -870,16 +901,30 @@ char is_subtype_of(classinfo_t*type, classinfo_t*supertype) return 1; // FIXME } -void breakjumpsto(code_t*c, code_t*jump) +void breakjumpsto(code_t*c, char*name, code_t*jump) { - while(c->prev) - c=c->prev; while(c) { if(c->opcode == OPCODE___BREAK__) { - c->opcode = OPCODE_JUMP; - c->branch = jump; + string_t*name2 = c->data[0]; + if(!name2->len || !strncmp(name2->str, name, name2->len)) { + c->opcode = OPCODE_JUMP; + c->branch = jump; + } + } + c=c->prev; + } +} +void continuejumpsto(code_t*c, char*name, code_t*jump) +{ + while(c) { + if(c->opcode == OPCODE___CONTINUE__) { + string_t*name2 = c->data[0]; + if(!name2->len || !strncmp(name2->str, name, name2->len)) { + c->opcode = OPCODE_JUMP; + c->branch = jump; + } } - c = c->next; + c = c->prev; } } @@ -907,19 +952,13 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to) return abc_coerce2(c, &m); } - if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) { - return abc_coerce2(c, &m); - } - if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) { - return abc_coerce2(c, &m); - } - /* these are subject to overflow */ - if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) { - return abc_coerce2(c, &m); - } - if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) { + if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) && + (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) { + // allow conversion between number types return abc_coerce2(c, &m); } + //printf("%s.%s\n", from.package, from.name); + //printf("%s.%s\n", to.package, to.name); classinfo_t*supertype = from; while(supertype) { @@ -930,7 +969,7 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to) int t=0; while(supertype->interfaces[t]) { if(supertype->interfaces[t]==to) { - // to type is one of from's interfaces + // target type is one of from's interfaces return abc_coerce2(c, &m); } t++; @@ -1158,13 +1197,21 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r /* ------------ code blocks / statements ---------------- */ -PROGRAM: MAYBECODE +PROGRAM: MAYBECODE { + /* todo: do something with this code if we're outside a function */ + if($1) + warning("ignored code"); +} -MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/} -MAYBECODE: {$$=code_new();} +MAYBECODE: CODE {$$=$1;} +MAYBECODE: {$$=code_new();} -CODE: CODE CODEPIECE {$$=code_append($1,$2);} -CODE: CODEPIECE {$$=$1;} +CODE: CODE CODEPIECE { + $$=code_append($1,$2); +} +CODE: CODEPIECE { + $$=$1; +} CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/} CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/} @@ -1176,13 +1223,17 @@ CODEPIECE: VARIABLE_DECLARATION {$$=$1} CODEPIECE: VOIDEXPRESSION {$$=$1} CODEPIECE: FOR {$$=$1} CODEPIECE: WHILE {$$=$1} +CODEPIECE: DO_WHILE {$$=$1} +CODEPIECE: SWITCH {$$=$1} CODEPIECE: BREAK {$$=$1} +CODEPIECE: CONTINUE {$$=$1} CODEPIECE: RETURN {$$=$1} CODEPIECE: IF {$$=$1} CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();} CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();} -CODEBLOCK : '{' MAYBECODE '}' {$$=$2;} +CODEBLOCK : '{' CODE '}' {$$=$2;} +CODEBLOCK : '{' '}' {$$=0;} CODEBLOCK : CODEPIECE ';' {$$=$1;} CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;} @@ -1251,7 +1302,7 @@ MAYBEELSE: %prec below_else {$$ = code_new();} MAYBEELSE: "else" CODEBLOCK {$$=$2;} //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;} -IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE { +IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE { $$ = code_new(); $$ = code_append($$, $4.c); code_t*myjmp,*myif = $$ = abc_iffalse($$, 0); @@ -1273,39 +1324,110 @@ FOR_INIT : {$$=code_new();} FOR_INIT : VARIABLE_DECLARATION FOR_INIT : VOIDEXPRESSION -FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK { +FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK { $$ = code_new(); $$ = code_append($$, $4); code_t*loopstart = $$ = abc_label($$); $$ = code_append($$, $6.c); code_t*myif = $$ = abc_iffalse($$, 0); $$ = code_append($$, $10); + code_t*cont = $$ = abc_nop($$); $$ = code_append($$, $8); $$ = abc_jump($$, loopstart); code_t*out = $$ = abc_nop($$); - breakjumpsto($$, out); + breakjumpsto($$, $1, out); + continuejumpsto($$, $1, cont); myif->branch = out; $$ = killvars($$);old_state(); } -WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK { +WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK { $$ = code_new(); code_t*myjmp = $$ = abc_jump($$, 0); code_t*loopstart = $$ = abc_label($$); $$ = code_append($$, $6); - myjmp->branch = $$ = abc_nop($$); + code_t*cont = $$ = abc_nop($$); + myjmp->branch = cont; $$ = code_append($$, $4.c); $$ = abc_iftrue($$, loopstart); code_t*out = $$ = abc_nop($$); - breakjumpsto($$, out); + breakjumpsto($$, $1, out); + continuejumpsto($$, $1, cont); - $$ = killvars($$);old_state(); + $$ = killvars($$); + old_state(); } -BREAK : "break" { - $$ = abc___break__(0); +DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' { + $$ = code_new(); + code_t*loopstart = $$ = abc_label($$); + $$ = code_append($$, $3); + code_t*cont = $$ = abc_nop($$); + $$ = code_append($$, $6.c); + $$ = abc_iftrue($$, loopstart); + code_t*out = $$ = abc_nop($$); + breakjumpsto($$, $1, out); + continuejumpsto($$, $1, cont); + $$ = killvars($$); + old_state(); +} + +BREAK : "break" %prec prec_none { + $$ = abc___break__(0, ""); +} +BREAK : "break" T_IDENTIFIER { + $$ = abc___break__(0, $2); +} +CONTINUE : "continue" %prec prec_none { + $$ = abc___continue__(0, ""); +} +CONTINUE : "continue" T_IDENTIFIER { + $$ = abc___continue__(0, $2); +} + +MAYBE_CASE_LIST : {$$=0;} +MAYBE_CASE_LIST : CASE_LIST {$$=$1;} +MAYBE_CASE_LIST : DEFAULT {$$=$1;} +MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);} +CASE_LIST: CASE {$$=$1} +CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);} + +CASE: "case" CONSTANT ':' MAYBECODE { + $$ = abc_dup(0); + $$ = code_append($$, $2.c); + code_t*j = $$ = abc_ifne($$, 0); + $$ = code_append($$, $4); + $$ = abc___continue__($$, ""); + code_t*e = $$ = abc_nop($$); + j->branch = e; +} +DEFAULT: "default" ':' MAYBECODE { + $$ = $3; +} +SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' { + $$=$4.c; + $$ = code_append($$, $7); + code_t*out = $$ = abc_pop($$); + breakjumpsto($$, $1, out); + + code_t*c = $$,*lastblock=0; + while(c) { + if(c->opcode == OPCODE_IFNE) { + lastblock=c->next; + } else if(c->opcode == OPCODE___CONTINUE__) { + if(lastblock) { + c->opcode = OPCODE_JUMP; + c->branch = lastblock; + } else { + /* fall through end of switch */ + c->opcode = OPCODE_NOP; + } + } + c=c->prev; + } + old_state(); } /* ------------ packages and imports ---------------- */ @@ -1549,6 +1671,7 @@ QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);} TYPE : QNAME {$$=$1;} | '*' {$$=registry_getanytype();} + | "void" {$$=registry_getanytype();} /* | "String" {$$=registry_getstringclass();} | "int" {$$=registry_getintclass();} @@ -1952,6 +2075,48 @@ E : E '[' E ']' { $$.t = 0; // array elements have unknown type } +E : '[' MAYBE_EXPRESSION_LIST ']' { + $$.c = code_new(); + typedcode_list_t*l = 0; + int len = 0; + for(l=$2;l;l=l->next) { + $$.c = code_append($$.c, l->typedcode->c);len++; + } + $$.c = abc_newarray($$.c, len); + $$.t = registry_getarrayclass(); +} + +MAYBE_EXPRPAIR_LIST : {$$=0;} +MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1}; + +EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION { + typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1; + typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3; + $$ = 0; + list_append($$, t1); + list_append($$, t2); +} +EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION { + $$=$1; + typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3; + typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5; + list_append($$, t1); + list_append($$, t2); +} +//MAYBECOMMA: ',' +//MAYBECOMMA: + +E : '{' MAYBE_EXPRPAIR_LIST '}' { + $$.c = code_new(); + typedcode_list_t*l = 0; + int len = 0; + for(l=$2;l;l=l->next) { + $$.c = code_append($$.c, l->typedcode->c);len++; + } + $$.c = abc_newobject($$.c, len/2); + $$.t = registry_getobjectclass(); +} + E : E "*=" E { code_t*c = $3.c; if(BOTH_INT($1,$3)) {