/* [<][>][^][v][top][bottom][index][help] */
/* $Id: swf5compiler.y,v 1.2 2008/10/28 13:05:13 kramm Exp $ */
%start program
%{
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include "compile.h"
#include "action.h"
#include "assembler.h"
#define YYPARSE_PARAM buffer
Buffer bf, bc;
%}
%union
{
Buffer action;
char *str;
SWFGetUrl2Method getURLMethod;
int op;
int intVal;
int len;
double doubleVal;
struct
{
Buffer buffer;
int count;
} exprlist;
struct switchcase switchcase;
struct switchcases switchcases;
struct
{
Buffer obj, ident, memexpr;
} lval;
}
/* tokens etc. */
%token BREAK CONTINUE FUNCTION ELSE SWITCH CASE DEFAULT FOR IN IF WHILE
%token DO VAR NEW DELETE RETURN END WITH ASM EVAL
%token RANDOM GETTIMER LENGTH CONCAT SUBSTR TRACE INT ORD CHR GETURL
%token GETURL1 NEXTFRAME PREVFRAME PLAY STOP TOGGLEQUALITY STOPSOUNDS
%token DUP SWAP POP PUSH SETREGISTER CALLFUNCTION CALLMETHOD
%token AND OR XOR MODULO ADD LESSTHAN EQUALS
%token INC DEC TYPEOF INSTANCEOF ENUMERATE INITOBJECT INITARRAY GETMEMBER
%token SETMEMBER SHIFTLEFT SHIFTRIGHT SHIFTRIGHT2 VAREQUALS OLDADD SUBTRACT
%token MULTIPLY DIVIDE OLDEQUALS OLDLESSTHAN LOGICALAND LOGICALOR NOT
%token STRINGEQ STRINGLENGTH SUBSTRING GETVARIABLE SETVARIABLE
%token SETTARGETEXPRESSION DUPLICATEMOVIECLIP REMOVEMOVIECLIP
%token STRINGLESSTHAN MBLENGTH MBSUBSTRING MBORD MBCHR
%token BRANCHALWAYS BRANCHIFTRUE GETURL2 POST GET
%token LOADVARIABLES LOADMOVIE LOADVARIABLESNUM LOADMOVIENUM
%token CALLFRAME STARTDRAG STOPDRAG GOTOFRAME SETTARGET
%token NULLVAL
%token <intVal> INTEGER
%token <doubleVal> DOUBLE
%token <intVal> BOOLEAN
%token <str> REGISTER
/* these two are strdup'ed in compiler.flex, so free them up here */
%token <str> STRING
%token <str> IDENTIFIER
%token EQ "=="
%token LE "<="
%token GE ">="
%token NE "!="
%token LAN "&&"
%token LOR "||"
%token INCR "++"
%token DECR "--"
%token IEQ "+="
%token DEQ "/="
%token MEQ "*="
%token SEQ "-="
%token REQ "%="
%token AEQ "&="
%token OEQ "|="
%token SHL "<<"
%token SHR ">>"
%token SHR2 ">>>"
%token SHLEQ "<<="
%token SHREQ ">>="
%token SHR2EQ ">>>="
/* ascending order of ops ..? */
%nonassoc NOELSE
%nonassoc ELSE
%left ','
%right '=' "*=" "/=" "%=" "+=" "-=" "&=" "|=" "^=" ">>=" ">>>=" "<<="
%right '?' ':'
%left "&&" "||"
%left "==" "!="
%left '<' '>' "<=" ">="
%left '&' '|' '^'
%left "<<" ">>" ">>>"
%left '+' '-'
%left '*' '/' '%'
%nonassoc "++" "--"
%right '!' '~' UMINUS
%right POSTFIX
%right TYPEOF
%nonassoc INSTANCEOF
%left '.' '[' ']'
%type <action> program code
%type <action> stmt stmts
%type <action> if_stmt iter_stmt cont_stmt break_stmt return_stmt
%type <action> with_stmt
%type <action> switch_stmt
%type <action> anon_function_decl function_decl anycode
%type <action> void_function_call function_call method_call
%type <action> assign_stmt assign_stmts assign_stmts_opt
%type <action> expr expr_or_obj objexpr expr_opt obj_ref
%type <action> emptybraces level init_vars init_var primary lvalue_expr
%type <lval> lvalue
%type <exprlist> expr_list objexpr_list formals_list
%type <switchcase> switch_case
%type <switchcases> switch_cases
%type <op> assignop incdecop
%type <getURLMethod> urlmethod
%type <str> identifier
%type <len> opcode opcode_list push_item with push_list
/*
%type <intVal> integer
%type <doubleVal> double
*/
%%
/* rules */
program
: { bf = newBuffer();
bc = newBuffer();
} code
{ Buffer b = newBuffer();
bufferWriteConstants(b);
bufferConcat(b, bf);
bufferConcat(b, bc);
*((Buffer *)buffer) = b; }
| /* nothing */ { Buffer b = newBuffer(); *((Buffer *)buffer) = b; }
;
code
: anycode
| code anycode
;
anycode
: stmt
{ bufferConcat(bc, $1); }
| function_decl
{ bufferConcat(bf, $1); }
;
stmts
: stmt
{ $$ = $1; }
| stmts stmt
{ $$ = $1;
bufferConcat($$, $2); }
;
emptybraces
: '{' '}' { }
;
stmt
: emptybraces { $$ = NULL; }
| '{' stmts '}' { $$ = $2; }
| ';' { $$ = NULL; }
| assign_stmt ';' { $$ = $1; }
| if_stmt
| iter_stmt
| cont_stmt
| break_stmt
| switch_stmt
| return_stmt
| with_stmt
;
with_stmt
: WITH '(' expr ')' '{' stmts '}'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_WITH);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($6));
bufferConcat($$, $6); }
;
// only possible if there is an active CTX_FUNCTION
// in some contexts, may have to pop a few values ...
return_stmt
: RETURN ';'
{ int tmp = chkctx(CTX_FUNCTION);
if(tmp < 0)
swf5error("return outside function");
$$ = newBuffer();
while(--tmp >= 0)
bufferWriteOp($$, SWFACTION_POP);
bufferWriteNull($$);
bufferWriteOp($$, SWFACTION_RETURN); }
| RETURN expr_or_obj ';'
{ int tmp = chkctx(CTX_FUNCTION);
if(tmp < 0)
swf5error("return outside function");
$$ = newBuffer();
while(--tmp >= 0)
bufferWriteOp($$, SWFACTION_POP);
bufferConcat($$, $2);
bufferWriteOp($$, SWFACTION_RETURN); }
;
assign_stmts
: assign_stmt
| assign_stmts ',' assign_stmt { bufferConcat($1, $3); }
;
if_stmt
: IF '(' expr ')' stmt ELSE stmt
{ $$ = $3;
bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($7)+5);
bufferConcat($$, $7);
bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($5));
bufferConcat($$, $5); }
| IF '(' expr ')' stmt %prec NOELSE
{ $$ = $3;
bufferWriteOp($$, SWFACTION_LOGICALNOT);
bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($5));
bufferConcat($$, $5); }
;
expr_opt
: /* empty */ { $$ = NULL; }
| expr { $$ = $1; }
;
switch_init
: SWITCH
{ addctx(CTX_SWITCH); }
;
switch_stmt
: switch_init '(' expr ')' '{'
switch_cases '}'
{ $$ = $3;
bufferResolveSwitch($$, &$6);
bufferResolveJumps($$);
bufferWriteOp($$, SWFACTION_POP);
delctx(CTX_SWITCH);
/* FIXME: continue in switch continues surrounding loop, if any */
}
;
/* XXX */
switch_cases
: /* empty */
{ $$.count = 0;
$$.list = 0; }
| switch_cases switch_case
{ $$ = $1;
$$.list = (struct switchcase*) realloc($$.list, ($$.count+1) * sizeof(struct switchcase));
$$.list[$$.count] = $2;
$$.count++; }
;
switch_case
: CASE expr ':' stmts BREAK ';'
{ $$.cond = $2;
$$.action = $4;
$$.isbreak = 1; }
| CASE expr ':' stmts
{ $$.cond = $2;
$$.action = $4;
$$.isbreak = 0; }
| DEFAULT ':' stmts
{ $$.cond = NULL;
$$.action = $3;
$$.isbreak = 0; }
;
/* there's GOT to be a better way than this.. */
identifier
: IDENTIFIER
| NEW { $$ = strdup("new"); }
| DELETE { $$ = strdup("delete"); }
| RANDOM { $$ = strdup("random"); }
| GETTIMER { $$ = strdup("getTimer"); }
| LENGTH { $$ = strdup("length"); }
| CONCAT { $$ = strdup("concat"); }
| SUBSTR { $$ = strdup("substr"); }
| TRACE { $$ = strdup("trace"); }
| INT { $$ = strdup("int"); }
| ORD { $$ = strdup("ord"); }
| CHR { $$ = strdup("chr"); }
| GETURL { $$ = strdup("getURL"); }
| GETURL1 { $$ = strdup("getURL1"); }
| NEXTFRAME { $$ = strdup("nextFrame"); }
| PREVFRAME { $$ = strdup("prevFrame"); }
| PLAY { $$ = strdup("play"); }
| STOP { $$ = strdup("stop"); }
| TOGGLEQUALITY { $$ = strdup("toggleQuality"); }
| STOPSOUNDS { $$ = strdup("stopSounds"); }
| DUP { $$ = strdup("dup"); }
| SWAP { $$ = strdup("swap"); }
| POP { $$ = strdup("pop"); }
| PUSH { $$ = strdup("push"); }
| SETREGISTER { $$ = strdup("setRegister"); }
| CALLFUNCTION { $$ = strdup("callFunction"); }
| CALLMETHOD { $$ = strdup("callMethod"); }
| AND { $$ = strdup("and"); }
| OR { $$ = strdup("or"); }
| XOR { $$ = strdup("xor"); }
| MODULO { $$ = strdup("modulo"); }
| ADD { $$ = strdup("add"); }
| LESSTHAN { $$ = strdup("lessThan"); }
| EQUALS { $$ = strdup("equals"); }
| INC { $$ = strdup("inc"); }
| DEC { $$ = strdup("dec"); }
| TYPEOF { $$ = strdup("typeof"); }
| INSTANCEOF { $$ = strdup("instanceof"); }
| ENUMERATE { $$ = strdup("enumerate"); }
| INITOBJECT { $$ = strdup("initobject"); }
| INITARRAY { $$ = strdup("initarray"); }
| GETMEMBER { $$ = strdup("getmember"); }
| SETMEMBER { $$ = strdup("setmember"); }
| SHIFTLEFT { $$ = strdup("shiftleft"); }
| SHIFTRIGHT { $$ = strdup("shiftright"); }
| SHIFTRIGHT2 { $$ = strdup("shiftright2"); }
| VAREQUALS { $$ = strdup("varequals"); }
| OLDADD { $$ = strdup("oldAdd"); }
| SUBTRACT { $$ = strdup("subtract"); }
| MULTIPLY { $$ = strdup("multiply"); }
| DIVIDE { $$ = strdup("divide"); }
| OLDEQUALS { $$ = strdup("oldequals"); }
| OLDLESSTHAN { $$ = strdup("oldlessthan"); }
| LOGICALAND { $$ = strdup("logicaland"); }
| LOGICALOR { $$ = strdup("logicalor"); }
| NOT { $$ = strdup("not"); }
| STRINGEQ { $$ = strdup("stringeq"); }
| STRINGLENGTH { $$ = strdup("stringlength"); }
| SUBSTRING { $$ = strdup("substring"); }
| GETVARIABLE { $$ = strdup("getvariable"); }
| SETVARIABLE { $$ = strdup("setvariable"); }
| SETTARGETEXPRESSION { $$ = strdup("settargetexpression"); }
| DUPLICATEMOVIECLIP { $$ = strdup("duplicatemovieclip"); }
| REMOVEMOVIECLIP { $$ = strdup("removemovieclip"); }
| STARTDRAG { $$ = strdup("startdrag"); }
| STOPDRAG { $$ = strdup("stopdrag"); }
| STRINGLESSTHAN { $$ = strdup("stringlessthan"); }
| MBLENGTH { $$ = strdup("mblength"); }
| MBSUBSTRING { $$ = strdup("mbsubstring"); }
| MBORD { $$ = strdup("mbord"); }
| MBCHR { $$ = strdup("mbchr"); }
| BRANCHALWAYS { $$ = strdup("branchalways"); }
| BRANCHIFTRUE { $$ = strdup("branchiftrue"); }
| GETURL2 { $$ = strdup("getURL2"); }
| POST { $$ = strdup("post"); }
| GET { $$ = strdup("get"); }
| LOADVARIABLES { $$ = strdup("loadvariables"); }
| LOADMOVIE { $$ = strdup("loadMovie"); }
;
formals_list
: /* empty */
{ $$.buffer = newBuffer();
$$.count = 0; }
| identifier
{ $$.buffer = newBuffer();
bufferWriteHardString($$.buffer, (byte*)$1, strlen($1)+1);
$$.count = 1; }
| formals_list ',' identifier
{ $$ = $1;
bufferWriteHardString($$.buffer, (byte*)$3, strlen($3)+1);
++$$.count; }
;
function_init
: FUNCTION
{ addctx(CTX_FUNCTION); }
;
function_decl
: function_init identifier '(' formals_list ')' stmt
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_DEFINEFUNCTION);
bufferWriteS16($$, strlen($2) +
bufferLength($4.buffer) + 5);
bufferWriteHardString($$, (byte*) $2, strlen($2)+1);
bufferWriteS16($$, $4.count);
bufferConcat($$, $4.buffer);
bufferWriteS16($$, bufferLength($6));
bufferConcat($$, $6);
delctx(CTX_FUNCTION); }
;
obj_ref
: identifier
{ $$ = newBuffer();
bufferWriteString($$, $1, strlen($1)+1);
free($1); }
| expr '.' identifier
{ $$ = $1;
bufferWriteString($$, $3, strlen($3)+1);
bufferWriteOp($$, SWFACTION_GETMEMBER);
free($3); }
| expr '[' expr ']'
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_GETMEMBER); }
| function_call
| method_call
;
while_init
: WHILE
{ addctx(CTX_LOOP); }
;
do_init
: DO
{ addctx(CTX_LOOP); }
;
for_init
: /* empty */
{ addctx(CTX_LOOP); }
;
for_in_init
: /* empty */
{ addctx(CTX_FOR_IN); }
;
iter_stmt
: while_init '(' expr ')' stmt
{ $$ = $3;
bufferWriteOp($$, SWFACTION_LOGICALNOT);
bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($5)+5);
bufferConcat($$, $5);
bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
bufferWriteS16($$, 2);
bufferWriteS16($$, -(bufferLength($$)+2));
bufferResolveJumps($$);
delctx(CTX_LOOP); }
| do_init stmt WHILE '(' expr ')'
{ if($2)
{ $$ = $2;
bufferConcat($$, $5);
}
else
$$ = $5;
bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($$, 2);
bufferWriteS16($$, -(bufferLength($$)+2));
bufferResolveJumps($$);
delctx(CTX_LOOP); }
| FOR '(' assign_stmts_opt ';' expr_opt ';' assign_stmts_opt ')' for_init stmt
{
if($3)
$$ = $3;
else
$$ = newBuffer();
if($7)
{
bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($7));
}
else
$7 = newBuffer();
if($5)
{
bufferConcat($7, $5);
bufferWriteOp($7, SWFACTION_LOGICALNOT);
bufferWriteOp($7, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($7, 2);
bufferWriteS16($7, bufferLength($10)+5);
}
bufferConcat($7, $10);
bufferWriteOp($7, SWFACTION_BRANCHALWAYS);
bufferWriteS16($7, 2);
bufferWriteS16($7, -(bufferLength($7)+2));
bufferResolveJumps($7);
bufferConcat($$, $7);
delctx(CTX_LOOP);
}
| FOR '(' identifier IN obj_ref ')' for_in_init stmt
{ Buffer b2, b3;
int tmp;
$$ = $5;
bufferWriteOp($$, SWFACTION_ENUMERATE);
b2 = newBuffer();
bufferWriteSetRegister(b2, 0);
bufferWriteOp(b2, SWFACTION_PUSHDATA);
bufferWriteS16(b2, 1);
bufferWriteU8(b2, 2);
bufferWriteOp(b2, SWFACTION_NEWEQUALS);
bufferWriteOp(b2, SWFACTION_BRANCHIFTRUE);
bufferWriteS16(b2, 2);
b3 = newBuffer();
/* basically a lvalue could be used here rather than an ident !!! */
/* probably by using reg1 for the test rather than reg0 */
bufferWriteString(b3, $3, strlen($3)+1);
bufferWriteRegister(b3, 0);
bufferWriteOp(b3, SWFACTION_SETVARIABLE);
bufferConcat(b3, $8);
bufferWriteS16(b2, bufferLength(b3) + 5);
tmp = bufferLength(b2) + bufferLength(b3) + 5;
bufferConcat($$, b2);
bufferWriteOp(b3, SWFACTION_BRANCHALWAYS);
bufferWriteS16(b3, 2);
bufferWriteS16(b3, -tmp);
bufferResolveJumps(b3);
bufferConcat($$, b3);
delctx(CTX_FOR_IN); }
| FOR '(' VAR identifier IN obj_ref ')' for_in_init stmt
{ Buffer b2, b3;
int tmp;
$$ = $6;
bufferWriteOp($$, SWFACTION_ENUMERATE);
b2 = newBuffer();
bufferWriteSetRegister(b2, 0);
bufferWriteOp(b2, SWFACTION_PUSHDATA);
bufferWriteS16(b2, 1);
bufferWriteU8(b2, 2);
bufferWriteOp(b2, SWFACTION_NEWEQUALS);
bufferWriteOp(b2, SWFACTION_BRANCHIFTRUE);
bufferWriteS16(b2, 2);
// add size later
b3 = newBuffer();
bufferWriteString(b3, $4, strlen($4)+1);
bufferWriteRegister(b3, 0);
bufferWriteOp(b3, SWFACTION_VAREQUALS);
bufferConcat(b3, $9);
bufferWriteS16(b2, bufferLength(b3) + 5);
tmp = bufferLength(b2) + bufferLength(b3) + 5;
bufferConcat($$, b2);
bufferWriteOp(b3, SWFACTION_BRANCHALWAYS);
bufferWriteS16(b3, 2);
bufferWriteS16(b3, -tmp);
bufferResolveJumps(b3);
bufferConcat($$, b3);
delctx(CTX_FOR_IN); }
;
assign_stmts_opt
: /* empty */ { $$ = NULL; }
| assign_stmts
;
// continue only makes sense if there is a CTX_LOOP or CTX_FOR_IN
// on the stack
cont_stmt
: CONTINUE ';'
{ if(chkctx(CTX_CONTINUE) < 0)
swf5error("continue outside loop");
$$ = newBuffer();
bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
bufferWriteS16($$, 2);
bufferWriteS16($$, MAGIC_CONTINUE_NUMBER); }
;
// break is possible if there is a CTX_LOOP, CTX_FOR_IN or CTX_SWITCH
break_stmt
: BREAK ';'
{ int tmp = chkctx(CTX_BREAK);
if(tmp < 0)
swf5error("break outside switch / loop");
$$ = newBuffer();
if(tmp) /* break out of a for .. in */
bufferWriteOp($$, SWFACTION_POP);
bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
bufferWriteS16($$, 2);
bufferWriteS16($$, MAGIC_BREAK_NUMBER); }
;
urlmethod
: /* empty */ { $$ = GETURL_METHOD_NOSEND; }
| ',' GET { $$ = GETURL_METHOD_GET; }
| ',' POST { $$ = GETURL_METHOD_POST; }
| ',' STRING { if(strcmp($2, "GET") == 0)
$$ = GETURL_METHOD_GET;
else if(strcmp($2, "POST") == 0)
$$ = GETURL_METHOD_POST; }
;
level
: INTEGER
{ char *lvlstring = (char*) malloc(12*sizeof(char));
sprintf(lvlstring, "_level%d", $1);
$$ = newBuffer();
bufferWriteString($$, lvlstring, strlen(lvlstring)+1);
free(lvlstring); }
| expr
{ $$ = newBuffer();
bufferWriteString($$, "_level", 7);
bufferConcat($$, $1);
bufferWriteOp($$, SWFACTION_STRINGCONCAT); }
;
void_function_call
: IDENTIFIER '(' expr_list ')'
{ $$ = $3.buffer;
bufferWriteInt($$, $3.count);
bufferWriteString($$, $1, strlen($1)+1);
bufferWriteOp($$, SWFACTION_CALLFUNCTION);
bufferWriteOp($$, SWFACTION_POP);
free($1); }
| DELETE IDENTIFIER
{ $$ = newBuffer();
bufferWriteString($$, $2, strlen($2)+1);
free($2);
bufferWriteOp($$, SWFACTION_DELETE); }
| DELETE lvalue_expr '.' IDENTIFIER
{ $$ = $2;
// bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferWriteString($$, $4, strlen($4)+1);
free($4);
bufferWriteOp($$, SWFACTION_DELETEVAR); }
| DELETE lvalue_expr '[' expr ']'
{ $$ = $2;
// bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferConcat($$, $4);
// bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferWriteOp($$, SWFACTION_DELETEVAR); }
| TRACE '(' expr_or_obj ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_TRACE); }
| GETURL '(' expr ',' expr urlmethod ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferWriteOp($$, SWFACTION_GETURL2);
bufferWriteS16($$, 1);
bufferWriteU8($$, $6); }
| LOADVARIABLES '(' expr ',' expr urlmethod ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferWriteOp($$, SWFACTION_GETURL2);
bufferWriteS16($$, 1);
bufferWriteU8($$, 0xc0+$6); }
| LOADVARIABLESNUM '(' expr ',' level urlmethod ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferWriteOp($$, SWFACTION_GETURL2);
bufferWriteS16($$, 1);
bufferWriteU8($$, 0x80+$6); }
| LOADMOVIE '(' expr ',' expr urlmethod ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferWriteOp($$, SWFACTION_GETURL2);
bufferWriteS16($$, 1);
bufferWriteU8($$, 0x40+$6); }
| LOADMOVIENUM '(' expr ',' level urlmethod ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferWriteOp($$, SWFACTION_GETURL2);
bufferWriteS16($$, 1);
bufferWriteU8($$, $6); }
| CALLFRAME '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_CALLFRAME);
bufferWriteS16($$, 0); }
/* startDrag(target, lock, [left, right, top, bottom]) */
| STARTDRAG '(' expr ',' expr ')'
{ $$ = newBuffer();
bufferWriteString($$, "0", 2); /* no constraint */
bufferConcat($$, $5);
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_STARTDRAGMOVIE); }
| STARTDRAG '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
{ $$ = newBuffer();
bufferConcat($$, $7);
bufferConcat($$, $11);
bufferConcat($$, $9);
bufferConcat($$, $13);
bufferWriteString($$, "1", 2); /* has constraint */
bufferConcat($$, $5);
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_STARTDRAGMOVIE); }
| STOPDRAG '(' ')' /* no args */
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_STOPDRAGMOVIE); }
/* duplicateMovieClip(target, new, depth) */
| DUPLICATEMOVIECLIP '(' expr ',' expr ',' expr ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferConcat($$, $7);
bufferWriteInt($$, 16384); /* magic number */
bufferWriteOp($$, SWFACTION_ADD);
bufferWriteOp($$, SWFACTION_DUPLICATECLIP); }
| REMOVEMOVIECLIP '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_REMOVECLIP); }
| GETURL1 '(' STRING ',' STRING ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_GETURL);
bufferWriteS16($$, strlen($3) + strlen($5) + 2);
bufferWriteHardString($$, (byte*)$3, strlen($3));
bufferWriteU8($$, 0);
bufferWriteHardString($$, (byte*)$5, strlen($5));
bufferWriteU8($$, 0); }
/* v3 actions */
| NEXTFRAME '(' ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_NEXTFRAME); }
| PREVFRAME '(' ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_PREVFRAME); }
| PLAY '(' ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_PLAY); }
| STOP '(' ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_STOP); }
| STOPSOUNDS '(' ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_STOPSOUNDS); }
| TOGGLEQUALITY '(' ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_TOGGLEQUALITY); }
| GOTOFRAME '(' INTEGER ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_GOTOFRAME);
bufferWriteS16($$, 2);
bufferWriteS16($$, $3); }
| GOTOFRAME '(' STRING ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_GOTOLABEL);
bufferWriteS16($$, strlen($3)+1);
bufferWriteHardString($$, (byte*)$3, strlen($3)+1);
free($3); }
| GOTOFRAME '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_GOTOEXPRESSION);
bufferWriteS16($$, 1);
bufferWriteU8($$, 0); } /* XXX - and stop */
| SETTARGET '(' STRING ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_SETTARGET);
bufferWriteS16($$, strlen($3)+1);
bufferWriteHardString($$, (byte*)$3, strlen($3)+1);
free($3); }
| SETTARGET '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_SETTARGETEXPRESSION); }
;
function_call
: IDENTIFIER '(' expr_list ')'
{ $$ = $3.buffer;
bufferWriteInt($$, $3.count);
bufferWriteString($$, $1, strlen($1)+1);
bufferWriteOp($$, SWFACTION_CALLFUNCTION);
free($1); }
| EVAL '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_GETVARIABLE); }
| GETTIMER '(' ')'
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_GETTIMER); }
| RANDOM '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_RANDOM); }
| LENGTH '(' expr_or_obj ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_STRINGLENGTH); }
| INT '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_INT); }
| ORD '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_ORD); }
| CHR '(' expr ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_CHR); }
| CONCAT '(' expr ',' expr ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferWriteOp($$, SWFACTION_STRINGCONCAT); }
| SUBSTRING '(' expr ',' expr ',' expr ')'
{ $$ = $3;
bufferConcat($$, $5);
bufferConcat($$, $7);
bufferWriteOp($$, SWFACTION_SUBSTRING); }
| TYPEOF '(' expr_or_obj ')'
{ $$ = $3;
bufferWriteOp($$, SWFACTION_TYPEOF); }
;
expr_list
: /* empty */
{ $$.buffer = newBuffer();
$$.count = 0; }
| expr_or_obj
{ $$.buffer = $1;
$$.count = 1; }
/* goes backwards. rrgh. */
| expr_list ',' expr_or_obj
{ Buffer tmp = newBuffer();
bufferConcat(tmp, $3);
bufferConcat(tmp, $$.buffer);
$$.buffer = tmp;
++$$.count; }
;
anon_function_decl
: function_init '(' formals_list ')' stmt
{ $$ = newBuffer();
bufferWriteOp($$, SWFACTION_DEFINEFUNCTION);
bufferWriteS16($$, bufferLength($3.buffer) + 5);
bufferWriteU8($$, 0); /* empty function name */
bufferWriteS16($$, $3.count);
bufferConcat($$, $3.buffer);
bufferWriteS16($$, bufferLength($5));
bufferConcat($$, $5);
delctx(CTX_FUNCTION); }
;
method_call
: lvalue_expr '.' identifier '(' expr_list ')'
{ $$ = $5.buffer;
bufferWriteInt($$, $5.count);
bufferConcat($$, $1);
bufferWriteString($$, $3, strlen($3)+1);
bufferWriteOp($$, SWFACTION_CALLMETHOD);
free($3); }
| lvalue_expr '[' expr ']' '(' expr_list ')'
{ $$ = $6.buffer;
bufferWriteInt($$, $6.count);
bufferConcat($$, $1);
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_CALLMETHOD); }
;
objexpr
: identifier ':' expr_or_obj
{ $$ = newBuffer();
bufferWriteString($$, $1, strlen($1)+1);
bufferConcat($$, $3); }
;
objexpr_list
: objexpr
{ $$.buffer = $1;
$$.count = 1; }
| objexpr_list ',' objexpr
{ bufferConcat($$.buffer, $3);
++$$.count; }
;
assignop
: "+=" { $$ = SWFACTION_NEWADD; }
| "-=" { $$ = SWFACTION_SUBTRACT; }
| "*=" { $$ = SWFACTION_MULTIPLY; }
| "/=" { $$ = SWFACTION_DIVIDE; }
| "%=" { $$ = SWFACTION_MODULO; }
| "&=" { $$ = SWFACTION_BITWISEAND; }
| "|=" { $$ = SWFACTION_BITWISEOR; }
| "^=" { $$ = SWFACTION_BITWISEXOR; }
| "<<=" { $$ = SWFACTION_SHIFTLEFT; }
| ">>=" { $$ = SWFACTION_SHIFTRIGHT; }
| ">>>=" { $$ = SWFACTION_SHIFTRIGHT2; }
;
incdecop
: "++" { $$ = SWFACTION_INCREMENT; }
| "--" { $$ = SWFACTION_DECREMENT; }
;
/*
integer
: '-' INTEGER %prec UMINUS { $$ = -$2; }
| INTEGER { $$ = $1; }
;
double
: '-' DOUBLE %prec UMINUS { $$ = -$2; }
| DOUBLE { $$ = $1; }
;
*/
/* resolves an lvalue into a buffer */
lvalue_expr
: lvalue
{ if($1.obj)
{
$$ = $1.obj;
if($1.ident)
bufferConcat($$, $1.ident);
else
bufferConcat($$, $1.memexpr);
bufferWriteOp($$, SWFACTION_GETMEMBER);
}
else
{
$$ = $1.ident;
bufferWriteOp($$, SWFACTION_GETVARIABLE);
}
}
| function_call
| method_call
;
/* lvalue - things you can assign to */
lvalue
: identifier
{ $$.ident = newBuffer();
bufferWriteString($$.ident, $1, strlen($1)+1);
free($1);
$$.obj = 0;
$$.memexpr = 0; }
| lvalue_expr '.' identifier %prec '.'
{ $$.obj = $1;
$$.ident = newBuffer();
bufferWriteString($$.ident, $3, strlen($3)+1);
$$.memexpr = 0; }
| lvalue_expr '[' expr ']' %prec '.'
{ $$.obj = $1;
$$.memexpr = $3;
$$.ident = 0; }
;
/* these leave a value on the stack */
expr
: primary
| '-' expr %prec UMINUS
{ $$ = $2;
bufferWriteInt($2, -1);
bufferWriteOp($2, SWFACTION_MULTIPLY); }
| '~' expr %prec UMINUS
{ $$ = $2;
bufferWriteInt($2, 0xffffffff);
bufferWriteOp($2, SWFACTION_BITWISEXOR); }
| '!' expr
{ $$ = $2;
bufferWriteOp($2, SWFACTION_LOGICALNOT); }
| expr "||" expr
{ $$ = $1;
bufferWriteOp($$, SWFACTION_DUP);
bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($3)+1);
bufferWriteOp($$, SWFACTION_POP);
bufferConcat($$, $3); }
| expr "&&" expr
{ $$ = $1;
bufferWriteOp($$, SWFACTION_DUP);
bufferWriteOp($$, SWFACTION_LOGICALNOT);
bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($$, 2);
bufferWriteS16($$, bufferLength($3)+1);
bufferWriteOp($$, SWFACTION_POP);
bufferConcat($$, $3); }
| expr '*' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_MULTIPLY); }
| expr '/' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_DIVIDE); }
| expr '%' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_MODULO); }
| expr '+' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_NEWADD); }
| expr '-' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_SUBTRACT); }
| expr '&' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_BITWISEAND); }
| expr '|' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_BITWISEOR); }
| expr '^' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_BITWISEXOR); }
| expr '<' expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_NEWLESSTHAN); }
| expr '>' expr
{ $$ = $3;
bufferConcat($$, $1);
bufferWriteOp($$, SWFACTION_NEWLESSTHAN); }
| expr "<=" expr
{ $$ = $3;
bufferConcat($$, $1);
bufferWriteOp($$, SWFACTION_NEWLESSTHAN);
bufferWriteOp($$, SWFACTION_LOGICALNOT); }
| expr ">=" expr
{ bufferConcat($1, $3);
bufferWriteOp($1, SWFACTION_NEWLESSTHAN);
bufferWriteOp($1, SWFACTION_LOGICALNOT); }
| expr "==" expr
{ bufferConcat($1, $3);
bufferWriteOp($1, SWFACTION_NEWEQUALS); }
| expr "!=" expr
{ bufferConcat($1, $3);
bufferWriteOp($1, SWFACTION_NEWEQUALS);
bufferWriteOp($1, SWFACTION_LOGICALNOT); }
| expr "<<" expr
{ bufferConcat($1, $3);
bufferWriteOp($1, SWFACTION_SHIFTLEFT); }
| expr ">>" expr
{ bufferConcat($1, $3);
bufferWriteOp($1, SWFACTION_SHIFTRIGHT); }
| expr ">>>" expr
{ bufferConcat($1, $3);
bufferWriteOp($1, SWFACTION_SHIFTRIGHT2); }
| expr '?' expr ':' expr
{ bufferWriteOp($1, SWFACTION_BRANCHIFTRUE);
bufferWriteS16($1, 2);
bufferWriteS16($1, bufferLength($5)+5);
bufferConcat($1, $5);
bufferWriteOp($1, SWFACTION_BRANCHALWAYS);
bufferWriteS16($1, 2);
bufferWriteS16($1, bufferLength($3));
bufferConcat($1, $3); }
| lvalue '=' expr_or_obj
{ if($1.obj) /* obj[memexpr] or obj.ident */
{
$$ = $1.obj;
if($1.ident)
bufferConcat($$, $1.ident);
else
bufferConcat($$, $1.memexpr);
bufferConcat($$, $3);
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SETMEMBER);
bufferWriteRegister($$, 0);
}
else /* just ident */
{
$$ = $3;
bufferWriteOp($$, SWFACTION_DUP);
bufferConcat($$, $1.ident);
bufferWriteOp($$, SWFACTION_SWAP);
bufferWriteOp($$, SWFACTION_SETVARIABLE);
}
/* tricky case missing here: lvalue ASSIGN expr */
/* like in x = y += z; */
}
| expr INSTANCEOF lvalue_expr
{ $$ = $1;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_INSTANCEOF); }
;
expr_or_obj
: expr
| NEW identifier
{ $$ = newBuffer();
bufferWriteInt($$, 0);
bufferWriteString($$, $2, strlen($2)+1);
bufferWriteOp($$, SWFACTION_NEW); }
| NEW identifier '(' expr_list ')'
{ $$ = $4.buffer;
bufferWriteInt($$, $4.count);
bufferWriteString($$, $2, strlen($2)+1);
bufferWriteOp($$, SWFACTION_NEW); }
| '[' expr_list ']'
{ $$ = $2.buffer;
bufferWriteInt($$, $2.count);
bufferWriteOp($$, SWFACTION_INITARRAY); }
| emptybraces
{ $$ = newBuffer();
bufferWriteInt($$, 0);
bufferWriteOp($$, SWFACTION_INITOBJECT); }
| '{' objexpr_list '}'
{ $$ = $2.buffer;
bufferWriteInt($$, $2.count);
bufferWriteOp($$, SWFACTION_INITOBJECT); }
;
primary
: function_call
| anon_function_decl
| method_call
| lvalue_expr
| incdecop lvalue %prec "++"
{ if($2.obj)
{
if($2.ident) // expr . identifier
{
$$ = $2.obj;
bufferWriteOp($$, SWFACTION_DUP); /* a, a */
bufferWriteBuffer($$, $2.ident); /* a, a, i */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a */
bufferConcat($$, $2.ident); /* a, i, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER);
bufferWriteOp($$, $1);
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+1 */
bufferWriteRegister($$, 0); /* a.i+1 */
}
else // expr [ expr ]
{
$$ = $2.memexpr; /* i */
bufferConcat($$, $2.obj); /* i, a */
bufferWriteSetRegister($$, 0); /* ($2.memexpr can use reg0) */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i */
bufferWriteOp($$, SWFACTION_DUP); /* a, i, i */
bufferWriteRegister($$, 0); /* a, i, i, a */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
bufferWriteOp($$, $1); /* a, i, a[i]+1 */
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+1 */
bufferWriteRegister($$, 0); /* a[i]+1 */
}
}
else // identifier
{
$$ = newBuffer();
bufferWriteBuffer($$, $2.ident);
bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferWriteOp($$, $1);
bufferWriteOp($$, SWFACTION_DUP);
bufferConcat($$, $2.ident);
bufferWriteOp($$, SWFACTION_SWAP);
bufferWriteOp($$, SWFACTION_SETVARIABLE);
}
}
| lvalue incdecop %prec POSTFIX
{ if($1.obj)
{
if($1.ident)
{
$$ = $1.obj; /* a */
bufferWriteOp($$, SWFACTION_DUP); /* a, a */
bufferWriteBuffer($$, $1.ident); /* a, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SWAP); /* a.i, a */
bufferConcat($$, $1.ident); /* a.i, a, i */
bufferWriteRegister($$, 0); /* a.i, a, i, a.i */
bufferWriteOp($$, $2); /* a.i, a, i, a.i+1 */
bufferWriteOp($$, SWFACTION_SETMEMBER);
}
else
{
$$ = $1.memexpr;
bufferConcat($$, $1.obj); /* i, a */
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SWAP); /* a, i */
bufferWriteOp($$, SWFACTION_DUP); /* a, i, i */
bufferWriteRegister($$, 0); /* a, i, i, a */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, $2); /* a, i, a[i]+1 */
bufferWriteOp($$, SWFACTION_SETMEMBER);
bufferWriteRegister($$, 0); /* a[i] */
}
}
else
{
$$ = newBuffer();
bufferWriteBuffer($$, $1.ident);
bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferWriteOp($$, SWFACTION_DUP);
bufferWriteOp($$, $2);
bufferConcat($$, $1.ident);
bufferWriteOp($$, SWFACTION_SWAP);
bufferWriteOp($$, SWFACTION_SETVARIABLE);
}
}
| '(' expr ')'
{ $$ = $2; }
| '-' INTEGER %prec UMINUS
{ $$ = newBuffer();
bufferWriteInt($$, -$2); }
| INTEGER
{ $$ = newBuffer();
bufferWriteInt($$, $1); }
| '-' DOUBLE %prec UMINUS
{ $$ = newBuffer();
bufferWriteDouble($$, -$2); }
| DOUBLE
{ $$ = newBuffer();
bufferWriteDouble($$, $1); }
| BOOLEAN
{ $$ = newBuffer();
bufferWriteBoolean($$, $1); }
| NULLVAL
{ $$ = newBuffer();
bufferWriteNull($$); }
| STRING
{ $$ = newBuffer();
bufferWriteString($$, $1, strlen($1)+1);
free($1); }
;
init_vars
: init_var
| init_vars ',' init_var
{ $$ = $1;
bufferConcat($$, $3); }
;
init_var
: identifier '=' expr_or_obj
{ $$ = newBuffer();
bufferWriteString($$, $1, strlen($1)+1);
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_VAREQUALS); }
| identifier
{ $$ = newBuffer();
bufferWriteString($$, $1, strlen($1)+1);
bufferWriteOp($$, SWFACTION_VAR); }
;
assign_stmt
: ASM '{'
{ asmBuffer = newBuffer(); }
opcode_list '}'
{ $$ = asmBuffer; }
| VAR init_vars
{ $$ = $2; }
| void_function_call
| function_call
{ $$ = $1;
bufferWriteOp($$, SWFACTION_POP); }
| method_call
{ $$ = $1;
bufferWriteOp($$, SWFACTION_POP); }
| incdecop lvalue %prec INCR
{ if($2.obj)
{
if($2.ident)
{
$$ = $2.obj; /* a */
bufferWriteOp($$, SWFACTION_DUP); /* a, a */
bufferWriteBuffer($$, $2.ident); /* a, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
bufferWriteOp($$, $1); /* a, a.i+1 */
bufferConcat($$, $2.ident); /* a, a.i+1, i */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a.i+1 */
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+1 */
}
else
{
/* weird contortions so that $2.memexpr can use reg 0 */
$$ = $2.memexpr; /* i */
bufferConcat($$, $2.obj); /* i, a */
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SWAP); /* a, i */
bufferWriteOp($$, SWFACTION_DUP); /* a, i, i */
bufferWriteRegister($$, 0); /* a, i, i, a */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
bufferWriteOp($$, $1); /* a, i, a[i]+1 */
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+1 */
}
}
else
{
$$ = $2.ident;
bufferWriteOp($$, SWFACTION_DUP);
bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferWriteOp($$, $1);
bufferWriteOp($$, SWFACTION_SETVARIABLE);
}
}
| lvalue incdecop %prec POSTFIX
{ if($1.obj)
{
if($1.ident)
{
$$ = $1.obj; /* a */
bufferWriteOp($$, SWFACTION_DUP); /* a, a */
bufferWriteBuffer($$, $1.ident); /* a, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
bufferWriteOp($$, $2); /* a, a.i+1 */
bufferConcat($$, $1.ident); /* a, a.i+1, i */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a.i+1 */
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+1 */
}
else
{
/* weird contortions so that $1.memexpr can use reg 0 */
$$ = $1.memexpr; /* i */
bufferConcat($$, $1.obj); /* i, a */
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SWAP); /* a, i */
bufferWriteOp($$, SWFACTION_DUP); /* a, i, i */
bufferWriteRegister($$, 0); /* a, i, i, a */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
bufferWriteOp($$, $2); /* a, i, a[i]+1 */
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+1 */
}
}
else
{
$$ = $1.ident;
bufferWriteOp($$, SWFACTION_DUP);
bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferWriteOp($$, $2);
bufferWriteOp($$, SWFACTION_SETVARIABLE);
}
}
| lvalue '=' expr_or_obj
{ if($1.obj)
{
$$ = $1.obj;
if($1.ident)
bufferConcat($$, $1.ident);
else
bufferConcat($$, $1.memexpr);
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_SETMEMBER);
}
else
{
$$ = $1.ident;
bufferConcat($$, $3);
bufferWriteOp($$, SWFACTION_SETVARIABLE);
}
}
| lvalue assignop expr
{ if($1.obj)
{
if($1.ident)
{
$$ = $1.obj; /* a */
bufferWriteOp($$, SWFACTION_DUP); /* a, a */
bufferWriteBuffer($$, $1.ident); /* a, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
bufferConcat($$, $3); /* a, a.i, v */
bufferWriteOp($$, $2); /* a, a.i+v */
bufferConcat($$, $1.ident); /* a, a.i+v, i */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a.i+v */
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+v */
}
else
{
$$ = $1.memexpr; /* i */
bufferConcat($$, $1.obj); /* i, a */
bufferWriteSetRegister($$, 0);
bufferWriteOp($$, SWFACTION_SWAP); /* a, i */
bufferWriteOp($$, SWFACTION_DUP); /* a, i, i */
bufferWriteRegister($$, 0); /* a, i, i, a */
bufferWriteOp($$, SWFACTION_SWAP); /* a, i, a, i */
bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
bufferConcat($$, $3); /* a, i, a[i], v */
bufferWriteOp($$, $2); /* a, i, a[i]+v */
bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+v */
}
}
else
{
$$ = $1.ident;
bufferWriteOp($$, SWFACTION_DUP);
bufferWriteOp($$, SWFACTION_GETVARIABLE);
bufferConcat($$, $3);
bufferWriteOp($$, $2);
bufferWriteOp($$, SWFACTION_SETVARIABLE);
}
}
;
/* assembler stuff */
opcode_list
: opcode
| opcode_list opcode { $$ = $1 + $2; }
;
with
: WITH
{ $$ = bufferWriteOp(asmBuffer,
SWFACTION_WITH); }
opcode_list END { $$ = $<len>2 + $3;
bufferPatchLength(asmBuffer, $3); }
;
push_item
: STRING { $$ = bufferWriteConstantString(asmBuffer,(byte*) $1,
strlen($1)+1); }
| INTEGER { bufferWriteU8(asmBuffer, PUSH_INT);
$$ = bufferWriteInt(asmBuffer, $1)+1; }
| DOUBLE { bufferWriteU8(asmBuffer, PUSH_DOUBLE);
$$ = bufferWriteDouble(asmBuffer, $1)+1; }
| BOOLEAN { bufferWriteU8(asmBuffer, PUSH_BOOLEAN);
$$ = bufferWriteU8(asmBuffer, $1)+1; }
| NULLVAL { $$ = bufferWriteU8(asmBuffer, PUSH_NULL); }
| REGISTER { bufferWriteU8(asmBuffer, PUSH_REGISTER);
$$ = bufferWriteU8(asmBuffer,
(char)atoi($1))+1; }
;
push_list
: push_item { $$ = $1; }
| push_list ',' push_item { $$ += $3; }
;
opcode
: PUSH { $$ = bufferWriteOp(asmBuffer,
SWFACTION_PUSHDATA);
$$ += bufferWriteS16(asmBuffer, 0); }
push_list { $$ = $<len>2 + $3;
bufferPatchLength(asmBuffer, $3); }
| with
| SETREGISTER REGISTER
{ $$ = bufferWriteOp(asmBuffer,
SWFACTION_SETREGISTER);
$$ += bufferWriteS16(asmBuffer, 1);
$$ += bufferWriteU8(asmBuffer,
(char)atoi($2)); }
/* no args */
| CALLFUNCTION { $$ = bufferWriteOp(asmBuffer,
SWFACTION_CALLFUNCTION); }
| RETURN { $$ = bufferWriteOp(asmBuffer,
SWFACTION_RETURN); }
| CALLMETHOD { $$ = bufferWriteOp(asmBuffer,
SWFACTION_CALLMETHOD); }
| AND { $$ = bufferWriteOp(asmBuffer,
SWFACTION_BITWISEAND); }
| OR { $$ = bufferWriteOp(asmBuffer,
SWFACTION_BITWISEOR); }
| XOR { $$ = bufferWriteOp(asmBuffer,
SWFACTION_BITWISEXOR); }
| MODULO { $$ = bufferWriteOp(asmBuffer,
SWFACTION_MODULO); }
| ADD { $$ = bufferWriteOp(asmBuffer,
SWFACTION_NEWADD); }
| LESSTHAN { $$ = bufferWriteOp(asmBuffer,
SWFACTION_NEWLESSTHAN); }
| EQUALS { $$ = bufferWriteOp(asmBuffer,
SWFACTION_NEWEQUALS); }
| INC { $$ = bufferWriteOp(asmBuffer,
SWFACTION_INCREMENT); }
| DEC { $$ = bufferWriteOp(asmBuffer,
SWFACTION_DECREMENT); }
| TYPEOF { $$ = bufferWriteOp(asmBuffer,
SWFACTION_TYPEOF); }
| INSTANCEOF { $$ = bufferWriteOp(asmBuffer,
SWFACTION_INSTANCEOF); }
| ENUMERATE { $$ = bufferWriteOp(asmBuffer,
SWFACTION_ENUMERATE); }
| DELETE { $$ = bufferWriteOp(asmBuffer,
SWFACTION_DELETE); }
| NEW { $$ = bufferWriteOp(asmBuffer,
SWFACTION_NEW); }
| INITARRAY { $$ = bufferWriteOp(asmBuffer,
SWFACTION_INITARRAY); }
| INITOBJECT { $$ = bufferWriteOp(asmBuffer,
SWFACTION_INITOBJECT); }
| GETMEMBER { $$ = bufferWriteOp(asmBuffer,
SWFACTION_GETMEMBER); }
| SETMEMBER { $$ = bufferWriteOp(asmBuffer,
SWFACTION_SETMEMBER); }
| SHIFTLEFT { $$ = bufferWriteOp(asmBuffer,
SWFACTION_SHIFTLEFT); }
| SHIFTRIGHT { $$ = bufferWriteOp(asmBuffer,
SWFACTION_SHIFTRIGHT); }
| SHIFTRIGHT2 { $$ = bufferWriteOp(asmBuffer,
SWFACTION_SHIFTRIGHT2); }
| VAR { $$ = bufferWriteOp(asmBuffer,
SWFACTION_VAR); }
| VAREQUALS { $$ = bufferWriteOp(asmBuffer,
SWFACTION_VAREQUALS); }
/* f4 ops */
| OLDADD { $$ = bufferWriteOp(asmBuffer, SWFACTION_ADD); }
| SUBTRACT { $$ = bufferWriteOp(asmBuffer, SWFACTION_SUBTRACT); }
| MULTIPLY { $$ = bufferWriteOp(asmBuffer, SWFACTION_MULTIPLY); }
| DIVIDE { $$ = bufferWriteOp(asmBuffer, SWFACTION_DIVIDE); }
| OLDEQUALS { $$ = bufferWriteOp(asmBuffer, SWFACTION_EQUAL); }
| OLDLESSTHAN { $$ = bufferWriteOp(asmBuffer, SWFACTION_LESSTHAN); }
| LOGICALAND { $$ = bufferWriteOp(asmBuffer, SWFACTION_LOGICALAND); }
| LOGICALOR { $$ = bufferWriteOp(asmBuffer, SWFACTION_LOGICALOR); }
| NOT { $$ = bufferWriteOp(asmBuffer, SWFACTION_LOGICALNOT); }
| STRINGEQ { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGEQ); }
| STRINGLENGTH { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGLENGTH); }
| SUBSTRING { $$ = bufferWriteOp(asmBuffer, SWFACTION_SUBSTRING); }
| INT { $$ = bufferWriteOp(asmBuffer, SWFACTION_INT); }
| DUP { $$ = bufferWriteOp(asmBuffer, SWFACTION_DUP); }
| SWAP { $$ = bufferWriteOp(asmBuffer, SWFACTION_SWAP); }
| POP { $$ = bufferWriteOp(asmBuffer, SWFACTION_POP); }
| GETVARIABLE { $$ = bufferWriteOp(asmBuffer, SWFACTION_GETVARIABLE); }
| SETVARIABLE { $$ = bufferWriteOp(asmBuffer, SWFACTION_SETVARIABLE); }
| SETTARGETEXPRESSION { $$ = bufferWriteOp(asmBuffer, SWFACTION_SETTARGETEXPRESSION); }
| CONCAT { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGCONCAT); }
| DUPLICATEMOVIECLIP { $$ = bufferWriteOp(asmBuffer, SWFACTION_DUPLICATECLIP); }
| REMOVEMOVIECLIP { $$ = bufferWriteOp(asmBuffer, SWFACTION_REMOVECLIP); }
| TRACE { $$ = bufferWriteOp(asmBuffer, SWFACTION_TRACE); }
| STRINGLESSTHAN { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGCOMPARE); }
| RANDOM { $$ = bufferWriteOp(asmBuffer, SWFACTION_RANDOM); }
| MBLENGTH { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBLENGTH); }
| ORD { $$ = bufferWriteOp(asmBuffer, SWFACTION_ORD); }
| CHR { $$ = bufferWriteOp(asmBuffer, SWFACTION_CHR); }
| GETTIMER { $$ = bufferWriteOp(asmBuffer, SWFACTION_GETTIMER); }
| MBSUBSTRING { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBSUBSTRING); }
| MBORD { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBORD); }
| MBCHR { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBCHR); }
/* with args */
| BRANCHALWAYS STRING { $$ = bufferWriteOp(asmBuffer, SWFACTION_BRANCHALWAYS);
$$ += bufferWriteS16(asmBuffer, 2);
$$ += bufferBranchTarget(asmBuffer, $2); }
| BRANCHIFTRUE STRING { $$ = bufferWriteOp(asmBuffer, SWFACTION_BRANCHIFTRUE);
$$ += bufferWriteS16(asmBuffer, 2);
$$ += bufferBranchTarget(asmBuffer, $2); }
;
%%