From 628e5b0c1264d8419cde6e458d09ed266bb1c79d Mon Sep 17 00:00:00 2001 From: kramm Date: Mon, 2 Feb 2004 10:12:34 +0000 Subject: [PATCH] file copied from ming 0.3alpha2 --- lib/action/action.h | 119 +++ lib/action/assembler.c | 131 ++++ lib/action/assembler.h | 21 + lib/action/compile.c | 786 +++++++++++++++++++ lib/action/compile.h | 163 ++++ lib/action/listaction.c | 557 ++++++++++++++ lib/action/swf4compiler.flex | 403 ++++++++++ lib/action/swf4compiler.y | 1039 ++++++++++++++++++++++++++ lib/action/swf5compiler.flex | 467 ++++++++++++ lib/action/swf5compiler.y | 1698 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 5384 insertions(+) create mode 100755 lib/action/action.h create mode 100644 lib/action/assembler.c create mode 100644 lib/action/assembler.h create mode 100755 lib/action/compile.c create mode 100755 lib/action/compile.h create mode 100755 lib/action/listaction.c create mode 100755 lib/action/swf4compiler.flex create mode 100755 lib/action/swf4compiler.y create mode 100644 lib/action/swf5compiler.flex create mode 100644 lib/action/swf5compiler.y diff --git a/lib/action/action.h b/lib/action/action.h new file mode 100755 index 0000000..5c35ce4 --- /dev/null +++ b/lib/action/action.h @@ -0,0 +1,119 @@ +/* action.h + * + * $Id: action.h,v 1.1 2004/02/02 10:12:34 kramm Exp $ + * + * Notice: This header file contains declarations of functions and types that + * are just used internally. All library functions and types that are supposed + * to be publicly accessable are defined in ./src/ming.h. + */ + +#ifndef SWF_COMPILER_ACTION_H_INCLUDED +#define SWF_COMPILER_ACTION_H_INCLUDED + +#include "ming.h" + +enum +{ + SWFACTION_END = 0x00, + +/* v3 actions */ + SWFACTION_NEXTFRAME = 0x04, + SWFACTION_PREVFRAME = 0x05, + SWFACTION_PLAY = 0x06, + SWFACTION_STOP = 0x07, + SWFACTION_TOGGLEQUALITY = 0x08, + SWFACTION_STOPSOUNDS = 0x09, + SWFACTION_GOTOFRAME = 0x81, /* >= 0x80 means record has args */ + SWFACTION_GETURL = 0x83, + SWFACTION_WAITFORFRAME = 0x8A, + SWFACTION_SETTARGET = 0x8B, + SWFACTION_GOTOLABEL = 0x8C, + +/* v4 actions */ + SWFACTION_ADD = 0x0A, + SWFACTION_SUBTRACT = 0x0B, + SWFACTION_MULTIPLY = 0x0C, + SWFACTION_DIVIDE = 0x0D, + SWFACTION_EQUAL = 0x0E, + SWFACTION_LESSTHAN = 0x0F, + SWFACTION_LOGICALAND = 0x10, + SWFACTION_LOGICALOR = 0x11, + SWFACTION_LOGICALNOT = 0x12, + SWFACTION_STRINGEQ = 0x13, + SWFACTION_STRINGLENGTH = 0x14, + SWFACTION_SUBSTRING = 0x15, + SWFACTION_POP = 0x17, + SWFACTION_INT = 0x18, + SWFACTION_GETVARIABLE = 0x1C, + SWFACTION_SETVARIABLE = 0x1D, + SWFACTION_SETTARGETEXPRESSION = 0x20, + SWFACTION_STRINGCONCAT = 0x21, + SWFACTION_GETPROPERTY = 0x22, + SWFACTION_SETPROPERTY = 0x23, + SWFACTION_DUPLICATECLIP = 0x24, + SWFACTION_REMOVECLIP = 0x25, + SWFACTION_TRACE = 0x26, + SWFACTION_STARTDRAGMOVIE = 0x27, + SWFACTION_STOPDRAGMOVIE = 0x28, + SWFACTION_STRINGCOMPARE = 0x29, + SWFACTION_RANDOM = 0x30, + SWFACTION_MBLENGTH = 0x31, + SWFACTION_ORD = 0x32, + SWFACTION_CHR = 0x33, + SWFACTION_GETTIMER = 0x34, + SWFACTION_MBSUBSTRING = 0x35, + SWFACTION_MBORD = 0x36, + SWFACTION_MBCHR = 0x37, + + SWFACTION_WAITFORFRAMEEXPRESSION = 0x8D, + SWFACTION_PUSHDATA = 0x96, + SWFACTION_BRANCHALWAYS = 0x99, + SWFACTION_GETURL2 = 0x9A, + SWFACTION_BRANCHIFTRUE = 0x9D, + SWFACTION_CALLFRAME = 0x9E, + SWFACTION_GOTOEXPRESSION = 0x9F, + +/* v5 actions */ + SWFACTION_DELETEVAR = 0x3A,/*not used yet*/ + SWFACTION_DELETE = 0x3B, + SWFACTION_VAREQUALS = 0x3C, + SWFACTION_CALLFUNCTION = 0x3D, + SWFACTION_RETURN = 0x3E, + SWFACTION_MODULO = 0x3F, + SWFACTION_NEW = 0x40, + SWFACTION_VAR = 0x41, + SWFACTION_INITARRAY = 0x42, + SWFACTION_INITOBJECT = 0x43, + SWFACTION_TYPEOF = 0x44, + SWFACTION_TARGETPATH = 0x45, + SWFACTION_ENUMERATE = 0x46, + SWFACTION_NEWADD = 0x47, + SWFACTION_NEWLESSTHAN = 0x48, + SWFACTION_NEWEQUALS = 0x49, + SWFACTION_TONUMBER = 0x4A, + SWFACTION_TOSTRING = 0x4B, + SWFACTION_DUP = 0x4C, + SWFACTION_SWAP = 0x4D, + SWFACTION_GETMEMBER = 0x4E, + SWFACTION_SETMEMBER = 0x4F, + SWFACTION_INCREMENT = 0x50, + SWFACTION_DECREMENT = 0x51, + SWFACTION_CALLMETHOD = 0x52, + SWFACTION_NEWMETHOD = 0x53,/*not used yet*/ + SWFACTION_INSTANCEOF = 0x54, + SWFACTION_ENUM2 = 0x55,/*not used yet*/ + SWFACTION_BITWISEAND = 0x60, + SWFACTION_BITWISEOR = 0x61, + SWFACTION_BITWISEXOR = 0x62, + SWFACTION_SHIFTLEFT = 0x63, + SWFACTION_SHIFTRIGHT = 0x64, + SWFACTION_SHIFTRIGHT2 = 0x65, + SWFACTION_STRICTEQ = 0x66, + SWFACTION_CONSTANTPOOL = 0x88, + SWFACTION_WITH = 0x94, + SWFACTION_DEFINEFUNCTION = 0x9B, + + SWFACTION_SETREGISTER = 0x87 +}; + +#endif /* SWF_COMPILER_ACTION_H_INCLUDED */ diff --git a/lib/action/assembler.c b/lib/action/assembler.c new file mode 100644 index 0000000..8526e99 --- /dev/null +++ b/lib/action/assembler.c @@ -0,0 +1,131 @@ +/* + Ming, an SWF output library + Copyright (C) 2002 Opaque Industries - http://www.opaque.net/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "assembler.h" +#include "compile.h" +#include "action.h" + + +int len; +Buffer asmBuffer; +int nLabels; + +struct label +{ + char *name; + int offset; +}; + +struct label labels[256]; + + +static int +findLabel(char *label) +{ + int i; + + for ( i=0; ibuffer; + + while ( i < len ) + { + if ( output[i] & 0x80 ) /* then it's a multibyte instruction */ + { + if ( output[i] == SWFACTION_BRANCHALWAYS || + output[i] == SWFACTION_BRANCHIFTRUE ) + { + int target, offset; + + i += 3; /* plus instruction plus two-byte length */ + + target = output[i]; + offset = labels[target].offset - (i+2); + output[i] = offset & 0xff; + output[++i] = (offset>>8) & 0xff; + ++i; + } + else + { + ++i; + l = output[i]; + ++i; + l += output[i]<<8; + + i += l+1; + } + } + else + ++i; + } +} + + +/* + * Local variables: + * tab-width: 2 + * c-basic-offset: 2 + * End: + */ diff --git a/lib/action/assembler.h b/lib/action/assembler.h new file mode 100644 index 0000000..c8e0388 --- /dev/null +++ b/lib/action/assembler.h @@ -0,0 +1,21 @@ +/* assembler.h + * + * $Id: assembler.h,v 1.1 2004/02/02 10:12:34 kramm Exp $ + * + * Notice: This header file contains declarations of functions and types that + * are just used internally. All library functions and types that are supposed + * to be publicly accessable are defined in ./src/ming.h. + */ + +#ifndef SWF_ASSEMBLER_H_INCLUDED +#define SWF_ASSEMBLER_H_INCLUDED + +#include "ming.h" +#include "compile.h" + +extern Buffer asmBuffer; + +void bufferPatchLength(Buffer buffer, int len); +int bufferBranchTarget(Buffer buffer, char *label); + +#endif /* SWF_ASSEMBLER_H_INCLUDED */ diff --git a/lib/action/compile.c b/lib/action/compile.c new file mode 100755 index 0000000..b658dd2 --- /dev/null +++ b/lib/action/compile.c @@ -0,0 +1,786 @@ +/* + Ming, an SWF output library + Copyright (C) 2002 Opaque Industries - http://www.opaque.net/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef WIN32 + #include +#endif + +#include +#include +#include +#include + +#include "libming.h" +#include "compile.h" +#include "action.h" +#include "blocks/error.h" + + +static int nConstants = {0}, maxConstants = {0}, sizeConstants = {0}; +static char **constants; + +/* XXX - temp hack until we check at compile time */ + +enum +{ + SWF_BIG_ENDIAN, + SWF_LITTLE_ENDIAN +}; + +static int byteorder; + +void checkByteOrder() +{ + unsigned int x; + unsigned char *p; + + x = 0x01020304; + p = (unsigned char *)&x; + + if(*p == 1) + byteorder = SWF_BIG_ENDIAN; + else + byteorder = SWF_LITTLE_ENDIAN; +} + + +char *stringConcat(char *a, char *b) +{ + if ( a != NULL ) + { + if ( b != NULL ) + { + a = (char*)realloc(a, strlen(a)+strlen(b)+1); + strcat(a, b); + free(b); + } + + return a; + } + else + return b; +} + +void bufferPatchLength(Buffer buffer, int back) +{ + unsigned char *output = buffer->buffer; + int len = bufferLength(buffer); + + output[len-back-1] = (back>>8) & 0xff; + output[len-back-2] = back & 0xff; +} + + +/* add len more bytes to length of the pushdata opcode pointed to by + buffer->pushloc */ + +void bufferPatchPushLength(Buffer buffer, int len) +{ + int oldsize; + + if(buffer->pushloc != NULL) + { + oldsize = (buffer->pushloc[0] & 0xff) | ((buffer->pushloc[1] & 0xff) << 8); + oldsize += len; + buffer->pushloc[0] = oldsize & 0xff; + buffer->pushloc[1] = (oldsize >> 8) & 0xff; + } + else + SWF_error("problem with bufferPatchPushLength\n"); +} + + +static int useConstants = 1; +void Ming_useConstants(int flag) +{ useConstants = flag; +} + + +int addConstant(const char *s) +{ + int i; + + for(i=0; i MAXCONSTANTPOOLSIZE ) return -1; + + if(nConstants == maxConstants) + constants = (char **) realloc(constants, (maxConstants += 64) * sizeof(char *)); + constants[nConstants] = strdup(s); + sizeConstants += (strlen(s)+1); + return nConstants++; +} + +int bufferWriteConstants(Buffer out) +{ + int i, len=2; + + if(nConstants == 0) + return 0; + + bufferWriteU8(out, SWFACTION_CONSTANTPOOL); + bufferWriteS16(out, 0); /* length */ + bufferWriteS16(out, nConstants); + + for(i=0; ibuffer = (byte*)malloc(BUFFER_INCREMENT); + out->pos = out->buffer; + *(out->pos) = 0; + out->buffersize = out->free = BUFFER_INCREMENT; + out->pushloc = NULL; + + return out; +} + +void destroyBuffer(Buffer out) +{ + free(out->buffer); + free(out); +} + +int bufferLength(Buffer out) +{ + if(out) + return (out->pos)-(out->buffer); + else + return 0; +} + +/* make sure there's enough space for bytes bytes */ +void bufferCheckSize(Buffer out, int bytes) +{ + if(bytes > out->free) + { + int New = BUFFER_INCREMENT * ((bytes-out->free-1)/BUFFER_INCREMENT + 1); + + int num = bufferLength(out); /* in case buffer gets displaced.. */ + unsigned char *newbuf = (unsigned char*)realloc(out->buffer, out->buffersize+New); + + if(newbuf != out->buffer) + { + int pushd; + + if(out->pushloc) + pushd = out->pos - out->pushloc; + + out->pos = newbuf+num; + + if(out->pushloc) + out->pushloc = out->pos - pushd; + } + + out->buffer = newbuf; + out->buffersize += New; + out->free += New; + } +} + +int bufferWriteData(Buffer b, const byte *data, int length) +{ + int i; + + bufferCheckSize(b, length); + + for(i=0; ibuffer, bufferLength(b)); + + return 0; +} + +/* if a's last op and b's first op are both PUSHDATA, concat into one op */ + +int bufferWriteDataAndPush(Buffer a, Buffer b) +{ + int i, pushd; + + byte *data = b->buffer; + int length = b->pos - b->buffer; + + if(a->pushloc && (b->buffer[0] == SWFACTION_PUSHDATA) && SWF_versionNum > 4) + { + pushd = (b->buffer[1] & 0xff) | ((b->buffer[2] & 0xff) << 8); + bufferPatchPushLength(a, pushd); + data += 3; + length -= 3; + } + + if(b->pushloc) + pushd = b->pos - b->pushloc; + + bufferCheckSize(a, length); + + for(i=0; ipushloc && + (b->buffer[0] == SWFACTION_PUSHDATA) && (b->pushloc == b->buffer+1)) + ; /* b is just one pushdata, so do nothing.. */ + else if(b->pushloc) + a->pushloc = a->pos - pushd; + else + a->pushloc = 0; + + return length; +} + +int bufferConcat(Buffer a, Buffer b) +{ + int len; + + if(!a) + return 0; + + if(b) + { len = bufferWriteDataAndPush(a, b); + destroyBuffer(b); + } + + return len; +} + +int bufferWriteOp(Buffer out, int data) +{ + bufferWriteU8(out, data); + out->pushloc = NULL; + + return 1; +} + +int bufferWritePushOp(Buffer out) +{ + bufferWriteU8(out, SWFACTION_PUSHDATA); + out->pushloc = out->pos; + + return 1; +} + +int bufferWriteU8(Buffer out, int data) +{ + bufferCheckSize(out, 1); + *(out->pos) = data; + out->pos++; + out->free--; + + return 1; +} + +int bufferWriteS16(Buffer out, int data) +{ + if(data < 0) + data = (1<<16)+data; + + bufferWriteU8(out, data%256); + data >>= 8; + bufferWriteU8(out, data%256); + + return 2; +} + +int bufferWriteHardString(Buffer out, byte *string, int length) +{ + int i; + + for(i=0; ipushloc == NULL) + { + bufferWritePushOp(out); + bufferWriteS16(out, 0); + } + + l = bufferWriteConstantString(out, string, length); + + bufferPatchPushLength(out, l); + return l; + } +} + +int bufferWriteInt(Buffer out, int i) +{ + int len = 0; + unsigned char *p = (unsigned char *)&i; + + if(out->pushloc == NULL || SWF_versionNum < 5) + { + len = 3; + bufferWritePushOp(out); + bufferWriteS16(out, 5); + } + else + bufferPatchPushLength(out, 5); + + bufferWriteU8(out, PUSH_INT); + + if(byteorder == SWF_LITTLE_ENDIAN) + { + bufferWriteU8(out, p[0]); + bufferWriteU8(out, p[1]); + bufferWriteU8(out, p[2]); + bufferWriteU8(out, p[3]); + } + else + { + bufferWriteU8(out, p[3]); + bufferWriteU8(out, p[2]); + bufferWriteU8(out, p[1]); + bufferWriteU8(out, p[0]); + } + + return len + 5; +} + +int bufferWriteDouble(Buffer out, double d) +{ + int len = 0; + unsigned char *p = (unsigned char *)&d; + + if(out->pushloc == NULL || SWF_versionNum < 5) + { + len = 3; + bufferWritePushOp(out); + bufferWriteS16(out, 9); + } + else + bufferPatchPushLength(out, 5); + + bufferWriteU8(out, PUSH_DOUBLE); + + if(byteorder == SWF_LITTLE_ENDIAN) + { + bufferWriteU8(out, p[4]); + bufferWriteU8(out, p[5]); + bufferWriteU8(out, p[6]); + bufferWriteU8(out, p[7]); + bufferWriteU8(out, p[0]); + bufferWriteU8(out, p[1]); + bufferWriteU8(out, p[2]); + bufferWriteU8(out, p[3]); + } + else + { + bufferWriteU8(out, p[3]); + bufferWriteU8(out, p[2]); + bufferWriteU8(out, p[1]); + bufferWriteU8(out, p[0]); + bufferWriteU8(out, p[7]); + bufferWriteU8(out, p[6]); + bufferWriteU8(out, p[5]); + bufferWriteU8(out, p[4]); + } + + return len + 9; +} + +int bufferWriteNull(Buffer out) +{ + int len = 0; + + if(out->pushloc == NULL || SWF_versionNum < 5) + { + len = 3; + bufferWritePushOp(out); + bufferWriteS16(out, 1); + } + else + bufferPatchPushLength(out, 1); + + bufferWriteU8(out, PUSH_NULL); + + return len + 1; +} + +int bufferWriteBoolean(Buffer out, int val) +{ + int len = 0; + + if(out->pushloc == NULL || SWF_versionNum < 5) + { + len = 3; + bufferWritePushOp(out); + bufferWriteS16(out, 2); + } + else + bufferPatchPushLength(out, 2); + + bufferWriteU8(out, PUSH_BOOLEAN); + bufferWriteU8(out, val ? 1 : 0); + + return len + 2; +} + +int bufferWriteRegister(Buffer out, int num) +{ + int len = 0; + + if(out->pushloc == NULL || SWF_versionNum < 5) + { + len = 3; + bufferWritePushOp(out); + bufferWriteS16(out, 2); + } + else + bufferPatchPushLength(out, 2); + + bufferWriteU8(out, PUSH_REGISTER); + bufferWriteU8(out, num); + + return len + 2; +} + +int bufferWriteSetRegister(Buffer out, int num) +{ + bufferWriteU8(out, SWFACTION_SETREGISTER); + bufferWriteS16(out, 1); + bufferWriteU8(out, num); + return 4; +} + +void lower(char *s) +{ + while(*s) + { + *s = tolower(*s); + ++s; + } +} + +/* this code will eventually help to pop extra values off the + stack and make sure that continue and break address the proper + context + */ +static enum ctx *ctx_stack = {0}; +static int ctx_count = {0}, ctx_len = {0}; +void addctx(enum ctx val) +{ if(ctx_count >= ctx_len) + ctx_stack = (enum ctx*) realloc(ctx_stack, (ctx_len += 10) * sizeof(enum ctx)); + ctx_stack[ctx_count++] = val; +} +void delctx(enum ctx val) +{ if(ctx_count <= 0 || ctx_stack[--ctx_count] != val) + SWF_error("consistency check in delctx"); +} + +int chkctx(enum ctx val) +{ int n, ret = 0; + switch(val) + { case CTX_FUNCTION: + for(n = ctx_count ; --n >= 0 ; ) + switch(ctx_stack[n]) + { case CTX_SWITCH: + case CTX_FOR_IN: + ret++; + break; + case CTX_FUNCTION: + return ret; + default: ; /* computers are stupid */ + } + return -1; + case CTX_BREAK: + for(n = ctx_count ; --n >= 0 ; ) + switch(ctx_stack[n]) + { case CTX_SWITCH: + case CTX_LOOP: + return 0; + case CTX_FOR_IN: + return 1; + case CTX_FUNCTION: + return -1; + default: ; /* computers are stupid */ + } + case CTX_CONTINUE: + for(n = ctx_count ; --n >= 0 ; ) + switch(ctx_stack[n]) + { case CTX_LOOP: + case CTX_FOR_IN: + return 0; + case CTX_FUNCTION: + return -1; + default: ; /* computers are stupid */ + } + default: ; /* computers are stupid */ + } + return 0; +} + +/* replace MAGIC_CONTINUE_NUMBER and MAGIC_BREAK_NUMBER with jumps to + head or tail, respectively */ +/* jump offset is relative to end of jump instruction */ +/* I can't believe this actually worked */ + +void bufferResolveJumps(Buffer out) +{ + byte *p = out->buffer; + int l, target; + + while(p < out->pos) + { + if(*p & 0x80) /* then it's a multibyte instruction */ + { + if(*p == SWFACTION_BRANCHALWAYS) + { + p += 3; /* plus instruction plus two-byte length */ + + if(*p == MAGIC_CONTINUE_NUMBER_LO && + *(p+1) == MAGIC_CONTINUE_NUMBER_HI) + { + target = out->buffer - (p+2); + *p = target & 0xff; + *(p+1) = (target>>8) & 0xff; + } + else if(*p == MAGIC_BREAK_NUMBER_LO && + *(p+1) == MAGIC_BREAK_NUMBER_HI) + { + target = out->pos - (p+2); + *p = target & 0xff; + *(p+1) = (target>>8) & 0xff; + } + + p += 2; + } + else + { + ++p; + l = *p; + ++p; + l += *p<<8; + ++p; + + p += l; + } + } + else + ++p; + } +} + +// handle SWITCH statement + +void bufferResolveSwitch(Buffer buffer, struct switchcases *slp) +{ struct switchcase *scp; + int n, len; + unsigned char *output; + + len = bufferLength(buffer); + for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++) + { scp->actlen = bufferLength(scp->action); + if((n < slp->count-1)) + scp->actlen += 5; + if(scp->cond) + { scp->condlen = bufferLength(scp->cond) + 8; + bufferWriteOp(buffer, SWFACTION_DUP); + bufferConcat(buffer, scp->cond); + bufferWriteOp(buffer, SWFACTION_NEWEQUALS); + bufferWriteOp(buffer, SWFACTION_LOGICALNOT); + bufferWriteOp(buffer, SWFACTION_BRANCHIFTRUE); + bufferWriteS16(buffer, 2); + bufferWriteS16(buffer, scp->actlen); + } + else + scp->condlen = 0; + bufferConcat(buffer, scp->action); + bufferWriteOp(buffer, SWFACTION_BRANCHALWAYS); + bufferWriteS16(buffer, 2); + bufferWriteS16(buffer, scp->isbreak ? MAGIC_BREAK_NUMBER : 0); + if(!scp->cond) + { slp->count = n+1; + break; + } + } + for(n = 0, scp = slp->list ; n < slp->count ; n++, scp++) + { len += scp->condlen; + output = buffer->buffer + len; + if((n < slp->count-1) && !scp->isbreak) + { output[scp->actlen-2] = (scp+1)->condlen & 0xff; + output[scp->actlen-1] = (scp+1)->condlen >> 8; + } + len += scp->actlen; + } +} + +int lookupSetProperty(char *string) +{ + lower(string); + + if(strcmp(string,"x")==0) return 0x0000; + if(strcmp(string,"y")==0) return 0x3f80; + if(strcmp(string,"xscale")==0) return 0x4000; + if(strcmp(string,"yscale")==0) return 0x4040; + if(strcmp(string,"alpha")==0) return 0x40c0; + if(strcmp(string,"visible")==0) return 0x40e0; + if(strcmp(string,"rotation")==0) return 0x4120; + if(strcmp(string,"name")==0) return 0x4140; + if(strcmp(string,"quality")==0) return 0x4180; + if(strcmp(string,"focusrect")==0) return 0x4188; + if(strcmp(string,"soundbuftime")==0) return 0x4190; + + SWF_error("No such property: %s\n", string); + return -1; +} + +int bufferWriteSetProperty(Buffer out, char *string) +{ + int property = lookupSetProperty(string); + + bufferWriteU8(out, SWFACTION_PUSHDATA); + bufferWriteS16(out, 5); + bufferWriteU8(out, PUSH_PROPERTY); + bufferWriteS16(out, 0); + bufferWriteS16(out, property); + + return 8; +} + +int bufferWriteWTHITProperty(Buffer out) +{ + bufferWriteU8(out, SWFACTION_PUSHDATA); + bufferWriteS16(out, 5); + bufferWriteU8(out, PUSH_PROPERTY); + bufferWriteS16(out, 0); + bufferWriteS16(out, 0x4680); + + return 8; +} + +const char *lookupGetProperty(char *string) +{ + lower(string); + + if(strcmp(string,"x")==0) return "0"; + if(strcmp(string,"y")==0) return "1"; + if(strcmp(string,"xscale")==0) return "2"; + if(strcmp(string,"yscale")==0) return "3"; + if(strcmp(string,"currentframe")==0) return "4"; + if(strcmp(string,"totalframes")==0) return "5"; + if(strcmp(string,"alpha")==0) return "6"; + if(strcmp(string,"visible")==0) return "7"; + if(strcmp(string,"width")==0) return "8"; + if(strcmp(string,"height")==0) return "9"; + if(strcmp(string,"rotation")==0) return "10"; + if(strcmp(string,"target")==0) return "11"; + if(strcmp(string,"framesloaded")==0) return "12"; + if(strcmp(string,"name")==0) return "13"; + if(strcmp(string,"droptarget")==0) return "14"; + if(strcmp(string,"url")==0) return "15"; + if(strcmp(string,"quality")==0) return "16"; + if(strcmp(string,"focusrect")==0) return "17"; + if(strcmp(string,"soundbuftime")==0) return "18"; + + SWF_error("No such property: %s\n", string); + return ""; +} + +int bufferWriteGetProperty(Buffer out, char *string) +{ + const char *property = lookupGetProperty(string); + + bufferWriteU8(out, SWFACTION_PUSHDATA); + bufferWriteS16(out, strlen(property)+2); + bufferWriteU8(out, PUSH_STRING); + + return 4 + bufferWriteData(out, (byte*) property, strlen(property)+1); +} + + +/* + * Local variables: + * tab-width: 2 + * c-basic-offset: 2 + * End: + */ diff --git a/lib/action/compile.h b/lib/action/compile.h new file mode 100755 index 0000000..cdedc2a --- /dev/null +++ b/lib/action/compile.h @@ -0,0 +1,163 @@ +/* compile.h + * + * $Id: compile.h,v 1.1 2004/02/02 10:12:34 kramm Exp $ + * + * Notice: This header file contains declarations of functions and types that + * are just used internally. All library functions and types that are supposed + * to be publicly accessable are defined in ./src/ming.h. + */ + +#ifndef SWF_COMPILE_H_INCLUDED +#define SWF_COMPILE_H_INCLUDED + +#include "ming.h" + +typedef struct _buffer *Buffer; + +/* shut up bison.simple */ +void yyerror(char *msg); +int yylex(); + +#ifndef max + #define max(x,y) (((x)>(y))?(x):(y)) +#endif + +enum +{ + PUSH_STRING = 0, + PUSH_PROPERTY = 1, + PUSH_NULL = 2, + PUSH_UNDEF = 3, + PUSH_REGISTER = 4, + PUSH_BOOLEAN = 5, + PUSH_DOUBLE = 6, + PUSH_INT = 7, + PUSH_CONSTANT = 8, + PUSH_CONSTANT16 = 9 +}; + +typedef enum +{ + FUNCTION_RANDOM, + FUNCTION_LENGTH, + FUNCTION_TIME, + FUNCTION_INT, + FUNCTION_CONCAT, + FUNCTION_DUPLICATECLIP +} SWFActionFunction; + +typedef enum +{ + GETURL_METHOD_NOSEND = 0, + GETURL_METHOD_GET = 1, + GETURL_METHOD_POST = 2 +} SWFGetUrl2Method; + +#define GETURL_LOADMOVIE 0x40 +#define GETURL_LOADVARIABLES 0x80 + +#define MAGIC_CONTINUE_NUMBER 0x7FFE +#define MAGIC_BREAK_NUMBER 0x7FFF + +#define MAGIC_CONTINUE_NUMBER_LO 0xFE +#define MAGIC_CONTINUE_NUMBER_HI 0x7F +#define MAGIC_BREAK_NUMBER_LO 0xFF +#define MAGIC_BREAK_NUMBER_HI 0x7F + +#define BUFFER_INCREMENT 128 + +struct _buffer +{ + byte *buffer; + byte *pos; + int buffersize; + int free; + byte *pushloc; +}; + +#define BUFFER_SIZE sizeof(struct _buffer) + +struct switchcase +{ Buffer cond, action; + int condlen, actlen, isbreak; +}; + +struct switchcases +{ + struct switchcase *list; + int count; +}; + +enum ctx +{ + CTX_FUNCTION = 1, + CTX_LOOP, + CTX_FOR_IN, + CTX_SWITCH, + + CTX_BREAK, + CTX_CONTINUE +}; + +void addctx(enum ctx val); +void delctx(enum ctx val); +int chkctx(enum ctx val); + +void checkByteOrder(); + +/* create/destroy buffer object */ +Buffer newBuffer(); +void destroyBuffer(Buffer out); +int bufferConcat(Buffer a, Buffer b); /* destroys b. */ +int bufferWriteBuffer(Buffer a, Buffer b); /* doesn't. */ + +/* utilities for writing */ +void bufferGrow(Buffer out); +void bufferCheckSize(Buffer out, int bytes); + +int bufferLength(Buffer out); + +/* constant pool stuff */ +int addConstant(const char *s); +int bufferWriteConstants(Buffer out); +#define MAXCONSTANTPOOLSIZE 65533 + +/* write data to buffer */ +int bufferWriteOp(Buffer out, int data); +int bufferWritePushOp(Buffer out); +int bufferWriteU8(Buffer out, int data); +int bufferWriteS16(Buffer out, int data); +int bufferWriteData(Buffer out, const byte *buffer, int bytes); +int bufferWriteHardString(Buffer out, byte *string, int length); +int bufferWriteConstantString(Buffer out, byte *string, int length); +int bufferWriteString(Buffer out, byte *string, int length); +#ifdef __cplusplus +/* helper function to avoid many casts */ +inline int bufferWriteString(Buffer out, char *string, int length) { + return bufferWriteString(out,(byte*) string, length); } +#endif +int bufferWriteInt(Buffer out, int i); +int bufferWriteDouble(Buffer out, double d); +int bufferWriteNull(Buffer out); +int bufferWriteBoolean(Buffer out, int val); +int bufferWriteRegister(Buffer out, int num); +int bufferWriteSetRegister(Buffer out, int num); +int bufferWriteGetProperty(Buffer out, char *string); +int bufferWriteSetProperty(Buffer out, char *string); +int bufferWriteWTHITProperty(Buffer out); + +/* concat b to a, destroy b */ +char *stringConcat(char *a, char *b); + +/* resolve magic number standins to relative offsets */ +void bufferResolveJumps(Buffer out); +void bufferResolveSwitch(Buffer buffer, struct switchcases *slp); + +/* rather than setting globals... */ +void swf4ParseInit(const char *string, int debug); +void swf5ParseInit(const char *string, int debug); + +int swf4parse(void *b); +int swf5parse(void *b); + +#endif /* SWF_COMPILE_H_INCLUDED */ diff --git a/lib/action/listaction.c b/lib/action/listaction.c new file mode 100755 index 0000000..b3309ce --- /dev/null +++ b/lib/action/listaction.c @@ -0,0 +1,557 @@ +#include +#include +#include +#include "action.h" +#include "compile.h" + + +#define print(x) {fputs(x,stdout);} + +int gIndent; +#define INDENT_LEVEL 2 + +void println(const char *s, ...) +{ + va_list ap; + int n = gIndent*INDENT_LEVEL; + + while(n-- > 0) + putchar(' '); + + va_start(ap, s); + vprintf(s, ap); + va_end(ap); + + putchar('\n'); +} + +int fileOffset = 0; + +int readUInt8(Buffer f) +{ + return f->buffer[fileOffset++]; +} + +int readSInt8(Buffer f) +{ + return (signed char)readUInt8(f); +} + +int readSInt16(Buffer f) +{ + return readUInt8(f) + readSInt8(f)*256; +} + +int readUInt16(Buffer f) +{ + return readUInt8(f) + (readUInt8(f)<<8); +} + +long readSInt32(Buffer f) +{ + return (long)readUInt8(f) + (readUInt8(f)<<8) + (readUInt8(f)<<16) + (readUInt8(f)<<24); +} + +unsigned long readUInt32(Buffer f) +{ + return (unsigned long)(readUInt8(f) + (readUInt8(f)<<8) + (readUInt8(f)<<16) + (readUInt8(f)<<24)); +} + +double readDouble(Buffer f) +{ + double d; + unsigned char *p = (unsigned char *)&d; + + p[4] = readUInt8(f); + p[5] = readUInt8(f); + p[6] = readUInt8(f); + p[7] = readUInt8(f); + p[0] = readUInt8(f); + p[1] = readUInt8(f); + p[2] = readUInt8(f); + p[3] = readUInt8(f); + + return d; +} + +char *readString(Buffer f) +{ + int len = 0, buflen = 256; + char c, *buf, *p; + + buf = (char *)malloc(sizeof(char)*256); + p = buf; + + while((c=(char)readUInt8(f)) != '\0') + { + if(len==buflen) + { + buf = (char *)realloc(buf, sizeof(char)*(buflen+256)); + buflen += 256; + p = buf+len; + } + + *(p++) = c; + ++len; + } + + *p = 0; + + return buf; +} + +void dumpBytes(Buffer f, int length) +{ + int j=0, i, k; + unsigned char buf[16]; + + if(length==0) + return; + + for(;;) + { + for(i=0; i<16; ++i) + { + printf("%02x ", buf[i] = readUInt8(f)); + ++j; + + if(j==length) + break; + } + + if(j==length) + { + for(k=i+1; k<16; ++k) + print(" "); + + ++i; + } + + print(" "); + + for(k=0; k 31) && (buf[k] < 128)) + putchar(buf[k]); + else + putchar('.'); + + putchar('\n'); + + if(j==length) + break; + } + putchar('\n'); + putchar('\n'); +} + +void printDoAction(Buffer f, int length); + +char *dictionary[256]; + +int printActionRecord(Buffer f) +{ + int length = 0, type; + + printf("(%i)\t", fileOffset); + + type = readUInt8(f); + + if((type&0x80) == 0x80) + length = readUInt16(f); + + switch(type) + { + case SWFACTION_ADD: + println("Add"); + break; + case SWFACTION_SUBTRACT: + println("Subtract"); + break; + case SWFACTION_MULTIPLY: + println("Multiply"); + break; + case SWFACTION_DIVIDE: + println("Divide"); + break; + case SWFACTION_EQUAL: + println("Equals"); + break; + case SWFACTION_LESSTHAN: + println("Less Than"); + break; + case SWFACTION_LOGICALAND: + println("And"); + break; + case SWFACTION_LOGICALOR: + println("Or"); + break; + case SWFACTION_LOGICALNOT: + println("Not"); + break; + case SWFACTION_STRINGEQ: + println("String eq"); + break; + case SWFACTION_STRINGLENGTH: + println("String Length"); + break; + case SWFACTION_SUBSTRING: + println("Substring"); + break; + case SWFACTION_POP: + println("Pop"); + break; + case SWFACTION_INT: + println("Int"); + break; + case SWFACTION_GETVARIABLE: + println("Get Variable"); + break; + case SWFACTION_SETVARIABLE: + println("Set Variable"); + break; + case SWFACTION_SETTARGETEXPRESSION: + println("Set Target Expression"); + break; + case SWFACTION_STRINGCONCAT: + println("String Concat"); + break; + case SWFACTION_GETPROPERTY: + println("Get Property"); + break; + case SWFACTION_SETPROPERTY: + println("Set Property"); + break; + case SWFACTION_DUPLICATECLIP: + println("Duplicate Clip"); + break; + case SWFACTION_REMOVECLIP: + println("Remove Clip"); + break; + case SWFACTION_TRACE: + println("Trace"); + break; + case SWFACTION_STARTDRAGMOVIE: + println("Start Drag Movie"); + break; + case SWFACTION_STOPDRAGMOVIE: + println("Stop Drag Movie"); + break; + case SWFACTION_STRINGCOMPARE: + println("String Compare"); + break; + case SWFACTION_RANDOM: + println("Random"); + break; + case SWFACTION_MBLENGTH: + println("String MB Length"); + break; + case SWFACTION_ORD: + println("Ord"); + break; + case SWFACTION_CHR: + println("Chr"); + break; + case SWFACTION_GETTIMER: + println("Get Timer"); + break; + case SWFACTION_MBSUBSTRING: + println("MB Substring"); + break; + case SWFACTION_MBORD: + println("MB Ord"); + break; + case SWFACTION_MBCHR: + println("MB Chr"); + break; + case SWFACTION_NEXTFRAME: + println("Next Frame"); + break; + case SWFACTION_PREVFRAME: + println("Previous Frame"); + break; + case SWFACTION_PLAY: + println("Play"); + break; + case SWFACTION_STOP: + println("Stop"); + break; + case SWFACTION_TOGGLEQUALITY: + println("Toggle Quality"); + break; + case SWFACTION_STOPSOUNDS: + println("Stop Sounds"); + break; + + /* ops with args */ + case SWFACTION_PUSHDATA: + { + int type; + int start = fileOffset; + + while(fileOffset < start+length) + { + switch(type = readUInt8(f)) + { + case 0: /* string */ + println("Push String: %s", readString(f)); + break; + case 1: /* property */ + readUInt16(f); /* always 0? */ + println("Push Property: %04x", readUInt16(f)); + break; + case 2: /* null */ + println("Push NULL"); + break; + case 3: /* ??? */ + println("Push type 3- ??"); + break; + case 4: + println("Push register %i", readUInt8(f)); + break; + case 5: + if(readUInt8(f)) + println("Push true"); + else + println("Push false"); + break; + case 6: /* double */ + println("Push %f", readDouble(f)); + break; + case 7: /* int */ + println("Push %i", readSInt32(f)); + break; + case 8: /* dictionary */ + println("Push \"%s\"", dictionary[readUInt8(f)]); + break; + case 9: /* dictionary */ + println("Push \"%s\"", dictionary[readSInt16(f)]); + default: + println("unknown push type: %i", type); + } + } + break; + } + case SWFACTION_GOTOFRAME: + println("Goto Frame %i", readUInt16(f)); + break; + case SWFACTION_GETURL: + { + char *url = readString(f); + println("Get URL \"%s\" target \"%s\"", url, readString(f)); + break; + } + case SWFACTION_WAITFORFRAMEEXPRESSION: + println("Wait For Frame Expression, skip %i\n", readUInt8(f)); + break; + case SWFACTION_BRANCHALWAYS: + println("Branch Always %i", readSInt16(f)); + break; + case SWFACTION_GETURL2: + { + int flags = readUInt8(f); + + const char *op = (flags & 0x80) ? "Get URL2 (loadvariables)" : "Get URL2"; + const char *tgt = (flags & 0x40) ? " into target" : ""; + + switch(flags & 0x03) + { + case 0: println("%s%s (Don't send)", op, tgt); break; + case 1: println("%s%s (GET)", op, tgt); break; + case 2: println("%s%s (POST)", op, tgt); break; + } + } + break; + case SWFACTION_BRANCHIFTRUE: + println("Branch If True %i", readSInt16(f)); + break; + case SWFACTION_CALLFRAME: + println("Call Frame"); + dumpBytes(f, length); + break; + case SWFACTION_GOTOEXPRESSION: + print("Goto Expression"); + if(readUInt8(f) == 1) + printf(" and Play\n"); + else + printf(" and Stop\n"); + break; + case SWFACTION_WAITFORFRAME: + { + int frame = readUInt16(f); + println("Wait for frame %i else skip %i", frame, readUInt8(f)); + break; + } + case SWFACTION_SETTARGET: + println("Set Target %s", readString(f)); + break; + case SWFACTION_GOTOLABEL: + println("Goto Label %s", readString(f)); + break; + case SWFACTION_END: + return 0; + break; + + /* f5 ops */ + case SWFACTION_DELETE: + println("Delete"); + break; + case SWFACTION_VAR: + println("Var"); + break; + case SWFACTION_VAREQUALS: + println("Var assign"); + break; + case SWFACTION_INITARRAY: + println("Init array"); + break; + case SWFACTION_INITOBJECT: + println("Init object"); + break; + case SWFACTION_CALLFUNCTION: + println("call function"); + break; + case SWFACTION_RETURN: + println("return"); + break; + case SWFACTION_MODULO: + println("modulo"); + break; + case SWFACTION_NEW: + println("new"); + break; + case SWFACTION_TYPEOF: + println("typeof"); + break; + case SWFACTION_NEWADD: + println("new add"); + break; + case SWFACTION_NEWLESSTHAN: + println("new less than"); + break; + case SWFACTION_NEWEQUALS: + println("new equals"); + break; + case SWFACTION_DUP: + println("dup"); + break; + case SWFACTION_SWAP: + println("swap"); + break; + case SWFACTION_GETMEMBER: + println("get member"); + break; + case SWFACTION_SETMEMBER: + println("set member"); + break; + case SWFACTION_INCREMENT: + println("increment"); + break; + case SWFACTION_CALLMETHOD: + println("call method"); + break; + case SWFACTION_BITWISEAND: + println("bitwise and"); + break; + case SWFACTION_BITWISEOR: + println("bitwise or"); + break; + case SWFACTION_BITWISEXOR: + println("bitwise xor"); + break; + case SWFACTION_SHIFTLEFT: + println("shift left"); + break; + case SWFACTION_SHIFTRIGHT: + println("shift right"); + break; + case SWFACTION_SHIFTRIGHT2: + println("shift right 2"); + break; + + case SWFACTION_CONSTANTPOOL: + { + int i, n = readUInt16(f); + print("declare dictionary:"); + + for(i=0; i 0) + { + printf("%s", readString(f)); + --n; + } + + for(; n>0; --n) + printf(", %s", readString(f)); + + putchar(')'); + putchar('\n'); + + ++gIndent; + printDoAction(f, readUInt16(f)); + --gIndent; + + break; + } + + case SWFACTION_ENUMERATE: + println("enumerate"); + break; + + case SWFACTION_SETREGISTER: + println("set register %i", readUInt8(f)); + break; + +/* f6 actions */ + case SWFACTION_INSTANCEOF: + println("instanceof"); + break; + case SWFACTION_STRICTEQ: + println("strict_equals"); + break; + case SWFACTION_ENUM2: + println("enum2"); + break; + + default: + println("Unknown Action: %02X", type); + dumpBytes(f, length); + } + + return 1; +} + +void printDoAction(Buffer f, int length) +{ + int end; + + if(!f) + return; + + end = fileOffset + length; + + while(fileOffset < end && printActionRecord(f)) + ; +} diff --git a/lib/action/swf4compiler.flex b/lib/action/swf4compiler.flex new file mode 100755 index 0000000..6a6dddd --- /dev/null +++ b/lib/action/swf4compiler.flex @@ -0,0 +1,403 @@ +%{ + +#include +#include + +#include "compile.h" +#include "action.h" +#include "blocks/error.h" +#include "swf4compiler.tab.h" /* defines token types */ + +static int swf4debug; + +static const char *lexBuffer = NULL; +static int lexBufferLen = 0; + +static int sLineNumber = 0; +static char szLine[1024]; +static char msgbufs[2][1024] = { {0}, {0} }, *msgline = {0}; +static int column = 0; + +static void comment(); +static void comment1(); +static void count(); +static void warning(char *msg); + +#define YY_INPUT(buf,result,max_size) result=lexBufferInput(buf, max_size) + +/* thanks to the prolific and brilliant Raff: */ +static int lexBufferInput(char *buf, int max_size) +{ + int l = lexBufferLen > max_size ? max_size : lexBufferLen; + + if (lexBufferLen <= 0) + return YY_NULL; + + memcpy(buf, lexBuffer, l); + lexBuffer += l; + lexBufferLen -= l; + return l; +} + + /* very inefficient method of unescaping strings */ +static void unescape(char *buf) +{ + char *p, *p1; + + for (p1=buf; (p=strchr(p1, '\\')) != 0; p1 = p+1) { + switch(p[1]) + { + case 'b' : p[1] = '\b'; break; + case 'f' : p[1] = '\f'; break; + case 'n' : p[1] = '\n'; break; + case 'r' : p[1] = '\r'; break; + case 't' : p[1] = '\t'; break; + case 'x' : + case 'u' : warning("unsupported escape sequence"); + } + strcpy(p, p+1); + } +} + +void swf4ParseInit(const char *script, int debug) +{ + checkByteOrder(); + yyrestart(NULL); + + swf4debug = debug; + + lexBuffer = script; + lexBufferLen = strlen(script); + sLineNumber = 0; + column = 0; + msgline = msgbufs[0]; +} + +%} + +%{ + // forward declaration needed by the following function +#ifndef YY_PROTO +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif +#endif + static void yyunput YY_PROTO(( int c, char *buf_ptr )); + + void do_unput4(const char c) { unput(c); } +%} + +DIGIT [0-9] +ID [a-zA-Z_][a-zA-Z0-9_]* +LEVEL \.\.? + +%% + +{DIGIT}+ { count(); swf4lval.str = strdup(yytext); + return NUMBER; } +{DIGIT}+"."{DIGIT}* { count(); swf4lval.str = strdup(yytext); + return NUMBER; } +true { count(); swf4lval.str = strdup("1"); + return NUMBER; } +false { count(); swf4lval.str = strdup("0"); + return NUMBER; } +break { count(); return BREAK; } +continue { count(); return CONTINUE; } +else { count(); return ELSE; } +for { count(); return FOR; } +if { count(); return IF; } +while { count(); return WHILE; } +do { count(); return DO; } +valueOf { count(); return EVAL; } + + /* functions */ +random { count(); return RANDOM; } +time { count(); return TIME; } +length { count(); return LENGTH; } +int { count(); return INT; } +concat { count(); return CONCAT; } +duplicateClip { count(); return DUPLICATECLIP; } +removeClip { count(); return REMOVECLIP; } +trace { count(); return TRACE; } +startDrag { count(); return STARTDRAG; } +stopDrag { count(); return STOPDRAG; } +ord { count(); return ORD; } +chr { count(); return CHR; } +callFrame { count(); return CALLFRAME; } +getURL { count(); return GETURL; } +getURL1 { count(); return GETURL1; } +loadMovie { count(); return LOADMOVIE; } +loadVariables { count(); return LOADVARIABLES; } +substr { count(); return SUBSTR; } + +getProperty { count(); return GETPROPERTY; } + + /* getURL2 methods */ +post { count(); swf4lval.getURLMethod = GETURL_METHOD_POST; + return GETURL_METHOD; } +get { count(); swf4lval.getURLMethod = GETURL_METHOD_GET; + return GETURL_METHOD; } +nosend { count(); swf4lval.getURLMethod = GETURL_METHOD_NOSEND; + return GETURL_METHOD; } + + + /* v3 functions */ +nextFrame { count(); return NEXTFRAME; } +prevFrame { count(); return PREVFRAME; } +play { count(); return PLAY; } +stop { count(); return STOP; } +toggleQuality { count(); return TOGGLEQUALITY; } +stopSounds { count(); return STOPSOUNDS; } +gotoFrame { count(); return GOTOFRAME; } +gotoAndPlay { count(); return GOTOANDPLAY; } +frameLoaded { count(); return FRAMELOADED; } +setTarget { count(); return SETTARGET; } + + /* high level functions */ +tellTarget { count(); return TELLTARGET; } + + +this { count(); return THIS; } + +{ID} { count(); swf4lval.str = strdup(yytext); + return IDENTIFIER; } + +{LEVEL}?("/"({ID}|{LEVEL}))+ { count(); swf4lval.str = strdup(yytext); + return PATH; } + +{ID}("/"({ID}|{LEVEL}))+ { count(); swf4lval.str = strdup(yytext); + return PATH; } + +\"(\\.|[^\\"])*\" { count(); swf4lval.str = strdup(yytext+1); + swf4lval.str[strlen(swf4lval.str)-1]=0; + unescape(swf4lval.str); + return STRING; } + +\'(\\.|[^\\'])*\' { count(); swf4lval.str = strdup(yytext+1); + swf4lval.str[strlen(swf4lval.str)-1]=0; + unescape(swf4lval.str); + return STRING; } + +\"(\\.|[^\\"])*$ { count(); swf4lval.str = strdup(""); + warning("Unterminated string!"); + return STRING; } + +\'(\\.|[^\\'])*$ { count(); swf4lval.str = strdup(""); + warning("Unterminated string!"); + return STRING; } + +"/*" { count(); comment(); } +"//" { count(); comment1(); } +[ \t\v\f] { count(); } + +"++" { count(); return INC; } +"--" { count(); return DEC; } +"<" { count(); return '<'; } +">" { count(); return '>'; } +"<=" { count(); return LE; } +">=" { count(); return GE; } +"==" { count(); return EQ; } +"!=" { count(); return NE; } +"&&" { count(); return LAN; } +"||" { count(); return LOR; } +"*=" { count(); return MEQ; } +"/=" { count(); return DEQ; } +"+=" { count(); return IEQ; } +"-=" { count(); return SEQ; } +"===" { count(); return STREQ; } +"!==" { count(); return STRNE; } +"<=>" { count(); return STRCMP; } +".." { count(); return PARENT; } + +";" { count(); return ';'; } +"=" { count(); return '='; } +"+" { count(); return '+'; } +"-" { count(); return '-'; } +"&" { count(); return '&'; } +"*" { count(); return '*'; } +"/" { count(); return '/'; } +"!" { count(); return '!'; } +"(" { count(); return '('; } +")" { count(); return ')'; } +"[" { count(); return '['; } +"]" { count(); return ']'; } +"{" { count(); return '{'; } +"}" { count(); return '}'; } +"," { count(); return ','; } +"." { count(); return '.'; } +"?" { count(); return '?'; } +":" { count(); return ':'; } + +\r?\n { count(); column = 0; + strcpy(szLine, yytext + 1); + ++sLineNumber; yyless(1); } + +. printf( "Unrecognized character: %s\n", yytext ); + +%% +static int getinput() { +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif +} + +int swf4wrap() +{ + return 1; +} + +static void countline() +{ + if(sLineNumber != 0) + msgline[column] = 0; + + ++sLineNumber; + column = 0; + msgline = msgbufs[sLineNumber & 1]; +} + +static int LineNumber(void) +{ + return (sLineNumber + 1); +} + +static int ColumnNumber(void) +{ + return column; +} + +static char *LineText(void) +{ + msgline[column] = 0; + return msgline; +} + +static void comment(void) +{ + // Handle block comments + + int c, c1; + +loop: + // We have the start of a comment so look skip everything up to the + // end of the comment character + while ((c = getinput()) != '*' && c != EOF) + { + if(column < 1023) + msgline[column] = c; + + ++column; + + // keep the line number in synch + if (c == '\n') + { + // start the output (matches the algorithim in the lexx above) + countline(); + } + + if (swf4debug) putchar(c); + } + + // is this the end of comment character + if ((c1 = getinput()) != '/' && c != EOF) + { + // false start as this was no end of comment + do_unput4(c1); + goto loop; + } + + // write out the start of the end of comment + if (c != EOF) + if (swf4debug) putchar(c); + + // write out the end of the end of comment + if (c1 != EOF) + if (swf4debug) putchar(c1); +} + +static void comment1(void) +{ + // Handle comment of type 1 (ie '//') + + int c; + + // this is a line comment + while ((c = getinput()) != '\n' && c != EOF) + { + if (swf4debug) putchar(c); + + if(column < 1023) + msgline[column] = c; + + ++column; + }; + + // keep the line number in synch + if (c == '\n') + { + if (swf4debug) putchar(c); + + countline(); + } +} + +static void count(void) +{ + int n; + + // Count the characters to maintain the current column position + if (yytext[0] == '\n') + { + if (swf4debug) printf("\n"); + } + else + { + if (swf4debug) printf("%s", yytext); + + for(n=0; n +#include +#include +#include "compile.h" +#include "action.h" + +#define YYPARSE_PARAM buffer + +%} + +%union { + Buffer action; + char *str; + SWFActionFunction function; + SWFGetUrl2Method getURLMethod; +} + +/* tokens etc. */ +%token BREAK +%token FOR +%token CONTINUE +%token IF +%token ELSE +%token DO +%token WHILE + +%token THIS + +/* functions */ +%token EVAL +%token TIME +%token RANDOM +%token LENGTH +%token INT +%token CONCAT +%token DUPLICATECLIP +%token REMOVECLIP +%token TRACE +%token STARTDRAG +%token STOPDRAG +%token ORD +%token CHR +%token CALLFRAME +%token GETURL +%token GETURL1 +%token LOADMOVIE +%token LOADVARIABLES +%token POSTURL +%token SUBSTR + +%token GETPROPERTY + +/* v3 functions */ +%token NEXTFRAME +%token PREVFRAME +%token PLAY +%token STOP +%token TOGGLEQUALITY +%token STOPSOUNDS +%token GOTOFRAME +%token GOTOANDPLAY +%token FRAMELOADED +%token SETTARGET + +/* high level functions */ +%token TELLTARGET + +/* these three are strdup'ed in compiler.flex, so free them here */ +%token STRING +%token NUMBER +%token IDENTIFIER +%token PATH + +%token GETURL_METHOD + +%token EQ "==" +%token LE "<=" +%token GE ">=" +%token NE "!=" +%token LAN "&&" +%token LOR "||" +%token INC "++" +%token DEC "--" +%token IEQ "+=" +%token DEQ "/=" +%token MEQ "*=" +%token SEQ "-=" +%token STREQ "===" +%token STRNE "!==" +%token STRCMP "<=>" +%token PARENT ".." + +%token END "end" + +/* ascending order of ops ..? */ +%left ',' +%right '=' "*=" "/=" "+=" "-=" +%right '?' ':' +%left "&&" "||" +%left "==" "!=" "===" "!==" +%left '<' '>' "<=" ">=" "<=>" +%left '&' +%left '+' '-' +%left '*' '/' +%right "++" "--" UMINUS '!' +%right POSTFIX +%right NEGATE + +%type elem +%type elems +%type stmt +%type statements +%type if_stmt +%type iter_stmt +%type cont_stmt +%type break_stmt +%type expr_opt +%type void_function_call +%type function_call +%type lhs_expr +%type pf_expr +%type rhs_expr +%type assign_stmt +%type assign_stmts +%type assign_stmts_opt +%type expr +%type program + +/* make sure to free these, too! */ +%type sprite +%type variable + +%% + +/* rules */ + +program + : elems + { *((Buffer *)buffer) = $1; } + + ; + +elems + : elem + | elems elem + { bufferConcat($1, $2); } + ; + +elem + : stmt + ; + +stmt + : '{' '}' { $$ = NULL; } + | '{' statements '}' { $$ = $2; } + | ';' { $$ = NULL; } + | assign_stmt ';' + | if_stmt + | iter_stmt + | cont_stmt + | break_stmt + ; + +assign_stmts + : assign_stmt + | assign_stmts ',' assign_stmt { bufferConcat($1, $3); } + ; + +statements + : /* empty */ { $$ = NULL; } + | stmt + | statements stmt + { bufferConcat($1, $2); } + ; + +if_stmt + /* XXX- I haven't tested the frameloaded() stuff yet.. */ + + : IF '(' FRAMELOADED '(' NUMBER ')' ')' stmt ELSE stmt + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_WAITFORFRAME); + bufferWriteS16($$, 3); + bufferWriteS16($$, atoi($5)); + free($5); + bufferWriteU8($$, 1); /* if not loaded, jump to.. */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($10)+5); + bufferConcat($$, $10); /* ..here */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($8)); + bufferConcat($$, $8); } + + | IF '(' FRAMELOADED '(' NUMBER ')' ')' stmt + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_WAITFORFRAME); + bufferWriteS16($$, 3); + bufferWriteS16($$, atoi($5)); + free($5); + bufferWriteU8($$, 1); /* if not loaded, jump to.. */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, 5); + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); /* ..here */ + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($8)); /* ..and then out */ + bufferConcat($$, $8); } + + /* make this case cleaner.. */ + | IF '(' '!' FRAMELOADED '(' NUMBER ')' ')' stmt + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_WAITFORFRAME); + bufferWriteS16($$, 3); + bufferWriteS16($$, atoi($6)); + free($6); + bufferWriteU8($$, 1); /* if not loaded, jump to.. */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($9)); + bufferConcat($$, $9); } /* ..here */ + + | IF '(' FRAMELOADED '(' expr ')' ')' stmt ELSE stmt + { $$ = $5; + bufferWriteU8($$, SWFACTION_WAITFORFRAMEEXPRESSION); + bufferWriteS16($$, 1); + bufferWriteU8($$, 1); /* if not loaded, jump to.. */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($10)+5); + bufferConcat($$, $10); /* ..here */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($8)); + bufferConcat($$, $8); } + + | IF '(' FRAMELOADED '(' expr ')' ')' stmt + { $$ = $5; + bufferWriteU8($$, SWFACTION_WAITFORFRAMEEXPRESSION); + bufferWriteS16($$, 1); + bufferWriteU8($$, 1); /* if not loaded, jump to.. */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, 5); + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); /* ..here */ + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($8)); /* ..and then out */ + bufferConcat($$, $8); } + + /* make this case cleaner.. */ + | IF '(' '!' FRAMELOADED '(' expr ')' ')' stmt + { $$ = $6; + bufferWriteU8($$, SWFACTION_WAITFORFRAMEEXPRESSION); + bufferWriteS16($$, 1); + bufferWriteU8($$, 1); /* if not loaded, jump to.. */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($9)); + bufferConcat($$, $9); } /* ..here */ + + | IF '(' expr ')' stmt ELSE stmt + { bufferWriteU8($3, SWFACTION_BRANCHIFTRUE); + bufferWriteS16($3, 2); + bufferWriteS16($3, bufferLength($7)+5); + bufferConcat($3, $7); + bufferWriteU8($3, SWFACTION_BRANCHALWAYS); + bufferWriteS16($3, 2); + bufferWriteS16($3, bufferLength($5)); + bufferConcat($3, $5); + $$ = $3; } + + | IF '(' expr ')' stmt + { bufferWriteU8($3, SWFACTION_LOGICALNOT); + bufferWriteU8($3, SWFACTION_BRANCHIFTRUE); + bufferWriteS16($3, 2); + bufferWriteS16($3, bufferLength($5)); + bufferConcat($3, $5); + $$ = $3; } + ; + +expr_opt + : /* empty */ { $$ = NULL; } + | expr { $$ = $1; } + ; + +/* not thought out yet.. +switch_stmt + : SWITCH '(' expr ')' '{' + { $$ = $3; + pushLoop(); } + switch_cases '}' + { bufferConcat($$, $7); } + ; + +switch_cases + : switch_cases switch_case + | switch_case + ; + +switch_case + : CASE INTEGER ':' stmt + { $$ = newBuffer(); } + ; +*/ + +iter_stmt + : WHILE '(' '!' FRAMELOADED '(' NUMBER ')' ')' stmt + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_WAITFORFRAME); + bufferWriteS16($$, 3); + bufferWriteS16($$, atoi($6)); + free($6); + bufferWriteU8($$, 1); /* if not loaded, jump to.. */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($9)+5); + bufferConcat($$, $9); /* ..here */ + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, -(bufferLength($$)+2)); } + + | WHILE '(' expr ')' stmt + { $$ = $3; + bufferWriteU8($$, SWFACTION_LOGICALNOT); + bufferWriteU8($$, SWFACTION_BRANCHIFTRUE); + bufferWriteS16($$, 2); + bufferWriteS16($$, bufferLength($5)+5); + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, -(bufferLength($$)+2)); + bufferResolveJumps($$); } + + | DO stmt WHILE '(' expr ')' + { $$ = $2; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_BRANCHIFTRUE); + bufferWriteS16($$, 2); + bufferWriteS16($$, -(bufferLength($$)+2)); + bufferResolveJumps($$); } + + | FOR '(' assign_stmts_opt ';' expr_opt ';' assign_stmts_opt ')' stmt + { if (!$5) + $5 = newBuffer(); + else { + bufferWriteU8($5, SWFACTION_LOGICALNOT); + bufferWriteU8($5, SWFACTION_BRANCHIFTRUE); + bufferWriteS16($5, 2); + bufferWriteS16($5, bufferLength($9)+bufferLength($7)+5); + } + bufferConcat($5, $9); + bufferConcat($5, $7); + bufferWriteU8($5, SWFACTION_BRANCHALWAYS); + bufferWriteS16($5, 2); + bufferWriteS16($5, -(bufferLength($5)+2)); + bufferResolveJumps($5); + $$ = $3; + if(!$$) $$ = newBuffer(); + bufferConcat($$, $5); + } + ; + +assign_stmts_opt + : /* empty */ { $$ = NULL; } + | assign_stmts + ; + +cont_stmt + : CONTINUE ';' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, MAGIC_CONTINUE_NUMBER); } + ; + +break_stmt + : BREAK ';' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_BRANCHALWAYS); + bufferWriteS16($$, 2); + bufferWriteS16($$, MAGIC_BREAK_NUMBER); } + ; + +void_function_call + : STOPDRAG '(' ')' /* no args */ + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_STOPDRAGMOVIE); } + + | CALLFRAME '(' variable ')' + { $$ = newBuffer(); + bufferWriteString($$, $3, strlen($3)+1); + bufferWriteU8($$, SWFACTION_CALLFRAME); + bufferWriteS16($$, 0); + free($3); } + + | CALLFRAME '(' STRING ')' + { $$ = newBuffer(); + bufferWriteString($$, $3, strlen($3)+1); + bufferWriteU8($$, SWFACTION_CALLFRAME); + bufferWriteS16($$, 0); + free($3); } + + | REMOVECLIP '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_REMOVECLIP); } + + | TRACE '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_TRACE); } + + /* getURL2(url, window, [method]) */ + | GETURL '(' expr ',' expr ')' + { $$ = $3; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_GETURL2); + bufferWriteS16($$, 1); + bufferWriteU8($$, GETURL_METHOD_NOSEND); } + + | GETURL '(' expr ',' expr ',' GETURL_METHOD ')' + { $$ = $3; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_GETURL2); + bufferWriteS16($$, 1); + bufferWriteU8($$, $7); } + + | GETURL1 '(' STRING ',' STRING ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_GETURL); + bufferWriteS16($$, strlen($3) + strlen($5) + 2); + bufferWriteHardString($$, (byte*)$3, strlen($3)); + bufferWriteU8($$, 0); + bufferWriteHardString($$, (byte*)$5, strlen($5)); + bufferWriteU8($$, 0); } + + | LOADMOVIE '(' expr ',' expr ')' + { $$ = $3; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_GETURL2); + bufferWriteS16($$, 1); + bufferWriteU8($$, GETURL_METHOD_NOSEND | GETURL_LOADMOVIE); } + + | LOADMOVIE '(' expr ',' expr ',' GETURL_METHOD ')' + { $$ = $3; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_GETURL2); + bufferWriteS16($$, 1); + bufferWriteU8($$, $7 | GETURL_LOADMOVIE); } + + | LOADVARIABLES '(' expr ',' expr ')' + { $$ = $3; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_GETURL2); + bufferWriteS16($$, 1); + bufferWriteU8($$, GETURL_METHOD_NOSEND | GETURL_LOADVARIABLES); } + + | LOADVARIABLES '(' expr ',' expr ',' GETURL_METHOD ')' + { $$ = $3; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_GETURL2); + bufferWriteS16($$, 1); + bufferWriteU8($$, $7 | GETURL_LOADVARIABLES); } + + /* startDrag(target, lock, [left, right, top, bottom]) */ + | STARTDRAG '(' expr ',' expr ')' + { $$ = newBuffer(); + bufferWriteString($$, "0", 2); /* no constraint */ + bufferConcat($$, $5); + bufferConcat($$, $3); + bufferWriteU8($$, 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); + bufferWriteU8($$, SWFACTION_STARTDRAGMOVIE); } + + /* duplicateClip(target, new, depth) */ + | DUPLICATECLIP '(' expr ',' expr ',' expr ')' + { $$ = $3; + bufferConcat($$, $5); + bufferConcat($$, $7); + bufferWriteWTHITProperty($$); + bufferWriteU8($$, SWFACTION_ADD); /* see docs for explanation */ + bufferWriteU8($$, SWFACTION_DUPLICATECLIP); } + + /* v3 actions */ + | NEXTFRAME '(' ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_NEXTFRAME); } + + | PREVFRAME '(' ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_PREVFRAME); } + + | PLAY '(' ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_PLAY); } + + | STOP '(' ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_STOP); } + + | TOGGLEQUALITY '(' ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_TOGGLEQUALITY); } + + | STOPSOUNDS '(' ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_STOPSOUNDS); } + + | GOTOFRAME '(' NUMBER ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_GOTOFRAME); + bufferWriteS16($$, 2); + bufferWriteS16($$, atoi($3)); + free($3); } + + | GOTOFRAME '(' STRING ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_GOTOLABEL); + bufferWriteS16($$, strlen($3)+1); + bufferWriteHardString($$, (byte*)$3, strlen($3)+1); + free($3); } + + | GOTOFRAME '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_GOTOEXPRESSION); + bufferWriteS16($$, 1); + bufferWriteU8($$, 0); } /* XXX - and stop */ + + | GOTOANDPLAY '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_GOTOEXPRESSION); + bufferWriteS16($$, 1); + bufferWriteU8($$, 1); } /* XXX - and play */ + + | SETTARGET '(' STRING ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_SETTARGET); + bufferWriteS16($$, strlen($3)+1); + bufferWriteHardString($$, (byte*)$3, strlen($3)+1); + free($3); } + + | SETTARGET '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_SETTARGETEXPRESSION); } + + | TELLTARGET '(' STRING ')' stmt + { $$ = newBuffer(); + /* SetTarget(STRING) */ + bufferWriteU8($$, SWFACTION_SETTARGET); + bufferWriteS16($$, strlen($3)+1); + bufferWriteHardString($$, (byte*)$3, strlen($3)+1); + /* stmt */ + bufferConcat($$, $5); + /* SetTarget('') */ + bufferWriteU8($$, SWFACTION_SETTARGET); + bufferWriteS16($$, 1); + bufferWriteU8($$, 0); + free($3); } + + | TELLTARGET '(' expr ')' stmt + { $$ = $3; + /* SetTarget(expr) */ + bufferWriteU8($$, SWFACTION_SETTARGETEXPRESSION); + /* stmt */ + bufferConcat($$, $5); + /* SetTarget('') */ + bufferWriteU8($$, SWFACTION_SETTARGET); + bufferWriteS16($$, 1); + bufferWriteU8($$, 0); } + ; + +function_call + : EVAL '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_GETVARIABLE); } + + | TIME '(' ')' + { $$ = newBuffer(); + bufferWriteU8($$, SWFACTION_GETTIMER); } + + | RANDOM '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_RANDOM); } + + | LENGTH '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_STRINGLENGTH); } + + | INT '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_INT); } + + | ORD '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_ORD); } + + | CHR '(' expr ')' + { $$ = $3; + bufferWriteU8($$, SWFACTION_CHR); } + + | CONCAT '(' expr ',' expr ')' + { $$ = $3; + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_STRINGCONCAT); } + + | SUBSTR '(' expr ',' expr ',' expr ')' + { $$ = $3; + bufferConcat($$, $5); + bufferConcat($$, $7); + bufferWriteU8($$, SWFACTION_SUBSTRING); } + + | GETPROPERTY '(' expr ',' STRING ')' + { $$ = newBuffer(); + bufferConcat($$, $3); + bufferWriteGetProperty($$, $5); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + free($5); } + ; + +pf_expr + : lhs_expr "++" %prec POSTFIX + { $$ = newBuffer(); + bufferWriteBuffer($$, $1); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteBuffer($$, $1); + bufferConcat($$, $1); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_ADD); + bufferWriteU8($$, SWFACTION_SETVARIABLE); } + + | lhs_expr "--" %prec POSTFIX + { $$ = newBuffer(); + bufferWriteBuffer($$, $1); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteBuffer($$, $1); + bufferConcat($$, $1); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_SUBTRACT); + bufferWriteU8($$, SWFACTION_SETVARIABLE); } + ; + +/* these leave a value on the stack */ +rhs_expr + : function_call + + | '(' rhs_expr ')' + { $$ = $2; } + + | NUMBER + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + free($1); } + + | '-' NUMBER %prec NEGATE + { $$ = newBuffer(); + bufferWriteString($$, "-", 2); + bufferWriteString($$, $2, strlen($2)+1); + free($2); } + + | STRING + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + free($1); } + + | variable + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + free($1); } + + | sprite + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + free($1); } + + | sprite '.' IDENTIFIER + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteGetProperty($$, $3); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + free($3); + free($1); } + + | "++" sprite '.' IDENTIFIER + { $$ = newBuffer(); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteGetProperty($$, $4); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteSetProperty($$, $4); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteGetProperty($$, $4); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_ADD); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + free($2); + free($4); } + + | "++" lhs_expr + { $$ = $2; + bufferWriteU8($$, SWFACTION_DUP); + bufferWriteU8($$, SWFACTION_DUP); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_ADD); + bufferWriteU8($$, SWFACTION_SETVARIABLE); + bufferWriteU8($$, SWFACTION_GETVARIABLE); } + + | "--" sprite '.' IDENTIFIER + { $$ = newBuffer(); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteGetProperty($$, $4); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteSetProperty($$, $4); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteGetProperty($$, $4); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_ADD); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + free($2); + free($4); } + + | "--" lhs_expr + { $$ = $2; + bufferWriteU8($$, SWFACTION_DUP); + bufferWriteU8($$, SWFACTION_DUP); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_SUBTRACT); + bufferWriteU8($$, SWFACTION_SETVARIABLE); + bufferWriteU8($$, SWFACTION_GETVARIABLE); } + + | '-' rhs_expr %prec UMINUS + { $$ = $2; + bufferWriteString($2, "-1", 3); + bufferWriteU8($2, SWFACTION_MULTIPLY); } + + | '!' rhs_expr + { $$ = $2; + bufferWriteU8($2, SWFACTION_LOGICALNOT); } + + | lhs_expr '=' rhs_expr /* assign and leave copy on stack */ + { $$ = $1; + bufferConcat($$, $3); + bufferWriteU8($$, SWFACTION_DUP); + bufferWriteU8($$, SWFACTION_SETVARIABLE); } + + | rhs_expr '*' rhs_expr + { $$ = $1; + bufferConcat($$, $3); + bufferWriteU8($$, SWFACTION_MULTIPLY); } + + | rhs_expr '/' rhs_expr + { $$ = $1; + bufferConcat($$, $3); + bufferWriteU8($$, SWFACTION_DIVIDE); } + + | rhs_expr '+' rhs_expr + { $$ = $1; + bufferConcat($$, $3); + bufferWriteU8($$, SWFACTION_ADD); } + + | rhs_expr '-' rhs_expr + { $$ = $1; + bufferConcat($$, $3); + bufferWriteU8($$, SWFACTION_SUBTRACT); } + + | rhs_expr '&' rhs_expr + { $$ = $1; + bufferConcat($$, $3); + bufferWriteU8($$, SWFACTION_STRINGCONCAT); } + + | rhs_expr '<' rhs_expr + { $$ = $1; + bufferConcat($$, $3); + bufferWriteU8($$, SWFACTION_LESSTHAN); } + + | rhs_expr '>' rhs_expr + { $$ = $3; + bufferConcat($$, $1); + bufferWriteU8($$, SWFACTION_LESSTHAN); } + + | rhs_expr "<=" rhs_expr + { $$ = $3; + bufferConcat($$, $1); + bufferWriteU8($$, SWFACTION_LESSTHAN); + bufferWriteU8($$, SWFACTION_LOGICALNOT); } + + | rhs_expr ">=" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_LESSTHAN); + bufferWriteU8($1, SWFACTION_LOGICALNOT); } + + | rhs_expr "!==" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_STRINGEQ); + bufferWriteU8($1, SWFACTION_LOGICALNOT); } + + | rhs_expr "===" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_STRINGEQ); } + + | rhs_expr "<=>" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_STRINGCOMPARE); } + + | rhs_expr "==" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_EQUAL); } + + | rhs_expr "!=" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_EQUAL); + bufferWriteU8($1, SWFACTION_LOGICALNOT); } + + | rhs_expr "&&" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_LOGICALAND); } + + | rhs_expr "||" rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_LOGICALOR); } + + | rhs_expr '?' rhs_expr ':' rhs_expr + { bufferWriteU8($1, SWFACTION_BRANCHIFTRUE); + bufferWriteS16($1, 2); + bufferWriteS16($1, bufferLength($5)+5); + bufferConcat($1, $5); + bufferWriteU8($1, SWFACTION_BRANCHALWAYS); + bufferWriteS16($1, 2); + bufferWriteS16($1, bufferLength($3)); + bufferConcat($1, $3); } + ; + +variable + : IDENTIFIER + + | sprite ':' IDENTIFIER + { $$ = $1; + $$ = stringConcat($$, strdup(":")); + $$ = stringConcat($$, $3); } + ; + +sprite + : THIS + { $$ = strdup(""); } + + | '.' + { $$ = strdup(""); } + + | '/' + { $$ = strdup("/"); } + + | PARENT + { $$ = strdup(".."); } + + | IDENTIFIER + { $$ = $1; } + + | PATH + { $$ = $1; } + ; + +lhs_expr + : variable + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + free($1); } + + | STRING + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + free($1); } + + | '(' rhs_expr ')' { $$ = $2; } + ; + +assign_stmt + : pf_expr + + | void_function_call + + | "++" lhs_expr + { $$ = $2; + bufferWriteBuffer($$, $2); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_ADD); + bufferWriteU8($$, SWFACTION_SETVARIABLE); } + + | "--" lhs_expr + { $$ = $2; + bufferWriteBuffer($$, $2); + bufferWriteU8($$, SWFACTION_GETVARIABLE); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_SUBTRACT); + bufferWriteU8($$, SWFACTION_SETVARIABLE); } + + | "++" sprite '.' IDENTIFIER + { $$ = newBuffer(); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteGetProperty($$, $4); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_ADD); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteSetProperty($$, $4); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + free($2); + free($4); } + + | "--" sprite '.' IDENTIFIER + { $$ = newBuffer(); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteGetProperty($$, $4); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + bufferWriteString($$, "1", 2); + bufferWriteU8($$, SWFACTION_SUBTRACT); + bufferWriteString($$, $2, strlen($2)+1); + bufferWriteSetProperty($$, $4); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + free($2); + free($4); } + + | lhs_expr '=' rhs_expr + { bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_SETVARIABLE); } + + | lhs_expr "*=" rhs_expr + { bufferWriteBuffer($1, $1); + bufferWriteU8($1, SWFACTION_GETVARIABLE); + bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_MULTIPLY); + bufferWriteU8($1, SWFACTION_SETVARIABLE); } + + | lhs_expr "/=" rhs_expr + { bufferWriteBuffer($1, $1); + bufferWriteU8($1, SWFACTION_GETVARIABLE); + bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_DIVIDE); + bufferWriteU8($1, SWFACTION_SETVARIABLE); } + + | lhs_expr "+=" rhs_expr + { bufferWriteBuffer($1, $1); + bufferWriteU8($1, SWFACTION_GETVARIABLE); + bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_ADD); + bufferWriteU8($1, SWFACTION_SETVARIABLE); } + + | lhs_expr "-=" rhs_expr + { bufferWriteBuffer($1, $1); + bufferWriteU8($1, SWFACTION_GETVARIABLE); + bufferConcat($1, $3); + bufferWriteU8($1, SWFACTION_SUBTRACT); + bufferWriteU8($1, SWFACTION_SETVARIABLE); } + + | sprite '.' IDENTIFIER '=' rhs_expr + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteSetProperty($$, $3); + bufferConcat($$,$5); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + free($1); + free($3); } + + | sprite '.' IDENTIFIER "*=" rhs_expr + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteSetProperty($$, $3); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteGetProperty($$, $3); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_MULTIPLY); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + free($1); + free($3); } + + | sprite '.' IDENTIFIER "/=" rhs_expr + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteSetProperty($$, $3); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteGetProperty($$, $3); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_DIVIDE); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + free($1); + free($3); } + + | sprite '.' IDENTIFIER "+=" rhs_expr + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteSetProperty($$, $3); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteGetProperty($$, $3); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_ADD); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + free($1); + free($3); } + + | sprite '.' IDENTIFIER "-=" rhs_expr + { $$ = newBuffer(); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteSetProperty($$, $3); + bufferWriteString($$, $1, strlen($1)+1); + bufferWriteGetProperty($$, $3); + bufferWriteU8($$, SWFACTION_GETPROPERTY); + bufferConcat($$, $5); + bufferWriteU8($$, SWFACTION_SUBTRACT); + bufferWriteU8($$, SWFACTION_SETPROPERTY); + free($1); + free($3); } + ; + +expr + : rhs_expr + ; + +%% diff --git a/lib/action/swf5compiler.flex b/lib/action/swf5compiler.flex new file mode 100644 index 0000000..86a74a3 --- /dev/null +++ b/lib/action/swf5compiler.flex @@ -0,0 +1,467 @@ +%{ + +#include +#include + +#include "compile.h" +#include "action.h" +#include "blocks/error.h" +#include "swf5compiler.tab.h" /* defines token types */ + +static int swf5debug; + +static const char *lexBuffer = NULL; +static int lexBufferLen = 0; + +static int sLineNumber = 0; +static char szLine[1024]; +static char msgbufs[2][1024] = { {0}, {0} }, *msgline = {0}; +static int column = 0; + +static void comment(); +static void comment1(); +static void count(); +static void countline(); +static void warning(char *msg); + +#define YY_INPUT(buf,result,max_size) result=lexBufferInput(buf, max_size) + +/* thanks to the prolific and brilliant Raff: */ +static int lexBufferInput(char *buf, int max_size) +{ + int l = lexBufferLen > max_size ? max_size : lexBufferLen; + + if (lexBufferLen <= 0) + return YY_NULL; + + memcpy(buf, lexBuffer, l); + lexBuffer += l; + lexBufferLen -= l; + return l; +} + + /* very inefficient method of unescaping strings */ +static void unescape(char *buf) +{ + char *p, *p1; + + for (p1=buf; (p=strchr(p1, '\\')) != 0; p1 = p+1) { + switch(p[1]) + { + case 'b' : p[1] = '\b'; break; + case 'f' : p[1] = '\f'; break; + case 'n' : p[1] = '\n'; break; + case 'r' : p[1] = '\r'; break; + case 't' : p[1] = '\t'; break; + case 'x' : + case 'u' : warning("unsupported escape sequence"); + } + strcpy(p, p+1); + } +} + +void swf5ParseInit(const char *script, int debug) +{ + checkByteOrder(); + yyrestart(NULL); + + swf5debug = debug; + + lexBuffer = script; + lexBufferLen = strlen(script); + sLineNumber = 0; + column = 0; + msgline = msgbufs[0]; +} + +%} + +%s asm + +%{ + // forward declaration needed by the following function +#ifndef YY_PROTO +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif +#endif + static void yyunput YY_PROTO(( int c, char *buf_ptr )); + + void do_unput5(const char c) { unput(c); } +%} + +DIGIT [0-9] +ID [a-zA-Z_][a-zA-Z0-9_]* + +%% + +0x[0-9a-fA-F]+ { count(); swf5lval.intVal = strtoul(yytext, NULL, 0); + return INTEGER; } +0[0-7]+ { count(); swf5lval.intVal = strtoul(yytext, NULL, 0); + return INTEGER; } +{DIGIT}+ { count(); swf5lval.intVal = atoi(yytext); + return INTEGER; } +{DIGIT}+"."{DIGIT}* { count(); swf5lval.doubleVal = atof(yytext); + return DOUBLE; } +true { count(); swf5lval.intVal = 1; + return BOOLEAN; } +false { count(); swf5lval.intVal = 0; + return BOOLEAN; } +null { count(); return NULLVAL; } +break { count(); return BREAK; } +continue { count(); return CONTINUE; } +function { count(); return FUNCTION; } +else { count(); return ELSE; } +switch { count(); return SWITCH; } +case { count(); return CASE; } +default { count(); return DEFAULT; } +for { count(); return FOR; } +in { count(); return IN; } +if { count(); return IF; } +while { count(); return WHILE; } +do { count(); return DO; } +var { count(); return VAR; } +new { count(); return NEW; } +delete { count(); return DELETE; } +return { count(); return RETURN; } +with { count(); return WITH; } +asm { count(); BEGIN(asm); return ASM; } +eval { count(); return EVAL; } +typeof { count(); return TYPEOF; } +instanceof { count(); return INSTANCEOF; } + + /* legacy functions */ +random { count(); return RANDOM; } +getTimer { count(); return GETTIMER; } +length { count(); return LENGTH; } +concat { count(); return CONCAT; } +substr { count(); return SUBSTR; } +trace { count(); return TRACE; } +int { count(); return INT; } +ord { count(); return ORD; } +chr { count(); return CHR; } +getURL { count(); return GETURL; } +getURL1 { count(); return GETURL1; } +nextFrame { count(); return NEXTFRAME; } +prevFrame { count(); return PREVFRAME; } +play { count(); return PLAY; } +stop { count(); return STOP; } +toggleQuality { count(); return TOGGLEQUALITY; } +stopSounds { count(); return STOPSOUNDS; } +callFrame { count(); return CALLFRAME; } +gotoFrame { count(); return GOTOFRAME; } +setTarget { count(); return SETTARGET; } +loadVariables { count(); return LOADVARIABLES; } +loadMovie { count(); return LOADMOVIE; } +loadVariablesNum { count(); return LOADVARIABLESNUM; } +loadMovieNum { count(); return LOADMOVIENUM; } +duplicateMovieClip { count(); return DUPLICATEMOVIECLIP; } +removeMovieClip { count(); return REMOVEMOVIECLIP; } + + /* assembler ops */ +{ +dup { count(); return DUP; } +swap { count(); return SWAP; } +pop { count(); return POP; } +push { count(); return PUSH; } +setregister { count(); return SETREGISTER; } +callfunction { count(); return CALLFUNCTION; } +callmethod { count(); return CALLMETHOD; } +and { count(); return AND; } +or { count(); return OR; } +xor { count(); return XOR; } +modulo { count(); return MODULO; } +add { count(); return ADD; } +newadd { count(); return ADD; } +lessthan { count(); return LESSTHAN; } +newlessthan { count(); return LESSTHAN; } +equals { count(); return EQUALS; } +newequals { count(); return EQUALS; } +inc { count(); return INC; } +dec { count(); return DEC; } +enumerate { count(); return ENUMERATE; } +initobject { count(); return INITOBJECT; } +initarray { count(); return INITARRAY; } +getmember { count(); return GETMEMBER; } +setmember { count(); return SETMEMBER; } +shiftleft { count(); return SHIFTLEFT; } +shiftright { count(); return SHIFTRIGHT; } +shiftright2 { count(); return SHIFTRIGHT2; } +varequals { count(); return VAREQUALS; } +oldadd { count(); return OLDADD; } +subtract { count(); return SUBTRACT; } +multiply { count(); return MULTIPLY; } +divide { count(); return DIVIDE; } +oldequals { count(); return OLDEQUALS; } +oldlessthan { count(); return OLDLESSTHAN; } +logicaland { count(); return LOGICALAND; } +logicalor { count(); return LOGICALOR; } +not { count(); return NOT; } +stringeq { count(); return STRINGEQ; } +stringlength { count(); return STRINGLENGTH; } +substring { count(); return SUBSTRING; } +getvariable { count(); return GETVARIABLE; } +setvariable { count(); return SETVARIABLE; } +settargetexpr { count(); return SETTARGETEXPRESSION; } +startdrag { count(); return STARTDRAG; } +stopdrag { count(); return STOPDRAG; } +stringlessthan { count(); return STRINGLESSTHAN; } +mblength { count(); return MBLENGTH; } +mbsubstring { count(); return MBSUBSTRING; } +mbord { count(); return MBORD; } +mbchr { count(); return MBCHR; } +branch { count(); return BRANCHALWAYS; } +branchalways { count(); return BRANCHALWAYS; } +branchiftrue { count(); return BRANCHIFTRUE; } +post { count(); return POST; } +get { count(); return GET; } +end { count(); return END; } +} + +r\:{DIGIT}+ { count(); swf5lval.str = strdup(yytext+2); + return REGISTER; } + + +{ID} { count(); swf5lval.str = strdup(yytext); + return IDENTIFIER; } + +\"(\\.|[^\\"])*\" { count(); swf5lval.str = strdup(yytext+1); + swf5lval.str[strlen(swf5lval.str)-1]=0; + unescape(swf5lval.str); + return STRING; } + +\'(\\.|[^\\'])*\' { count(); swf5lval.str = strdup(yytext+1); + swf5lval.str[strlen(swf5lval.str)-1]=0; + unescape(swf5lval.str); + return STRING; } + +\"(\\.|[^\\"])*$ { count(); swf5lval.str = strdup(""); + warning("Unterminated string!"); + return STRING; } + +\'(\\.|[^\\'])*$ { count(); swf5lval.str = strdup(""); + warning("Unterminated string!"); + return STRING; } + +"/*" { count(); comment(); } +"//" { count(); comment1(); } +[ \t\v\f] { count(); } + +"++" { count(); return INCR; } +"--" { count(); return DECR; } +"<=" { count(); return LE; } +">=" { count(); return GE; } +"==" { count(); return EQ; } +"!=" { count(); return NE; } +"&&" { count(); return LAN; } +"||" { count(); return LOR; } +"*=" { count(); return MEQ; } +"/=" { count(); return DEQ; } +"+=" { count(); return IEQ; } +"-=" { count(); return SEQ; } +"&=" { count(); return AEQ; } +"|=" { count(); return OEQ; } +"<<" { count(); return SHL; } +">>" { count(); return SHR; } +">>>" { count(); return SHR2; } +"<<=" { count(); return SHLEQ; } +">>=" { count(); return SHREQ; } +">>>=" { count(); return SHR2EQ; } + +"<" { count(); return '<'; } +">" { count(); return '>'; } +";" { count(); return ';'; } +"=" { count(); return '='; } +"+" { count(); return '+'; } +"-" { count(); return '-'; } +"&" { count(); return '&'; } +"|" { count(); return '|'; } +"^" { count(); return '^'; } +"*" { count(); return '*'; } +"/" { count(); return '/'; } +"%" { count(); return '%'; } +"!" { count(); return '!'; } +"(" { count(); return '('; } +")" { count(); return ')'; } +"[" { count(); return '['; } +"]" { count(); return ']'; } +"{" { count(); return '{'; } +"}" { count(); BEGIN(0); return '}'; } +"," { count(); return ','; } +"." { count(); return '.'; } +"?" { count(); return '?'; } +":" { count(); return ':'; } +"~" { count(); return '~'; } + +\r?\n { count(); strcpy(szLine, yytext + 1); + countline(); yyless(1); } + +. SWF_error("Unrecognized character: %s\n", yytext); + +%% +static int getinput() { +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif +} + +int swf5wrap() +{ + return 1; +} + +static void countline() +{ + if(sLineNumber != 0) + msgline[column] = 0; + + ++sLineNumber; + column = 0; + msgline = msgbufs[sLineNumber & 1]; +} + +static int LineNumber(void) +{ + return (sLineNumber + 1); +} + +static int ColumnNumber(void) +{ + return column; +} + +static char *LineText(void) +{ + msgline[column] = 0; + return msgline; +} + +static void comment() +{ + // Handle block comments + + int c, c1; + +loop: + // We have the start of a comment so look skip everything up to the + // end of the comment character + while ((c = getinput()) != '*' && c != EOF) + { + if(column < 1023) + msgline[column] = c; + + ++column; + + // keep the line number in synch + if (c == '\n') + { + // start the output (matches the algorithim in the lexx above) + countline(); + } + + if (swf5debug) putchar(c); + } + + // is this the end of comment character + if ((c1 = getinput()) != '/' && c != EOF) + { + // false start as this was no end of comment + do_unput5(c1); + goto loop; + } + + // write out the start of the end of comment + if (c != EOF) + if (swf5debug) putchar(c); + + // write out the end of the end of comment + if (c1 != EOF) + if (swf5debug) putchar(c1); +} + +static void comment1() +{ + // Handle comment of type 1 (ie '//') + + int c; + + // this is a line comment + while ((c = getinput()) != '\n' && c != EOF) + { + if (swf5debug) putchar(c); + + if(column < 1023) + msgline[column] = c; + + ++column; + }; + + // keep the line number in synch + if (c == '\n') + { + if (swf5debug) putchar(c); + + countline(); + } +} + +static void count(void) +{ + int n; + + // Count the characters to maintain the current column position + if (yytext[0] == '\n') + { + if (swf5debug) printf("\n"); + } + else + { + if (swf5debug) printf("%s", yytext); + + for(n=0; n +#include +#include +#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 INTEGER +%token DOUBLE +%token BOOLEAN +%token REGISTER + +/* these two are strdup'ed in compiler.flex, so free them up here */ +%token STRING +%token 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 program code +%type stmt stmts +%type if_stmt iter_stmt cont_stmt break_stmt return_stmt +%type with_stmt +%type switch_stmt +%type anon_function_decl function_decl anycode +%type void_function_call function_call method_call +%type assign_stmt assign_stmts assign_stmts_opt +%type expr expr_or_obj objexpr expr_opt obj_ref +%type emptybraces level init_vars init_var primary lvalue_expr +%type lvalue + +%type expr_list objexpr_list formals_list + +%type switch_case +%type switch_cases + +%type assignop incdecop +%type urlmethod + +%type identifier + +%type opcode opcode_list push_item with push_list + +/* +%type integer +%type 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 { $$ = $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 { $$ = $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); } + ; + +%% + -- 1.7.10.4