file copied from ming 0.3alpha2
authorkramm <kramm>
Mon, 2 Feb 2004 10:12:34 +0000 (10:12 +0000)
committerkramm <kramm>
Mon, 2 Feb 2004 10:12:34 +0000 (10:12 +0000)
lib/action/action.h [new file with mode: 0755]
lib/action/assembler.c [new file with mode: 0644]
lib/action/assembler.h [new file with mode: 0644]
lib/action/compile.c [new file with mode: 0755]
lib/action/compile.h [new file with mode: 0755]
lib/action/listaction.c [new file with mode: 0755]
lib/action/swf4compiler.flex [new file with mode: 0755]
lib/action/swf4compiler.y [new file with mode: 0755]
lib/action/swf5compiler.flex [new file with mode: 0644]
lib/action/swf5compiler.y [new file with mode: 0644]

diff --git a/lib/action/action.h b/lib/action/action.h
new file mode 100755 (executable)
index 0000000..5c35ce4
--- /dev/null
@@ -0,0 +1,119 @@
+/* action.h
+ *
+ * $Id: action.h,v 1.1 2004/02/02 10:12:34 kramm Exp $
+ * 
+ * Notice: This header file contains declarations of functions and types that
+ * are just used internally. All library functions and types that are supposed
+ * to be publicly accessable are defined in ./src/ming.h.
+ */
+
+#ifndef SWF_COMPILER_ACTION_H_INCLUDED
+#define SWF_COMPILER_ACTION_H_INCLUDED
+
+#include "ming.h"
+
+enum
+{
+  SWFACTION_END        = 0x00,
+
+/* v3 actions */
+  SWFACTION_NEXTFRAME     = 0x04,
+  SWFACTION_PREVFRAME     = 0x05,
+  SWFACTION_PLAY          = 0x06,
+  SWFACTION_STOP          = 0x07,
+  SWFACTION_TOGGLEQUALITY = 0x08,
+  SWFACTION_STOPSOUNDS    = 0x09,
+  SWFACTION_GOTOFRAME     = 0x81, /* >= 0x80 means record has args */
+  SWFACTION_GETURL        = 0x83,
+  SWFACTION_WAITFORFRAME  = 0x8A,
+  SWFACTION_SETTARGET     = 0x8B,
+  SWFACTION_GOTOLABEL     = 0x8C,
+
+/* v4 actions */
+  SWFACTION_ADD                     = 0x0A,
+  SWFACTION_SUBTRACT                = 0x0B,
+  SWFACTION_MULTIPLY                = 0x0C,
+  SWFACTION_DIVIDE                  = 0x0D,
+  SWFACTION_EQUAL                   = 0x0E,
+  SWFACTION_LESSTHAN                = 0x0F,
+  SWFACTION_LOGICALAND              = 0x10,
+  SWFACTION_LOGICALOR               = 0x11,
+  SWFACTION_LOGICALNOT              = 0x12,
+  SWFACTION_STRINGEQ                = 0x13,
+  SWFACTION_STRINGLENGTH            = 0x14,
+  SWFACTION_SUBSTRING               = 0x15,
+  SWFACTION_POP                     = 0x17,
+  SWFACTION_INT                     = 0x18,
+  SWFACTION_GETVARIABLE             = 0x1C,
+  SWFACTION_SETVARIABLE             = 0x1D,
+  SWFACTION_SETTARGETEXPRESSION     = 0x20,
+  SWFACTION_STRINGCONCAT            = 0x21,
+  SWFACTION_GETPROPERTY             = 0x22,
+  SWFACTION_SETPROPERTY             = 0x23,
+  SWFACTION_DUPLICATECLIP           = 0x24,
+  SWFACTION_REMOVECLIP              = 0x25,
+  SWFACTION_TRACE                   = 0x26,
+  SWFACTION_STARTDRAGMOVIE          = 0x27,
+  SWFACTION_STOPDRAGMOVIE           = 0x28,
+  SWFACTION_STRINGCOMPARE           = 0x29,
+  SWFACTION_RANDOM                  = 0x30,
+  SWFACTION_MBLENGTH                = 0x31,
+  SWFACTION_ORD                     = 0x32,
+  SWFACTION_CHR                     = 0x33,
+  SWFACTION_GETTIMER                = 0x34,
+  SWFACTION_MBSUBSTRING             = 0x35,
+  SWFACTION_MBORD                   = 0x36,
+  SWFACTION_MBCHR                   = 0x37,
+
+  SWFACTION_WAITFORFRAMEEXPRESSION  = 0x8D,
+  SWFACTION_PUSHDATA                = 0x96,
+  SWFACTION_BRANCHALWAYS            = 0x99,
+  SWFACTION_GETURL2                 = 0x9A,
+  SWFACTION_BRANCHIFTRUE            = 0x9D,
+  SWFACTION_CALLFRAME               = 0x9E,
+  SWFACTION_GOTOEXPRESSION          = 0x9F,
+
+/* v5 actions */
+  SWFACTION_DELETEVAR               = 0x3A,/*not used yet*/
+  SWFACTION_DELETE                  = 0x3B,
+  SWFACTION_VAREQUALS               = 0x3C,
+  SWFACTION_CALLFUNCTION            = 0x3D,
+  SWFACTION_RETURN                  = 0x3E,
+  SWFACTION_MODULO                  = 0x3F,
+  SWFACTION_NEW                     = 0x40,
+  SWFACTION_VAR                     = 0x41,
+  SWFACTION_INITARRAY               = 0x42,
+  SWFACTION_INITOBJECT              = 0x43,
+  SWFACTION_TYPEOF                  = 0x44,
+  SWFACTION_TARGETPATH              = 0x45,
+  SWFACTION_ENUMERATE               = 0x46,
+  SWFACTION_NEWADD                  = 0x47,
+  SWFACTION_NEWLESSTHAN             = 0x48,
+  SWFACTION_NEWEQUALS               = 0x49,
+  SWFACTION_TONUMBER                = 0x4A,
+  SWFACTION_TOSTRING                = 0x4B,
+  SWFACTION_DUP                     = 0x4C,
+  SWFACTION_SWAP                    = 0x4D,
+  SWFACTION_GETMEMBER               = 0x4E,
+  SWFACTION_SETMEMBER               = 0x4F,
+  SWFACTION_INCREMENT               = 0x50,
+  SWFACTION_DECREMENT               = 0x51,
+  SWFACTION_CALLMETHOD              = 0x52,
+  SWFACTION_NEWMETHOD               = 0x53,/*not used yet*/
+  SWFACTION_INSTANCEOF              = 0x54,
+  SWFACTION_ENUM2                   = 0x55,/*not used yet*/
+  SWFACTION_BITWISEAND              = 0x60,
+  SWFACTION_BITWISEOR               = 0x61,
+  SWFACTION_BITWISEXOR              = 0x62,
+  SWFACTION_SHIFTLEFT               = 0x63,
+  SWFACTION_SHIFTRIGHT              = 0x64,
+  SWFACTION_SHIFTRIGHT2             = 0x65,
+  SWFACTION_STRICTEQ                = 0x66,
+  SWFACTION_CONSTANTPOOL            = 0x88,
+  SWFACTION_WITH                    = 0x94,
+  SWFACTION_DEFINEFUNCTION          = 0x9B,
+
+  SWFACTION_SETREGISTER             = 0x87
+};
+
+#endif /* SWF_COMPILER_ACTION_H_INCLUDED */
diff --git a/lib/action/assembler.c b/lib/action/assembler.c
new file mode 100644 (file)
index 0000000..8526e99
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+    Ming, an SWF output library
+    Copyright (C) 2002  Opaque Industries - http://www.opaque.net/
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <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:
+ */
diff --git a/lib/action/assembler.h b/lib/action/assembler.h
new file mode 100644 (file)
index 0000000..c8e0388
--- /dev/null
@@ -0,0 +1,21 @@
+/* assembler.h
+ * 
+ * $Id: assembler.h,v 1.1 2004/02/02 10:12:34 kramm Exp $
+ * 
+ * Notice: This header file contains declarations of functions and types that
+ * are just used internally. All library functions and types that are supposed
+ * to be publicly accessable are defined in ./src/ming.h.
+ */
+
+#ifndef SWF_ASSEMBLER_H_INCLUDED
+#define SWF_ASSEMBLER_H_INCLUDED
+
+#include "ming.h"
+#include "compile.h"
+
+extern Buffer asmBuffer;
+
+void bufferPatchLength(Buffer buffer, int len);
+int bufferBranchTarget(Buffer buffer, char *label);
+
+#endif /* SWF_ASSEMBLER_H_INCLUDED */
diff --git a/lib/action/compile.c b/lib/action/compile.c
new file mode 100755 (executable)
index 0000000..b658dd2
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+    Ming, an SWF output library
+    Copyright (C) 2002  Opaque Industries - http://www.opaque.net/
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef WIN32
+       #include <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:
+ */
diff --git a/lib/action/compile.h b/lib/action/compile.h
new file mode 100755 (executable)
index 0000000..cdedc2a
--- /dev/null
@@ -0,0 +1,163 @@
+/* compile.h
+ * 
+ * $Id: compile.h,v 1.1 2004/02/02 10:12:34 kramm Exp $
+ * 
+ * Notice: This header file contains declarations of functions and types that
+ * are just used internally. All library functions and types that are supposed
+ * to be publicly accessable are defined in ./src/ming.h.
+ */
+
+#ifndef SWF_COMPILE_H_INCLUDED
+#define SWF_COMPILE_H_INCLUDED
+
+#include "ming.h"
+
+typedef struct _buffer *Buffer;
+
+/* shut up bison.simple */
+void yyerror(char *msg);
+int yylex();
+
+#ifndef max
+  #define max(x,y)     (((x)>(y))?(x):(y))
+#endif
+
+enum
+{
+  PUSH_STRING = 0,
+  PUSH_PROPERTY = 1,
+  PUSH_NULL = 2,
+  PUSH_UNDEF = 3,
+  PUSH_REGISTER = 4,
+  PUSH_BOOLEAN = 5,
+  PUSH_DOUBLE = 6,
+  PUSH_INT = 7,
+  PUSH_CONSTANT = 8,
+  PUSH_CONSTANT16 = 9
+};
+
+typedef enum
+{
+  FUNCTION_RANDOM,
+  FUNCTION_LENGTH,
+  FUNCTION_TIME,
+  FUNCTION_INT,
+  FUNCTION_CONCAT,
+  FUNCTION_DUPLICATECLIP
+} SWFActionFunction;
+
+typedef enum
+{
+  GETURL_METHOD_NOSEND = 0,
+  GETURL_METHOD_GET    = 1,
+  GETURL_METHOD_POST   = 2
+} SWFGetUrl2Method;
+
+#define GETURL_LOADMOVIE 0x40
+#define GETURL_LOADVARIABLES 0x80
+
+#define MAGIC_CONTINUE_NUMBER 0x7FFE
+#define MAGIC_BREAK_NUMBER    0x7FFF
+
+#define MAGIC_CONTINUE_NUMBER_LO 0xFE
+#define MAGIC_CONTINUE_NUMBER_HI 0x7F
+#define MAGIC_BREAK_NUMBER_LO    0xFF
+#define MAGIC_BREAK_NUMBER_HI    0x7F
+
+#define BUFFER_INCREMENT 128
+
+struct _buffer
+{
+  byte *buffer;
+  byte *pos;
+  int buffersize;
+  int free;
+  byte *pushloc;
+};
+
+#define BUFFER_SIZE sizeof(struct _buffer)
+
+struct switchcase
+{      Buffer cond, action;
+       int condlen, actlen, isbreak;
+};
+
+struct switchcases
+{
+       struct switchcase *list;
+       int count;
+};
+
+enum ctx
+{
+       CTX_FUNCTION = 1,
+       CTX_LOOP,
+       CTX_FOR_IN,
+       CTX_SWITCH,
+
+       CTX_BREAK,
+       CTX_CONTINUE
+};
+
+void addctx(enum ctx val);
+void delctx(enum ctx val);
+int chkctx(enum ctx val);
+
+void checkByteOrder();
+
+/* create/destroy buffer object */
+Buffer newBuffer();
+void destroyBuffer(Buffer out);
+int bufferConcat(Buffer a, Buffer b);        /* destroys b. */
+int bufferWriteBuffer(Buffer a, Buffer b);   /* doesn't. */
+
+/* utilities for writing */
+void bufferGrow(Buffer out);
+void bufferCheckSize(Buffer out, int bytes);
+
+int bufferLength(Buffer out);
+
+/* constant pool stuff */
+int addConstant(const char *s);
+int bufferWriteConstants(Buffer out);
+#define MAXCONSTANTPOOLSIZE 65533
+
+/* write data to buffer */
+int bufferWriteOp(Buffer out, int data);
+int bufferWritePushOp(Buffer out);
+int bufferWriteU8(Buffer out, int data);
+int bufferWriteS16(Buffer out, int data);
+int bufferWriteData(Buffer out, const byte *buffer, int bytes);
+int bufferWriteHardString(Buffer out, byte *string, int length);
+int bufferWriteConstantString(Buffer out, byte *string, int length);
+int bufferWriteString(Buffer out, byte *string, int length);
+#ifdef __cplusplus
+/* helper function to avoid many casts */
+inline int bufferWriteString(Buffer out, char *string, int length) {
+       return bufferWriteString(out,(byte*) string, length); }
+#endif
+int bufferWriteInt(Buffer out, int i);
+int bufferWriteDouble(Buffer out, double d);
+int bufferWriteNull(Buffer out);
+int bufferWriteBoolean(Buffer out, int val);
+int bufferWriteRegister(Buffer out, int num);
+int bufferWriteSetRegister(Buffer out, int num);
+int bufferWriteGetProperty(Buffer out, char *string);
+int bufferWriteSetProperty(Buffer out, char *string);
+int bufferWriteWTHITProperty(Buffer out);
+
+/* concat b to a, destroy b */
+char *stringConcat(char *a, char *b);
+
+/* resolve magic number standins to relative offsets */
+void bufferResolveJumps(Buffer out);
+void bufferResolveSwitch(Buffer buffer, struct switchcases *slp);
+
+/* rather than setting globals... */
+void swf4ParseInit(const char *string, int debug);
+void swf5ParseInit(const char *string, int debug);
+
+int swf4parse(void *b);
+int swf5parse(void *b);
+
+#endif /* SWF_COMPILE_H_INCLUDED */
diff --git a/lib/action/listaction.c b/lib/action/listaction.c
new file mode 100755 (executable)
index 0000000..b3309ce
--- /dev/null
@@ -0,0 +1,557 @@
+#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))
+    ;
+}
diff --git a/lib/action/swf4compiler.flex b/lib/action/swf4compiler.flex
new file mode 100755 (executable)
index 0000000..6a6dddd
--- /dev/null
@@ -0,0 +1,403 @@
+%{
+
+#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());
+  }
+}
diff --git a/lib/action/swf4compiler.y b/lib/action/swf4compiler.y
new file mode 100755 (executable)
index 0000000..c57ab9a
--- /dev/null
@@ -0,0 +1,1039 @@
+/* $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
+       ;
+
+%%
diff --git a/lib/action/swf5compiler.flex b/lib/action/swf5compiler.flex
new file mode 100644 (file)
index 0000000..86a74a3
--- /dev/null
@@ -0,0 +1,467 @@
+%{
+
+#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());
+  }
+}
diff --git a/lib/action/swf5compiler.y b/lib/action/swf5compiler.y
new file mode 100644 (file)
index 0000000..d80acb0
--- /dev/null
@@ -0,0 +1,1698 @@
+/* $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); }
+       ;
+
+%%
+