3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #include "tokenizer.h"
44 class_signature_t*class_signature;
45 class_signature_list_t*class_signature_list;
48 unsigned int number_uint;
52 typedcode_list_t*value_list;
53 writeable_t writeable;
58 %token<token> T_IDENTIFIER
59 %token<string> T_STRING
60 %token<token> T_REGEXP
62 %token<number_int> T_INT
63 %token<number_uint> T_UINT
64 %token<number_uint> T_BYTE
65 %token<number_uint> T_SHORT
66 %token<number_float> T_FLOAT
68 %token<token> KW_IMPLEMENTS
69 %token<token> KW_NAMESPACE "namespace"
70 %token<token> KW_PACKAGE "package"
71 %token<token> KW_PROTECTED
72 %token<token> KW_PUBLIC
73 %token<token> KW_PRIVATE
74 %token<token> KW_USE "use"
75 %token<token> KW_INTERNAL
76 %token<token> KW_NEW "new"
77 %token<token> KW_NATIVE
78 %token<token> KW_FUNCTION "function"
79 %token<token> KW_FOR "for"
80 %token<token> KW_CLASS "class"
81 %token<token> KW_CONST "const"
82 %token<token> KW_SET "set"
83 %token<token> KW_STATIC
84 %token<token> KW_IMPORT "import"
85 %token<token> KW_INTERFACE "interface"
87 %token<token> KW_VAR "var"
88 %token<token> KW_DYNAMIC
89 %token<token> KW_OVERRIDE
90 %token<token> KW_FINAL
91 %token<token> KW_GET "get"
92 %token<token> KW_EXTENDS
93 %token<token> KW_FALSE "false"
94 %token<token> KW_TRUE "true"
95 %token<token> KW_BOOLEAN "Boolean"
96 %token<token> KW_UINT "uint"
97 %token<token> KW_INT "int"
98 %token<token> KW_WHILE "while"
99 %token<token> KW_NUMBER "Number"
100 %token<token> KW_STRING "String"
101 %token<token> KW_IF "if"
102 %token<token> KW_ELSE "else"
103 %token<token> KW_BREAK "break"
104 %token<token> KW_IS "is"
105 %token<token> KW_AS "as"
107 %token<token> T_EQEQ "=="
108 %token<token> T_EQEQEQ "==="
109 %token<token> T_NE "!="
110 %token<token> T_LE "<="
111 %token<token> T_GE ">="
112 %token<token> T_DIVBY "/="
113 %token<token> T_MODBY "%="
114 %token<token> T_PLUSBY "+="
115 %token<token> T_MINUSBY "-="
116 %token<token> T_SHRBY ">>="
117 %token<token> T_SHLBY "<<="
118 %token<token> T_USHRBY ">>>="
119 %token<token> T_OROR "||"
120 %token<token> T_ANDAND "&&"
121 %token<token> T_COLONCOLON "::"
122 %token<token> T_MINUSMINUS "--"
123 %token<token> T_PLUSPLUS "++"
124 %token<token> T_DOTDOT ".."
125 %token<token> T_SHL "<<"
126 %token<token> T_USHR ">>>"
127 %token<token> T_SHR ">>"
128 %token<token> T_SEMICOLON ';'
129 %token<token> T_STAR '*'
130 %token<token> T_DOT '.'
133 %type <code> CODEPIECE
134 %type <code> CODEBLOCK MAYBECODE
135 %type <token> PACKAGE_DECLARATION
136 %type <token> FUNCTION_DECLARATION
137 %type <code> VARIABLE_DECLARATION
138 %type <token> CLASS_DECLARATION
139 %type <token> NAMESPACE_DECLARATION
140 %type <token> INTERFACE_DECLARATION
141 %type <code> VOIDEXPRESSION
142 %type <value> EXPRESSION
143 %type <value> MAYBEEXPRESSION
146 %type <value> CONSTANT
147 %type <code> FOR IF WHILE MAYBEELSE BREAK
148 %type <token> USE_NAMESPACE
149 %type <code> ASSIGNMENT FOR_INIT
151 %type <class_signature> MAYBETYPE
152 %type <token> PACKAGESPEC
156 %type <token> PARAM_LIST
157 %type <token> MODIFIERS
158 %type <token> MODIFIER_LIST
159 %type <class_signature_list> IMPLEMENTS_LIST
160 %type <class_signature> EXTENDS
161 %type <class_signature_list> EXTENDS_LIST
162 %type <class_signature> PACKAGEANDCLASS
163 %type <class_signature_list> PACKAGEANDCLASS_LIST
164 %type <token> MULTILEVELIDENTIFIER
165 %type <class_signature> TYPE
167 //%type <token> VARIABLE
168 %type <value> VAR_READ
170 %type <token> X_IDENTIFIER
171 %type <token> MODIFIER
172 %type <token> PACKAGE
173 %type <value> FUNCTIONCALL
174 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST
176 // precendence: from low to high
177 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
192 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
208 %nonassoc T_IDENTIFIER
209 %left below_semicolon
218 static int yyerror(char*s)
220 syntaxerror("%s", s);
222 static token_t* concat2(token_t* t1, token_t* t2)
225 int l1 = strlen(t1->text);
226 int l2 = strlen(t2->text);
227 t->text = malloc(l1+l2+1);
228 memcpy(t->text , t1->text, l1);
229 memcpy(t->text+l1, t2->text, l2);
233 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
236 int l1 = strlen(t1->text);
237 int l2 = strlen(t2->text);
238 int l3 = strlen(t3->text);
239 t->text = malloc(l1+l2+l3+1);
240 memcpy(t->text , t1->text, l1);
241 memcpy(t->text+l1, t2->text, l2);
242 memcpy(t->text+l1+l2, t3->text, l3);
243 t->text[l1+l2+l3] = 0;
246 static char* concat3str(const char* t1, const char* t2, const char* t3)
251 char*text = malloc(l1+l2+l3+1);
252 memcpy(text , t1, l1);
253 memcpy(text+l1, t2, l2);
254 memcpy(text+l1+l2, t3, l3);
259 typedef struct _import {
263 DECLARE_LIST(import);
265 typedef struct _state {
273 /* code that needs to be executed at the start of
274 a method (like initializing local registers) */
278 import_list_t*imports;
288 static state_t* state = 0;
292 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
294 static state_list_t*state_stack=0;
296 static void new_state()
299 NEW(state_list_t, sl);
301 state_t*oldstate = state;
303 memcpy(s, state, sizeof(state_t)); //shallow copy
304 sl->next = state_stack;
307 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
311 state->vars = array_new();
314 static void old_state()
316 if(!state_stack || !state_stack->next)
317 syntaxerror("invalid nesting");
318 state_t*oldstate = state;
319 state_list_t*old = state_stack;
320 state_stack = state_stack->next;
322 state = state_stack->state;
323 /*if(state->initcode) {
324 printf("residual initcode\n");
325 code_dump(state->initcode, 0, 0, "", stdout);
327 state->initcode = code_append(state->initcode, oldstate->initcode);
329 void initialize_state()
333 state->file = abc_file_new();
334 state->file->flags &= ~ABCFILE_LAZY;
336 state->init = abc_initscript(state->file, 0, 0);
337 abc_method_body_t*m = state->init->method->body;
340 __ findpropstrict(m, "[package]::trace");
341 __ pushstring(m, "[entering global init function]");
342 __ callpropvoid(m, "[package]::trace", 1);
344 void* finalize_state()
346 if(state->level!=1) {
347 syntaxerror("unexpected end of file");
349 abc_method_body_t*m = state->init->method->body;
352 __ findpropstrict(m, "[package]::trace");
353 __ pushstring(m, "[leaving global init function]");
354 __ callpropvoid(m, "[package]::trace", 1);
360 static void startpackage(token_t*t)
363 syntaxerror("Packages can not be nested.");
366 char*name = t?t->text:"";
367 /*printf("entering package \"%s\"\n", name);*/
368 state->package = name;
370 static void endpackage()
372 /*printf("leaving package \"%s\"\n", state->package);*/
377 static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements)
380 syntaxerror("inner classes now allowed");
383 state->classname = name->text;
386 class_signature_list_t*mlist=0;
387 /*printf("entering class %s\n", name->text);
388 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
390 printf(" extends: %s.%s\n", extends->package, extends->name);
392 printf(" implements (%d): ", list_length(implements));
393 for(mlist=implements;mlist;mlist=mlist->next) {
394 printf("%s ", mlist->class_signature->name);
398 char public=0,internal=0,final=0,sealed=1;
399 for(t=modifiers->tokens;t;t=t->next) {
400 if(t->token->type == KW_INTERNAL) {
401 /* the programmer is being explicit-
402 being internal is the default anyway */
404 } else if(t->token->type == KW_PUBLIC) {
406 } else if(t->token->type == KW_FINAL) {
409 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
413 syntaxerror("public and internal not supported at the same time.");
415 /* create the class name, together with the proper attributes */
419 if(!public && !state->package) {
420 access = ACCESS_PRIVATE; package = current_filename;
421 } else if(!public && state->package) {
422 access = ACCESS_PACKAGEINTERNAL; package = state->package;
423 } else if(state->package) {
424 access = ACCESS_PACKAGE; package = state->package;
426 syntaxerror("public classes only allowed inside a package");
429 if(registry_findclass(package, state->classname)) {
430 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
433 class_signature_t* classname = class_signature_register(access, package, state->classname);
435 multiname_t*extends2 = sig2mname(extends);
436 multiname_t*classname2 = sig2mname(classname);
438 state->cls = abc_class_new(state->file, classname2, extends2);
439 if(final) abc_class_final(state->cls);
440 if(sealed) abc_class_sealed(state->cls);
442 for(mlist=implements;mlist;mlist=mlist->next) {
443 MULTINAME(m, mlist->class_signature);
444 abc_class_add_interface(state->cls, &m);
447 /* now write the construction code for this class */
448 int slotindex = abc_initscript_addClassTrait(state->init, classname2, state->cls);
450 abc_method_body_t*m = state->init->method->body;
451 __ getglobalscope(m);
452 class_signature_t*s = extends;
457 //TODO: take a look at the current scope stack, maybe
458 // we can re-use something
463 multiname_t*s2 = sig2mname(s);
465 multiname_destroy(s2);
468 m->code = m->code->prev->prev; // invert
471 /* continue appending after last op end */
472 while(m->code && m->code->next) m->code = m->code->next;
474 /* TODO: if this is one of *our* classes, we can also
475 do a getglobalscope/getslot <nr> (which references
476 the init function's slots) */
477 __ getlex2(m, extends2);
479 __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
480 __ newclass(m,state->cls);
484 __ setslot(m, slotindex);
486 /* flash.display.MovieClip handling */
487 if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
488 if(state->package && state->package[0]) {
489 globalclass = concat3str(state->package, ".", state->classname);
491 globalclass = strdup(state->classname);
496 static void endclass()
498 /*printf("leaving class %s\n", state->classname);*/
501 static void addimport(token_t*t)
505 list_append(state->imports, i);
507 static void print_imports()
509 import_list_t*l = state->imports;
511 printf(" import %s\n", l->import->path);
515 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
516 token_t*params, class_signature_t*type)
520 state->function = name->text;
522 /*printf("entering function %s\n", name->text);
524 printf(" namespace: %s\n", ns->text);
525 printf(" getset: %s\n", getset->text);
526 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
527 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
529 printf(" type: %s.%s\n", type->package, type->name);
533 syntaxerror("not able to start another method scope");
536 multiname_t*type2 = sig2mname(type);
538 if(!strcmp(state->classname,name->text)) {
539 state->m = abc_class_constructor(state->cls, type2, 0);
541 state->m = abc_class_method(state->cls, type2, name->text, 0);
543 /* state->vars is initialized by state_new */
544 array_append(state->vars, "this", 0);
546 __ getlocal_0(state->m);
547 __ pushscope(state->m);
549 multiname_destroy(type2);
551 static void endfunction()
553 /*printf("leaving function %s\n", state->function);*/
554 __ returnvoid(state->m);
560 static token_t* empty_token()
568 void extend(token_t*list, token_t*add) {
569 list_append(list->tokens,add);
571 list->text = add->text;
573 void extend_s(token_t*list, char*seperator, token_t*add) {
574 list_append(list->tokens,add);
575 char*t1 = list->text;
581 list->text = malloc(l1+l2+l3+1);
582 strcpy(list->text, t1);
583 strcpy(list->text+l1, t2);
584 strcpy(list->text+l1+l2, t3);
585 list->text[l1+l2+l3]=0;
588 static int find_variable(char*name, class_signature_t**m)
590 state_list_t* s = state_stack;
592 int i = array_find(s->state->vars, name);
595 *m = array_getvalue(s->state->vars, i);
597 return i + s->state->local_var_base;
601 syntaxerror("undefined variable: %s", name);
603 static char variable_exists(char*name)
605 return array_contains(state->vars, name);
607 static int new_variable(char*name, class_signature_t*type)
609 return array_append(state->vars, name, type) + state->local_var_base;
611 code_t* killvars(code_t*c)
614 for(t=0;t<state->vars->num;t++) {
615 class_signature_t*type = array_getvalue(state->vars, t);
616 //do this always, otherwise register types don't match
617 //in the verifier when doing nested loops
618 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
619 c = abc_kill(c, t+state->local_var_base);
625 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
627 return registry_getanytype(); // FIXME
629 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
634 void breakjumpsto(code_t*c, code_t*jump)
639 if(c->opcode == OPCODE___BREAK__) {
640 c->opcode = OPCODE_JUMP;
646 code_t*converttype(code_t*c, class_signature_t*from, class_signature_t*to)
649 /*TODO: can omit this if from is zero? */
650 return abc_coerce_a(c);
652 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
653 MULTINAME(m, TYPE_UINT);
654 return abc_coerce2(c, &m);
656 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
657 MULTINAME(m, TYPE_INT);
658 return abc_coerce2(c, &m);
663 code_t*defaultvalue(code_t*c, class_signature_t*type)
665 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
666 c = abc_pushbyte(c, 0);
667 } else if(TYPE_IS_BOOLEAN(type)) {
668 c = abc_pushfalse(c);
680 /* ------------ code blocks / statements ---------------- */
684 MAYBECODE: CODE {$$=$1;}
685 MAYBECODE: {$$=code_new();}
687 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
688 CODE: CODEPIECE {$$=$1;}
690 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
691 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
692 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
693 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
694 CODEPIECE: ';' {$$=code_new();}
695 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
696 CODEPIECE: VOIDEXPRESSION {$$=$1}
697 CODEPIECE: FOR {$$=$1}
698 CODEPIECE: WHILE {$$=$1}
699 CODEPIECE: BREAK {$$=$1}
700 CODEPIECE: IF {$$=$1}
701 CODEPIECE: ASSIGNMENT {$$=$1}
702 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
703 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
704 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
706 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
707 CODEBLOCK : CODEPIECE ';' {$$=$1;}
708 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
710 /* ------------ functions --------------------------- */
712 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
713 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
714 if(!state->m) syntaxerror("internal error: undefined function");
715 state->initcode = abc_nop(state->initcode);
716 state->initcode = abc_nop(state->initcode);
717 state->initcode = abc_nop(state->initcode);
718 state->m->code = code_append(state->initcode, $11);state->initcode=0;
722 /* ------------ variables --------------------------- */
724 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
725 | {$$.c=abc_pushundefined(0);
729 VAR : "const" | "var"
730 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
731 if(variable_exists($2->text))
732 syntaxerror("Variable %s already defined", $2->text);
734 if(!is_subtype_of($4.t, $3)) {
735 syntaxerror("Can't convert %s to %s", $4.t->name,
739 int index = new_variable($2->text, $3);
742 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
744 $$ = converttype($$, $4.t, $3);
745 $$ = abc_setlocal($$, index);
747 $$ = defaultvalue(0, $3);
748 $$ = abc_setlocal($$, index);
751 /* push default value for type on stack */
752 state->initcode = defaultvalue(state->initcode, $3);
753 state->initcode = abc_setlocal(state->initcode, index);
755 /* only bother to actually set this variable if its syntax is either
760 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
762 $$ = abc_coerce_a($$);
763 $$ = abc_setlocal($$, index);
769 /* that's the default for a local register, anyway
771 state->initcode = abc_pushundefined(state->initcode);
772 state->initcode = abc_setlocal(state->initcode, index);
774 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
776 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
777 class_signature_t*type=0;
778 int i = find_variable($1->text, &type);
781 // convert to "any" type, the register is untyped
782 $$ = abc_coerce_a($$);
784 // TODO: convert ints to strings etc.
786 $$ = abc_setlocal($$, i);
789 /* ------------ control flow ------------------------- */
791 MAYBEELSE: %prec prec_none {$$ = code_new();}
792 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
793 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
795 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
796 $$ = state->initcode;state->initcode=0;
798 $$ = code_append($$, $4.c);
799 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
801 $$ = code_append($$, $6);
803 myjmp = $$ = abc_jump($$, 0);
805 myif->branch = $$ = abc_label($$);
807 $$ = code_append($$, $7);
808 myjmp->branch = $$ = abc_label($$);
811 $$ = killvars($$);old_state();
814 FOR_INIT : {$$=code_new();}
815 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
817 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
818 $$ = state->initcode;state->initcode=0;
820 $$ = code_append($$, $4);
821 code_t*loopstart = $$ = abc_label($$);
822 $$ = code_append($$, $6.c);
823 code_t*myif = $$ = abc_iffalse($$, 0);
824 $$ = code_append($$, $10);
825 $$ = code_append($$, $8);
826 $$ = abc_jump($$, loopstart);
827 code_t*out = $$ = abc_label($$);
828 breakjumpsto($$, out);
831 $$ = killvars($$);old_state();
834 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
835 $$ = state->initcode;state->initcode=0;
837 code_t*myjmp = $$ = abc_jump($$, 0);
838 code_t*loopstart = $$ = abc_label($$);
839 $$ = code_append($$, $6);
840 myjmp->branch = $$ = abc_label($$);
841 $$ = code_append($$, $4.c);
842 $$ = abc_iftrue($$, loopstart);
843 code_t*out = $$ = abc_label($$);
844 breakjumpsto($$, out);
846 $$ = killvars($$);old_state();
850 $$ = abc___break__(0);
853 /* ------------ packages and imports ---------------- */
855 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
856 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
858 IMPORT : "import" PACKAGESPEC {addimport($2);}
860 TYPE : PACKAGEANDCLASS {$$=$1;}
861 | '*' {$$=registry_getanytype();}
862 | "String" {$$=registry_getstringclass();}
863 | "int" {$$=registry_getintclass();}
864 | "uint" {$$=registry_getuintclass();}
865 | "Boolean" {$$=registry_getbooleanclass();}
866 | "Number" {$$=registry_getnumberclass();}
868 MAYBETYPE: ':' TYPE {$$=$2;}
871 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
872 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
875 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
876 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
877 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
879 //NAMESPACE : {$$=empty_token();}
880 //NAMESPACE : T_IDENTIFIER {$$=$1};
882 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
883 //MULTINAME(m, registry_getintclass());
884 //$$.c = abc_coerce2($$.c, &m); // FIXME
887 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
890 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
893 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
896 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
899 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
902 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
905 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
908 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
912 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
915 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
916 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
919 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
920 E : NEW {$$.c = abc_pushundefined(0); /* FIXME */
923 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
927 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
930 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
933 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
936 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
939 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
942 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
945 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
951 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
952 $$.t = join_types($1.t, $3.t, '+');
954 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
955 $$.t = join_types($1.t, $3.t, '%');
957 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
958 $$.t = join_types($1.t, $3.t, '*');
963 E : '(' E ')' {$$=$2;}
966 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
967 class_signature_t*type = join_types($1.type, $3.t, '+');
968 $$.c=converttype($$.c, type, $1.type);
969 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
972 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
973 class_signature_t*type = join_types($1.type, $3.t, '-');
974 $$.c=converttype($$.c, type, $1.type);
975 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
979 // TODO: use inclocal where appropriate
980 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
981 class_signature_t*type = $1.type;
982 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
983 $$.c=converttype($$.c, type, $1.type);
984 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
987 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
988 class_signature_t*type = $1.type;
989 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
990 $$.c=converttype($$.c, 0, $1.type);
991 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
996 int i = find_variable($1->text, &$$.type);
997 $$.read = abc_getlocal(0, i);
998 $$.write = abc_setlocal(0, i);
1001 NEW : "new" T_IDENTIFIER {$$.c=0;$$.t=0;/*FIXME*/}
1002 | "new" T_IDENTIFIER '(' ')' {$$.c=0;$$.t=0;/*FIXME*/}
1003 | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
1005 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1006 /* TODO: use abc_call (for calling local variables),
1007 abc_callstatic (for calling own methods) */
1009 $$.c = abc_findpropstrict($$.c, $1->text);
1010 typedcode_list_t*l = $3;
1011 // push parameters on stack
1014 $$.c = code_append($$.c, l->typedcode.c);
1018 $$.c = abc_callproperty($$.c, $1->text, len);
1021 MAYBE_EXPRESSION_LIST : {$$=0;}
1022 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1023 EXPRESSION_LIST : EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1025 $$->typedcode = $1;}
1026 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1031 VAR_READ : T_IDENTIFIER {
1032 int i = find_variable($1->text, &$$.t);
1033 $$.c = abc_getlocal(0, i);
1036 //VARIABLE : T_IDENTIFIER
1037 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1038 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1039 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1040 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1041 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1043 // keywords which also may be identifiers
1044 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1046 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
1047 $$ = concat3($1,$2,$3);}
1048 PACKAGESPEC : X_IDENTIFIER {$$=$1;}
1049 PACKAGESPEC : '*' {$$=$1;}
1051 GETSET : "get" {$$=$1;}
1053 | {$$=empty_token();}
1055 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
1056 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
1058 PARAMS: {$$=empty_token();}
1059 PARAMS: PARAM_LIST {$$=$1;}
1060 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
1061 PARAM_LIST: PARAM {$$=empty_token();extend($$,$1);}
1062 PARAM: T_IDENTIFIER ':' TYPE {$$=$1;}
1064 MODIFIERS : {$$=empty_token();}
1065 MODIFIERS : MODIFIER_LIST {$$=$1}
1066 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1067 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
1068 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1070 DECLARATION : VARIABLE_DECLARATION
1071 DECLARATION : FUNCTION_DECLARATION
1073 IDECLARATION : VARIABLE_DECLARATION
1074 IDECLARATION : FUNCTION_DECLARATION
1076 IMPLEMENTS_LIST : {$$=list_new();}
1077 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
1079 EXTENDS : {$$=registry_getobjectclass();}
1080 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
1082 EXTENDS_LIST : {$$=list_new();}
1083 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
1085 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1086 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1088 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
1089 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
1090 PACKAGE : X_IDENTIFIER
1091 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
1093 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1094 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1096 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1097 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1099 MAYBE_DECLARATION_LIST :
1100 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1101 DECLARATION_LIST : DECLARATION
1102 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1104 MAYBE_IDECLARATION_LIST :
1105 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1106 IDECLARATION_LIST : IDECLARATION
1107 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1110 // keywords: as break case catch class const continue default delete do else extends false finally for function if implements import in instanceof interface internal is native new null package private protected public return super switch this throw to true try typeof use var void while with
1111 // syntactic keywords: each get set namespace include dynamic final native override static