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 struct _class_signature*class_signature;
45 struct _class_signature_list*class_signature_list;
48 unsigned int number_uint;
51 struct _typedcode value;
52 struct _typedcode_list*value_list;
53 struct _writeable 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 state->initcode = code_append(state->initcode, oldstate->initcode);
325 void initialize_state()
329 state->file = abc_file_new();
330 state->file->flags &= ~ABCFILE_LAZY;
332 state->init = abc_initscript(state->file, 0, 0);
333 abc_method_body_t*m = state->init->method->body;
336 __ findpropstrict(m, "[package]::trace");
337 __ pushstring(m, "[entering global init function]");
338 __ callpropvoid(m, "[package]::trace", 1);
340 void* finalize_state()
342 if(state->level!=1) {
343 syntaxerror("unexpected end of file");
345 abc_method_body_t*m = state->init->method->body;
348 __ findpropstrict(m, "[package]::trace");
349 __ pushstring(m, "[leaving global init function]");
350 __ callpropvoid(m, "[package]::trace", 1);
356 static void startpackage(token_t*t)
359 syntaxerror("Packages can not be nested.");
362 char*name = t?t->text:"";
363 printf("entering package \"%s\"\n", name);
364 state->package = name;
366 static void endpackage()
368 printf("leaving package \"%s\"\n", state->package);
373 static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements)
376 syntaxerror("inner classes now allowed");
379 state->classname = name->text;
380 printf("entering class %s\n", name->text);
382 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
384 printf(" extends: %s.%s\n", extends->package, extends->name);
386 class_signature_list_t*mlist=0;
387 printf(" implements (%d): ", list_length(implements));
388 for(mlist=implements;mlist;mlist=mlist->next) {
389 printf("%s ", mlist->class_signature->name);
393 char public=0,internal=0,final=0,sealed=1;
394 for(t=modifiers->tokens;t;t=t->next) {
395 if(t->token->type == KW_INTERNAL) {
396 /* the programmer is being explicit-
397 being internal is the default anyway */
399 } else if(t->token->type == KW_PUBLIC) {
401 } else if(t->token->type == KW_FINAL) {
404 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
408 syntaxerror("public and internal not supported at the same time.");
410 /* create the class name, together with the proper attributes */
414 if(!public && !state->package) {
415 access = ACCESS_PRIVATE; package = current_filename;
416 } else if(!public && state->package) {
417 access = ACCESS_PACKAGEINTERNAL; package = state->package;
418 } else if(state->package) {
419 access = ACCESS_PACKAGE; package = state->package;
421 syntaxerror("public classes only allowed inside a package");
424 if(registry_findclass(package, state->classname)) {
425 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
428 class_signature_t* classname = class_signature_register(access, package, state->classname);
430 multiname_t*extends2 = sig2mname(extends);
431 multiname_t*classname2 = sig2mname(classname);
433 state->cls = abc_class_new(state->file, classname2, extends2);
434 if(final) abc_class_final(state->cls);
435 if(sealed) abc_class_sealed(state->cls);
437 for(mlist=implements;mlist;mlist=mlist->next) {
438 MULTINAME(m, mlist->class_signature);
439 abc_class_add_interface(state->cls, &m);
442 /* now write the construction code for this class */
443 int slotindex = abc_initscript_addClassTrait(state->init, classname2, state->cls);
445 abc_method_body_t*m = state->init->method->body;
446 __ getglobalscope(m);
447 class_signature_t*s = extends;
452 //TODO: take a look at the current scope stack, maybe
453 // we can re-use something
458 multiname_t*s2 = sig2mname(s);
460 multiname_destroy(s2);
463 m->code = m->code->prev->prev; // invert
466 /* continue appending after last op end */
467 while(m->code && m->code->next) m->code = m->code->next;
469 /* TODO: if this is one of *our* classes, we can also
470 do a getglobalscope/getslot <nr> (which references
471 the init function's slots) */
472 __ getlex2(m, extends2);
474 __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
475 __ newclass(m,state->cls);
479 __ setslot(m, slotindex);
481 /* flash.display.MovieClip handling */
482 if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
483 if(state->package && state->package[0]) {
484 globalclass = concat3str(state->package, ".", state->classname);
486 globalclass = strdup(state->classname);
491 static void endclass()
493 printf("leaving class %s\n", state->classname);
496 static void addimport(token_t*t)
500 list_append(state->imports, i);
502 static void print_imports()
504 import_list_t*l = state->imports;
506 printf(" import %s\n", l->import->path);
510 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
511 token_t*params, class_signature_t*type)
515 state->function = name->text;
516 printf("entering function %s\n", name->text);
518 printf(" namespace: %s\n", ns->text);
519 printf(" getset: %s\n", getset->text);
520 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
521 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
523 printf(" type: %s.%s\n", type->package, type->name);
527 syntaxerror("not able to start another method scope");
530 multiname_t*type2 = sig2mname(type);
532 if(!strcmp(state->classname,name->text)) {
533 state->m = abc_class_constructor(state->cls, type2, 0);
535 state->m = abc_class_method(state->cls, type2, name->text, 0);
537 array_append(state->vars, "this", 0);
539 __ getlocal_0(state->m);
540 __ pushscope(state->m);
542 multiname_destroy(type2);
544 static void endfunction()
546 printf("leaving function %s\n", state->function);
547 __ returnvoid(state->m);
551 static token_t* empty_token()
559 void extend(token_t*list, token_t*add) {
560 list_append(list->tokens,add);
562 list->text = add->text;
564 void extend_s(token_t*list, char*seperator, token_t*add) {
565 list_append(list->tokens,add);
566 char*t1 = list->text;
572 list->text = malloc(l1+l2+l3+1);
573 strcpy(list->text, t1);
574 strcpy(list->text+l1, t2);
575 strcpy(list->text+l1+l2, t3);
576 list->text[l1+l2+l3]=0;
579 int find_variable(char*name, class_signature_t**m)
581 state_list_t* s = state_stack;
583 int i = array_find(s->state->vars, name);
586 *m = array_getvalue(s->state->vars, i);
588 return i + s->state->local_var_base;
592 syntaxerror("undefined variable: %s", name);
595 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
597 return registry_getanytype(); // FIXME
599 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
604 #define TYPE_ANY registry_getanytype()
605 #define TYPE_IS_ANY(t) ((t) == registry_getanytype())
606 #define TYPE_INT registry_getintclass()
607 #define TYPE_IS_INT(t) ((t) == registry_getintclass())
608 #define TYPE_UINT registry_getuintclass()
609 #define TYPE_IS_UINT(t) ((t) == registry_getuintclass())
610 #define TYPE_FLOAT registry_getnumberclass()
611 #define TYPE_IS_FLOAT(t) ((t) == registry_getnumberclass())
612 #define TYPE_BOOLEAN registry_getbooleanclass()
613 #define TYPE_IS_BOOLEAN(t)((t) == registry_getbooleanclass())
614 #define TYPE_STRING registry_getstringclass()
615 #define TYPE_IS_STRING(t) ((t) == registry_getstringclass())
616 #define TYPE_NULL registry_getnullclass()
617 #define TYPE_IS_NULL(t) ((t) == registry_getnullclass())
624 /* ------------ code blocks / statements ---------------- */
628 MAYBECODE: CODE {$$=$1;}
629 MAYBECODE: {$$=code_new();}
631 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
632 CODE: CODEPIECE {$$=$1;}
634 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
635 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
636 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
637 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
638 CODEPIECE: ';' {$$=code_new();}
639 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
640 CODEPIECE: VOIDEXPRESSION {$$=$1}
641 CODEPIECE: FOR {$$=$1}
642 CODEPIECE: WHILE {$$=$1}
643 CODEPIECE: BREAK {$$=$1}
644 CODEPIECE: IF {$$=$1}
645 CODEPIECE: ASSIGNMENT {$$=$1}
646 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
647 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
648 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
650 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
651 CODEBLOCK : CODEPIECE ';' {$$=$1;}
652 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
654 /* ------------ functions --------------------------- */
656 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
657 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
658 if(!state->m) syntaxerror("internal error: undefined function");
659 state->m->code = code_append(state->initcode, $11);state->initcode=0;
663 /* ------------ variables --------------------------- */
665 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
666 | {$$.c=abc_pushundefined(0);
670 VAR : "const" | "var"
671 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
672 if(array_contains(state->vars, $2->text))
673 syntaxerror("Variable %s already defined", $2->text);
676 if(!is_subtype_of($4.t, $3)) {
677 syntaxerror("Can't convert %s to %s", $4.t->name,
681 int index = array_append(state->vars, $2->text, $3) + state->local_var_base;
682 $$ = abc_setlocal($$, index);
685 if(TYPE_IS_INT($3) || TYPE_IS_UINT($3) || TYPE_IS_FLOAT($3)) {
686 state->initcode = abc_pushbyte(state->initcode, 32);
687 } else if(TYPE_IS_BOOLEAN($3)) {
688 state->initcode = abc_pushfalse(state->initcode);
690 state->initcode = abc_pushnull(state->initcode);
692 state->initcode = abc_setlocal(state->initcode, index);
694 // that's the default for a local register, anyway
695 state->initcode = abc_pushundefined(state->initcode);
696 state->initcode = abc_setlocal(state->initcode, index);
698 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t->name);
700 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
701 class_signature_t*type=0;
702 int i = find_variable($1->text, &type);
705 // convert to "any" type, the register is untyped
706 $$ = abc_coerce_a($$);
708 // TODO: convert ints to strings etc.
710 $$ = abc_setlocal($$, i);
713 /* ------------ control flow ------------------------- */
715 MAYBEELSE: %prec prec_none {$$ = code_new();}
716 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
717 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
719 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
721 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
723 $$ = code_append($$, $6);
725 myjmp = $$ = abc_jump($$, 0);
727 myif->branch = $$ = abc_label($$);
729 $$ = code_append($$, $7);
730 myjmp->branch = $$ = abc_label($$);
735 FOR_INIT : {$$=code_new();}
736 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
738 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
740 code_t*loopstart = $$ = abc_label($$);
741 $$ = code_append($$, $6.c);
742 code_t*myif = $$ = abc_iffalse($$, 0);
743 $$ = code_append($$, $10);
744 $$ = code_append($$, $8);
745 $$ = abc_jump($$, loopstart);
751 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
752 code_t*myjmp = $$ = abc_jump(0, 0);
753 code_t*loopstart = $$ = abc_label($$);
754 $$ = code_append($$, $6);
755 myjmp->branch = $$ = abc_label($$);
756 $$ = code_append($$, $4.c);
757 $$ = abc_iftrue($$, loopstart);
762 $$ = abc___break__(0);
765 /* ------------ packages and imports ---------------- */
767 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
768 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
770 IMPORT : "import" PACKAGESPEC {addimport($2);}
772 TYPE : PACKAGEANDCLASS {$$=$1;}
773 | '*' {$$=registry_getanytype();}
774 | "String" {$$=registry_getstringclass();}
775 | "int" {$$=registry_getintclass();}
776 | "uint" {$$=registry_getuintclass();}
777 | "Boolean" {$$=registry_getbooleanclass();}
778 | "Number" {$$=registry_getnumberclass();}
780 MAYBETYPE: ':' TYPE {$$=$2;}
783 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
784 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
787 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
788 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
789 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
791 //NAMESPACE : {$$=empty_token();}
792 //NAMESPACE : T_IDENTIFIER {$$=$1};
794 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
795 MULTINAME(m, registry_getintclass());
796 $$.c = abc_coerce2($$.c, &m); // FIXME
799 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
802 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
805 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
808 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
811 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
814 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
817 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
820 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
824 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
827 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
828 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
831 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
832 E : NEW {$$.c = abc_pushundefined(0); /* FIXME */
835 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
839 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
842 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
845 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
848 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
851 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
854 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
857 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
863 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
864 $$.t = join_types($1.t, $3.t, '+');
866 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
867 $$.t = join_types($1.t, $3.t, '%');
869 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
870 $$.t = join_types($1.t, $3.t, '*');
875 E : '(' E ')' {$$=$2;}
878 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
879 MULTINAME(m, registry_getintclass());
880 $$.c=abc_coerce2($$.c, &m); // FIXME
881 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
884 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
885 MULTINAME(m, registry_getintclass());
886 $$.c=abc_coerce2($$.c, &m); // FIXME
887 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
891 // TODO: use inclocal where appropriate
892 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
893 MULTINAME(m, registry_getintclass());
894 $$.c=abc_coerce2($$.c, &m); //FIXME
895 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
898 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
899 MULTINAME(m, registry_getintclass());
900 $$.c=abc_coerce2($$.c, &m); //FIXME
901 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
906 int i = find_variable($1->text, &$$.type);
907 $$.read = abc_getlocal(0, i);
908 $$.write = abc_setlocal(0, i);
911 NEW : "new" T_IDENTIFIER {$$.c=0;$$.t=0;/*FIXME*/}
912 | "new" T_IDENTIFIER '(' ')' {$$.c=0;$$.t=0;/*FIXME*/}
913 | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
915 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
916 /* TODO: use abc_call (for calling local variables),
917 abc_callstatic (for calling own methods) */
919 $$.c = abc_findpropstrict($$.c, $1->text);
920 typedcode_list_t*l = $3;
921 // push parameters on stack
924 $$.c = code_append($$.c, l->typedcode.c);
928 $$.c = abc_callproperty($$.c, $1->text, len);
931 MAYBE_EXPRESSION_LIST : {$$=0;}
932 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
933 EXPRESSION_LIST : EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
936 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
941 VAR_READ : T_IDENTIFIER {
942 int i = find_variable($1->text, &$$.t);
943 $$.c = abc_getlocal(0, i);
946 //VARIABLE : T_IDENTIFIER
947 //VARIABLE : VARIABLE '.' T_IDENTIFIER
948 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
949 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
950 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
951 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
953 // keywords which also may be identifiers
954 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
956 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
957 $$ = concat3($1,$2,$3);}
958 PACKAGESPEC : X_IDENTIFIER {$$=$1;}
959 PACKAGESPEC : '*' {$$=$1;}
961 GETSET : "get" {$$=$1;}
963 | {$$=empty_token();}
965 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
966 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
968 PARAMS: {$$=empty_token();}
969 PARAMS: PARAM_LIST {$$=$1;}
970 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
971 PARAM_LIST: PARAM {$$=empty_token();extend($$,$1);}
972 PARAM: T_IDENTIFIER ':' TYPE {$$=$1;}
974 MODIFIERS : {$$=empty_token();}
975 MODIFIERS : MODIFIER_LIST {$$=$1}
976 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
977 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
978 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
980 DECLARATION : VARIABLE_DECLARATION
981 DECLARATION : FUNCTION_DECLARATION
983 IDECLARATION : VARIABLE_DECLARATION
984 IDECLARATION : FUNCTION_DECLARATION
986 IMPLEMENTS_LIST : {$$=list_new();}
987 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
989 EXTENDS : {$$=registry_getobjectclass();}
990 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
992 EXTENDS_LIST : {$$=list_new();}
993 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
995 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
996 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
998 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
999 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
1000 PACKAGE : X_IDENTIFIER
1001 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
1003 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1004 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1006 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1007 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1009 MAYBE_DECLARATION_LIST :
1010 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1011 DECLARATION_LIST : DECLARATION
1012 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1014 MAYBE_IDECLARATION_LIST :
1015 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1016 IDECLARATION_LIST : IDECLARATION
1017 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1020 // 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
1021 // syntactic keywords: each get set namespace include dynamic final native override static