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)
652 code_t*defaultvalue(code_t*c, class_signature_t*type)
654 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
655 c = abc_pushbyte(c, 0);
656 } else if(TYPE_IS_BOOLEAN(type)) {
657 c = abc_pushfalse(c);
669 /* ------------ code blocks / statements ---------------- */
673 MAYBECODE: CODE {$$=$1;}
674 MAYBECODE: {$$=code_new();}
676 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
677 CODE: CODEPIECE {$$=$1;}
679 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
680 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
681 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
682 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
683 CODEPIECE: ';' {$$=code_new();}
684 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
685 CODEPIECE: VOIDEXPRESSION {$$=$1}
686 CODEPIECE: FOR {$$=$1}
687 CODEPIECE: WHILE {$$=$1}
688 CODEPIECE: BREAK {$$=$1}
689 CODEPIECE: IF {$$=$1}
690 CODEPIECE: ASSIGNMENT {$$=$1}
691 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
692 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
693 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
695 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
696 CODEBLOCK : CODEPIECE ';' {$$=$1;}
697 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
699 /* ------------ functions --------------------------- */
701 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
702 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
703 if(!state->m) syntaxerror("internal error: undefined function");
704 state->initcode = abc_nop(state->initcode);
705 state->initcode = abc_nop(state->initcode);
706 state->initcode = abc_nop(state->initcode);
707 state->m->code = code_append(state->initcode, $11);state->initcode=0;
711 /* ------------ variables --------------------------- */
713 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
714 | {$$.c=abc_pushundefined(0);
718 VAR : "const" | "var"
719 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
720 if(variable_exists($2->text))
721 syntaxerror("Variable %s already defined", $2->text);
723 if(!is_subtype_of($4.t, $3)) {
724 syntaxerror("Can't convert %s to %s", $4.t->name,
728 int index = new_variable($2->text, $3);
731 if($4.c->prev || $4.c->opcode != OPCODE_PUSH_UNDEFINED) {
733 $$ = converttype($$, $4.t, $3);
734 $$ = abc_setlocal($$, index);
736 $$ = defaultvalue(0, $3);
737 $$ = abc_setlocal($$, index);
740 /* push default value for type on stack */
741 state->initcode = defaultvalue(state->initcode, $3);
742 state->initcode = abc_setlocal(state->initcode, index);
744 /* only bother to actually set this variable if its syntax is either
749 if($4.c->prev || $4.c->opcode != OPCODE_PUSH_UNDEFINED) {
751 $$ = abc_coerce_a($$);
752 $$ = abc_setlocal($$, index);
758 /* that's the default for a local register, anyway
760 state->initcode = abc_pushundefined(state->initcode);
761 state->initcode = abc_setlocal(state->initcode, index);
763 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
765 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
766 class_signature_t*type=0;
767 int i = find_variable($1->text, &type);
770 // convert to "any" type, the register is untyped
771 $$ = abc_coerce_a($$);
773 // TODO: convert ints to strings etc.
775 $$ = abc_setlocal($$, i);
778 /* ------------ control flow ------------------------- */
780 MAYBEELSE: %prec prec_none {$$ = code_new();}
781 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
782 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
784 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
785 $$ = state->initcode;state->initcode=0;
787 $$ = code_append($$, $4.c);
788 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
790 $$ = code_append($$, $6);
792 myjmp = $$ = abc_jump($$, 0);
794 myif->branch = $$ = abc_label($$);
796 $$ = code_append($$, $7);
797 myjmp->branch = $$ = abc_label($$);
800 $$ = killvars($$);old_state();
803 FOR_INIT : {$$=code_new();}
804 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
806 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
807 code_append($$, state->initcode);state->initcode=0;
809 $$ = code_append($$, $4);
810 code_t*loopstart = $$ = abc_label($$);
811 $$ = code_append($$, $6.c);
812 code_t*myif = $$ = abc_iffalse($$, 0);
813 $$ = code_append($$, $10);
814 $$ = code_append($$, $8);
815 $$ = abc_jump($$, loopstart);
816 code_t*out = $$ = abc_label($$);
817 breakjumpsto($$, out);
820 $$ = killvars($$);old_state();
823 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
824 $$ = state->initcode;state->initcode=0;
826 code_t*myjmp = $$ = abc_jump($$, 0);
827 code_t*loopstart = $$ = abc_label($$);
828 $$ = code_append($$, $6);
829 myjmp->branch = $$ = abc_label($$);
830 $$ = code_append($$, $4.c);
831 $$ = abc_iftrue($$, loopstart);
832 code_t*out = $$ = abc_label($$);
833 breakjumpsto($$, out);
835 $$ = killvars($$);old_state();
839 $$ = abc___break__(0);
842 /* ------------ packages and imports ---------------- */
844 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
845 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
847 IMPORT : "import" PACKAGESPEC {addimport($2);}
849 TYPE : PACKAGEANDCLASS {$$=$1;}
850 | '*' {$$=registry_getanytype();}
851 | "String" {$$=registry_getstringclass();}
852 | "int" {$$=registry_getintclass();}
853 | "uint" {$$=registry_getuintclass();}
854 | "Boolean" {$$=registry_getbooleanclass();}
855 | "Number" {$$=registry_getnumberclass();}
857 MAYBETYPE: ':' TYPE {$$=$2;}
860 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
861 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
864 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
865 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
866 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
868 //NAMESPACE : {$$=empty_token();}
869 //NAMESPACE : T_IDENTIFIER {$$=$1};
871 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
872 //MULTINAME(m, registry_getintclass());
873 //$$.c = abc_coerce2($$.c, &m); // FIXME
876 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
879 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
882 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
885 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
888 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
891 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
894 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
897 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
901 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
904 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
905 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
908 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
909 E : NEW {$$.c = abc_pushundefined(0); /* FIXME */
912 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
916 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
919 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
922 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
925 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
928 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
931 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
934 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
940 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
941 $$.t = join_types($1.t, $3.t, '+');
943 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
944 $$.t = join_types($1.t, $3.t, '%');
946 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
947 $$.t = join_types($1.t, $3.t, '*');
952 E : '(' E ')' {$$=$2;}
955 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
956 MULTINAME(m, registry_getintclass());
957 $$.c=abc_coerce2($$.c, &m); // FIXME
958 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
961 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
962 MULTINAME(m, registry_getintclass());
963 $$.c=abc_coerce2($$.c, &m); // FIXME
964 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
968 // TODO: use inclocal where appropriate
969 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
970 MULTINAME(m, registry_getintclass());
971 $$.c=abc_coerce2($$.c, &m); //FIXME
972 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
975 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
976 MULTINAME(m, registry_getintclass());
977 $$.c=abc_coerce2($$.c, &m); //FIXME
978 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
983 int i = find_variable($1->text, &$$.type);
984 $$.read = abc_getlocal(0, i);
985 $$.write = abc_setlocal(0, i);
988 NEW : "new" T_IDENTIFIER {$$.c=0;$$.t=0;/*FIXME*/}
989 | "new" T_IDENTIFIER '(' ')' {$$.c=0;$$.t=0;/*FIXME*/}
990 | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
992 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
993 /* TODO: use abc_call (for calling local variables),
994 abc_callstatic (for calling own methods) */
996 $$.c = abc_findpropstrict($$.c, $1->text);
997 typedcode_list_t*l = $3;
998 // push parameters on stack
1001 $$.c = code_append($$.c, l->typedcode.c);
1005 $$.c = abc_callproperty($$.c, $1->text, len);
1008 MAYBE_EXPRESSION_LIST : {$$=0;}
1009 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1010 EXPRESSION_LIST : EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1012 $$->typedcode = $1;}
1013 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1018 VAR_READ : T_IDENTIFIER {
1019 int i = find_variable($1->text, &$$.t);
1020 $$.c = abc_getlocal(0, i);
1023 //VARIABLE : T_IDENTIFIER
1024 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1025 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1026 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1027 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1028 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1030 // keywords which also may be identifiers
1031 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1033 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
1034 $$ = concat3($1,$2,$3);}
1035 PACKAGESPEC : X_IDENTIFIER {$$=$1;}
1036 PACKAGESPEC : '*' {$$=$1;}
1038 GETSET : "get" {$$=$1;}
1040 | {$$=empty_token();}
1042 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
1043 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
1045 PARAMS: {$$=empty_token();}
1046 PARAMS: PARAM_LIST {$$=$1;}
1047 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
1048 PARAM_LIST: PARAM {$$=empty_token();extend($$,$1);}
1049 PARAM: T_IDENTIFIER ':' TYPE {$$=$1;}
1051 MODIFIERS : {$$=empty_token();}
1052 MODIFIERS : MODIFIER_LIST {$$=$1}
1053 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1054 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
1055 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1057 DECLARATION : VARIABLE_DECLARATION
1058 DECLARATION : FUNCTION_DECLARATION
1060 IDECLARATION : VARIABLE_DECLARATION
1061 IDECLARATION : FUNCTION_DECLARATION
1063 IMPLEMENTS_LIST : {$$=list_new();}
1064 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
1066 EXTENDS : {$$=registry_getobjectclass();}
1067 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
1069 EXTENDS_LIST : {$$=list_new();}
1070 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
1072 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1073 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1075 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
1076 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
1077 PACKAGE : X_IDENTIFIER
1078 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
1080 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1081 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1083 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1084 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1086 MAYBE_DECLARATION_LIST :
1087 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1088 DECLARATION_LIST : DECLARATION
1089 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1091 MAYBE_IDECLARATION_LIST :
1092 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1093 IDECLARATION_LIST : IDECLARATION
1094 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1097 // 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
1098 // syntactic keywords: each get set namespace include dynamic final native override static