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"
43 multiname_t*multiname;
44 multiname_list_t*multiname_list;
46 unsigned int number_uint;
49 struct _typedcode value;
50 struct _typedcode_list*value_list;
51 struct _writeable writeable;
56 %token<token> T_IDENTIFIER
57 %token<string> T_STRING
58 %token<token> T_REGEXP
60 %token<number_int> T_INT
61 %token<number_uint> T_UINT
62 %token<number_uint> T_BYTE
63 %token<number_uint> T_SHORT
64 %token<number_float> T_FLOAT
66 %token<token> KW_IMPLEMENTS
67 %token<token> KW_NAMESPACE "namespace"
68 %token<token> KW_PACKAGE "package"
69 %token<token> KW_PROTECTED
70 %token<token> KW_PUBLIC
71 %token<token> KW_PRIVATE
72 %token<token> KW_USE "use"
73 %token<token> KW_INTERNAL
74 %token<token> KW_NEW "new"
75 %token<token> KW_NATIVE
76 %token<token> KW_FUNCTION "function"
77 %token<token> KW_FOR "for"
78 %token<token> KW_CLASS "class"
79 %token<token> KW_CONST "const"
80 %token<token> KW_SET "set"
81 %token<token> KW_STATIC
82 %token<token> KW_IMPORT "import"
83 %token<token> KW_INTERFACE "interface"
85 %token<token> KW_VAR "var"
86 %token<token> KW_DYNAMIC
87 %token<token> KW_OVERRIDE
88 %token<token> KW_FINAL
89 %token<token> KW_GET "get"
90 %token<token> KW_EXTENDS
91 %token<token> KW_FALSE "false"
92 %token<token> KW_TRUE "true"
93 %token<token> KW_BOOLEAN "Boolean"
94 %token<token> KW_UINT "uint"
95 %token<token> KW_INT "int"
96 %token<token> KW_WHILE "while"
97 %token<token> KW_NUMBER "Number"
98 %token<token> KW_STRING "String"
99 %token<token> KW_IF "if"
100 %token<token> KW_ELSE "else"
101 %token<token> KW_BREAK "break"
102 %token<token> KW_IS "is"
103 %token<token> KW_AS "as"
105 %token<token> T_EQEQ "=="
106 %token<token> T_EQEQEQ "==="
107 %token<token> T_NE "!="
108 %token<token> T_LE "<="
109 %token<token> T_GE ">="
110 %token<token> T_DIVBY "/="
111 %token<token> T_MODBY "%="
112 %token<token> T_PLUSBY "+="
113 %token<token> T_MINUSBY "-="
114 %token<token> T_SHRBY ">>="
115 %token<token> T_SHLBY "<<="
116 %token<token> T_USHRBY ">>>="
117 %token<token> T_OROR "||"
118 %token<token> T_ANDAND "&&"
119 %token<token> T_COLONCOLON "::"
120 %token<token> T_MINUSMINUS "--"
121 %token<token> T_PLUSPLUS "++"
122 %token<token> T_DOTDOT ".."
123 %token<token> T_SHL "<<"
124 %token<token> T_USHR ">>>"
125 %token<token> T_SHR ">>"
126 %token<token> T_SEMICOLON ';'
127 %token<token> T_STAR '*'
128 %token<token> T_DOT '.'
131 %type <code> CODEPIECE
132 %type <code> CODEBLOCK MAYBECODE
133 %type <token> PACKAGE_DECLARATION
134 %type <token> FUNCTION_DECLARATION
135 %type <code> VARIABLE_DECLARATION
136 %type <token> CLASS_DECLARATION
137 %type <token> NAMESPACE_DECLARATION
138 %type <token> INTERFACE_DECLARATION
139 %type <code> VOIDEXPRESSION
140 %type <value> EXPRESSION
141 %type <value> MAYBEEXPRESSION
144 %type <value> CONSTANT
145 %type <code> FOR IF WHILE MAYBEELSE BREAK
146 %type <token> USE_NAMESPACE
147 %type <code> ASSIGNMENT FOR_INIT
149 %type <multiname> MAYBETYPE
150 %type <token> PACKAGESPEC
154 %type <token> PARAM_LIST
155 %type <token> MODIFIERS
156 %type <token> MODIFIER_LIST
157 %type <multiname_list> IMPLEMENTS_LIST
158 %type <multiname> EXTENDS
159 %type <multiname_list> EXTENDS_LIST
160 %type <multiname> PACKAGEANDCLASS
161 %type <multiname_list> PACKAGEANDCLASS_LIST
162 %type <token> MULTILEVELIDENTIFIER
163 %type <multiname> TYPE
165 //%type <token> VARIABLE
166 %type <value> VAR_READ
168 %type <token> X_IDENTIFIER
169 %type <token> MODIFIER
170 %type <token> PACKAGE
171 %type <value> FUNCTIONCALL
172 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST
174 // precendence: from low to high
175 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
190 %nonassoc "!=" "==" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
206 %nonassoc T_IDENTIFIER
207 %left below_semicolon
216 static int yyerror(char*s)
218 syntaxerror("%s", s);
220 static token_t* concat2(token_t* t1, token_t* t2)
223 int l1 = strlen(t1->text);
224 int l2 = strlen(t2->text);
225 t->text = malloc(l1+l2+1);
226 memcpy(t->text , t1->text, l1);
227 memcpy(t->text+l1, t2->text, l2);
231 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
234 int l1 = strlen(t1->text);
235 int l2 = strlen(t2->text);
236 int l3 = strlen(t3->text);
237 t->text = malloc(l1+l2+l3+1);
238 memcpy(t->text , t1->text, l1);
239 memcpy(t->text+l1, t2->text, l2);
240 memcpy(t->text+l1+l2, t3->text, l3);
241 t->text[l1+l2+l3] = 0;
244 static char* concat3str(const char* t1, const char* t2, const char* t3)
249 char*text = malloc(l1+l2+l3+1);
250 memcpy(text , t1, l1);
251 memcpy(text+l1, t2, l2);
252 memcpy(text+l1+l2, t3, l3);
257 typedef struct _import {
261 DECLARE_LIST(import);
263 typedef struct _state {
271 /* code that needs to be executed at the start of
272 a method (like initializing local registers) */
276 import_list_t*imports;
286 static state_t* state = 0;
290 static state_list_t*state_stack=0;
292 static void new_state()
295 NEW(state_list_t, sl);
297 state_t*oldstate = state;
299 memcpy(s, state, sizeof(state_t)); //shallow copy
300 sl->next = state_stack;
303 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
307 state->vars = array_new();
310 static void old_state()
312 if(!state_stack || !state_stack->next)
313 syntaxerror("invalid nesting");
314 state_t*oldstate = state;
315 state_list_t*old = state_stack;
316 state_stack = state_stack->next;
318 state = state_stack->state;
319 state->initcode = code_append(state->initcode, oldstate->initcode);
321 void initialize_state()
325 state->file = abc_file_new();
326 state->file->flags &= ~ABCFILE_LAZY;
328 state->init = abc_initscript(state->file, 0, 0);
329 abc_method_body_t*m = state->init->method->body;
332 __ findpropstrict(m, "[package]::trace");
333 __ pushstring(m, "[entering global init function]");
334 __ callpropvoid(m, "[package]::trace", 1);
336 void* finalize_state()
338 if(state->level!=1) {
339 syntaxerror("unexpected end of file");
341 abc_method_body_t*m = state->init->method->body;
344 __ findpropstrict(m, "[package]::trace");
345 __ pushstring(m, "[leaving global init function]");
346 __ callpropvoid(m, "[package]::trace", 1);
352 static void startpackage(token_t*t)
355 syntaxerror("Packages can not be nested.");
358 char*name = t?t->text:"";
359 printf("entering package \"%s\"\n", name);
360 state->package = name;
362 static void endpackage()
364 printf("leaving package \"%s\"\n", state->package);
369 static void startclass(token_t*modifiers, token_t*name, multiname_t*extends, multiname_list_t*implements)
372 syntaxerror("inner classes now allowed");
375 state->classname = name->text;
376 printf("entering class %s\n", name->text);
378 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
379 printf(" extends: %s\n", multiname_tostring(extends));
381 multiname_list_t*mlist=0;
382 printf(" implements (%d): ", list_length(implements));
383 for(mlist=implements;mlist;mlist=mlist->next) {
384 printf("%s ", multiname_tostring(mlist->multiname));
388 char public=0,internal=0,final=0,sealed=1;
389 for(t=modifiers->tokens;t;t=t->next) {
390 if(t->token->type == KW_INTERNAL) {
391 /* the programmer is being explicit-
392 being internal is the default anyway */
394 } else if(t->token->type == KW_PUBLIC) {
396 } else if(t->token->type == KW_FINAL) {
399 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
403 syntaxerror("public and internal not supported at the same time.");
405 /* create the class name, together with the proper attributes */
406 multiname_t* classname = 0;
407 if(!public && !state->package)
408 classname = multiname_new(namespace_new_private(current_filename), state->classname);
409 else if(!public && state->package)
410 classname = multiname_new(namespace_new_packageinternal(state->package), state->classname);
411 else if(state->package)
412 classname = multiname_new(namespace_new_package(state->package), state->classname);
414 syntaxerror("public classes only allowed inside a package");
416 state->cls = abc_class_new(state->file, classname, extends);
417 if(final) abc_class_final(state->cls);
418 if(sealed) abc_class_sealed(state->cls);
420 for(mlist=implements;mlist;mlist=mlist->next) {
421 abc_class_add_interface(state->cls, mlist->multiname);
424 /* now write the construction code for this class */
425 int slotindex = abc_initscript_addClassTrait(state->init, classname, state->cls);
427 abc_method_body_t*m = state->init->method->body;
428 __ getglobalscope(m);
429 multiname_t*s = extends;
434 //TODO: take a look at the current scope stack, maybe
435 // we can re-use something
436 s = registry_getsuperclass(s);
441 m->code = m->code->prev->prev; // invert
444 /* continue appending after last op end */
445 while(m->code && m->code->next) m->code = m->code->next;
447 /* TODO: if this is one of *our* classes, we can also
448 do a getglobalscope/getslot <nr> (which references
449 the init function's slots) */
450 __ getlex2(m, extends);
452 __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
453 __ newclass(m,state->cls);
457 __ setslot(m, slotindex);
459 if(!globalclass && public && multiname_equals(registry_getMovieClip(),extends)) {
460 if(state->package && state->package[0]) {
461 globalclass = concat3str(state->package, ".", state->classname);
463 globalclass = strdup(state->classname);
468 static void endclass()
470 printf("leaving class %s\n", state->classname);
473 static void addimport(token_t*t)
477 list_append(state->imports, i);
479 static void print_imports()
481 import_list_t*l = state->imports;
483 printf(" import %s\n", l->import->path);
487 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
488 token_t*params, multiname_t*type)
492 state->function = name->text;
493 printf("entering function %s\n", name->text);
495 printf(" namespace: %s\n", ns->text);
496 printf(" getset: %s\n", getset->text);
497 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
498 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
499 printf(" type: %s\n", multiname_tostring(type));
503 syntaxerror("not able to start another method scope");
506 if(!strcmp(state->classname,name->text)) {
507 state->m = abc_class_constructor(state->cls, type, 0);
509 state->m = abc_class_method(state->cls, type, name->text, 0);
511 array_append(state->vars, "this", 0);
513 __ getlocal_0(state->m);
514 __ pushscope(state->m);
516 static void endfunction()
518 printf("leaving function %s\n", state->function);
519 __ returnvoid(state->m);
523 static token_t* empty_token()
531 void extend(token_t*list, token_t*add) {
532 list_append(list->tokens,add);
534 list->text = add->text;
536 void extend_s(token_t*list, char*seperator, token_t*add) {
537 list_append(list->tokens,add);
538 char*t1 = list->text;
544 list->text = malloc(l1+l2+l3+1);
545 strcpy(list->text, t1);
546 strcpy(list->text+l1, t2);
547 strcpy(list->text+l1+l2, t3);
548 list->text[l1+l2+l3]=0;
551 int find_variable(char*name, multiname_t**m)
553 state_list_t* s = state_stack;
555 int i = array_find(s->state->vars, name);
558 *m = array_getvalue(s->state->vars, i);
560 return i + s->state->local_var_base;
564 syntaxerror("undefined variable: %s", name);
567 multiname_t*join_types(multiname_t*type1, multiname_t*type2, char op)
569 return registry_getanytype(); // FIXME
571 char is_subtype_of(multiname_t*type, multiname_t*supertype)
576 #define TYPE_ANY registry_getanytype()
577 #define TYPE_IS_ANY(t) ((t) == registry_getanytype())
578 #define TYPE_INT registry_getintclass()
579 #define TYPE_IS_INT(t) ((t) == registry_getintclass())
580 #define TYPE_UINT registry_getuintclass()
581 #define TYPE_IS_UINT(t) ((t) == registry_getuintclass())
582 #define TYPE_FLOAT registry_getnumberclass()
583 #define TYPE_IS_FLOAT(t) ((t) == registry_getnumberclass())
584 #define TYPE_BOOLEAN registry_getbooleanclass()
585 #define TYPE_IS_BOOLEAN(t)((t) == registry_getbooleanclass())
586 #define TYPE_STRING registry_getstringclass()
587 #define TYPE_IS_STRING(t) ((t) == registry_getstringclass())
588 #define TYPE_NULL registry_getnullclass()
589 #define TYPE_IS_NULL(t) ((t) == registry_getnullclass())
596 /* ------------ code blocks / statements ---------------- */
600 MAYBECODE: CODE {$$=$1;}
601 MAYBECODE: {$$=code_new();}
603 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
604 CODE: CODEPIECE {$$=$1;}
606 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
607 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
608 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
609 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
610 CODEPIECE: ';' {$$=code_new();}
611 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
612 CODEPIECE: VOIDEXPRESSION {$$=$1}
613 CODEPIECE: FOR {$$=$1}
614 CODEPIECE: WHILE {$$=$1}
615 CODEPIECE: BREAK {$$=$1}
616 CODEPIECE: IF {$$=$1}
617 CODEPIECE: ASSIGNMENT {$$=$1}
618 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
619 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
620 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
622 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
623 CODEBLOCK : CODEPIECE ';' {$$=$1;}
624 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
626 /* ------------ functions --------------------------- */
628 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
629 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
630 if(!state->m) syntaxerror("internal error: undefined function");
631 state->m->code = code_append(state->initcode, $11);state->initcode=0;
635 /* ------------ variables --------------------------- */
637 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
638 | {$$.c=abc_pushundefined(0);
642 VAR : "const" | "var"
643 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
644 if(array_contains(state->vars, $2->text))
645 syntaxerror("Variable %s already defined", $2->text);
648 if(!is_subtype_of($4.t, $3)) {
649 syntaxerror("Can't convert %s to %s", multiname_tostring($4.t), multiname_tostring($3));
652 int index = array_append(state->vars, $2->text, $3) + state->local_var_base;
653 $$ = abc_setlocal($$, index);
656 if(TYPE_IS_INT($3) || TYPE_IS_UINT($3) || TYPE_IS_FLOAT($3)) {
657 state->initcode = abc_pushbyte(state->initcode, 32);
658 } else if(TYPE_IS_BOOLEAN($3)) {
659 state->initcode = abc_pushfalse(state->initcode);
661 state->initcode = abc_pushnull(state->initcode);
663 state->initcode = abc_setlocal(state->initcode, index);
665 // that's the default for a local register, anyway
666 state->initcode = abc_pushundefined(state->initcode);
667 state->initcode = abc_setlocal(state->initcode, index);
669 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t->name);
671 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
673 int i = find_variable($1->text, &type);
676 // convert to "any" type, the register is untyped
677 $$ = abc_coerce_a($$);
679 // TODO: convert ints to strings etc.
681 $$ = abc_setlocal($$, i);
684 /* ------------ control flow ------------------------- */
686 MAYBEELSE: %prec prec_none {$$ = code_new();}
687 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
688 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
690 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
692 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
694 $$ = code_append($$, $6);
696 myjmp = $$ = abc_jump($$, 0);
698 myif->branch = $$ = abc_label($$);
700 $$ = code_append($$, $7);
701 myjmp->branch = $$ = abc_label($$);
706 FOR_INIT : {$$=code_new();}
707 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
709 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
711 code_t*loopstart = $$ = abc_label($$);
712 $$ = code_append($$, $6.c);
713 code_t*myif = $$ = abc_iffalse($$, 0);
714 $$ = code_append($$, $10);
715 $$ = code_append($$, $8);
716 $$ = abc_jump($$, loopstart);
722 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
723 code_t*myjmp = $$ = abc_jump(0, 0);
724 code_t*loopstart = $$ = abc_label($$);
725 $$ = code_append($$, $6);
726 myjmp->branch = $$ = abc_label($$);
727 $$ = code_append($$, $4.c);
728 $$ = abc_iftrue($$, loopstart);
733 $$ = abc___break__(0);
736 /* ------------ packages and imports ---------------- */
738 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
739 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
741 IMPORT : "import" PACKAGESPEC {addimport($2);}
743 TYPE : PACKAGEANDCLASS {$$=$1;}
744 | '*' {$$=registry_getanytype();}
745 | "String" {$$=registry_getstringclass();}
746 | "int" {$$=registry_getintclass();}
747 | "uint" {$$=registry_getuintclass();}
748 | "Boolean" {$$=registry_getbooleanclass();}
749 | "Number" {$$=registry_getnumberclass();}
751 MAYBETYPE: ':' TYPE {$$=$2;}
754 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
755 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
758 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
759 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
760 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
762 //NAMESPACE : {$$=empty_token();}
763 //NAMESPACE : T_IDENTIFIER {$$=$1};
765 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
766 $$.c = abc_coerce2($$.c, registry_getintclass()); // FIXME
769 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
772 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
775 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
778 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
781 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
784 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
787 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
790 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
794 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
797 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
798 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
801 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
802 E : NEW {$$.c = abc_pushundefined(0); /* FIXME */
805 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
809 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
812 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
815 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
818 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
821 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
824 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
827 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
833 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
834 $$.t = join_types($1.t, $3.t, '+');
836 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
837 $$.t = join_types($1.t, $3.t, '%');
839 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
840 $$.t = join_types($1.t, $3.t, '*');
845 E : '(' E ')' {$$=$2;}
848 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
849 $$.c=abc_coerce2($$.c, registry_getintclass()); // FIXME
850 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
853 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
854 $$.c=abc_coerce2($$.c, registry_getintclass()); // FIXME
855 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
859 // TODO: use inclocal where appropriate
860 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
861 $$.c=abc_coerce2($$.c, registry_getintclass()); //FIXME
862 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
865 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
866 $$.c=abc_coerce2($$.c, registry_getintclass()); //FIXME
867 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
872 int i = find_variable($1->text, &$$.type);
873 $$.read = abc_getlocal(0, i);
874 $$.write = abc_setlocal(0, i);
877 NEW : "new" T_IDENTIFIER {$$.c=0;$$.t=0;/*FIXME*/}
878 | "new" T_IDENTIFIER '(' ')' {$$.c=0;$$.t=0;/*FIXME*/}
879 | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
881 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
882 /* TODO: use abc_call (for calling local variables),
883 abc_callstatic (for calling own methods) */
885 $$.c = abc_findpropstrict($$.c, $1->text);
886 typedcode_list_t*l = $3;
887 // push parameters on stack
890 $$.c = code_append($$.c, l->typedcode.c);
894 $$.c = abc_callproperty($$.c, $1->text, len);
897 MAYBE_EXPRESSION_LIST : {$$=0;}
898 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
899 EXPRESSION_LIST : EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
902 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
907 VAR_READ : T_IDENTIFIER {
908 int i = find_variable($1->text, &$$.t);
909 $$.c = abc_getlocal(0, i);
912 //VARIABLE : T_IDENTIFIER
913 //VARIABLE : VARIABLE '.' T_IDENTIFIER
914 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
915 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
916 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
917 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
919 // keywords which also may be identifiers
920 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
922 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
923 $$ = concat3($1,$2,$3);}
924 PACKAGESPEC : X_IDENTIFIER {$$=$1;}
925 PACKAGESPEC : '*' {$$=$1;}
927 GETSET : "get" {$$=$1;}
929 | {$$=empty_token();}
931 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
932 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
934 PARAMS: {$$=empty_token();}
935 PARAMS: PARAM_LIST {$$=$1;}
936 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
937 PARAM_LIST: PARAM {$$=empty_token();extend($$,$1);}
938 PARAM: T_IDENTIFIER ':' TYPE {$$=$1;}
940 MODIFIERS : {$$=empty_token();}
941 MODIFIERS : MODIFIER_LIST {$$=$1}
942 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
943 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
944 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
946 DECLARATION : VARIABLE_DECLARATION
947 DECLARATION : FUNCTION_DECLARATION
949 IDECLARATION : VARIABLE_DECLARATION
950 IDECLARATION : FUNCTION_DECLARATION
952 IMPLEMENTS_LIST : {$$=list_new();}
953 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
955 EXTENDS : {$$=registry_getobjectclass();}
956 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
958 EXTENDS_LIST : {$$=list_new();}
959 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
961 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
962 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
964 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
965 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
966 PACKAGE : X_IDENTIFIER
967 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
969 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
970 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
972 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
973 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
975 MAYBE_DECLARATION_LIST :
976 MAYBE_DECLARATION_LIST : DECLARATION_LIST
977 DECLARATION_LIST : DECLARATION
978 DECLARATION_LIST : DECLARATION_LIST DECLARATION
980 MAYBE_IDECLARATION_LIST :
981 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
982 IDECLARATION_LIST : IDECLARATION
983 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
986 // 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
987 // syntactic keywords: each get set namespace include dynamic final native override static