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;
382 class_signature_list_t*mlist=0;
383 /*printf("entering class %s\n", name->text);
384 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
386 printf(" extends: %s.%s\n", extends->package, extends->name);
388 printf(" implements (%d): ", list_length(implements));
389 for(mlist=implements;mlist;mlist=mlist->next) {
390 printf("%s ", mlist->class_signature->name);
394 char public=0,internal=0,final=0,sealed=1;
395 for(t=modifiers->tokens;t;t=t->next) {
396 if(t->token->type == KW_INTERNAL) {
397 /* the programmer is being explicit-
398 being internal is the default anyway */
400 } else if(t->token->type == KW_PUBLIC) {
402 } else if(t->token->type == KW_FINAL) {
405 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
409 syntaxerror("public and internal not supported at the same time.");
411 /* create the class name, together with the proper attributes */
415 if(!public && !state->package) {
416 access = ACCESS_PRIVATE; package = current_filename;
417 } else if(!public && state->package) {
418 access = ACCESS_PACKAGEINTERNAL; package = state->package;
419 } else if(state->package) {
420 access = ACCESS_PACKAGE; package = state->package;
422 syntaxerror("public classes only allowed inside a package");
425 if(registry_findclass(package, state->classname)) {
426 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
429 class_signature_t* classname = class_signature_register(access, package, state->classname);
431 multiname_t*extends2 = sig2mname(extends);
432 multiname_t*classname2 = sig2mname(classname);
434 state->cls = abc_class_new(state->file, classname2, extends2);
435 if(final) abc_class_final(state->cls);
436 if(sealed) abc_class_sealed(state->cls);
438 for(mlist=implements;mlist;mlist=mlist->next) {
439 MULTINAME(m, mlist->class_signature);
440 abc_class_add_interface(state->cls, &m);
443 /* now write the construction code for this class */
444 int slotindex = abc_initscript_addClassTrait(state->init, classname2, state->cls);
446 abc_method_body_t*m = state->init->method->body;
447 __ getglobalscope(m);
448 class_signature_t*s = extends;
453 //TODO: take a look at the current scope stack, maybe
454 // we can re-use something
459 multiname_t*s2 = sig2mname(s);
461 multiname_destroy(s2);
464 m->code = m->code->prev->prev; // invert
467 /* continue appending after last op end */
468 while(m->code && m->code->next) m->code = m->code->next;
470 /* TODO: if this is one of *our* classes, we can also
471 do a getglobalscope/getslot <nr> (which references
472 the init function's slots) */
473 __ getlex2(m, extends2);
475 __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
476 __ newclass(m,state->cls);
480 __ setslot(m, slotindex);
482 /* flash.display.MovieClip handling */
483 if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
484 if(state->package && state->package[0]) {
485 globalclass = concat3str(state->package, ".", state->classname);
487 globalclass = strdup(state->classname);
492 static void endclass()
494 /*printf("leaving class %s\n", state->classname);*/
497 static void addimport(token_t*t)
501 list_append(state->imports, i);
503 static void print_imports()
505 import_list_t*l = state->imports;
507 printf(" import %s\n", l->import->path);
511 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
512 token_t*params, class_signature_t*type)
516 state->function = name->text;
518 /*printf("entering function %s\n", name->text);
520 printf(" namespace: %s\n", ns->text);
521 printf(" getset: %s\n", getset->text);
522 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
523 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
525 printf(" type: %s.%s\n", type->package, type->name);
529 syntaxerror("not able to start another method scope");
532 multiname_t*type2 = sig2mname(type);
534 if(!strcmp(state->classname,name->text)) {
535 state->m = abc_class_constructor(state->cls, type2, 0);
537 state->m = abc_class_method(state->cls, type2, name->text, 0);
539 array_append(state->vars, "this", 0);
541 __ getlocal_0(state->m);
542 __ pushscope(state->m);
544 multiname_destroy(type2);
546 static void endfunction()
548 printf("leaving function %s\n", state->function);
549 __ returnvoid(state->m);
553 static token_t* empty_token()
561 void extend(token_t*list, token_t*add) {
562 list_append(list->tokens,add);
564 list->text = add->text;
566 void extend_s(token_t*list, char*seperator, token_t*add) {
567 list_append(list->tokens,add);
568 char*t1 = list->text;
574 list->text = malloc(l1+l2+l3+1);
575 strcpy(list->text, t1);
576 strcpy(list->text+l1, t2);
577 strcpy(list->text+l1+l2, t3);
578 list->text[l1+l2+l3]=0;
581 int find_variable(char*name, class_signature_t**m)
583 state_list_t* s = state_stack;
585 int i = array_find(s->state->vars, name);
588 *m = array_getvalue(s->state->vars, i);
590 return i + s->state->local_var_base;
594 syntaxerror("undefined variable: %s", name);
597 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
599 return registry_getanytype(); // FIXME
601 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
606 #define TYPE_ANY registry_getanytype()
607 #define TYPE_IS_ANY(t) ((t) == registry_getanytype())
608 #define TYPE_INT registry_getintclass()
609 #define TYPE_IS_INT(t) ((t) == registry_getintclass())
610 #define TYPE_UINT registry_getuintclass()
611 #define TYPE_IS_UINT(t) ((t) == registry_getuintclass())
612 #define TYPE_FLOAT registry_getnumberclass()
613 #define TYPE_IS_FLOAT(t) ((t) == registry_getnumberclass())
614 #define TYPE_BOOLEAN registry_getbooleanclass()
615 #define TYPE_IS_BOOLEAN(t)((t) == registry_getbooleanclass())
616 #define TYPE_STRING registry_getstringclass()
617 #define TYPE_IS_STRING(t) ((t) == registry_getstringclass())
618 #define TYPE_NULL registry_getnullclass()
619 #define TYPE_IS_NULL(t) ((t) == registry_getnullclass())
626 /* ------------ code blocks / statements ---------------- */
630 MAYBECODE: CODE {$$=$1;}
631 MAYBECODE: {$$=code_new();}
633 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
634 CODE: CODEPIECE {$$=$1;}
636 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
637 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
638 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
639 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
640 CODEPIECE: ';' {$$=code_new();}
641 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
642 CODEPIECE: VOIDEXPRESSION {$$=$1}
643 CODEPIECE: FOR {$$=$1}
644 CODEPIECE: WHILE {$$=$1}
645 CODEPIECE: BREAK {$$=$1}
646 CODEPIECE: IF {$$=$1}
647 CODEPIECE: ASSIGNMENT {$$=$1}
648 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
649 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
650 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
652 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
653 CODEBLOCK : CODEPIECE ';' {$$=$1;}
654 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
656 /* ------------ functions --------------------------- */
658 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
659 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
660 if(!state->m) syntaxerror("internal error: undefined function");
661 state->m->code = code_append(state->initcode, $11);state->initcode=0;
665 /* ------------ variables --------------------------- */
667 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
668 | {$$.c=abc_pushundefined(0);
672 VAR : "const" | "var"
673 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
674 if(array_contains(state->vars, $2->text))
675 syntaxerror("Variable %s already defined", $2->text);
678 if(!is_subtype_of($4.t, $3)) {
679 syntaxerror("Can't convert %s to %s", $4.t->name,
683 int index = array_append(state->vars, $2->text, $3) + state->local_var_base;
684 $$ = abc_setlocal($$, index);
687 if(TYPE_IS_INT($3) || TYPE_IS_UINT($3) || TYPE_IS_FLOAT($3)) {
688 state->initcode = abc_pushbyte(state->initcode, 32);
689 } else if(TYPE_IS_BOOLEAN($3)) {
690 state->initcode = abc_pushfalse(state->initcode);
692 state->initcode = abc_pushnull(state->initcode);
694 state->initcode = abc_setlocal(state->initcode, index);
696 // that's the default for a local register, anyway
697 state->initcode = abc_pushundefined(state->initcode);
698 state->initcode = abc_setlocal(state->initcode, index);
700 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t->name);
702 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
703 class_signature_t*type=0;
704 int i = find_variable($1->text, &type);
707 // convert to "any" type, the register is untyped
708 $$ = abc_coerce_a($$);
710 // TODO: convert ints to strings etc.
712 $$ = abc_setlocal($$, i);
715 /* ------------ control flow ------------------------- */
717 MAYBEELSE: %prec prec_none {$$ = code_new();}
718 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
719 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
721 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
723 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
725 $$ = code_append($$, $6);
727 myjmp = $$ = abc_jump($$, 0);
729 myif->branch = $$ = abc_label($$);
731 $$ = code_append($$, $7);
732 myjmp->branch = $$ = abc_label($$);
737 FOR_INIT : {$$=code_new();}
738 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
740 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
742 code_t*loopstart = $$ = abc_label($$);
743 $$ = code_append($$, $6.c);
744 code_t*myif = $$ = abc_iffalse($$, 0);
745 $$ = code_append($$, $10);
746 $$ = code_append($$, $8);
747 $$ = abc_jump($$, loopstart);
753 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
754 code_t*myjmp = $$ = abc_jump(0, 0);
755 code_t*loopstart = $$ = abc_label($$);
756 $$ = code_append($$, $6);
757 myjmp->branch = $$ = abc_label($$);
758 $$ = code_append($$, $4.c);
759 $$ = abc_iftrue($$, loopstart);
764 $$ = abc___break__(0);
767 /* ------------ packages and imports ---------------- */
769 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
770 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
772 IMPORT : "import" PACKAGESPEC {addimport($2);}
774 TYPE : PACKAGEANDCLASS {$$=$1;}
775 | '*' {$$=registry_getanytype();}
776 | "String" {$$=registry_getstringclass();}
777 | "int" {$$=registry_getintclass();}
778 | "uint" {$$=registry_getuintclass();}
779 | "Boolean" {$$=registry_getbooleanclass();}
780 | "Number" {$$=registry_getnumberclass();}
782 MAYBETYPE: ':' TYPE {$$=$2;}
785 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
786 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
789 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
790 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
791 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
793 //NAMESPACE : {$$=empty_token();}
794 //NAMESPACE : T_IDENTIFIER {$$=$1};
796 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
797 MULTINAME(m, registry_getintclass());
798 $$.c = abc_coerce2($$.c, &m); // FIXME
801 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
804 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
807 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
810 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
813 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
816 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
819 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
822 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
826 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
829 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
830 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
833 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
834 E : NEW {$$.c = abc_pushundefined(0); /* FIXME */
837 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
841 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
844 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
847 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
850 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
853 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
856 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
859 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
865 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
866 $$.t = join_types($1.t, $3.t, '+');
868 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
869 $$.t = join_types($1.t, $3.t, '%');
871 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
872 $$.t = join_types($1.t, $3.t, '*');
877 E : '(' E ')' {$$=$2;}
880 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
881 MULTINAME(m, registry_getintclass());
882 $$.c=abc_coerce2($$.c, &m); // FIXME
883 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
886 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
887 MULTINAME(m, registry_getintclass());
888 $$.c=abc_coerce2($$.c, &m); // FIXME
889 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
893 // TODO: use inclocal where appropriate
894 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
895 MULTINAME(m, registry_getintclass());
896 $$.c=abc_coerce2($$.c, &m); //FIXME
897 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
900 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
901 MULTINAME(m, registry_getintclass());
902 $$.c=abc_coerce2($$.c, &m); //FIXME
903 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
908 int i = find_variable($1->text, &$$.type);
909 $$.read = abc_getlocal(0, i);
910 $$.write = abc_setlocal(0, i);
913 NEW : "new" T_IDENTIFIER {$$.c=0;$$.t=0;/*FIXME*/}
914 | "new" T_IDENTIFIER '(' ')' {$$.c=0;$$.t=0;/*FIXME*/}
915 | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
917 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
918 /* TODO: use abc_call (for calling local variables),
919 abc_callstatic (for calling own methods) */
921 $$.c = abc_findpropstrict($$.c, $1->text);
922 typedcode_list_t*l = $3;
923 // push parameters on stack
926 $$.c = code_append($$.c, l->typedcode.c);
930 $$.c = abc_callproperty($$.c, $1->text, len);
933 MAYBE_EXPRESSION_LIST : {$$=0;}
934 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
935 EXPRESSION_LIST : EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
938 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
943 VAR_READ : T_IDENTIFIER {
944 int i = find_variable($1->text, &$$.t);
945 $$.c = abc_getlocal(0, i);
948 //VARIABLE : T_IDENTIFIER
949 //VARIABLE : VARIABLE '.' T_IDENTIFIER
950 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
951 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
952 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
953 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
955 // keywords which also may be identifiers
956 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
958 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
959 $$ = concat3($1,$2,$3);}
960 PACKAGESPEC : X_IDENTIFIER {$$=$1;}
961 PACKAGESPEC : '*' {$$=$1;}
963 GETSET : "get" {$$=$1;}
965 | {$$=empty_token();}
967 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
968 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
970 PARAMS: {$$=empty_token();}
971 PARAMS: PARAM_LIST {$$=$1;}
972 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
973 PARAM_LIST: PARAM {$$=empty_token();extend($$,$1);}
974 PARAM: T_IDENTIFIER ':' TYPE {$$=$1;}
976 MODIFIERS : {$$=empty_token();}
977 MODIFIERS : MODIFIER_LIST {$$=$1}
978 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
979 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
980 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
982 DECLARATION : VARIABLE_DECLARATION
983 DECLARATION : FUNCTION_DECLARATION
985 IDECLARATION : VARIABLE_DECLARATION
986 IDECLARATION : FUNCTION_DECLARATION
988 IMPLEMENTS_LIST : {$$=list_new();}
989 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
991 EXTENDS : {$$=registry_getobjectclass();}
992 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
994 EXTENDS_LIST : {$$=list_new();}
995 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
997 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
998 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1000 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
1001 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
1002 PACKAGE : X_IDENTIFIER
1003 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
1005 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1006 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1008 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1009 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1011 MAYBE_DECLARATION_LIST :
1012 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1013 DECLARATION_LIST : DECLARATION
1014 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1016 MAYBE_IDECLARATION_LIST :
1017 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1018 IDECLARATION_LIST : IDECLARATION
1019 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1022 // 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
1023 // syntactic keywords: each get set namespace include dynamic final native override static