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