TinyJS on mbed. TinyJS is very simple JavaScript engine.

Dependencies:   mbed

TinyJS on mbed

what's this ?

TinyJS is an extremely simple (under than 2000 lines) JavaScript interpreter engine.
I ported on mbed. but it restrict any features.
TinyJS project is https://github.com/gfwilliams/tiny-js

TinyJSは2000行以下で書かれた非常に小さいJavaScriptインタプリタエンジンです。
これをmbedに移植してみました。(ただし、いろいろ制限があります)
本家はこちら。 https://github.com/gfwilliams/tiny-js

how to use

You must use on serial terminal application by mbed serial USB.
baud is 57600bps
USBシリアルとして、ターミナルソフトを接続するとコンソールが表示されます。
ボーレートは57600bpsになってます。

functions

functions for mbed.
mbed用関数

  • mbed.DigitalIn(pinName, mode)
  • mbed.DigitalOut(pinName, val)
  • mbed.AnalogIn(pinName)
  • mbed.AnalogOut(pinName, val)
  • mbed.InterruptIn(pinName, edge, mode, callback)
  • mbed.TimerStart()
  • mbed.TimerStop()
  • mbed.TimerReset()
  • mbed.TimerRead()
  • mbed.Timeout(callback, t)
  • mbed.wait(s)
  • mbed.memfree()

sample JavaScript codes

DigitalOut

mbed.DigitalOut('LED1', 1);
mbed.DigitalOut('LED2', 0);
mbed.DigitalOut('LED3', 1);
mbed.DigitalOut('LED4', 0);

LED1 = On, LED2=Off, LED3=On, ED4=Off
LED1 = 点灯、LED2=消灯、LED3=点灯、LED4=消灯

DigitalIn

print(mbed.DigitalIn('p5', 'PullUp'));

p5 is pull up, read, and print on console.
p5をPullUpして読みプリントする。

AnalogOut

mbed.AnalogOut('p18', 0.8);

p18 is analog output, value is 0.8.
p18を 値0.8でアナログ出力する。

AnalogIn

print(mbed.AnalogIn('p20'));

p20 is read analog voltage, and print on console.
p20をアナログ入力しプリントする。

InterruptIn

var led1 = 0;
mbed.InterruptIn('p5', 'fall', 'PullUp', function() {led1 = !led1; mbed.DigitalOut('LED1', led1);});

Interrupt on p5, and ON/OFF does LED1.
p5で割り込んでLED1をON/OFFする。

Timeout and wait sample code

mbed.Timeout(function() {mbed.DigitalOut('LED1', 1);mbed.wait(3);mbed.DigitalOut('LED1', 0);}, 4);

LED1=on when wait for 4 seconds. and LED1=off for 3 seconds later.
LED1を4秒待って点灯して3秒後に消灯する。

memfree

print(mbed.memfree());

This prints the number of bytes of the remainder memory on mbed where TinyJS is usable.
これはTinyJSが使えるmbed上での残りメモリのバイト数をプリントアウトする。

LED Blinker by Timeout

blinker = function() {var led = 0; mbed.Timeout(function() {led = !led; mbed.DigitalOut('LED1', led);blinker();}, 0.5);};
blinker();

LED Blinker by Timeout.
Timeoutを使ったLチカ。

restrictions

  • There is very little available memory. (Less than 9kbytes on LPC1768)
  • Registration of InterruptIn is 4 limit.
  • The loop to 8,192 times.
  • The built-in functions (general JavaScript functions) that TinyJS prepares for for securing of memory is not included.

more, more, more ....

制限事項

  • 利用できるメモリは非常に少ない。(LPC1768で9kbytes以下)
  • InterruptInで登録できる割り込みは4つまで。4つを超えると1つめから順番に削除される。
  • ループは8192回まで。
  • メモリ確保のためTinyJSが用意している組み込み関数(一般的なJavaScript関数)は含まれない。

他、多数....

sample movies

http://www.youtube.com/watch?v=ARp0DK70JGM
http://www.youtube.com/watch?v=UOZQ4eEC4xA

Files at this revision

API Documentation at this revision

Comitter:
ohneta
Date:
Sat Jan 11 20:19:11 2014 +0000
Child:
1:d793f113cfc0
Commit message:
TinyJS for mbed porting.; 1st edition.

Changed in this revision

Script.cpp Show annotated file Show diff for this revision Revisions of this file
TinyJS.cpp Show annotated file Show diff for this revision Revisions of this file
TinyJS.h Show annotated file Show diff for this revision Revisions of this file
TinyJS_Functions.cpp Show annotated file Show diff for this revision Revisions of this file
TinyJS_Functions.h Show annotated file Show diff for this revision Revisions of this file
TinyJS_MathFunctions.cpp Show annotated file Show diff for this revision Revisions of this file
TinyJS_MathFunctions.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Script.cpp	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,148 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This is a simple program showing how to use TinyJS
+ */
+
+/*
+ * TinyJS for mbed.
+ *
+ * Authored by Takehisa Oneta (ohneta@gmail.com)
+ * 10th Jan. 2013
+ */
+#include "TinyJS.h"
+#include "TinyJS_Functions.h"
+#include <assert.h>
+#include <stdio.h>
+
+#include "mbed.h"
+
+
+//const char *code = "var a = 5; if (a==5) a=4; else a=3;";
+//const char *code = "{ var a = 4; var b = 1; while (a>0) { b = b * 2; a = a - 1; } var c = 5; }";
+//const char *code = "{ var b = 1; for (var i=0;i<4;i=i+1) b = b * 2; }";
+const char *code = "function myfunc(x, y) { return x + y; } var a = myfunc(1,2); print(a);";
+
+void js_print(CScriptVar *v, void *userdata) {
+    printf("> %s\n", v->getParameter("text")->getString().c_str());
+}
+
+void js_dump(CScriptVar *v, void *userdata) {
+    CTinyJS *js = (CTinyJS*)userdata;
+    js->root->trace(">  ");
+}
+
+#ifndef MBED
+int main(int argc, char **argv)
+{
+  CTinyJS *js = new CTinyJS();
+  /* add the functions from TinyJS_Functions.cpp */
+  registerFunctions(js);
+  /* Add a native function */
+  js->addNative("function print(text)", &js_print, 0);
+  js->addNative("function dump()", &js_dump, js);
+  /* Execute out bit of code - we could call 'evaluate' here if
+     we wanted something returned */
+  try {
+    js->execute("var lets_quit = 0; function quit() { lets_quit = 1; }");
+    js->execute("print(\"Interactive mode... Type quit(); to exit, or print(...); to print something, or dump() to dump the symbol table!\");");
+  } catch (CScriptException *e) {
+    printf("ERROR: %s\n", e->text.c_str());
+  }
+
+  while (js->evaluate("lets_quit") == "0") {
+    char buffer[2048];
+    fgets ( buffer, sizeof(buffer), stdin );
+    try {
+      js->execute(buffer);
+    } catch (CScriptException *e) {
+      printf("ERROR: %s\n", e->text.c_str());
+    }
+  }
+  delete js;
+#ifdef _WIN32
+#ifdef _DEBUG
+  _CrtDumpMemoryLeaks();
+#endif
+#endif
+  return 0;
+}
+#else
+
+int mbedErrorFlag;
+std::string mbedErrorMessage;
+
+extern int readOneLine(char *buffer, const int bufferSize);
+
+// mbed function(s)
+extern void mbedDigitalOut(CScriptVar *c, void *);
+extern char *mbedLedsVarString(int ledNo);
+extern void mbedMemfree(CScriptVar *c, void *);
+
+
+int tinyjs_main(int argc, char **argv)
+{
+  CTinyJS *js = new CTinyJS();
+  //registerFunctions(js);
+
+  js->addNative("function print(text)", &js_print, 0);
+  js->addNative("function dump()", &js_dump, js);
+
+  js->execute("var lets_quit = 0; function quit() { lets_quit = 1; }");
+  js->execute("print(\"Interactive mode... Type quit(); to exit, or print(...); to print something, or dump() to dump the symbol table!\");");
+
+  // add mbed functions
+  js->addNative("function mbed.memfree()", &mbedMemfree, 0);
+  js->addNative("function mbed.DigitalOut(pinName, val)", &mbedDigitalOut, 0);
+  js->execute(mbedLedsVarString(1));
+  js->execute(mbedLedsVarString(2));
+  js->execute(mbedLedsVarString(3));
+  js->execute(mbedLedsVarString(4));
+
+  while (js->evaluate("lets_quit") == "0") {
+    char buffer[2048];
+    int len = readOneLine(buffer, 2048);
+    {
+      mbedErrorFlag = 0;
+      js->execute(buffer);
+      if (mbedErrorFlag != 0) {
+        printf("ERROR: %s\n", mbedErrorMessage.c_str());
+      }
+    }
+  }
+  delete js;
+
+#ifdef _WIN32
+#ifdef _DEBUG
+  _CrtDumpMemoryLeaks();
+#endif
+#endif
+  return 0;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyJS.cpp	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,2927 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Version 0.1  :  (gw) First published on Google Code
+   Version 0.11 :  Making sure the 'root' variable never changes
+                   'symbol_base' added for the current base of the sybmbol table
+   Version 0.12 :  Added findChildOrCreate, changed string passing to use references
+                   Fixed broken string encoding in getJSString()
+                   Removed getInitCode and added getJSON instead
+                   Added nil
+                   Added rough JSON parsing
+                   Improved example app
+   Version 0.13 :  Added tokenEnd/tokenLastEnd to lexer to avoid parsing whitespace
+                   Ability to define functions without names
+                   Can now do "var mine = function(a,b) { ... };"
+                   Slightly better 'trace' function
+                   Added findChildOrCreateByPath function
+                   Added simple test suite
+                   Added skipping of blocks when not executing
+   Version 0.14 :  Added parsing of more number types
+                   Added parsing of string defined with '
+                   Changed nil to null as per spec, added 'undefined'
+                   Now set variables with the correct scope, and treat unknown
+                              as 'undefined' rather than failing
+                   Added proper (I hope) handling of null and undefined
+                   Added === check
+   Version 0.15 :  Fix for possible memory leaks
+   Version 0.16 :  Removal of un-needed findRecursive calls
+                   symbol_base removed and replaced with 'scopes' stack
+                   Added reference counting a proper tree structure
+                       (Allowing pass by reference)
+                   Allowed JSON output to output IDs, not strings
+                   Added get/set for array indices
+                   Changed Callbacks to include user data pointer
+                   Added some support for objects
+                   Added more Java-esque builtin functions
+   Version 0.17 :  Now we don't deepCopy the parent object of the class
+                   Added JSON.stringify and eval()
+                   Nicer JSON indenting
+                   Fixed function output in JSON
+                   Added evaluateComplex
+                   Fixed some reentrancy issues with evaluate/execute
+   Version 0.18 :  Fixed some issues with code being executed when it shouldn't
+   Version 0.19 :  Added array.length
+                   Changed '__parent' to 'prototype' to bring it more in line with javascript
+   Version 0.20 :  Added '%' operator
+   Version 0.21 :  Added array type
+                   String.length() no more - now String.length
+                   Added extra constructors to reduce confusion
+                   Fixed checks against undefined
+   Version 0.22 :  First part of ardi's changes:
+                       sprintf -> sprintf_s
+                       extra tokens parsed
+                       array memory leak fixed
+                   Fixed memory leak in evaluateComplex
+                   Fixed memory leak in FOR loops
+                   Fixed memory leak for unary minus
+   Version 0.23 :  Allowed evaluate[Complex] to take in semi-colon separated
+                     statements and then only return the value from the last one.
+                     Also checks to make sure *everything* was parsed.
+                   Ints + doubles are now stored in binary form (faster + more precise)
+   Version 0.24 :  More useful error for maths ops
+                   Don't dump everything on a match error.
+   Version 0.25 :  Better string escaping
+   Version 0.26 :  Add CScriptVar::equals
+                   Add built-in array functions
+   Version 0.27 :  Added OZLB's TinyJS.setVariable (with some tweaks)
+                   Added OZLB's Maths Functions
+   Version 0.28 :  Ternary operator
+                   Rudimentary call stack on error
+                   Added String Character functions
+                   Added shift operators
+   Version 0.29 :  Added new object via functions
+                   Fixed getString() for double on some platforms
+   Version 0.30 :  Rlyeh Mario's patch for Math Functions on VC++
+   Version 0.31 :  Add exec() to TinyJS functions
+                   Now print quoted JSON that can be read by PHP/Python parsers
+                   Fixed postfix increment operator
+   Version 0.32 :  Fixed Math.randInt on 32 bit PCs, where it was broken
+   Version 0.33 :  Fixed Memory leak + brokenness on === comparison
+
+    NOTE:
+          Constructing an array with an initial length 'Array(5)' doesn't work
+          Recursive loops of data such as a.foo = a; fail to be garbage collected
+          length variable cannot be set
+          The postfix increment operator returns the current value, not the previous as it should.
+          There is no prefix increment operator
+          Arrays are implemented as a linked list - hence a lookup time is O(n)
+
+    TODO:
+          Utility va-args style function in TinyJS for executing a function directly
+          Merge the parsing of expressions/statements so eval("statement") works like we'd expect.
+          Move 'shift' implementation into mathsOp
+
+ */
+/*
+ * TinyJS for mbed.
+ *
+ * Authored by Takehisa Oneta (ohneta@gmail.com)
+ * 10th Jan. 2013
+ */
+
+#include "TinyJS.h"
+#include <assert.h>
+
+#define ASSERT(X) assert(X)
+/* Frees the given link IF it isn't owned by anything else */
+#define CLEAN(x) { CScriptVarLink *__v = x; if (__v && !__v->owned) { delete __v; } }
+/* Create a LINK to point to VAR and free the old link.
+ * BUT this is more clever - it tries to keep the old link if it's not owned to save allocations */
+#define CREATE_LINK(LINK, VAR) { if (!LINK || LINK->owned) LINK = new CScriptVarLink(VAR); else LINK->replaceWith(VAR); }
+
+#include <string>
+#include <string.h>
+#include <sstream>
+#include <cstdlib>
+#include <stdio.h>
+
+using namespace std;
+
+#ifdef _WIN32
+#ifdef _DEBUG
+   #ifndef DBG_NEW
+      #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+      #define new DBG_NEW
+   #endif
+#endif
+#endif
+
+#ifdef __GNUC__
+#define vsprintf_s vsnprintf
+#define sprintf_s snprintf
+#ifndef MBED
+#define _strdup strdup
+#else
+char *_strdup(const char *str)
+{
+    size_t siz;
+    char *copy;
+
+    siz = strlen(str) + 1;
+    if ((copy = (char *)malloc(siz)) == NULL)
+        return(NULL);
+    (void)memcpy(copy, str, siz);
+    return(copy);
+}
+#endif
+#endif
+
+#ifdef MBED
+extern int mbedErrorFlag;
+extern std::string mbedErrorMessage;  
+
+#define LMATCH_VOID(c)  {mbedErrorFlag = 0;l->match(c);if (mbedErrorFlag != 0) return;}
+#define LMATCH(c)  {mbedErrorFlag = 0;l->match(c);if (mbedErrorFlag != 0) return 0;}
+//#define LMATCH_VOID(c)  {l->match(c);}
+//#define LMATCH(c)  {l->match(c);}
+#endif
+
+
+// ----------------------------------------------------------------------------------- Memory Debug
+
+#if DEBUG_MEMORY
+
+vector<CScriptVar*> allocatedVars;
+vector<CScriptVarLink*> allocatedLinks;
+
+void mark_allocated(CScriptVar *v) {
+    allocatedVars.push_back(v);
+}
+
+void mark_deallocated(CScriptVar *v) {
+    for (size_t i=0;i<allocatedVars.size();i++) {
+      if (allocatedVars[i] == v) {
+        allocatedVars.erase(allocatedVars.begin()+i);
+        break;
+      }
+    }
+}
+
+void mark_allocated(CScriptVarLink *v) {
+    allocatedLinks.push_back(v);
+}
+
+void mark_deallocated(CScriptVarLink *v) {
+    for (size_t i=0;i<allocatedLinks.size();i++) {
+      if (allocatedLinks[i] == v) {
+        allocatedLinks.erase(allocatedLinks.begin()+i);
+        break;
+      }
+    }
+}
+
+void show_allocated() {
+    for (size_t i=0;i<allocatedVars.size();i++) {
+      printf("ALLOCATED, %d refs\n", allocatedVars[i]->getRefs());
+      allocatedVars[i]->trace("  ");
+    }
+    for (size_t i=0;i<allocatedLinks.size();i++) {
+      printf("ALLOCATED LINK %s, allocated[%d] to \n", allocatedLinks[i]->name.c_str(), allocatedLinks[i]->var->getRefs());
+      allocatedLinks[i]->var->trace("  ");
+    }
+    allocatedVars.clear();
+    allocatedLinks.clear();
+}
+#endif
+
+// ----------------------------------------------------------------------------------- Utils
+bool isWhitespace(char ch) {
+    return (ch==' ') || (ch=='\t') || (ch=='\n') || (ch=='\r');
+}
+
+bool isNumeric(char ch) {
+    return (ch>='0') && (ch<='9');
+}
+bool isNumber(const string &str) {
+    for (size_t i=0;i<str.size();i++)
+      if (!isNumeric(str[i])) return false;
+    return true;
+}
+bool isHexadecimal(char ch) {
+    return ((ch>='0') && (ch<='9')) ||
+           ((ch>='a') && (ch<='f')) ||
+           ((ch>='A') && (ch<='F'));
+}
+bool isAlpha(char ch) {
+    return ((ch>='a') && (ch<='z')) || ((ch>='A') && (ch<='Z')) || ch=='_';
+}
+
+bool isIDString(const char *s) {
+    if (!isAlpha(*s))
+        return false;
+    while (*s) {
+        if (!(isAlpha(*s) || isNumeric(*s)))
+            return false;
+        s++;
+    }
+    return true;
+}
+
+void replace(string &str, char textFrom, const char *textTo) {
+    int sLen = strlen(textTo);
+    size_t p = str.find(textFrom);
+    while (p != string::npos) {
+        str = str.substr(0, p) + textTo + str.substr(p+1);
+        p = str.find(textFrom, p+sLen);
+    }
+}
+
+/// convert the given string into a quoted string suitable for javascript
+std::string getJSString(const std::string &str) {
+    std::string nStr = str;
+    for (size_t i=0;i<nStr.size();i++) {
+      const char *replaceWith = "";
+      bool replace = true;
+
+      switch (nStr[i]) {
+        case '\\': replaceWith = "\\\\"; break;
+        case '\n': replaceWith = "\\n"; break;
+        case '\r': replaceWith = "\\r"; break;
+        case '\a': replaceWith = "\\a"; break;
+        case '"': replaceWith = "\\\""; break;
+        default: {
+          int nCh = ((int)nStr[i]) &0xFF;
+          if (nCh<32 || nCh>127) {
+            char buffer[5];
+            sprintf_s(buffer, 5, "\\x%02X", nCh);
+            replaceWith = buffer;
+          } else replace=false;
+        }
+      }
+
+      if (replace) {
+        nStr = nStr.substr(0, i) + replaceWith + nStr.substr(i+1);
+        i += strlen(replaceWith)-1;
+      }
+    }
+    return "\"" + nStr + "\"";
+}
+
+/** Is the string alphanumeric */
+bool isAlphaNum(const std::string &str) {
+    if (str.size()==0) return true;
+    if (!isAlpha(str[0])) return false;
+    for (size_t i=0;i<str.size();i++)
+      if (!(isAlpha(str[i]) || isNumeric(str[i])))
+        return false;
+    return true;
+}
+
+// ----------------------------------------------------------------------------------- CSCRIPTEXCEPTION
+
+CScriptException::CScriptException(const string &exceptionText) {
+    text = exceptionText;
+}
+
+// ----------------------------------------------------------------------------------- CSCRIPTLEX
+
+CScriptLex::CScriptLex(const string &input) {
+    data = _strdup(input.c_str());
+    dataOwned = true;
+    dataStart = 0;
+    dataEnd = strlen(data);
+    reset();
+}
+
+CScriptLex::CScriptLex(CScriptLex *owner, int startChar, int endChar) {
+    data = owner->data;
+    dataOwned = false;
+    dataStart = startChar;
+    dataEnd = endChar;
+    reset();
+}
+
+CScriptLex::~CScriptLex(void)
+{
+    if (dataOwned)
+        free((void*)data);
+}
+
+void CScriptLex::reset() {
+    dataPos = dataStart;
+    tokenStart = 0;
+    tokenEnd = 0;
+    tokenLastEnd = 0;
+    tk = 0;
+    tkStr = "";
+    getNextCh();
+    getNextCh();
+    getNextToken();
+}
+
+void CScriptLex::match(int expected_tk) {
+    if (tk!=expected_tk) {
+#ifndef MBED
+        ostringstream errorString;
+        errorString << "Got " << getTokenStr(tk) << " expected " << getTokenStr(expected_tk)
+         << " at " << getPosition(tokenStart);
+        throw new CScriptException(errorString.str());
+#else
+        mbedErrorFlag = 1;
+        mbedErrorMessage = "Got ";
+        mbedErrorMessage += getTokenStr(tk);
+        mbedErrorMessage += " expected ";
+        mbedErrorMessage += getTokenStr(expected_tk);
+        mbedErrorMessage += " at ";
+        mbedErrorMessage += getPosition(tokenStart);
+        return;
+#endif
+    }
+    getNextToken();
+}
+
+string CScriptLex::getTokenStr(int token) {
+    if (token>32 && token<128) {
+        char buf[4] = "' '";
+        buf[1] = (char)token;
+        return buf;
+    }
+    switch (token) {
+        case LEX_EOF : return "EOF";
+        case LEX_ID : return "ID";
+        case LEX_INT : return "INT";
+        case LEX_FLOAT : return "FLOAT";
+        case LEX_STR : return "STRING";
+        case LEX_EQUAL : return "==";
+        case LEX_TYPEEQUAL : return "===";
+        case LEX_NEQUAL : return "!=";
+        case LEX_NTYPEEQUAL : return "!==";
+        case LEX_LEQUAL : return "<=";
+        case LEX_LSHIFT : return "<<";
+        case LEX_LSHIFTEQUAL : return "<<=";
+        case LEX_GEQUAL : return ">=";
+        case LEX_RSHIFT : return ">>";
+        case LEX_RSHIFTUNSIGNED : return ">>";
+        case LEX_RSHIFTEQUAL : return ">>=";
+        case LEX_PLUSEQUAL : return "+=";
+        case LEX_MINUSEQUAL : return "-=";
+        case LEX_PLUSPLUS : return "++";
+        case LEX_MINUSMINUS : return "--";
+        case LEX_ANDEQUAL : return "&=";
+        case LEX_ANDAND : return "&&";
+        case LEX_OREQUAL : return "|=";
+        case LEX_OROR : return "||";
+        case LEX_XOREQUAL : return "^=";
+                // reserved words
+        case LEX_R_IF : return "if";
+        case LEX_R_ELSE : return "else";
+        case LEX_R_DO : return "do";
+        case LEX_R_WHILE : return "while";
+        case LEX_R_FOR : return "for";
+        case LEX_R_BREAK : return "break";
+        case LEX_R_CONTINUE : return "continue";
+        case LEX_R_FUNCTION : return "function";
+        case LEX_R_RETURN : return "return";
+        case LEX_R_VAR : return "var";
+        case LEX_R_TRUE : return "true";
+        case LEX_R_FALSE : return "false";
+        case LEX_R_NULL : return "null";
+        case LEX_R_UNDEFINED : return "undefined";
+        case LEX_R_NEW : return "new";
+    }
+
+#ifndef MBED
+    ostringstream msg;
+    msg << "?[" << token << "]";
+    return msg.str();
+#else
+    string msg;
+    msg = "?[";
+    msg += token;
+    msg += "]";
+    return msg;
+#endif
+}
+
+void CScriptLex::getNextCh() {
+    currCh = nextCh;
+    if (dataPos < dataEnd)
+        nextCh = data[dataPos];
+    else
+        nextCh = 0;
+    dataPos++;
+}
+
+void CScriptLex::getNextToken() {
+    tk = LEX_EOF;
+    tkStr.clear();
+    while (currCh && isWhitespace(currCh)) getNextCh();
+    // newline comments
+    if (currCh=='/' && nextCh=='/') {
+        while (currCh && currCh!='\n') getNextCh();
+        getNextCh();
+        getNextToken();
+        return;
+    }
+    // block comments
+    if (currCh=='/' && nextCh=='*') {
+        while (currCh && (currCh!='*' || nextCh!='/')) getNextCh();
+        getNextCh();
+        getNextCh();
+        getNextToken();
+        return;
+    }
+    // record beginning of this token
+    tokenStart = dataPos-2;
+    // tokens
+    if (isAlpha(currCh)) { //  IDs
+        while (isAlpha(currCh) || isNumeric(currCh)) {
+            tkStr += currCh;
+            getNextCh();
+        }
+        tk = LEX_ID;
+             if (tkStr=="if") tk = LEX_R_IF;
+        else if (tkStr=="else") tk = LEX_R_ELSE;
+        else if (tkStr=="do") tk = LEX_R_DO;
+        else if (tkStr=="while") tk = LEX_R_WHILE;
+        else if (tkStr=="for") tk = LEX_R_FOR;
+        else if (tkStr=="break") tk = LEX_R_BREAK;
+        else if (tkStr=="continue") tk = LEX_R_CONTINUE;
+        else if (tkStr=="function") tk = LEX_R_FUNCTION;
+        else if (tkStr=="return") tk = LEX_R_RETURN;
+        else if (tkStr=="var") tk = LEX_R_VAR;
+        else if (tkStr=="true") tk = LEX_R_TRUE;
+        else if (tkStr=="false") tk = LEX_R_FALSE;
+        else if (tkStr=="null") tk = LEX_R_NULL;
+        else if (tkStr=="undefined") tk = LEX_R_UNDEFINED;
+        else if (tkStr=="new") tk = LEX_R_NEW;
+    } else if (isNumeric(currCh)) { // Numbers
+        bool isHex = false;
+        if (currCh=='0') { tkStr += currCh; getNextCh(); }
+        if (currCh=='x') {
+          isHex = true;
+          tkStr += currCh; getNextCh();
+        }
+        tk = LEX_INT;
+        while (isNumeric(currCh) || (isHex && isHexadecimal(currCh))) {
+            tkStr += currCh;
+            getNextCh();
+        }
+        if (!isHex && currCh=='.') {
+            tk = LEX_FLOAT;
+            tkStr += '.';
+            getNextCh();
+            while (isNumeric(currCh)) {
+                tkStr += currCh;
+                getNextCh();
+            }
+        }
+        // do fancy e-style floating point
+        if (!isHex && (currCh=='e'||currCh=='E')) {
+          tk = LEX_FLOAT;
+          tkStr += currCh; getNextCh();
+          if (currCh=='-') { tkStr += currCh; getNextCh(); }
+          while (isNumeric(currCh)) {
+             tkStr += currCh; getNextCh();
+          }
+        }
+    } else if (currCh=='"') {
+        // strings...
+        getNextCh();
+        while (currCh && currCh!='"') {
+            if (currCh == '\\') {
+                getNextCh();
+                switch (currCh) {
+                case 'n' : tkStr += '\n'; break;
+                case '"' : tkStr += '"'; break;
+                case '\\' : tkStr += '\\'; break;
+                default: tkStr += currCh;
+                }
+            } else {
+                tkStr += currCh;
+            }
+            getNextCh();
+        }
+        getNextCh();
+        tk = LEX_STR;
+    } else if (currCh=='\'') {
+        // strings again...
+        getNextCh();
+        while (currCh && currCh!='\'') {
+            if (currCh == '\\') {
+                getNextCh();
+                switch (currCh) {
+                case 'n' : tkStr += '\n'; break;
+                case 'a' : tkStr += '\a'; break;
+                case 'r' : tkStr += '\r'; break;
+                case 't' : tkStr += '\t'; break;
+                case '\'' : tkStr += '\''; break;
+                case '\\' : tkStr += '\\'; break;
+                case 'x' : { // hex digits
+                              char buf[3] = "??";
+                              getNextCh(); buf[0] = currCh;
+                              getNextCh(); buf[1] = currCh;
+                              tkStr += (char)strtol(buf,0,16);
+                           } break;
+                default: if (currCh>='0' && currCh<='7') {
+                           // octal digits
+                           char buf[4] = "???";
+                           buf[0] = currCh;
+                           getNextCh(); buf[1] = currCh;
+                           getNextCh(); buf[2] = currCh;
+                           tkStr += (char)strtol(buf,0,8);
+                         } else
+                           tkStr += currCh;
+                }
+            } else {
+                tkStr += currCh;
+            }
+            getNextCh();
+        }
+        getNextCh();
+        tk = LEX_STR;
+    } else {
+        // single chars
+        tk = currCh;
+        if (currCh) getNextCh();
+        if (tk=='=' && currCh=='=') { // ==
+            tk = LEX_EQUAL;
+            getNextCh();
+            if (currCh=='=') { // ===
+              tk = LEX_TYPEEQUAL;
+              getNextCh();
+            }
+        } else if (tk=='!' && currCh=='=') { // !=
+            tk = LEX_NEQUAL;
+            getNextCh();
+            if (currCh=='=') { // !==
+              tk = LEX_NTYPEEQUAL;
+              getNextCh();
+            }
+        } else if (tk=='<' && currCh=='=') {
+            tk = LEX_LEQUAL;
+            getNextCh();
+        } else if (tk=='<' && currCh=='<') {
+            tk = LEX_LSHIFT;
+            getNextCh();
+            if (currCh=='=') { // <<=
+              tk = LEX_LSHIFTEQUAL;
+              getNextCh();
+            }
+        } else if (tk=='>' && currCh=='=') {
+            tk = LEX_GEQUAL;
+            getNextCh();
+        } else if (tk=='>' && currCh=='>') {
+            tk = LEX_RSHIFT;
+            getNextCh();
+            if (currCh=='=') { // >>=
+              tk = LEX_RSHIFTEQUAL;
+              getNextCh();
+            } else if (currCh=='>') { // >>>
+              tk = LEX_RSHIFTUNSIGNED;
+              getNextCh();
+            }
+        }  else if (tk=='+' && currCh=='=') {
+            tk = LEX_PLUSEQUAL;
+            getNextCh();
+        }  else if (tk=='-' && currCh=='=') {
+            tk = LEX_MINUSEQUAL;
+            getNextCh();
+        }  else if (tk=='+' && currCh=='+') {
+            tk = LEX_PLUSPLUS;
+            getNextCh();
+        }  else if (tk=='-' && currCh=='-') {
+            tk = LEX_MINUSMINUS;
+            getNextCh();
+        } else if (tk=='&' && currCh=='=') {
+            tk = LEX_ANDEQUAL;
+            getNextCh();
+        } else if (tk=='&' && currCh=='&') {
+            tk = LEX_ANDAND;
+            getNextCh();
+        } else if (tk=='|' && currCh=='=') {
+            tk = LEX_OREQUAL;
+            getNextCh();
+        } else if (tk=='|' && currCh=='|') {
+            tk = LEX_OROR;
+            getNextCh();
+        } else if (tk=='^' && currCh=='=') {
+            tk = LEX_XOREQUAL;
+            getNextCh();
+        }
+    }
+    /* This isn't quite right yet */
+    tokenLastEnd = tokenEnd;
+    tokenEnd = dataPos-3;
+}
+
+string CScriptLex::getSubString(int lastPosition) {
+    int lastCharIdx = tokenLastEnd+1;
+    if (lastCharIdx < dataEnd) {
+        /* save a memory alloc by using our data array to create the
+           substring */
+        char old = data[lastCharIdx];
+        data[lastCharIdx] = 0;
+        std::string value = &data[lastPosition];
+        data[lastCharIdx] = old;
+        return value;
+    } else {
+        return std::string(&data[lastPosition]);
+    }
+}
+
+
+CScriptLex *CScriptLex::getSubLex(int lastPosition) {
+    int lastCharIdx = tokenLastEnd+1;
+    if (lastCharIdx < dataEnd)
+        return new CScriptLex(this, lastPosition, lastCharIdx);
+    else
+        return new CScriptLex(this, lastPosition, dataEnd );
+}
+
+string CScriptLex::getPosition(int pos) {
+    if (pos<0) pos=tokenLastEnd;
+    int line = 1,col = 1;
+    for (int i=0;i<pos;i++) {
+        char ch;
+        if (i < dataEnd)
+            ch = data[i];
+        else
+            ch = 0;
+        col++;
+        if (ch=='\n') {
+            line++;
+            col = 0;
+        }
+    }
+    char buf[256];
+    sprintf_s(buf, 256, "(line: %d, col: %d)", line, col);
+    return buf;
+}
+
+// ----------------------------------------------------------------------------------- CSCRIPTVARLINK
+
+CScriptVarLink::CScriptVarLink(CScriptVar *var, const std::string &name) {
+#if DEBUG_MEMORY
+    mark_allocated(this);
+#endif
+    this->name = name;
+    this->nextSibling = 0;
+    this->prevSibling = 0;
+    this->var = var->ref();
+    this->owned = false;
+}
+
+CScriptVarLink::CScriptVarLink(const CScriptVarLink &link) {
+    // Copy constructor
+#if DEBUG_MEMORY
+    mark_allocated(this);
+#endif
+    this->name = link.name;
+    this->nextSibling = 0;
+    this->prevSibling = 0;
+    this->var = link.var->ref();
+    this->owned = false;
+}
+
+CScriptVarLink::~CScriptVarLink() {
+#if DEBUG_MEMORY
+    mark_deallocated(this);
+#endif
+    var->unref();
+}
+
+void CScriptVarLink::replaceWith(CScriptVar *newVar) {
+    CScriptVar *oldVar = var;
+    var = newVar->ref();
+    oldVar->unref();
+}
+
+void CScriptVarLink::replaceWith(CScriptVarLink *newVar) {
+    if (newVar)
+      replaceWith(newVar->var);
+    else
+      replaceWith(new CScriptVar());
+}
+
+int CScriptVarLink::getIntName() {
+    return atoi(name.c_str());
+}
+void CScriptVarLink::setIntName(int n) {
+    char sIdx[64];
+    sprintf_s(sIdx, sizeof(sIdx), "%d", n);
+    name = sIdx;
+}
+
+// ----------------------------------------------------------------------------------- CSCRIPTVAR
+
+CScriptVar::CScriptVar() {
+    refs = 0;
+#if DEBUG_MEMORY
+    mark_allocated(this);
+#endif
+    init();
+    flags = SCRIPTVAR_UNDEFINED;
+}
+
+CScriptVar::CScriptVar(const string &str) {
+    refs = 0;
+#if DEBUG_MEMORY
+    mark_allocated(this);
+#endif
+    init();
+    flags = SCRIPTVAR_STRING;
+    data = str;
+}
+
+
+CScriptVar::CScriptVar(const string &varData, int varFlags) {
+    refs = 0;
+#if DEBUG_MEMORY
+    mark_allocated(this);
+#endif
+    init();
+    flags = varFlags;
+    if (varFlags & SCRIPTVAR_INTEGER) {
+      intData = strtol(varData.c_str(),0,0);
+    } else if (varFlags & SCRIPTVAR_DOUBLE) {
+      doubleData = strtod(varData.c_str(),0);
+    } else
+      data = varData;
+}
+
+CScriptVar::CScriptVar(double val) {
+    refs = 0;
+#if DEBUG_MEMORY
+    mark_allocated(this);
+#endif
+    init();
+    setDouble(val);
+}
+
+CScriptVar::CScriptVar(int val) {
+    refs = 0;
+#if DEBUG_MEMORY
+    mark_allocated(this);
+#endif
+    init();
+    setInt(val);
+}
+
+CScriptVar::~CScriptVar(void) {
+#if DEBUG_MEMORY
+    mark_deallocated(this);
+#endif
+    removeAllChildren();
+}
+
+void CScriptVar::init() {
+    firstChild = 0;
+    lastChild = 0;
+    flags = 0;
+    jsCallback = 0;
+    jsCallbackUserData = 0;
+    data = TINYJS_BLANK_DATA;
+    intData = 0;
+    doubleData = 0;
+}
+
+CScriptVar *CScriptVar::getReturnVar() {
+    return getParameter(TINYJS_RETURN_VAR);
+}
+
+void CScriptVar::setReturnVar(CScriptVar *var) {
+    findChildOrCreate(TINYJS_RETURN_VAR)->replaceWith(var);
+}
+
+
+CScriptVar *CScriptVar::getParameter(const std::string &name) {
+    return findChildOrCreate(name)->var;
+}
+
+CScriptVarLink *CScriptVar::findChild(const string &childName) {
+    CScriptVarLink *v = firstChild;
+    while (v) {
+        if (v->name.compare(childName)==0)
+            return v;
+        v = v->nextSibling;
+    }
+    return 0;
+}
+
+CScriptVarLink *CScriptVar::findChildOrCreate(const string &childName, int varFlags) {
+    CScriptVarLink *l = findChild(childName);
+    if (l) return l;
+
+    return addChild(childName, new CScriptVar(TINYJS_BLANK_DATA, varFlags));
+}
+
+CScriptVarLink *CScriptVar::findChildOrCreateByPath(const std::string &path) {
+  size_t p = path.find('.');
+  if (p == string::npos)
+    return findChildOrCreate(path);
+
+  return findChildOrCreate(path.substr(0,p), SCRIPTVAR_OBJECT)->var->
+            findChildOrCreateByPath(path.substr(p+1));
+}
+
+CScriptVarLink *CScriptVar::addChild(const std::string &childName, CScriptVar *child) {
+  if (isUndefined()) {
+    flags = SCRIPTVAR_OBJECT;
+  }
+    // if no child supplied, create one
+    if (!child)
+      child = new CScriptVar();
+
+    CScriptVarLink *link = new CScriptVarLink(child, childName);
+    link->owned = true;
+    if (lastChild) {
+        lastChild->nextSibling = link;
+        link->prevSibling = lastChild;
+        lastChild = link;
+    } else {
+        firstChild = link;
+        lastChild = link;
+    }
+    return link;
+}
+
+CScriptVarLink *CScriptVar::addChildNoDup(const std::string &childName, CScriptVar *child) {
+    // if no child supplied, create one
+    if (!child)
+      child = new CScriptVar();
+
+    CScriptVarLink *v = findChild(childName);
+    if (v) {
+        v->replaceWith(child);
+    } else {
+        v = addChild(childName, child);
+    }
+
+    return v;
+}
+
+void CScriptVar::removeChild(CScriptVar *child) {
+    CScriptVarLink *link = firstChild;
+    while (link) {
+        if (link->var == child)
+            break;
+        link = link->nextSibling;
+    }
+    ASSERT(link);
+    removeLink(link);
+}
+
+void CScriptVar::removeLink(CScriptVarLink *link) {
+    if (!link) return;
+    if (link->nextSibling)
+      link->nextSibling->prevSibling = link->prevSibling;
+    if (link->prevSibling)
+      link->prevSibling->nextSibling = link->nextSibling;
+    if (lastChild == link)
+        lastChild = link->prevSibling;
+    if (firstChild == link)
+        firstChild = link->nextSibling;
+    delete link;
+}
+
+void CScriptVar::removeAllChildren() {
+    CScriptVarLink *c = firstChild;
+    while (c) {
+        CScriptVarLink *t = c->nextSibling;
+        delete c;
+        c = t;
+    }
+    firstChild = 0;
+    lastChild = 0;
+}
+
+CScriptVar *CScriptVar::getArrayIndex(int idx) {
+    char sIdx[64];
+    sprintf_s(sIdx, sizeof(sIdx), "%d", idx);
+    CScriptVarLink *link = findChild(sIdx);
+    if (link) return link->var;
+    else return new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_NULL); // undefined
+}
+
+void CScriptVar::setArrayIndex(int idx, CScriptVar *value) {
+    char sIdx[64];
+    sprintf_s(sIdx, sizeof(sIdx), "%d", idx);
+    CScriptVarLink *link = findChild(sIdx);
+
+    if (link) {
+      if (value->isUndefined())
+        removeLink(link);
+      else
+        link->replaceWith(value);
+    } else {
+      if (!value->isUndefined())
+        addChild(sIdx, value);
+    }
+}
+
+int CScriptVar::getArrayLength() {
+    int highest = -1;
+    if (!isArray()) return 0;
+
+    CScriptVarLink *link = firstChild;
+    while (link) {
+      if (isNumber(link->name)) {
+        int val = atoi(link->name.c_str());
+        if (val > highest) highest = val;
+      }
+      link = link->nextSibling;
+    }
+    return highest+1;
+}
+
+int CScriptVar::getChildren() {
+    int n = 0;
+    CScriptVarLink *link = firstChild;
+    while (link) {
+      n++;
+      link = link->nextSibling;
+    }
+    return n;
+}
+
+int CScriptVar::getInt() {
+    /* strtol understands about hex and octal */
+    if (isInt()) return intData;
+    if (isNull()) return 0;
+    if (isUndefined()) return 0;
+    if (isDouble()) return (int)doubleData;
+    return 0;
+}
+
+double CScriptVar::getDouble() {
+    if (isDouble()) return doubleData;
+    if (isInt()) return intData;
+    if (isNull()) return 0;
+    if (isUndefined()) return 0;
+    return 0; /* or NaN? */
+}
+
+const string &CScriptVar::getString() {
+    /* Because we can't return a string that is generated on demand.
+     * I should really just use char* :) */
+    static string s_null = "null";
+    static string s_undefined = "undefined";
+    if (isInt()) {
+      char buffer[32];
+      sprintf_s(buffer, sizeof(buffer), "%ld", intData);
+      data = buffer;
+      return data;
+    }
+    if (isDouble()) {
+      char buffer[32];
+      sprintf_s(buffer, sizeof(buffer), "%f", doubleData);
+      data = buffer;
+      return data;
+    }
+    if (isNull()) return s_null;
+    if (isUndefined()) return s_undefined;
+    // are we just a string here?
+    return data;
+}
+
+void CScriptVar::setInt(int val) {
+    flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_INTEGER;
+    intData = val;
+    doubleData = 0;
+    data = TINYJS_BLANK_DATA;
+}
+
+void CScriptVar::setDouble(double val) {
+    flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_DOUBLE;
+    doubleData = val;
+    intData = 0;
+    data = TINYJS_BLANK_DATA;
+}
+
+void CScriptVar::setString(const string &str) {
+    // name sure it's not still a number or integer
+    flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_STRING;
+    data = str;
+    intData = 0;
+    doubleData = 0;
+}
+
+void CScriptVar::setUndefined() {
+    // name sure it's not still a number or integer
+    flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_UNDEFINED;
+    data = TINYJS_BLANK_DATA;
+    intData = 0;
+    doubleData = 0;
+    removeAllChildren();
+}
+
+void CScriptVar::setArray() {
+    // name sure it's not still a number or integer
+    flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_ARRAY;
+    data = TINYJS_BLANK_DATA;
+    intData = 0;
+    doubleData = 0;
+    removeAllChildren();
+}
+
+bool CScriptVar::equals(CScriptVar *v) {
+    CScriptVar *resV = mathsOp(v, LEX_EQUAL);
+    bool res = resV->getBool();
+    delete resV;
+    return res;
+}
+
+CScriptVar *CScriptVar::mathsOp(CScriptVar *b, int op) {
+    CScriptVar *a = this;
+    // Type equality check
+    if (op == LEX_TYPEEQUAL || op == LEX_NTYPEEQUAL) {
+      // check type first, then call again to check data
+      bool eql = ((a->flags & SCRIPTVAR_VARTYPEMASK) ==
+                  (b->flags & SCRIPTVAR_VARTYPEMASK));
+      if (eql) {
+        CScriptVar *contents = a->mathsOp(b, LEX_EQUAL);
+        if (!contents->getBool()) eql = false;
+        if (!contents->refs) delete contents;
+      }
+                 ;
+      if (op == LEX_TYPEEQUAL)
+        return new CScriptVar(eql);
+      else
+        return new CScriptVar(!eql);
+    }
+    // do maths...
+    if (a->isUndefined() && b->isUndefined()) {
+      if (op == LEX_EQUAL) return new CScriptVar(true);
+      else if (op == LEX_NEQUAL) return new CScriptVar(false);
+      else return new CScriptVar(); // undefined
+    } else if ((a->isNumeric() || a->isUndefined()) &&
+               (b->isNumeric() || b->isUndefined())) {
+        if (!a->isDouble() && !b->isDouble()) {
+            // use ints
+            int da = a->getInt();
+            int db = b->getInt();
+            switch (op) {
+                case '+': return new CScriptVar(da+db);
+                case '-': return new CScriptVar(da-db);
+                case '*': return new CScriptVar(da*db);
+                case '/': return new CScriptVar(da/db);
+                case '&': return new CScriptVar(da&db);
+                case '|': return new CScriptVar(da|db);
+                case '^': return new CScriptVar(da^db);
+                case '%': return new CScriptVar(da%db);
+                case LEX_EQUAL:     return new CScriptVar(da==db);
+                case LEX_NEQUAL:    return new CScriptVar(da!=db);
+                case '<':     return new CScriptVar(da<db);
+                case LEX_LEQUAL:    return new CScriptVar(da<=db);
+                case '>':     return new CScriptVar(da>db);
+                case LEX_GEQUAL:    return new CScriptVar(da>=db);
+#ifndef MBED
+                default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Int datatype");
+#else
+                default:
+                    mbedErrorFlag = 1;
+                    mbedErrorMessage = "Operation ";
+                    mbedErrorMessage += CScriptLex::getTokenStr(op);
+                    mbedErrorMessage += " not supported on the Int datatype";
+                    return 0;
+#endif
+            }
+        } else {
+            // use doubles
+            double da = a->getDouble();
+            double db = b->getDouble();
+            switch (op) {
+                case '+': return new CScriptVar(da+db);
+                case '-': return new CScriptVar(da-db);
+                case '*': return new CScriptVar(da*db);
+                case '/': return new CScriptVar(da/db);
+                case LEX_EQUAL:     return new CScriptVar(da==db);
+                case LEX_NEQUAL:    return new CScriptVar(da!=db);
+                case '<':     return new CScriptVar(da<db);
+                case LEX_LEQUAL:    return new CScriptVar(da<=db);
+                case '>':     return new CScriptVar(da>db);
+                case LEX_GEQUAL:    return new CScriptVar(da>=db);
+#ifndef MBED
+                default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Double datatype");
+#else
+                default:
+                    mbedErrorFlag = 1;
+                    mbedErrorMessage = "Operation ";
+                    mbedErrorMessage += CScriptLex::getTokenStr(op);
+                    mbedErrorMessage += " not supported on the Double datatype";
+                    return 0;
+#endif
+            }
+        }
+    } else if (a->isArray()) {
+      /* Just check pointers */
+      switch (op) {
+           case LEX_EQUAL: return new CScriptVar(a==b);
+           case LEX_NEQUAL: return new CScriptVar(a!=b);
+#ifndef MBED
+           default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Array datatype");
+#else
+           default:
+             mbedErrorFlag = 1;;
+             mbedErrorMessage = "Operation ";
+             mbedErrorMessage += CScriptLex::getTokenStr(op);
+             mbedErrorMessage += " not supported on the Array datatype";
+             return 0;
+
+#endif
+      }
+    } else if (a->isObject()) {
+          /* Just check pointers */
+          switch (op) {
+               case LEX_EQUAL: return new CScriptVar(a==b);
+               case LEX_NEQUAL: return new CScriptVar(a!=b);
+#ifndef MBED
+               default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Object datatype");
+#else
+               default:
+                 mbedErrorFlag = 1;
+                 mbedErrorMessage = "Operation ";
+                 mbedErrorMessage += CScriptLex::getTokenStr(op);
+                 mbedErrorMessage += " not supported on the Object datatype";
+                 return 0;
+#endif
+          }
+    } else {
+       string da = a->getString();
+       string db = b->getString();
+       // use strings
+       switch (op) {
+           case '+':           return new CScriptVar(da+db, SCRIPTVAR_STRING);
+           case LEX_EQUAL:     return new CScriptVar(da==db);
+           case LEX_NEQUAL:    return new CScriptVar(da!=db);
+           case '<':     return new CScriptVar(da<db);
+           case LEX_LEQUAL:    return new CScriptVar(da<=db);
+           case '>':     return new CScriptVar(da>db);
+           case LEX_GEQUAL:    return new CScriptVar(da>=db);
+#ifndef MBED
+           default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the string datatype");
+#else
+           default:
+             mbedErrorFlag = 1;
+             mbedErrorMessage = "Operation ";
+             mbedErrorMessage += CScriptLex::getTokenStr(op);
+             mbedErrorMessage += " not supported on the string datatype";
+             return 0;
+#endif
+       }
+    }
+    ASSERT(0);
+    return 0;
+}
+
+void CScriptVar::copySimpleData(CScriptVar *val) {
+    data = val->data;
+    intData = val->intData;
+    doubleData = val->doubleData;
+    flags = (flags & ~SCRIPTVAR_VARTYPEMASK) | (val->flags & SCRIPTVAR_VARTYPEMASK);
+}
+
+void CScriptVar::copyValue(CScriptVar *val) {
+    if (val) {
+      copySimpleData(val);
+      // remove all current children
+      removeAllChildren();
+      // copy children of 'val'
+      CScriptVarLink *child = val->firstChild;
+      while (child) {
+        CScriptVar *copied;
+        // don't copy the 'parent' object...
+        if (child->name != TINYJS_PROTOTYPE_CLASS)
+          copied = child->var->deepCopy();
+        else
+          copied = child->var;
+
+        addChild(child->name, copied);
+
+        child = child->nextSibling;
+      }
+    } else {
+      setUndefined();
+    }
+}
+
+CScriptVar *CScriptVar::deepCopy() {
+    CScriptVar *newVar = new CScriptVar();
+    newVar->copySimpleData(this);
+    // copy children
+    CScriptVarLink *child = firstChild;
+    while (child) {
+        CScriptVar *copied;
+        // don't copy the 'parent' object...
+        if (child->name != TINYJS_PROTOTYPE_CLASS)
+          copied = child->var->deepCopy();
+        else
+          copied = child->var;
+
+        newVar->addChild(child->name, copied);
+        child = child->nextSibling;
+    }
+    return newVar;
+}
+
+void CScriptVar::trace(string indentStr, const string &name) {
+    TRACE("%s'%s' = '%s' %s\n",
+        indentStr.c_str(),
+        name.c_str(),
+        getString().c_str(),
+        getFlagsAsString().c_str());
+    string indent = indentStr+" ";
+    CScriptVarLink *link = firstChild;
+    while (link) {
+      link->var->trace(indent, link->name);
+      link = link->nextSibling;
+    }
+}
+
+string CScriptVar::getFlagsAsString() {
+  string flagstr = "";
+  if (flags&SCRIPTVAR_FUNCTION) flagstr = flagstr + "FUNCTION ";
+  if (flags&SCRIPTVAR_OBJECT) flagstr = flagstr + "OBJECT ";
+  if (flags&SCRIPTVAR_ARRAY) flagstr = flagstr + "ARRAY ";
+  if (flags&SCRIPTVAR_NATIVE) flagstr = flagstr + "NATIVE ";
+  if (flags&SCRIPTVAR_DOUBLE) flagstr = flagstr + "DOUBLE ";
+  if (flags&SCRIPTVAR_INTEGER) flagstr = flagstr + "INTEGER ";
+  if (flags&SCRIPTVAR_STRING) flagstr = flagstr + "STRING ";
+  return flagstr;
+}
+
+string CScriptVar::getParsableString() {
+  // Numbers can just be put in directly
+  if (isNumeric())
+    return getString();
+  if (isFunction()) {
+#ifndef MBED
+    ostringstream funcStr;
+    funcStr << "function (";
+    // get list of parameters
+    CScriptVarLink *link = firstChild;
+    while (link) {
+      funcStr << link->name;
+      if (link->nextSibling) funcStr << ",";
+      link = link->nextSibling;
+    }
+    // add function body
+    funcStr << ") " << getString();
+    return funcStr.str();
+#else
+    string funcStr;
+    funcStr = "function (";
+    CScriptVarLink *link = firstChild;
+    while (link) {
+      funcStr += link->name;
+      if (link->nextSibling)  funcStr += ",";
+      link = link->nextSibling;
+    }
+    // add function body
+    funcStr += ") ";
+    funcStr += getString();
+    return funcStr;
+#endif
+  }
+  // if it is a string then we quote it
+  if (isString())
+    return getJSString(getString());
+  if (isNull())
+      return "null";
+  return "undefined";
+}
+
+#ifndef MBED
+void CScriptVar::getJSON(ostringstream &destination, const string linePrefix) {
+   if (isObject()) {
+      string indentedLinePrefix = linePrefix+"  ";
+      // children - handle with bracketed list
+      destination << "{ \n";
+      CScriptVarLink *link = firstChild;
+      while (link) {
+        destination << indentedLinePrefix;
+        destination  << getJSString(link->name);
+        destination  << " : ";
+        link->var->getJSON(destination, indentedLinePrefix);
+        link = link->nextSibling;
+        if (link) {
+          destination  << ",\n";
+        }
+      }
+      destination << "\n" << linePrefix << "}";
+    } else if (isArray()) {
+      string indentedLinePrefix = linePrefix+"  ";
+      destination << "[\n";
+      int len = getArrayLength();
+      if (len>10000) len=10000; // we don't want to get stuck here!
+
+      for (int i=0;i<len;i++) {
+        getArrayIndex(i)->getJSON(destination, indentedLinePrefix);
+        if (i<len-1) destination  << ",\n";
+      }
+
+      destination << "\n" << linePrefix << "]";
+    } else {
+      // no children or a function... just write value directly
+      destination << getParsableString();
+    }
+}
+#else
+void CScriptVar::getJSON(string &destination, const string linePrefix) {
+   if (isObject()) {
+      string indentedLinePrefix = linePrefix+"  ";
+      // children - handle with bracketed list
+      destination += "{ \n";
+      CScriptVarLink *link = firstChild;
+      while (link) {
+        destination += indentedLinePrefix;
+        destination += getJSString(link->name);
+        destination += " : ";
+        link->var->getJSON(destination, indentedLinePrefix);
+        link = link->nextSibling;
+        if (link) {
+          destination += ",\n";
+        }
+      }
+      destination += "\n";
+      destination += linePrefix;
+      destination += "}";
+    } else if (isArray()) {
+      string indentedLinePrefix = linePrefix+"  ";
+      destination + "[\n";
+      int len = getArrayLength();
+      if (len>10000) len=10000; // we don't want to get stuck here!
+
+      for (int i=0;i<len;i++) {
+        getArrayIndex(i)->getJSON(destination, indentedLinePrefix);
+        if (i<len-1) {
+            destination += ",\n";
+        }
+      }
+
+      destination += "\n";
+      destination += linePrefix;
+      destination += "]";
+    } else {
+      // no children or a function... just write value directly
+      destination += getParsableString();
+    }
+}
+#endif
+
+void CScriptVar::setCallback(JSCallback callback, void *userdata) {
+    jsCallback = callback;
+    jsCallbackUserData = userdata;
+}
+
+CScriptVar *CScriptVar::ref() {
+    refs++;
+    return this;
+}
+
+void CScriptVar::unref() {
+    if (refs<=0) printf("OMFG, we have unreffed too far!\n");
+    if ((--refs)==0) {
+      delete this;
+    }
+}
+
+int CScriptVar::getRefs() {
+    return refs;
+}
+
+
+// ----------------------------------------------------------------------------------- CSCRIPT
+
+CTinyJS::CTinyJS() {
+    l = 0;
+    root = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref();
+    // Add built-in classes
+    stringClass = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref();
+    arrayClass = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref();
+    objectClass = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref();
+    root->addChild("String", stringClass);
+    root->addChild("Array", arrayClass);
+    root->addChild("Object", objectClass);
+}
+
+CTinyJS::~CTinyJS() {
+    ASSERT(!l);
+    scopes.clear();
+    stringClass->unref();
+    arrayClass->unref();
+    objectClass->unref();
+    root->unref();
+
+#if DEBUG_MEMORY
+    show_allocated();
+#endif
+}
+
+void CTinyJS::trace() {
+    root->trace();
+}
+
+void CTinyJS::execute(const string &code) {
+    CScriptLex *oldLex = l;
+    vector<CScriptVar*> oldScopes = scopes;
+    l = new CScriptLex(code);
+#ifdef TINYJS_CALL_STACK
+    call_stack.clear();
+#endif
+    scopes.clear();
+    scopes.push_back(root);
+
+#ifndef MBED
+    try {
+        bool execute = true;
+        while (l->tk) statement(execute);
+    } catch (CScriptException *e) {
+        ostringstream msg;
+        msg << "Error " << e->text;
+#ifdef TINYJS_CALL_STACK
+        for (int i=(int)call_stack.size()-1;i>=0;i--)
+          msg << "\n" << i << ": " << call_stack.at(i);
+#endif
+        msg << " at " << l->getPosition();
+        delete l;
+        l = oldLex;
+
+        throw new CScriptException(msg.str());
+    }
+#else
+    {
+      bool execute = true;
+      while (l->tk) {
+        mbedErrorFlag = 0;
+        statement(execute);
+        if (mbedErrorFlag != 0) {
+          string msg;
+          msg = "Error ";
+          msg += mbedErrorMessage;
+#ifdef TINYJS_CALL_STACK
+          for (int i=(int)call_stack.size()-1;i>=0;i--) {
+            msg += "\n";
+            msg += i;
+            msg += ": ";
+            msg += call_stack.at(i);
+          }
+#endif
+          msg += " at ";
+          msg += l->getPosition();
+
+          delete l;
+          l = oldLex;
+
+          mbedErrorFlag = 1;
+          mbedErrorMessage = msg;
+          return;
+        }
+      }
+    }
+#endif
+
+
+    delete l;
+    l = oldLex;
+    scopes = oldScopes;
+}
+
+CScriptVarLink CTinyJS::evaluateComplex(const string &code) {
+    CScriptLex *oldLex = l;
+    vector<CScriptVar*> oldScopes = scopes;
+
+    l = new CScriptLex(code);
+#ifdef TINYJS_CALL_STACK
+    call_stack.clear();
+#endif
+    scopes.clear();
+    scopes.push_back(root);
+    CScriptVarLink *v = 0;
+#ifndef MBED
+    try {
+        bool execute = true;
+        do {
+          CLEAN(v);
+          v = base(execute);
+          if (l->tk!=LEX_EOF) l->match(';');
+        } while (l->tk!=LEX_EOF);
+    } catch (CScriptException *e) {
+      ostringstream msg;
+      msg << "Error " << e->text;
+#ifdef TINYJS_CALL_STACK
+      for (int i=(int)call_stack.size()-1;i>=0;i--)
+        msg << "\n" << i << ": " << call_stack.at(i);
+#endif
+      msg << " at " << l->getPosition();
+      delete l;
+      l = oldLex;
+
+        throw new CScriptException(msg.str());
+    }
+#else
+    {
+      bool execute = true;
+      do {
+        CLEAN(v);
+        mbedErrorFlag = 0;
+        v = base(execute);
+        if (mbedErrorFlag != 0) {
+          string msg;
+          msg = "Error ";
+          msg += mbedErrorMessage;
+#ifdef TINYJS_CALL_STACK
+          for (int i=(int)call_stack.size()-1;i>=0;i--) {
+            msg += "\n";
+            msg += i;
+            msg += ": ";
+            msg += call_stack.at(i);
+          }
+#endif
+          msg += " at ";
+          msg += l->getPosition();
+          delete l;
+          l = oldLex;
+
+          mbedErrorFlag = 1;
+          mbedErrorMessage = msg;
+          return 0;
+        }
+
+        if (l->tk!=LEX_EOF) {
+            mbedErrorFlag = 0;
+            l->match(';');
+            if (mbedErrorFlag != 0)  return 0;
+        }
+      } while (l->tk!=LEX_EOF);
+    }
+#endif
+    delete l;
+    l = oldLex;
+    scopes = oldScopes;
+
+    if (v) {
+        CScriptVarLink r = *v;
+        CLEAN(v);
+        return r;
+    }
+    // return undefined...
+    return CScriptVarLink(new CScriptVar());
+}
+
+string CTinyJS::evaluate(const string &code) {
+    return evaluateComplex(code).var->getString();
+}
+
+void CTinyJS::parseFunctionArguments(CScriptVar *funcVar) {
+#ifndef MBED
+  l->match('(');
+  while (l->tk!=')') {
+      funcVar->addChildNoDup(l->tkStr);
+      l->match(LEX_ID);
+      if (l->tk!=')') l->match(',');
+  }
+  l->match(')');
+#else
+  LMATCH_VOID('(');
+  while (l->tk!=')') {
+      funcVar->addChildNoDup(l->tkStr);
+      LMATCH_VOID(LEX_ID);
+      if (l->tk!=')') {
+        LMATCH_VOID(',');
+      }
+  }
+  LMATCH_VOID(')');
+#endif
+}
+
+void CTinyJS::addNative(const string &funcDesc, JSCallback ptr, void *userdata) {
+    CScriptLex *oldLex = l;
+    l = new CScriptLex(funcDesc);
+
+    CScriptVar *base = root;
+#ifndef MBED
+    l->match(LEX_R_FUNCTION);
+#else
+    LMATCH_VOID(LEX_R_FUNCTION);
+#endif
+    string funcName = l->tkStr;
+#ifndef MBED
+    l->match(LEX_ID);
+#else
+    LMATCH_VOID(LEX_ID);
+#endif
+    /* Check for dots, we might want to do something like function String.substring ... */
+    while (l->tk == '.') {
+#ifndef MBED
+      l->match('.');
+#else
+      LMATCH_VOID('.');
+#endif
+      CScriptVarLink *link = base->findChild(funcName);
+      // if it doesn't exist, make an object class
+      if (!link) link = base->addChild(funcName, new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT));
+      base = link->var;
+      funcName = l->tkStr;
+#ifndef MBED
+      l->match(LEX_ID);
+#else
+      LMATCH_VOID(LEX_ID);
+#endif
+    }
+
+    CScriptVar *funcVar = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION | SCRIPTVAR_NATIVE);
+    funcVar->setCallback(ptr, userdata);
+    parseFunctionArguments(funcVar);
+    delete l;
+    l = oldLex;
+
+    base->addChild(funcName, funcVar);
+}
+
+CScriptVarLink *CTinyJS::parseFunctionDefinition() {
+  // actually parse a function...
+#ifndef MBED
+  l->match(LEX_R_FUNCTION);
+#else
+  LMATCH(LEX_R_FUNCTION);
+#endif
+  string funcName = TINYJS_TEMP_NAME;
+  /* we can have functions without names */
+  if (l->tk==LEX_ID) {
+    funcName = l->tkStr;
+#ifndef MBED
+    l->match(LEX_ID);
+#else
+    LMATCH(LEX_ID);
+#endif
+  }
+  CScriptVarLink *funcVar = new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION), funcName);
+  parseFunctionArguments(funcVar->var);
+  int funcBegin = l->tokenStart;
+  bool noexecute = false;
+  block(noexecute);
+  funcVar->var->data = l->getSubString(funcBegin);
+  return funcVar;
+}
+
+/** Handle a function call (assumes we've parsed the function name and we're
+ * on the start bracket). 'parent' is the object that contains this method,
+ * if there was one (otherwise it's just a normnal function).
+ */
+CScriptVarLink *CTinyJS::functionCall(bool &execute, CScriptVarLink *function, CScriptVar *parent) {
+  if (execute) {
+    if (!function->var->isFunction()) {
+        string errorMsg = "Expecting '";
+        errorMsg = errorMsg + function->name + "' to be a function";
+#ifndef MBED
+        throw new CScriptException(errorMsg.c_str());
+#else
+        mbedErrorFlag = 1;
+        mbedErrorMessage = errorMsg;
+        return 0;
+#endif
+    }
+#ifndef MBED
+    l->match('(');
+#else
+    LMATCH('(');
+#endif
+    // create a new symbol table entry for execution of this function
+    CScriptVar *functionRoot = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION);
+    if (parent)
+      functionRoot->addChildNoDup("this", parent);
+    // grab in all parameters
+    CScriptVarLink *v = function->var->firstChild;
+    while (v) {
+        CScriptVarLink *value = base(execute);
+        if (execute) {
+            if (value->var->isBasic()) {
+              // pass by value
+              functionRoot->addChild(v->name, value->var->deepCopy());
+            } else {
+              // pass by reference
+              functionRoot->addChild(v->name, value->var);
+            }
+        }
+        CLEAN(value);
+#ifndef MBED
+        if (l->tk!=')') l->match(',');
+#else
+        if (l->tk!=')')  LMATCH(',');
+#endif
+        v = v->nextSibling;
+    }
+#ifndef MBED
+    l->match(')');
+#else
+    LMATCH(')');
+#endif
+    // setup a return variable
+    CScriptVarLink *returnVar = NULL;
+    // execute function!
+    // add the function's execute space to the symbol table so we can recurse
+    CScriptVarLink *returnVarLink = functionRoot->addChild(TINYJS_RETURN_VAR);
+    scopes.push_back(functionRoot);
+#ifdef TINYJS_CALL_STACK
+    call_stack.push_back(function->name + " from " + l->getPosition());
+#endif
+
+    if (function->var->isNative()) {
+        ASSERT(function->var->jsCallback);
+        function->var->jsCallback(functionRoot, function->var->jsCallbackUserData);
+    } else {
+        /* we just want to execute the block, but something could
+         * have messed up and left us with the wrong ScriptLex, so
+         * we want to be careful here... */
+#ifndef MBED
+        CScriptException *exception = 0;
+        CScriptLex *oldLex = l;
+        CScriptLex *newLex = new CScriptLex(function->var->getString());
+        l = newLex;
+
+        try {
+          block(execute);
+          // because return will probably have called this, and set execute to false
+          execute = true;
+        } catch (CScriptException *e) {
+          exception = e;
+        }
+        delete newLex;
+        l = oldLex;
+
+        if (exception)
+          throw exception;
+#else
+        CScriptLex *oldLex = l;
+        CScriptLex *newLex = new CScriptLex(function->var->getString());
+        l = newLex;
+
+        {
+          mbedErrorFlag = 0;
+          block(execute);
+          if (mbedErrorFlag != 0) {
+            delete newLex;
+            l = oldLex;
+            return 0;
+          } else {
+            execute = true;
+
+            delete newLex;
+            l = oldLex;
+          }
+        }
+#endif
+
+    }
+#ifdef TINYJS_CALL_STACK
+    if (!call_stack.empty()) call_stack.pop_back();
+#endif
+    scopes.pop_back();
+    /* get the real return var before we remove it from our function */
+    returnVar = new CScriptVarLink(returnVarLink->var);
+    functionRoot->removeLink(returnVarLink);
+    delete functionRoot;
+    if (returnVar)
+      return returnVar;
+    else
+      return new CScriptVarLink(new CScriptVar());
+  } else {
+    // function, but not executing - just parse args and be done
+#ifndef MBED
+    l->match('(');
+    while (l->tk != ')') {
+      CScriptVarLink *value = base(execute);
+      CLEAN(value);
+      if (l->tk!=')') l->match(',');
+    }
+    l->match(')');
+#else
+    LMATCH('(');
+    while (l->tk != ')') {
+      CScriptVarLink *value = base(execute);
+      CLEAN(value);
+      if (l->tk!=')') LMATCH(',');
+    }
+    LMATCH(')');
+#endif
+    if (l->tk == '{') { // TODO: why is this here?
+      block(execute);
+    }
+    /* function will be a blank scriptvarlink if we're not executing,
+     * so just return it rather than an alloc/free */
+    return function;
+  }
+}
+
+#ifndef MBED
+CScriptVarLink *CTinyJS::factor(bool &execute) {
+    if (l->tk=='(') {
+        l->match('(');
+        CScriptVarLink *a = base(execute);
+        l->match(')');
+        return a;
+    }
+    if (l->tk==LEX_R_TRUE) {
+        l->match(LEX_R_TRUE);
+        return new CScriptVarLink(new CScriptVar(1));
+    }
+    if (l->tk==LEX_R_FALSE) {
+        l->match(LEX_R_FALSE);
+        return new CScriptVarLink(new CScriptVar(0));
+    }
+    if (l->tk==LEX_R_NULL) {
+        l->match(LEX_R_NULL);
+        return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_NULL));
+    }
+    if (l->tk==LEX_R_UNDEFINED) {
+        l->match(LEX_R_UNDEFINED);
+        return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_UNDEFINED));
+    }
+    if (l->tk==LEX_ID) {
+        CScriptVarLink *a = execute ? findInScopes(l->tkStr) : new CScriptVarLink(new CScriptVar());
+        //printf("0x%08X for %s at %s\n", (unsigned int)a, l->tkStr.c_str(), l->getPosition().c_str());
+        /* The parent if we're executing a method call */
+        CScriptVar *parent = 0;
+
+        if (execute && !a) {
+          /* Variable doesn't exist! JavaScript says we should create it
+           * (we won't add it here. This is done in the assignment operator)*/
+          a = new CScriptVarLink(new CScriptVar(), l->tkStr);
+        }
+        l->match(LEX_ID);
+        while (l->tk=='(' || l->tk=='.' || l->tk=='[') {
+            if (l->tk=='(') { // ------------------------------------- Function Call
+                a = functionCall(execute, a, parent);
+            } else if (l->tk == '.') { // ------------------------------------- Record Access
+                l->match('.');
+                if (execute) {
+                  const string &name = l->tkStr;
+                  CScriptVarLink *child = a->var->findChild(name);
+                  if (!child) child = findInParentClasses(a->var, name);
+                  if (!child) {
+                    /* if we haven't found this defined yet, use the built-in
+                       'length' properly */
+                    if (a->var->isArray() && name == "length") {
+                      int l = a->var->getArrayLength();
+                      child = new CScriptVarLink(new CScriptVar(l));
+                    } else if (a->var->isString() && name == "length") {
+                      int l = a->var->getString().size();
+                      child = new CScriptVarLink(new CScriptVar(l));
+                    } else {
+                      child = a->var->addChild(name);
+                    }
+                  }
+                  parent = a->var;
+                  a = child;
+                }
+                l->match(LEX_ID);
+            } else if (l->tk == '[') { // ------------------------------------- Array Access
+                l->match('[');
+                CScriptVarLink *index = base(execute);
+                l->match(']');
+                if (execute) {
+                  CScriptVarLink *child = a->var->findChildOrCreate(index->var->getString());
+                  parent = a->var;
+                  a = child;
+                }
+                CLEAN(index);
+            } else ASSERT(0);
+        }
+        return a;
+    }
+    if (l->tk==LEX_INT || l->tk==LEX_FLOAT) {
+        CScriptVar *a = new CScriptVar(l->tkStr,
+            ((l->tk==LEX_INT)?SCRIPTVAR_INTEGER:SCRIPTVAR_DOUBLE));
+        l->match(l->tk);
+        return new CScriptVarLink(a);
+    }
+    if (l->tk==LEX_STR) {
+        CScriptVar *a = new CScriptVar(l->tkStr, SCRIPTVAR_STRING);
+        l->match(LEX_STR);
+        return new CScriptVarLink(a);
+    }
+    if (l->tk=='{') {
+        CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT);
+        /* JSON-style object definition */
+        l->match('{');
+        while (l->tk != '}') {
+          string id = l->tkStr;
+          // we only allow strings or IDs on the left hand side of an initialisation
+          if (l->tk==LEX_STR) l->match(LEX_STR);
+          else l->match(LEX_ID);
+          l->match(':');
+          if (execute) {
+            CScriptVarLink *a = base(execute);
+            contents->addChild(id, a->var);
+            CLEAN(a);
+          }
+          // no need to clean here, as it will definitely be used
+          if (l->tk != '}') l->match(',');
+        }
+
+        l->match('}');
+        return new CScriptVarLink(contents);
+    }
+    if (l->tk=='[') {
+        CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_ARRAY);
+        /* JSON-style array */
+        l->match('[');
+        int idx = 0;
+        while (l->tk != ']') {
+          if (execute) {
+            char idx_str[16]; // big enough for 2^32
+            sprintf_s(idx_str, sizeof(idx_str), "%d",idx);
+
+            CScriptVarLink *a = base(execute);
+            contents->addChild(idx_str, a->var);
+            CLEAN(a);
+          }
+          // no need to clean here, as it will definitely be used
+          if (l->tk != ']') l->match(',');
+          idx++;
+        }
+        l->match(']');
+        return new CScriptVarLink(contents);
+    }
+    if (l->tk==LEX_R_FUNCTION) {
+      CScriptVarLink *funcVar = parseFunctionDefinition();
+        if (funcVar->name != TINYJS_TEMP_NAME)
+          TRACE("Functions not defined at statement-level are not meant to have a name");
+        return funcVar;
+    }
+    if (l->tk==LEX_R_NEW) {
+      // new -> create a new object
+      l->match(LEX_R_NEW);
+      const string &className = l->tkStr;
+      if (execute) {
+        CScriptVarLink *objClassOrFunc = findInScopes(className);
+        if (!objClassOrFunc) {
+          TRACE("%s is not a valid class name", className.c_str());
+          return new CScriptVarLink(new CScriptVar());
+        }
+        l->match(LEX_ID);
+        CScriptVar *obj = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT);
+        CScriptVarLink *objLink = new CScriptVarLink(obj);
+        if (objClassOrFunc->var->isFunction()) {
+          CLEAN(functionCall(execute, objClassOrFunc, obj));
+        } else {
+          obj->addChild(TINYJS_PROTOTYPE_CLASS, objClassOrFunc->var);
+          if (l->tk == '(') {
+            l->match('(');
+            l->match(')');
+          }
+        }
+        return objLink;
+      } else {
+        l->match(LEX_ID);
+        if (l->tk == '(') {
+          l->match('(');
+          l->match(')');
+        }
+      }
+    }
+    // Nothing we can do here... just hope it's the end...
+    l->match(LEX_EOF);
+    return 0;
+}
+#else
+CScriptVarLink *CTinyJS::factor(bool &execute) {
+    if (l->tk=='(') {
+        LMATCH('(');
+        CScriptVarLink *a = base(execute);
+        LMATCH(')');
+        return a;
+    }
+    if (l->tk==LEX_R_TRUE) {
+        LMATCH(LEX_R_TRUE);
+        return new CScriptVarLink(new CScriptVar(1));
+    }
+    if (l->tk==LEX_R_FALSE) {
+        LMATCH(LEX_R_FALSE);
+        return new CScriptVarLink(new CScriptVar(0));
+    }
+    if (l->tk==LEX_R_NULL) {
+        LMATCH(LEX_R_NULL);
+        return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_NULL));
+    }
+    if (l->tk==LEX_R_UNDEFINED) {
+        LMATCH(LEX_R_UNDEFINED);
+        return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_UNDEFINED));
+    }
+    if (l->tk==LEX_ID) {
+        CScriptVarLink *a = execute ? findInScopes(l->tkStr) : new CScriptVarLink(new CScriptVar());
+        //printf("0x%08X for %s at %s\n", (unsigned int)a, l->tkStr.c_str(), l->getPosition().c_str());
+        /* The parent if we're executing a method call */
+        CScriptVar *parent = 0;
+
+        if (execute && !a) {
+          /* Variable doesn't exist! JavaScript says we should create it
+           * (we won't add it here. This is done in the assignment operator)*/
+          a = new CScriptVarLink(new CScriptVar(), l->tkStr);
+        }
+        LMATCH(LEX_ID);
+        while (l->tk=='(' || l->tk=='.' || l->tk=='[') {
+            if (l->tk=='(') { // ------------------------------------- Function Call
+                a = functionCall(execute, a, parent);
+            } else if (l->tk == '.') { // ------------------------------------- Record Access
+                LMATCH('.');
+                if (execute) {
+                  const string &name = l->tkStr;
+                  CScriptVarLink *child = a->var->findChild(name);
+                  if (!child) child = findInParentClasses(a->var, name);
+                  if (!child) {
+                    /* if we haven't found this defined yet, use the built-in
+                       'length' properly */
+                    if (a->var->isArray() && name == "length") {
+                      int l = a->var->getArrayLength();
+                      child = new CScriptVarLink(new CScriptVar(l));
+                    } else if (a->var->isString() && name == "length") {
+                      int l = a->var->getString().size();
+                      child = new CScriptVarLink(new CScriptVar(l));
+                    } else {
+                      child = a->var->addChild(name);
+                    }
+                  }
+                  parent = a->var;
+                  a = child;
+                }
+                LMATCH(LEX_ID);
+            } else if (l->tk == '[') { // ------------------------------------- Array Access
+                LMATCH('[');
+                CScriptVarLink *index = base(execute);
+                LMATCH(']');
+                if (execute) {
+                  CScriptVarLink *child = a->var->findChildOrCreate(index->var->getString());
+                  parent = a->var;
+                  a = child;
+                }
+                CLEAN(index);
+            } else ASSERT(0);
+        }
+        return a;
+    }
+    if (l->tk==LEX_INT || l->tk==LEX_FLOAT) {
+        CScriptVar *a = new CScriptVar(l->tkStr,
+            ((l->tk==LEX_INT)?SCRIPTVAR_INTEGER:SCRIPTVAR_DOUBLE));
+        LMATCH(l->tk);
+        return new CScriptVarLink(a);
+    }
+    if (l->tk==LEX_STR) {
+        CScriptVar *a = new CScriptVar(l->tkStr, SCRIPTVAR_STRING);
+        LMATCH(LEX_STR);
+        return new CScriptVarLink(a);
+    }
+    if (l->tk=='{') {
+        CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT);
+        /* JSON-style object definition */
+        LMATCH('{');
+        while (l->tk != '}') {
+          string id = l->tkStr;
+          // we only allow strings or IDs on the left hand side of an initialisation
+          if (l->tk==LEX_STR) {
+              LMATCH(LEX_STR);
+          } else {
+              LMATCH(LEX_ID);
+          }
+          LMATCH(':');
+          if (execute) {
+            CScriptVarLink *a = base(execute);
+            contents->addChild(id, a->var);
+            CLEAN(a);
+          }
+          // no need to clean here, as it will definitely be used
+          if (l->tk != '}') LMATCH(',');
+        }
+
+        LMATCH('}');
+        return new CScriptVarLink(contents);
+    }
+    if (l->tk=='[') {
+        CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_ARRAY);
+        /* JSON-style array */
+        LMATCH('[');
+        int idx = 0;
+        while (l->tk != ']') {
+          if (execute) {
+            char idx_str[16]; // big enough for 2^32
+            sprintf_s(idx_str, sizeof(idx_str), "%d",idx);
+
+            CScriptVarLink *a = base(execute);
+            contents->addChild(idx_str, a->var);
+            CLEAN(a);
+          }
+          // no need to clean here, as it will definitely be used
+          if (l->tk != ']') LMATCH(',');
+          idx++;
+        }
+        LMATCH(']');
+        return new CScriptVarLink(contents);
+    }
+    if (l->tk==LEX_R_FUNCTION) {
+      CScriptVarLink *funcVar = parseFunctionDefinition();
+        if (funcVar->name != TINYJS_TEMP_NAME)
+          TRACE("Functions not defined at statement-level are not meant to have a name");
+        return funcVar;
+    }
+    if (l->tk==LEX_R_NEW) {
+      // new -> create a new object
+      LMATCH(LEX_R_NEW);
+      const string &className = l->tkStr;
+      if (execute) {
+        CScriptVarLink *objClassOrFunc = findInScopes(className);
+        if (!objClassOrFunc) {
+          TRACE("%s is not a valid class name", className.c_str());
+          return new CScriptVarLink(new CScriptVar());
+        }
+        LMATCH(LEX_ID);
+        CScriptVar *obj = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT);
+        CScriptVarLink *objLink = new CScriptVarLink(obj);
+        if (objClassOrFunc->var->isFunction()) {
+          CLEAN(functionCall(execute, objClassOrFunc, obj));
+        } else {
+          obj->addChild(TINYJS_PROTOTYPE_CLASS, objClassOrFunc->var);
+          if (l->tk == '(') {
+            LMATCH('(');
+            LMATCH(')');
+          }
+        }
+        return objLink;
+      } else {
+        LMATCH(LEX_ID);
+        if (l->tk == '(') {
+          LMATCH('(');
+          LMATCH(')');
+        }
+      }
+    }
+    // Nothing we can do here... just hope it's the end...
+    LMATCH(LEX_EOF);
+    return 0;
+}
+#endif
+
+CScriptVarLink *CTinyJS::unary(bool &execute) {
+    CScriptVarLink *a;
+    if (l->tk=='!') {
+#ifndef MBED
+        l->match('!'); // binary not
+#else
+        LMATCH('!'); // binary not
+#endif
+        a = factor(execute);
+        if (execute) {
+            CScriptVar zero(0);
+            CScriptVar *res = a->var->mathsOp(&zero, LEX_EQUAL);
+            CREATE_LINK(a, res);
+        }
+    } else
+        a = factor(execute);
+    return a;
+}
+
+CScriptVarLink *CTinyJS::term(bool &execute) {
+    CScriptVarLink *a = unary(execute);
+    while (l->tk=='*' || l->tk=='/' || l->tk=='%') {
+        int op = l->tk;
+#ifndef MBED
+        l->match(l->tk);
+#else
+        LMATCH(l->tk);
+#endif
+        CScriptVarLink *b = unary(execute);
+        if (execute) {
+            CScriptVar *res = a->var->mathsOp(b->var, op);
+            CREATE_LINK(a, res);
+        }
+        CLEAN(b);
+    }
+    return a;
+}
+
+CScriptVarLink *CTinyJS::expression(bool &execute) {
+    bool negate = false;
+    if (l->tk=='-') {
+#ifndef MBED
+        l->match('-');
+#else
+        LMATCH('-');
+#endif
+        negate = true;
+    }
+    CScriptVarLink *a = term(execute);
+    if (negate) {
+        CScriptVar zero(0);
+        CScriptVar *res = zero.mathsOp(a->var, '-');
+        CREATE_LINK(a, res);
+    }
+
+    while (l->tk=='+' || l->tk=='-' ||
+        l->tk==LEX_PLUSPLUS || l->tk==LEX_MINUSMINUS) {
+        int op = l->tk;
+#ifndef MBED
+        l->match(l->tk);
+#else
+        LMATCH(l->tk);
+#endif
+        if (op==LEX_PLUSPLUS || op==LEX_MINUSMINUS) {
+            if (execute) {
+                CScriptVar one(1);
+                CScriptVar *res = a->var->mathsOp(&one, op==LEX_PLUSPLUS ? '+' : '-');
+                CScriptVarLink *oldValue = new CScriptVarLink(a->var);
+                // in-place add/subtract
+                a->replaceWith(res);
+                CLEAN(a);
+                a = oldValue;
+            }
+        } else {
+            CScriptVarLink *b = term(execute);
+            if (execute) {
+                // not in-place, so just replace
+                CScriptVar *res = a->var->mathsOp(b->var, op);
+                CREATE_LINK(a, res);
+            }
+            CLEAN(b);
+        }
+    }
+    return a;
+}
+
+CScriptVarLink *CTinyJS::shift(bool &execute) {
+  CScriptVarLink *a = expression(execute);
+  if (l->tk==LEX_LSHIFT || l->tk==LEX_RSHIFT || l->tk==LEX_RSHIFTUNSIGNED) {
+    int op = l->tk;
+#ifndef MBED
+    l->match(op);
+#else
+    LMATCH(op);
+#endif
+    CScriptVarLink *b = base(execute);
+    int shift = execute ? b->var->getInt() : 0;
+    CLEAN(b);
+    if (execute) {
+      if (op==LEX_LSHIFT) a->var->setInt(a->var->getInt() << shift);
+      if (op==LEX_RSHIFT) a->var->setInt(a->var->getInt() >> shift);
+      if (op==LEX_RSHIFTUNSIGNED) a->var->setInt(((unsigned int)a->var->getInt()) >> shift);
+    }
+  }
+  return a;
+}
+
+CScriptVarLink *CTinyJS::condition(bool &execute) {
+    CScriptVarLink *a = shift(execute);
+    CScriptVarLink *b;
+    while (l->tk==LEX_EQUAL || l->tk==LEX_NEQUAL ||
+           l->tk==LEX_TYPEEQUAL || l->tk==LEX_NTYPEEQUAL ||
+           l->tk==LEX_LEQUAL || l->tk==LEX_GEQUAL ||
+           l->tk=='<' || l->tk=='>') {
+        int op = l->tk;
+#ifndef MBED
+        l->match(l->tk);
+#else
+        LMATCH(l->tk);
+#endif
+        b = shift(execute);
+        if (execute) {
+            CScriptVar *res = a->var->mathsOp(b->var, op);
+            CREATE_LINK(a,res);
+        }
+        CLEAN(b);
+    }
+    return a;
+}
+
+CScriptVarLink *CTinyJS::logic(bool &execute) {
+    CScriptVarLink *a = condition(execute);
+    CScriptVarLink *b;
+    while (l->tk=='&' || l->tk=='|' || l->tk=='^' || l->tk==LEX_ANDAND || l->tk==LEX_OROR) {
+        bool noexecute = false;
+        int op = l->tk;
+#ifndef MBED
+        l->match(l->tk);
+#else
+        LMATCH(l->tk);
+#endif
+        bool shortCircuit = false;
+        bool boolean = false;
+        // if we have short-circuit ops, then if we know the outcome
+        // we don't bother to execute the other op. Even if not
+        // we need to tell mathsOp it's an & or |
+        if (op==LEX_ANDAND) {
+            op = '&';
+            shortCircuit = !a->var->getBool();
+            boolean = true;
+        } else if (op==LEX_OROR) {
+            op = '|';
+            shortCircuit = a->var->getBool();
+            boolean = true;
+        }
+        b = condition(shortCircuit ? noexecute : execute);
+        if (execute && !shortCircuit) {
+            if (boolean) {
+              CScriptVar *newa = new CScriptVar(a->var->getBool());
+              CScriptVar *newb = new CScriptVar(b->var->getBool());
+              CREATE_LINK(a, newa);
+              CREATE_LINK(b, newb);
+            }
+            CScriptVar *res = a->var->mathsOp(b->var, op);
+            CREATE_LINK(a, res);
+        }
+        CLEAN(b);
+    }
+    return a;
+}
+
+CScriptVarLink *CTinyJS::ternary(bool &execute) {
+  CScriptVarLink *lhs = logic(execute);
+  bool noexec = false;
+  if (l->tk=='?') {
+#ifndef MBED
+    l->match('?');
+#else
+    LMATCH('?');
+#endif
+    if (!execute) {
+      CLEAN(lhs);
+      CLEAN(base(noexec));
+#ifndef MBED
+      l->match(':');
+#else
+      LMATCH(':');
+#endif
+      CLEAN(base(noexec));
+    } else {
+      bool first = lhs->var->getBool();
+      CLEAN(lhs);
+      if (first) {
+        lhs = base(execute);
+#ifndef MBED
+        l->match(':');
+#else
+        LMATCH(':');
+#endif
+        CLEAN(base(noexec));
+      } else {
+        CLEAN(base(noexec));
+#ifndef MBED
+        l->match(':');
+#else
+        LMATCH(':');
+#endif
+        lhs = base(execute);
+      }
+    }
+  }
+
+  return lhs;
+}
+
+CScriptVarLink *CTinyJS::base(bool &execute) {
+    CScriptVarLink *lhs = ternary(execute);
+    if (l->tk=='=' || l->tk==LEX_PLUSEQUAL || l->tk==LEX_MINUSEQUAL) {
+        /* If we're assigning to this and we don't have a parent,
+         * add it to the symbol table root as per JavaScript. */
+        if (execute && !lhs->owned) {
+          if (lhs->name.length()>0) {
+            CScriptVarLink *realLhs = root->addChildNoDup(lhs->name, lhs->var);
+            CLEAN(lhs);
+            lhs = realLhs;
+          } else
+            TRACE("Trying to assign to an un-named type\n");
+        }
+
+        int op = l->tk;
+#ifndef MBED
+        l->match(l->tk);
+#else
+        LMATCH(l->tk);
+#endif
+        CScriptVarLink *rhs = base(execute);
+        if (execute) {
+            if (op=='=') {
+                lhs->replaceWith(rhs);
+            } else if (op==LEX_PLUSEQUAL) {
+                CScriptVar *res = lhs->var->mathsOp(rhs->var, '+');
+                lhs->replaceWith(res);
+            } else if (op==LEX_MINUSEQUAL) {
+                CScriptVar *res = lhs->var->mathsOp(rhs->var, '-');
+                lhs->replaceWith(res);
+            } else ASSERT(0);
+        }
+        CLEAN(rhs);
+    }
+    return lhs;
+}
+
+#ifndef MBED
+void CTinyJS::block(bool &execute) {
+    l->match('{');
+    if (execute) {
+      while (l->tk && l->tk!='}')
+        statement(execute);
+      l->match('}');
+    } else {
+      // fast skip of blocks
+      int brackets = 1;
+      while (l->tk && brackets) {
+        if (l->tk == '{') brackets++;
+        if (l->tk == '}') brackets--;
+        l->match(l->tk);
+      }
+    }
+}
+#else
+void CTinyJS::block(bool &execute) {
+    LMATCH_VOID('{');
+    if (execute) {
+      while (l->tk && l->tk!='}')
+        statement(execute);
+      LMATCH_VOID('}');
+    } else {
+      // fast skip of blocks
+      int brackets = 1;
+      while (l->tk && brackets) {
+        if (l->tk == '{') brackets++;
+        if (l->tk == '}') brackets--;
+        LMATCH_VOID(l->tk);
+      }
+    }
+}
+#endif
+
+#ifndef MBED
+void CTinyJS::statement(bool &execute) {
+    if (l->tk==LEX_ID ||
+        l->tk==LEX_INT ||
+        l->tk==LEX_FLOAT ||
+        l->tk==LEX_STR ||
+        l->tk=='-') {
+        /* Execute a simple statement that only contains basic arithmetic... */
+        CLEAN(base(execute));
+        l->match(';');
+    } else if (l->tk=='{') {
+        /* A block of code */
+        block(execute);
+    } else if (l->tk==';') {
+        /* Empty statement - to allow things like ;;; */
+        l->match(';');
+    } else if (l->tk==LEX_R_VAR) {
+        /* variable creation. TODO - we need a better way of parsing the left
+         * hand side. Maybe just have a flag called can_create_var that we
+         * set and then we parse as if we're doing a normal equals.*/
+        l->match(LEX_R_VAR);
+        while (l->tk != ';') {
+          CScriptVarLink *a = 0;
+          if (execute)
+            a = scopes.back()->findChildOrCreate(l->tkStr);
+          l->match(LEX_ID);
+          // now do stuff defined with dots
+          while (l->tk == '.') {
+              l->match('.');
+              if (execute) {
+                  CScriptVarLink *lastA = a;
+                  a = lastA->var->findChildOrCreate(l->tkStr);
+              }
+              l->match(LEX_ID);
+          }
+          // sort out initialiser
+          if (l->tk == '=') {
+              l->match('=');
+              CScriptVarLink *var = base(execute);
+              if (execute)
+                  a->replaceWith(var);
+              CLEAN(var);
+          }
+          if (l->tk != ';')
+            l->match(',');
+        }       
+        l->match(';');
+    } else if (l->tk==LEX_R_IF) {
+        l->match(LEX_R_IF);
+        l->match('(');
+        CScriptVarLink *var = base(execute);
+        l->match(')');
+        bool cond = execute && var->var->getBool();
+        CLEAN(var);
+        bool noexecute = false; // because we need to be abl;e to write to it
+        statement(cond ? execute : noexecute);
+        if (l->tk==LEX_R_ELSE) {
+            l->match(LEX_R_ELSE);
+            statement(cond ? noexecute : execute);
+        }
+    } else if (l->tk==LEX_R_WHILE) {
+        // We do repetition by pulling out the string representing our statement
+        // there's definitely some opportunity for optimisation here
+        l->match(LEX_R_WHILE);
+        l->match('(');
+        int whileCondStart = l->tokenStart;
+        bool noexecute = false;
+        CScriptVarLink *cond = base(execute);
+        bool loopCond = execute && cond->var->getBool();
+        CLEAN(cond);
+        CScriptLex *whileCond = l->getSubLex(whileCondStart);
+        l->match(')');
+        int whileBodyStart = l->tokenStart;
+        statement(loopCond ? execute : noexecute);
+        CScriptLex *whileBody = l->getSubLex(whileBodyStart);
+        CScriptLex *oldLex = l;
+        int loopCount = TINYJS_LOOP_MAX_ITERATIONS;
+        while (loopCond && loopCount-->0) {
+            whileCond->reset();
+            l = whileCond;
+            cond = base(execute);
+            loopCond = execute && cond->var->getBool();
+            CLEAN(cond);
+            if (loopCond) {
+                whileBody->reset();
+                l = whileBody;
+                statement(execute);
+            }
+        }
+        l = oldLex;
+        delete whileCond;
+        delete whileBody;
+
+        if (loopCount<=0) {
+            root->trace();
+            TRACE("WHILE Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str());
+            throw new CScriptException("LOOP_ERROR");
+        }
+    } else if (l->tk==LEX_R_FOR) {
+        l->match(LEX_R_FOR);
+        l->match('(');
+        statement(execute); // initialisation
+        //l->match(';');
+        int forCondStart = l->tokenStart;
+        bool noexecute = false;
+        CScriptVarLink *cond = base(execute); // condition
+        bool loopCond = execute && cond->var->getBool();
+        CLEAN(cond);
+        CScriptLex *forCond = l->getSubLex(forCondStart);
+        l->match(';');
+        int forIterStart = l->tokenStart;
+        CLEAN(base(noexecute)); // iterator
+        CScriptLex *forIter = l->getSubLex(forIterStart);
+        l->match(')');
+        int forBodyStart = l->tokenStart;
+        statement(loopCond ? execute : noexecute);
+        CScriptLex *forBody = l->getSubLex(forBodyStart);
+        CScriptLex *oldLex = l;
+        if (loopCond) {
+            forIter->reset();
+            l = forIter;
+            CLEAN(base(execute));
+        }
+        int loopCount = TINYJS_LOOP_MAX_ITERATIONS;
+        while (execute && loopCond && loopCount-->0) {
+            forCond->reset();
+            l = forCond;
+            cond = base(execute);
+            loopCond = cond->var->getBool();
+            CLEAN(cond);
+            if (execute && loopCond) {
+                forBody->reset();
+                l = forBody;
+                statement(execute);
+            }
+            if (execute && loopCond) {
+                forIter->reset();
+                l = forIter;
+                CLEAN(base(execute));
+            }
+        }
+        l = oldLex;
+        delete forCond;
+        delete forIter;
+        delete forBody;
+        if (loopCount<=0) {
+            root->trace();
+            TRACE("FOR Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str());
+            throw new CScriptException("LOOP_ERROR");
+        }
+    } else if (l->tk==LEX_R_RETURN) {
+        l->match(LEX_R_RETURN);
+        CScriptVarLink *result = 0;
+        if (l->tk != ';')
+          result = base(execute);
+        if (execute) {
+          CScriptVarLink *resultVar = scopes.back()->findChild(TINYJS_RETURN_VAR);
+          if (resultVar)
+            resultVar->replaceWith(result);
+          else
+            TRACE("RETURN statement, but not in a function.\n");
+          execute = false;
+        }
+        CLEAN(result);
+        l->match(';');
+    } else if (l->tk==LEX_R_FUNCTION) {
+        CScriptVarLink *funcVar = parseFunctionDefinition();
+        if (execute) {
+          if (funcVar->name == TINYJS_TEMP_NAME)
+            TRACE("Functions defined at statement-level are meant to have a name\n");
+          else
+            scopes.back()->addChildNoDup(funcVar->name, funcVar->var);
+        }
+        CLEAN(funcVar);
+    } else l->match(LEX_EOF);
+}
+
+#else
+
+void CTinyJS::statement(bool &execute) {
+    if (l->tk==LEX_ID ||
+        l->tk==LEX_INT ||
+        l->tk==LEX_FLOAT ||
+        l->tk==LEX_STR ||
+        l->tk=='-') {
+        /* Execute a simple statement that only contains basic arithmetic... */
+        CLEAN(base(execute));
+        LMATCH_VOID(';');
+    } else if (l->tk=='{') {
+        /* A block of code */
+        block(execute);
+    } else if (l->tk==';') {
+        /* Empty statement - to allow things like ;;; */
+        LMATCH_VOID(';');
+    } else if (l->tk==LEX_R_VAR) {
+        /* variable creation. TODO - we need a better way of parsing the left
+         * hand side. Maybe just have a flag called can_create_var that we
+         * set and then we parse as if we're doing a normal equals.*/
+        LMATCH_VOID(LEX_R_VAR);
+        while (l->tk != ';') {
+          CScriptVarLink *a = 0;
+          if (execute)
+            a = scopes.back()->findChildOrCreate(l->tkStr);
+          LMATCH_VOID(LEX_ID);
+          // now do stuff defined with dots
+          while (l->tk == '.') {
+              LMATCH_VOID('.');
+              if (execute) {
+                  CScriptVarLink *lastA = a;
+                  a = lastA->var->findChildOrCreate(l->tkStr);
+              }
+              LMATCH_VOID(LEX_ID);
+          }
+          // sort out initialiser
+          if (l->tk == '=') {
+              LMATCH_VOID('=');
+              CScriptVarLink *var = base(execute);
+              if (execute)
+                  a->replaceWith(var);
+              CLEAN(var);
+          }
+          if (l->tk != ';')
+            LMATCH_VOID(',');
+        }       
+        LMATCH_VOID(';');
+    } else if (l->tk==LEX_R_IF) {
+        LMATCH_VOID(LEX_R_IF);
+        LMATCH_VOID('(');
+        CScriptVarLink *var = base(execute);
+        LMATCH_VOID(')');
+        bool cond = execute && var->var->getBool();
+        CLEAN(var);
+        bool noexecute = false; // because we need to be abl;e to write to it
+        statement(cond ? execute : noexecute);
+        if (l->tk==LEX_R_ELSE) {
+            LMATCH_VOID(LEX_R_ELSE);
+            statement(cond ? noexecute : execute);
+        }
+    } else if (l->tk==LEX_R_WHILE) {
+        // We do repetition by pulling out the string representing our statement
+        // there's definitely some opportunity for optimisation here
+        LMATCH_VOID(LEX_R_WHILE);
+        LMATCH_VOID('(');
+        int whileCondStart = l->tokenStart;
+        bool noexecute = false;
+        CScriptVarLink *cond = base(execute);
+        bool loopCond = execute && cond->var->getBool();
+        CLEAN(cond);
+        CScriptLex *whileCond = l->getSubLex(whileCondStart);
+        LMATCH_VOID(')');
+        int whileBodyStart = l->tokenStart;
+        statement(loopCond ? execute : noexecute);
+        CScriptLex *whileBody = l->getSubLex(whileBodyStart);
+        CScriptLex *oldLex = l;
+        int loopCount = TINYJS_LOOP_MAX_ITERATIONS;
+        while (loopCond && loopCount-->0) {
+            whileCond->reset();
+            l = whileCond;
+            cond = base(execute);
+            loopCond = execute && cond->var->getBool();
+            CLEAN(cond);
+            if (loopCond) {
+                whileBody->reset();
+                l = whileBody;
+                statement(execute);
+            }
+        }
+        l = oldLex;
+        delete whileCond;
+        delete whileBody;
+
+        if (loopCount<=0) {
+            root->trace();
+            TRACE("WHILE Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str());
+            mbedErrorFlag = 1;
+            mbedErrorMessage = "LOOP_ERROR";
+            return;
+        }
+    } else if (l->tk==LEX_R_FOR) {
+        LMATCH_VOID(LEX_R_FOR);
+        LMATCH_VOID('(');
+        statement(execute); // initialisation
+        //LMATCH(';');
+        int forCondStart = l->tokenStart;
+        bool noexecute = false;
+        CScriptVarLink *cond = base(execute); // condition
+        bool loopCond = execute && cond->var->getBool();
+        CLEAN(cond);
+        CScriptLex *forCond = l->getSubLex(forCondStart);
+        LMATCH_VOID(';');
+        int forIterStart = l->tokenStart;
+        CLEAN(base(noexecute)); // iterator
+        CScriptLex *forIter = l->getSubLex(forIterStart);
+        LMATCH_VOID(')');
+        int forBodyStart = l->tokenStart;
+        statement(loopCond ? execute : noexecute);
+        CScriptLex *forBody = l->getSubLex(forBodyStart);
+        CScriptLex *oldLex = l;
+        if (loopCond) {
+            forIter->reset();
+            l = forIter;
+            CLEAN(base(execute));
+        }
+        int loopCount = TINYJS_LOOP_MAX_ITERATIONS;
+        while (execute && loopCond && loopCount-->0) {
+            forCond->reset();
+            l = forCond;
+            cond = base(execute);
+            loopCond = cond->var->getBool();
+            CLEAN(cond);
+            if (execute && loopCond) {
+                forBody->reset();
+                l = forBody;
+                statement(execute);
+            }
+            if (execute && loopCond) {
+                forIter->reset();
+                l = forIter;
+                CLEAN(base(execute));
+            }
+        }
+        l = oldLex;
+        delete forCond;
+        delete forIter;
+        delete forBody;
+        if (loopCount<=0) {
+            root->trace();
+            TRACE("FOR Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str());
+            mbedErrorFlag = 1;
+            mbedErrorMessage = "LOOP_ERROR";
+            return;
+        }
+    } else if (l->tk==LEX_R_RETURN) {
+        LMATCH_VOID(LEX_R_RETURN);
+        CScriptVarLink *result = 0;
+        if (l->tk != ';')
+          result = base(execute);
+        if (execute) {
+          CScriptVarLink *resultVar = scopes.back()->findChild(TINYJS_RETURN_VAR);
+          if (resultVar)
+            resultVar->replaceWith(result);
+          else
+            TRACE("RETURN statement, but not in a function.\n");
+          execute = false;
+        }
+        CLEAN(result);
+        LMATCH_VOID(';');
+    } else if (l->tk==LEX_R_FUNCTION) {
+        CScriptVarLink *funcVar = parseFunctionDefinition();
+        if (execute) {
+          if (funcVar->name == TINYJS_TEMP_NAME)
+            TRACE("Functions defined at statement-level are meant to have a name\n");
+          else
+            scopes.back()->addChildNoDup(funcVar->name, funcVar->var);
+        }
+        CLEAN(funcVar);
+    } else LMATCH_VOID(LEX_EOF);
+}
+#endif
+
+/// Get the given variable specified by a path (var1.var2.etc), or return 0
+CScriptVar *CTinyJS::getScriptVariable(const string &path) {
+    // traverse path
+    size_t prevIdx = 0;
+    size_t thisIdx = path.find('.');
+    if (thisIdx == string::npos) thisIdx = path.length();
+    CScriptVar *var = root;
+    while (var && prevIdx<path.length()) {
+        string el = path.substr(prevIdx, thisIdx-prevIdx);
+        CScriptVarLink *varl = var->findChild(el);
+        var = varl?varl->var:0;
+        prevIdx = thisIdx+1;
+        thisIdx = path.find('.', prevIdx);
+        if (thisIdx == string::npos) thisIdx = path.length();
+    }
+    return var;
+}
+
+/// Get the value of the given variable, or return 0
+const string *CTinyJS::getVariable(const string &path) {
+    CScriptVar *var = getScriptVariable(path);
+    // return result
+    if (var)
+        return &var->getString();
+    else
+        return 0;
+}
+
+/// set the value of the given variable, return trur if it exists and gets set
+bool CTinyJS::setVariable(const std::string &path, const std::string &varData) {
+    CScriptVar *var = getScriptVariable(path);
+    // return result
+    if (var) {
+        if (var->isInt())
+            var->setInt((int)strtol(varData.c_str(),0,0));
+        else if (var->isDouble())
+            var->setDouble(strtod(varData.c_str(),0));
+        else
+            var->setString(varData.c_str());
+        return true;
+    }    
+    else
+        return false;
+}
+
+/// Finds a child, looking recursively up the scopes
+CScriptVarLink *CTinyJS::findInScopes(const std::string &childName) {
+    for (int s=scopes.size()-1;s>=0;s--) {
+      CScriptVarLink *v = scopes[s]->findChild(childName);
+      if (v) return v;
+    }
+    return NULL;
+
+}
+
+/// Look up in any parent classes of the given object
+CScriptVarLink *CTinyJS::findInParentClasses(CScriptVar *object, const std::string &name) {
+    // Look for links to actual parent classes
+    CScriptVarLink *parentClass = object->findChild(TINYJS_PROTOTYPE_CLASS);
+    while (parentClass) {
+      CScriptVarLink *implementation = parentClass->var->findChild(name);
+      if (implementation) return implementation;
+      parentClass = parentClass->var->findChild(TINYJS_PROTOTYPE_CLASS);
+    }
+    // else fake it for strings and finally objects
+    if (object->isString()) {
+      CScriptVarLink *implementation = stringClass->findChild(name);
+      if (implementation) return implementation;
+    }
+    if (object->isArray()) {
+      CScriptVarLink *implementation = arrayClass->findChild(name);
+      if (implementation) return implementation;
+    }
+    CScriptVarLink *implementation = objectClass->findChild(name);
+    if (implementation) return implementation;
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyJS.h	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,377 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/*
+ * TinyJS for mbed.
+ *
+ * Authored by Takehisa Oneta (ohneta@gmail.com)
+ * 10th Jan. 2013
+*/
+
+#ifndef TINYJS_H
+#define TINYJS_H
+
+// If defined, this keeps a note of all calls and where from in memory. This is slower, but good for debugging
+#define TINYJS_CALL_STACK
+
+#ifdef _WIN32
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+#endif
+#include <string>
+#include <vector>
+
+#ifndef TRACE
+#define TRACE printf
+#endif // TRACE
+
+#ifndef MBED
+#define MBED	1
+#endif // MBED
+
+#define DEBUG_MEMORY 0
+
+
+const int TINYJS_LOOP_MAX_ITERATIONS = 8192;
+
+enum LEX_TYPES {
+    LEX_EOF = 0,
+    LEX_ID = 256,
+    LEX_INT,
+    LEX_FLOAT,
+    LEX_STR,
+
+    LEX_EQUAL,
+    LEX_TYPEEQUAL,
+    LEX_NEQUAL,
+    LEX_NTYPEEQUAL,
+    LEX_LEQUAL,
+    LEX_LSHIFT,
+    LEX_LSHIFTEQUAL,
+    LEX_GEQUAL,
+    LEX_RSHIFT,
+    LEX_RSHIFTUNSIGNED,
+    LEX_RSHIFTEQUAL,
+    LEX_PLUSEQUAL,
+    LEX_MINUSEQUAL,
+    LEX_PLUSPLUS,
+    LEX_MINUSMINUS,
+    LEX_ANDEQUAL,
+    LEX_ANDAND,
+    LEX_OREQUAL,
+    LEX_OROR,
+    LEX_XOREQUAL,
+    // reserved words
+#define LEX_R_LIST_START LEX_R_IF
+    LEX_R_IF,
+    LEX_R_ELSE,
+    LEX_R_DO,
+    LEX_R_WHILE,
+    LEX_R_FOR,
+    LEX_R_BREAK,
+    LEX_R_CONTINUE,
+    LEX_R_FUNCTION,
+    LEX_R_RETURN,
+    LEX_R_VAR,
+    LEX_R_TRUE,
+    LEX_R_FALSE,
+    LEX_R_NULL,
+    LEX_R_UNDEFINED,
+    LEX_R_NEW,
+
+	LEX_R_LIST_END /* always the last entry */
+};
+
+enum SCRIPTVAR_FLAGS {
+    SCRIPTVAR_UNDEFINED   = 0,
+    SCRIPTVAR_FUNCTION    = 1,
+    SCRIPTVAR_OBJECT      = 2,
+    SCRIPTVAR_ARRAY       = 4,
+    SCRIPTVAR_DOUBLE      = 8,  // floating point double
+    SCRIPTVAR_INTEGER     = 16, // integer number
+    SCRIPTVAR_STRING      = 32, // string
+    SCRIPTVAR_NULL        = 64, // it seems null is its own data type
+
+    SCRIPTVAR_NATIVE      = 128, // to specify this is a native function
+    SCRIPTVAR_NUMERICMASK = SCRIPTVAR_NULL |
+                            SCRIPTVAR_DOUBLE |
+                            SCRIPTVAR_INTEGER,
+    SCRIPTVAR_VARTYPEMASK = SCRIPTVAR_DOUBLE |
+                            SCRIPTVAR_INTEGER |
+                            SCRIPTVAR_STRING |
+                            SCRIPTVAR_FUNCTION |
+                            SCRIPTVAR_OBJECT |
+                            SCRIPTVAR_ARRAY |
+                            SCRIPTVAR_NULL,
+
+};
+
+#define TINYJS_RETURN_VAR "return"
+#define TINYJS_PROTOTYPE_CLASS "prototype"
+#define TINYJS_TEMP_NAME ""
+#define TINYJS_BLANK_DATA ""
+
+/// convert the given string into a quoted string suitable for javascript
+std::string getJSString(const std::string &str);
+
+class CScriptException {
+public:
+    std::string text;
+    CScriptException(const std::string &exceptionText);
+};
+
+class CScriptLex
+{
+public:
+    CScriptLex(const std::string &input);
+    CScriptLex(CScriptLex *owner, int startChar, int endChar);
+    ~CScriptLex(void);
+
+    char currCh, nextCh;
+    int tk; ///< The type of the token that we have
+    int tokenStart; ///< Position in the data at the beginning of the token we have here
+    int tokenEnd; ///< Position in the data at the last character of the token we have here
+    int tokenLastEnd; ///< Position in the data at the last character of the last token
+    std::string tkStr; ///< Data contained in the token we have here
+
+    void match(int expected_tk); ///< Lexical match wotsit
+    static std::string getTokenStr(int token); ///< Get the string representation of the given token
+    void reset(); ///< Reset this lex so we can start again
+
+    std::string getSubString(int pos); ///< Return a sub-string from the given position up until right now
+    CScriptLex *getSubLex(int lastPosition); ///< Return a sub-lexer from the given position up until right now
+
+    std::string getPosition(int pos=-1); ///< Return a string representing the position in lines and columns of the character pos given
+
+protected:
+    /* When we go into a loop, we use getSubLex to get a lexer for just the sub-part of the
+       relevant string. This doesn't re-allocate and copy the string, but instead copies
+       the data pointer and sets dataOwned to false, and dataStart/dataEnd to the relevant things. */
+    char *data; ///< Data string to get tokens from
+    int dataStart, dataEnd; ///< Start and end position in data string
+    bool dataOwned; ///< Do we own this data string?
+
+    int dataPos; ///< Position in data (we CAN go past the end of the string here)
+
+    void getNextCh();
+    void getNextToken(); ///< Get the text token from our text string
+};
+
+class CScriptVar;
+
+typedef void (*JSCallback)(CScriptVar *var, void *userdata);
+
+class CScriptVarLink
+{
+public:
+  std::string name;
+  CScriptVarLink *nextSibling;
+  CScriptVarLink *prevSibling;
+  CScriptVar *var;
+  bool owned;
+
+  CScriptVarLink(CScriptVar *var, const std::string &name = TINYJS_TEMP_NAME);
+  CScriptVarLink(const CScriptVarLink &link); ///< Copy constructor
+  ~CScriptVarLink();
+  void replaceWith(CScriptVar *newVar); ///< Replace the Variable pointed to
+  void replaceWith(CScriptVarLink *newVar); ///< Replace the Variable pointed to (just dereferences)
+  int getIntName(); ///< Get the name as an integer (for arrays)
+  void setIntName(int n); ///< Set the name as an integer (for arrays)
+};
+
+/// Variable class (containing a doubly-linked list of children)
+class CScriptVar
+{
+public:
+    CScriptVar(); ///< Create undefined
+    CScriptVar(const std::string &varData, int varFlags); ///< User defined
+    CScriptVar(const std::string &str); ///< Create a string
+    CScriptVar(double varData);
+    CScriptVar(int val);
+    ~CScriptVar(void);
+
+    CScriptVar *getReturnVar(); ///< If this is a function, get the result value (for use by native functions)
+    void setReturnVar(CScriptVar *var); ///< Set the result value. Use this when setting complex return data as it avoids a deepCopy()
+    CScriptVar *getParameter(const std::string &name); ///< If this is a function, get the parameter with the given name (for use by native functions)
+
+    CScriptVarLink *findChild(const std::string &childName); ///< Tries to find a child with the given name, may return 0
+    CScriptVarLink *findChildOrCreate(const std::string &childName, int varFlags=SCRIPTVAR_UNDEFINED); ///< Tries to find a child with the given name, or will create it with the given flags
+    CScriptVarLink *findChildOrCreateByPath(const std::string &path); ///< Tries to find a child with the given path (separated by dots)
+    CScriptVarLink *addChild(const std::string &childName, CScriptVar *child=NULL);
+    CScriptVarLink *addChildNoDup(const std::string &childName, CScriptVar *child=NULL); ///< add a child overwriting any with the same name
+    void removeChild(CScriptVar *child);
+    void removeLink(CScriptVarLink *link); ///< Remove a specific link (this is faster than finding via a child)
+    void removeAllChildren();
+    CScriptVar *getArrayIndex(int idx); ///< The the value at an array index
+    void setArrayIndex(int idx, CScriptVar *value); ///< Set the value at an array index
+    int getArrayLength(); ///< If this is an array, return the number of items in it (else 0)
+    int getChildren(); ///< Get the number of children
+
+    int getInt();
+    bool getBool() { return getInt() != 0; }
+    double getDouble();
+    const std::string &getString();
+    std::string getParsableString(); ///< get Data as a parsable javascript string
+    void setInt(int num);
+    void setDouble(double val);
+    void setString(const std::string &str);
+    void setUndefined();
+    void setArray();
+    bool equals(CScriptVar *v);
+
+    bool isInt() { return (flags&SCRIPTVAR_INTEGER)!=0; }
+    bool isDouble() { return (flags&SCRIPTVAR_DOUBLE)!=0; }
+    bool isString() { return (flags&SCRIPTVAR_STRING)!=0; }
+    bool isNumeric() { return (flags&SCRIPTVAR_NUMERICMASK)!=0; }
+    bool isFunction() { return (flags&SCRIPTVAR_FUNCTION)!=0; }
+    bool isObject() { return (flags&SCRIPTVAR_OBJECT)!=0; }
+    bool isArray() { return (flags&SCRIPTVAR_ARRAY)!=0; }
+    bool isNative() { return (flags&SCRIPTVAR_NATIVE)!=0; }
+    bool isUndefined() { return (flags & SCRIPTVAR_VARTYPEMASK) == SCRIPTVAR_UNDEFINED; }
+    bool isNull() { return (flags & SCRIPTVAR_NULL)!=0; }
+    bool isBasic() { return firstChild==0; } ///< Is this *not* an array/object/etc
+
+    CScriptVar *mathsOp(CScriptVar *b, int op); ///< do a maths op with another script variable
+    void copyValue(CScriptVar *val); ///< copy the value from the value given
+    CScriptVar *deepCopy(); ///< deep copy this node and return the result
+
+    void trace(std::string indentStr = "", const std::string &name = ""); ///< Dump out the contents of this using trace
+    std::string getFlagsAsString(); ///< For debugging - just dump a string version of the flags
+#ifndef MBED
+    void getJSON(std::ostringstream &destination, const std::string linePrefix=""); ///< Write out all the JS code needed to recreate this script variable to the stream (as JSON)
+#else
+    void getJSON(std::string &destination, const std::string linePrefix=""); ///< Write out all the JS code needed to recreate this script variable to the stream (as JSON)
+#endif
+    void setCallback(JSCallback callback, void *userdata); ///< Set the callback for native functions
+
+    CScriptVarLink *firstChild;
+    CScriptVarLink *lastChild;
+
+    /// For memory management/garbage collection
+    CScriptVar *ref(); ///< Add reference to this variable
+    void unref(); ///< Remove a reference, and delete this variable if required
+    int getRefs(); ///< Get the number of references to this script variable
+protected:
+    int refs; ///< The number of references held to this - used for garbage collection
+
+    std::string data; ///< The contents of this variable if it is a string
+    long intData; ///< The contents of this variable if it is an int
+    double doubleData; ///< The contents of this variable if it is a double
+    int flags; ///< the flags determine the type of the variable - int/double/string/etc
+    JSCallback jsCallback; ///< Callback for native functions
+    void *jsCallbackUserData; ///< user data passed as second argument to native functions
+
+    void init(); ///< initialisation of data members
+
+    /** Copy the basic data and flags from the variable given, with no
+      * children. Should be used internally only - by copyValue and deepCopy */
+    void copySimpleData(CScriptVar *val);
+
+    friend class CTinyJS;
+};
+
+class CTinyJS {
+public:
+    CTinyJS();
+    ~CTinyJS();
+
+    void execute(const std::string &code);
+    /** Evaluate the given code and return a link to a javascript object,
+     * useful for (dangerous) JSON parsing. If nothing to return, will return
+     * 'undefined' variable type. CScriptVarLink is returned as this will
+     * automatically unref the result as it goes out of scope. If you want to
+     * keep it, you must use ref() and unref() */
+    CScriptVarLink evaluateComplex(const std::string &code);
+    /** Evaluate the given code and return a string. If nothing to return, will return
+     * 'undefined' */
+    std::string evaluate(const std::string &code);
+
+    /// add a native function to be called from TinyJS
+    /** example:
+       \code
+           void scRandInt(CScriptVar *c, void *userdata) { ... }
+           tinyJS->addNative("function randInt(min, max)", scRandInt, 0);
+       \endcode
+
+       or
+
+       \code
+           void scSubstring(CScriptVar *c, void *userdata) { ... }
+           tinyJS->addNative("function String.substring(lo, hi)", scSubstring, 0);
+       \endcode
+    */
+    void addNative(const std::string &funcDesc, JSCallback ptr, void *userdata);
+
+    /// Get the given variable specified by a path (var1.var2.etc), or return 0
+    CScriptVar *getScriptVariable(const std::string &path);
+    /// Get the value of the given variable, or return 0
+    const std::string *getVariable(const std::string &path);
+    /// set the value of the given variable, return trur if it exists and gets set
+    bool setVariable(const std::string &path, const std::string &varData);
+
+    /// Send all variables to stdout
+    void trace();
+
+    CScriptVar *root;   /// root of symbol table
+private:
+    CScriptLex *l;             /// current lexer
+    std::vector<CScriptVar*> scopes; /// stack of scopes when parsing
+#ifdef TINYJS_CALL_STACK
+    std::vector<std::string> call_stack; /// Names of places called so we can show when erroring
+#endif
+
+    CScriptVar *stringClass; /// Built in string class
+    CScriptVar *objectClass; /// Built in object class
+    CScriptVar *arrayClass; /// Built in array class
+
+    // parsing - in order of precedence
+    CScriptVarLink *functionCall(bool &execute, CScriptVarLink *function, CScriptVar *parent);
+    CScriptVarLink *factor(bool &execute);
+    CScriptVarLink *unary(bool &execute);
+    CScriptVarLink *term(bool &execute);
+    CScriptVarLink *expression(bool &execute);
+    CScriptVarLink *shift(bool &execute);
+    CScriptVarLink *condition(bool &execute);
+    CScriptVarLink *logic(bool &execute);
+    CScriptVarLink *ternary(bool &execute);
+    CScriptVarLink *base(bool &execute);
+    void block(bool &execute);
+    void statement(bool &execute);
+    // parsing utility functions
+    CScriptVarLink *parseFunctionDefinition();
+    void parseFunctionArguments(CScriptVar *funcVar);
+
+    CScriptVarLink *findInScopes(const std::string &childName); ///< Finds a child, looking recursively up the scopes
+    /// Look up in any parent classes of the given object
+    CScriptVarLink *findInParentClasses(CScriptVar *object, const std::string &name);
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyJS_Functions.cpp	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,254 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * - Useful language functions
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "TinyJS_Functions.h"
+#include <math.h>
+#include <cstdlib>
+#include <sstream>
+
+using namespace std;
+// ----------------------------------------------- Actual Functions
+void scTrace(CScriptVar *c, void *userdata) {
+    CTinyJS *js = (CTinyJS*)userdata;
+    js->root->trace();
+}
+
+void scObjectDump(CScriptVar *c, void *) {
+    c->getParameter("this")->trace("> ");
+}
+
+void scObjectClone(CScriptVar *c, void *) {
+    CScriptVar *obj = c->getParameter("this");
+    c->getReturnVar()->copyValue(obj);
+}
+
+void scMathRand(CScriptVar *c, void *) {
+    c->getReturnVar()->setDouble((double)rand()/RAND_MAX);
+}
+
+void scMathRandInt(CScriptVar *c, void *) {
+    int min = c->getParameter("min")->getInt();
+    int max = c->getParameter("max")->getInt();
+    int val = min + (int)(rand()%(1+max-min));
+    c->getReturnVar()->setInt(val);
+}
+
+void scCharToInt(CScriptVar *c, void *) {
+    string str = c->getParameter("ch")->getString();;
+    int val = 0;
+    if (str.length()>0)
+        val = (int)str.c_str()[0];
+    c->getReturnVar()->setInt(val);
+}
+
+void scStringIndexOf(CScriptVar *c, void *) {
+    string str = c->getParameter("this")->getString();
+    string search = c->getParameter("search")->getString();
+    size_t p = str.find(search);
+    int val = (p==string::npos) ? -1 : p;
+    c->getReturnVar()->setInt(val);
+}
+
+void scStringSubstring(CScriptVar *c, void *) {
+    string str = c->getParameter("this")->getString();
+    int lo = c->getParameter("lo")->getInt();
+    int hi = c->getParameter("hi")->getInt();
+
+    int l = hi-lo;
+    if (l>0 && lo>=0 && lo+l<=(int)str.length())
+      c->getReturnVar()->setString(str.substr(lo, l));
+    else
+      c->getReturnVar()->setString("");
+}
+
+void scStringCharAt(CScriptVar *c, void *) {
+    string str = c->getParameter("this")->getString();
+    int p = c->getParameter("pos")->getInt();
+    if (p>=0 && p<(int)str.length())
+      c->getReturnVar()->setString(str.substr(p, 1));
+    else
+      c->getReturnVar()->setString("");
+}
+
+void scStringCharCodeAt(CScriptVar *c, void *) {
+    string str = c->getParameter("this")->getString();
+    int p = c->getParameter("pos")->getInt();
+    if (p>=0 && p<(int)str.length())
+      c->getReturnVar()->setInt(str.at(p));
+    else
+      c->getReturnVar()->setInt(0);
+}
+
+void scStringSplit(CScriptVar *c, void *) {
+    string str = c->getParameter("this")->getString();
+    string sep = c->getParameter("separator")->getString();
+    CScriptVar *result = c->getReturnVar();
+    result->setArray();
+    int length = 0;
+
+    size_t pos = str.find(sep);
+    while (pos != string::npos) {
+      result->setArrayIndex(length++, new CScriptVar(str.substr(0,pos)));
+      str = str.substr(pos+1);
+      pos = str.find(sep);
+    }
+
+    if (str.size()>0)
+      result->setArrayIndex(length++, new CScriptVar(str));
+}
+
+void scStringFromCharCode(CScriptVar *c, void *) {
+    char str[2];
+    str[0] = c->getParameter("char")->getInt();
+    str[1] = 0;
+    c->getReturnVar()->setString(str);
+}
+
+void scIntegerParseInt(CScriptVar *c, void *) {
+    string str = c->getParameter("str")->getString();
+    int val = strtol(str.c_str(),0,0);
+    c->getReturnVar()->setInt(val);
+}
+
+void scIntegerValueOf(CScriptVar *c, void *) {
+    string str = c->getParameter("str")->getString();
+
+    int val = 0;
+    if (str.length()==1)
+      val = str[0];
+    c->getReturnVar()->setInt(val);
+}
+
+void scJSONStringify(CScriptVar *c, void *) {
+#ifndef MBED
+    std::ostringstream result;
+    c->getParameter("obj")->getJSON(result);
+    c->getReturnVar()->setString(result.str());
+#else
+    std::string result;
+    c->getParameter("obj")->getJSON(result);
+    c->getReturnVar()->setString(result);
+#endif
+}
+
+void scExec(CScriptVar *c, void *data) {
+    CTinyJS *tinyJS = (CTinyJS *)data;
+    std::string str = c->getParameter("jsCode")->getString();
+    tinyJS->execute(str);
+}
+
+void scEval(CScriptVar *c, void *data) {
+    CTinyJS *tinyJS = (CTinyJS *)data;
+    std::string str = c->getParameter("jsCode")->getString();
+    c->setReturnVar(tinyJS->evaluateComplex(str).var);
+}
+
+void scArrayContains(CScriptVar *c, void *data) {
+  CScriptVar *obj = c->getParameter("obj");
+  CScriptVarLink *v = c->getParameter("this")->firstChild;
+
+  bool contains = false;
+  while (v) {
+      if (v->var->equals(obj)) {
+        contains = true;
+        break;
+      }
+      v = v->nextSibling;
+  }
+
+  c->getReturnVar()->setInt(contains);
+}
+
+void scArrayRemove(CScriptVar *c, void *data) {
+  CScriptVar *obj = c->getParameter("obj");
+  vector<int> removedIndices;
+  CScriptVarLink *v;
+  // remove
+  v = c->getParameter("this")->firstChild;
+  while (v) {
+      if (v->var->equals(obj)) {
+        removedIndices.push_back(v->getIntName());
+      }
+      v = v->nextSibling;
+  }
+  // renumber
+  v = c->getParameter("this")->firstChild;
+  while (v) {
+      int n = v->getIntName();
+      int newn = n;
+      for (size_t i=0;i<removedIndices.size();i++)
+        if (n>=removedIndices[i])
+          newn--;
+      if (newn!=n)
+        v->setIntName(newn);
+      v = v->nextSibling;
+  }
+}
+
+void scArrayJoin(CScriptVar *c, void *data) {
+  string sep = c->getParameter("separator")->getString();
+  CScriptVar *arr = c->getParameter("this");
+
+  ostringstream sstr;
+  int l = arr->getArrayLength();
+  for (int i=0;i<l;i++) {
+    if (i>0) sstr << sep;
+    sstr << arr->getArrayIndex(i)->getString();
+  }
+
+  c->getReturnVar()->setString(sstr.str());
+}
+
+// ----------------------------------------------- Register Functions
+void registerFunctions(CTinyJS *tinyJS) {
+    tinyJS->addNative("function exec(jsCode)", scExec, tinyJS); // execute the given code
+    tinyJS->addNative("function eval(jsCode)", scEval, tinyJS); // execute the given string (an expression) and return the result
+    tinyJS->addNative("function trace()", scTrace, tinyJS);
+    tinyJS->addNative("function Object.dump()", scObjectDump, 0);
+    tinyJS->addNative("function Object.clone()", scObjectClone, 0);
+    tinyJS->addNative("function Math.rand()", scMathRand, 0);
+    tinyJS->addNative("function Math.randInt(min, max)", scMathRandInt, 0);
+    tinyJS->addNative("function charToInt(ch)", scCharToInt, 0); //  convert a character to an int - get its value
+    tinyJS->addNative("function String.indexOf(search)", scStringIndexOf, 0); // find the position of a string in a string, -1 if not
+    tinyJS->addNative("function String.substring(lo,hi)", scStringSubstring, 0);
+    tinyJS->addNative("function String.charAt(pos)", scStringCharAt, 0);
+    tinyJS->addNative("function String.charCodeAt(pos)", scStringCharCodeAt, 0);
+    tinyJS->addNative("function String.fromCharCode(char)", scStringFromCharCode, 0);
+    tinyJS->addNative("function String.split(separator)", scStringSplit, 0);
+    tinyJS->addNative("function Integer.parseInt(str)", scIntegerParseInt, 0); // string to int
+    tinyJS->addNative("function Integer.valueOf(str)", scIntegerValueOf, 0); // value of a single character
+    tinyJS->addNative("function JSON.stringify(obj, replacer)", scJSONStringify, 0); // convert to JSON. replacer is ignored at the moment
+    // JSON.parse is left out as you can (unsafely!) use eval instead
+    tinyJS->addNative("function Array.contains(obj)", scArrayContains, 0);
+    tinyJS->addNative("function Array.remove(obj)", scArrayRemove, 0);
+    tinyJS->addNative("function Array.join(separator)", scArrayJoin, 0);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyJS_Functions.h	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef TINYJS_FUNCTIONS_H
+#define TINYJS_FUNCTIONS_H
+
+#include "TinyJS.h"
+
+/// Register useful functions with the TinyJS interpreter
+extern void registerFunctions(CTinyJS *tinyJS);
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyJS_MathFunctions.cpp	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,286 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * -  Math and Trigonometry functions
+ *
+ * Authored By O.Z.L.B. <ozlbinfo@gmail.com>
+ *
+ * Copyright (C) 2011 O.Z.L.B.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <math.h>
+#include <cstdlib>
+#include <sstream>
+#include "TinyJS_MathFunctions.h"
+
+using namespace std;
+
+#define k_E                 exp(1.0)
+#define k_PI                3.1415926535897932384626433832795
+
+#define F_ABS(a)            ((a)>=0 ? (a) : (-(a)))
+#define F_MIN(a,b)          ((a)>(b) ? (b) : (a))
+#define F_MAX(a,b)          ((a)>(b) ? (a) : (b))
+#define F_SGN(a)            ((a)>0 ? 1 : ((a)<0 ? -1 : 0 ))
+#define F_RNG(a,min,max)    ((a)<(min) ? min : ((a)>(max) ? max : a ))
+#define F_ROUND(a)          ((a)>0 ? (int) ((a)+0.5) : (int) ((a)-0.5) )
+ 
+//CScriptVar shortcut macro
+#define scIsInt(a)          ( c->getParameter(a)->isInt() )
+#define scIsDouble(a)       ( c->getParameter(a)->isDouble() )  
+#define scGetInt(a)         ( c->getParameter(a)->getInt() )
+#define scGetDouble(a)      ( c->getParameter(a)->getDouble() )  
+#define scReturnInt(a)      ( c->getReturnVar()->setInt(a) )
+#define scReturnDouble(a)   ( c->getReturnVar()->setDouble(a) )  
+
+#ifdef _MSC_VER
+namespace
+{
+    double asinh( const double &value )
+    {
+        double returned;
+
+        if(value>0)
+        returned = log(value + sqrt(value * value + 1));
+        else
+        returned = -log(-value + sqrt(value * value + 1));
+
+        return(returned);
+    }
+
+    double acosh( const double &value )
+    {
+        double returned;
+
+        if(value>0)
+        returned = log(value + sqrt(value * value - 1));
+        else
+        returned = -log(-value + sqrt(value * value - 1));
+
+        return(returned);
+    }
+}
+#endif
+
+//Math.abs(x) - returns absolute of given value
+void scMathAbs(CScriptVar *c, void *userdata) {
+    if ( scIsInt("a") ) {
+      scReturnInt( F_ABS( scGetInt("a") ) );
+    } else if ( scIsDouble("a") ) {
+      scReturnDouble( F_ABS( scGetDouble("a") ) );
+    }
+}
+
+//Math.round(a) - returns nearest round of given value
+void scMathRound(CScriptVar *c, void *userdata) {
+    if ( scIsInt("a") ) {
+      scReturnInt( F_ROUND( scGetInt("a") ) );
+    } else if ( scIsDouble("a") ) {
+      scReturnDouble( F_ROUND( scGetDouble("a") ) );
+    }
+}
+
+//Math.min(a,b) - returns minimum of two given values 
+void scMathMin(CScriptVar *c, void *userdata) {
+    if ( (scIsInt("a")) && (scIsInt("b")) ) {
+      scReturnInt( F_MIN( scGetInt("a"), scGetInt("b") ) );
+    } else {
+      scReturnDouble( F_MIN( scGetDouble("a"), scGetDouble("b") ) );
+    }
+}
+
+//Math.max(a,b) - returns maximum of two given values  
+void scMathMax(CScriptVar *c, void *userdata) {
+    if ( (scIsInt("a")) && (scIsInt("b")) ) {
+      scReturnInt( F_MAX( scGetInt("a"), scGetInt("b") ) );
+    } else {
+      scReturnDouble( F_MAX( scGetDouble("a"), scGetDouble("b") ) );
+    }
+}
+
+//Math.range(x,a,b) - returns value limited between two given values  
+void scMathRange(CScriptVar *c, void *userdata) {
+    if ( (scIsInt("x")) ) {
+      scReturnInt( F_RNG( scGetInt("x"), scGetInt("a"), scGetInt("b") ) );
+    } else {
+      scReturnDouble( F_RNG( scGetDouble("x"), scGetDouble("a"), scGetDouble("b") ) );
+    }
+}
+
+//Math.sign(a) - returns sign of given value (-1==negative,0=zero,1=positive)
+void scMathSign(CScriptVar *c, void *userdata) {
+    if ( scIsInt("a") ) {
+      scReturnInt( F_SGN( scGetInt("a") ) );
+    } else if ( scIsDouble("a") ) {
+      scReturnDouble( F_SGN( scGetDouble("a") ) );
+    }
+}
+
+//Math.PI() - returns PI value
+void scMathPI(CScriptVar *c, void *userdata) {
+    scReturnDouble(k_PI);
+}
+
+//Math.toDegrees(a) - returns degree value of a given angle in radians
+void scMathToDegrees(CScriptVar *c, void *userdata) {
+    scReturnDouble( (180.0/k_PI)*( scGetDouble("a") ) );
+}
+
+//Math.toRadians(a) - returns radians value of a given angle in degrees
+void scMathToRadians(CScriptVar *c, void *userdata) {
+    scReturnDouble( (k_PI/180.0)*( scGetDouble("a") ) );
+}
+
+//Math.sin(a) - returns trig. sine of given angle in radians
+void scMathSin(CScriptVar *c, void *userdata) {
+    scReturnDouble( sin( scGetDouble("a") ) );
+}
+
+//Math.asin(a) - returns trig. arcsine of given angle in radians
+void scMathASin(CScriptVar *c, void *userdata) {
+    scReturnDouble( asin( scGetDouble("a") ) );
+}
+
+//Math.cos(a) - returns trig. cosine of given angle in radians
+void scMathCos(CScriptVar *c, void *userdata) {
+    scReturnDouble( cos( scGetDouble("a") ) );
+}
+
+//Math.acos(a) - returns trig. arccosine of given angle in radians
+void scMathACos(CScriptVar *c, void *userdata) {
+    scReturnDouble( acos( scGetDouble("a") ) );
+}
+
+//Math.tan(a) - returns trig. tangent of given angle in radians
+void scMathTan(CScriptVar *c, void *userdata) {
+    scReturnDouble( tan( scGetDouble("a") ) );
+}
+
+//Math.atan(a) - returns trig. arctangent of given angle in radians
+void scMathATan(CScriptVar *c, void *userdata) {
+    scReturnDouble( atan( scGetDouble("a") ) );
+}
+
+//Math.sinh(a) - returns trig. hyperbolic sine of given angle in radians
+void scMathSinh(CScriptVar *c, void *userdata) {
+    scReturnDouble( sinh( scGetDouble("a") ) );
+}
+
+//Math.asinh(a) - returns trig. hyperbolic arcsine of given angle in radians
+void scMathASinh(CScriptVar *c, void *userdata) {
+    scReturnDouble( asinh( scGetDouble("a") ) );
+}
+
+//Math.cosh(a) - returns trig. hyperbolic cosine of given angle in radians
+void scMathCosh(CScriptVar *c, void *userdata) {
+    scReturnDouble( cosh( scGetDouble("a") ) );
+}
+
+//Math.acosh(a) - returns trig. hyperbolic arccosine of given angle in radians
+void scMathACosh(CScriptVar *c, void *userdata) {
+    scReturnDouble( acosh( scGetDouble("a") ) );
+}
+
+//Math.tanh(a) - returns trig. hyperbolic tangent of given angle in radians
+void scMathTanh(CScriptVar *c, void *userdata) {
+    scReturnDouble( tanh( scGetDouble("a") ) );
+}
+
+//Math.atan(a) - returns trig. hyperbolic arctangent of given angle in radians
+void scMathATanh(CScriptVar *c, void *userdata) {
+    scReturnDouble( atan( scGetDouble("a") ) );
+}
+
+//Math.E() - returns E Neplero value
+void scMathE(CScriptVar *c, void *userdata) {
+    scReturnDouble(k_E);
+}
+
+//Math.log(a) - returns natural logaritm (base E) of given value
+void scMathLog(CScriptVar *c, void *userdata) {
+    scReturnDouble( log( scGetDouble("a") ) );
+}
+
+//Math.log10(a) - returns logaritm(base 10) of given value
+void scMathLog10(CScriptVar *c, void *userdata) {
+    scReturnDouble( log10( scGetDouble("a") ) );
+}
+
+//Math.exp(a) - returns e raised to the power of a given number
+void scMathExp(CScriptVar *c, void *userdata) {
+    scReturnDouble( exp( scGetDouble("a") ) );
+}
+
+//Math.pow(a,b) - returns the result of a number raised to a power (a)^(b)
+void scMathPow(CScriptVar *c, void *userdata) {
+    scReturnDouble( pow( scGetDouble("a"), scGetDouble("b") ) );
+}
+
+//Math.sqr(a) - returns square of given value
+void scMathSqr(CScriptVar *c, void *userdata) {
+    scReturnDouble( ( scGetDouble("a") * scGetDouble("a") ) );
+}
+
+//Math.sqrt(a) - returns square root of given value
+void scMathSqrt(CScriptVar *c, void *userdata) {
+    scReturnDouble( sqrtf( scGetDouble("a") ) );
+}
+
+// ----------------------------------------------- Register Functions
+void registerMathFunctions(CTinyJS *tinyJS) {
+     
+    // --- Math and Trigonometry functions ---
+    tinyJS->addNative("function Math.abs(a)", scMathAbs, 0);
+    tinyJS->addNative("function Math.round(a)", scMathRound, 0);
+    tinyJS->addNative("function Math.min(a,b)", scMathMin, 0);
+    tinyJS->addNative("function Math.max(a,b)", scMathMax, 0);
+    tinyJS->addNative("function Math.range(x,a,b)", scMathRange, 0);
+    tinyJS->addNative("function Math.sign(a)", scMathSign, 0);
+    
+    tinyJS->addNative("function Math.PI()", scMathPI, 0);
+    tinyJS->addNative("function Math.toDegrees(a)", scMathToDegrees, 0);
+    tinyJS->addNative("function Math.toRadians(a)", scMathToRadians, 0);
+    tinyJS->addNative("function Math.sin(a)", scMathSin, 0);
+    tinyJS->addNative("function Math.asin(a)", scMathASin, 0);
+    tinyJS->addNative("function Math.cos(a)", scMathCos, 0);
+    tinyJS->addNative("function Math.acos(a)", scMathACos, 0);
+    tinyJS->addNative("function Math.tan(a)", scMathTan, 0);
+    tinyJS->addNative("function Math.atan(a)", scMathATan, 0);
+    tinyJS->addNative("function Math.sinh(a)", scMathSinh, 0);
+    tinyJS->addNative("function Math.asinh(a)", scMathASinh, 0);
+    tinyJS->addNative("function Math.cosh(a)", scMathCosh, 0);
+    tinyJS->addNative("function Math.acosh(a)", scMathACosh, 0);
+    tinyJS->addNative("function Math.tanh(a)", scMathTanh, 0);
+    tinyJS->addNative("function Math.atanh(a)", scMathATanh, 0);
+       
+    tinyJS->addNative("function Math.E()", scMathE, 0);
+    tinyJS->addNative("function Math.log(a)", scMathLog, 0);
+    tinyJS->addNative("function Math.log10(a)", scMathLog10, 0);
+    tinyJS->addNative("function Math.exp(a)", scMathExp, 0);
+    tinyJS->addNative("function Math.pow(a,b)", scMathPow, 0);
+    
+    tinyJS->addNative("function Math.sqr(a)", scMathSqr, 0);
+    tinyJS->addNative("function Math.sqrt(a)", scMathSqrt, 0);    
+  
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyJS_MathFunctions.h	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,10 @@
+#ifndef TINYJS_MATHFUNCTIONS_H
+#define TINYJS_MATHFUNCTIONS_H
+
+#include "TinyJS.h"
+
+/// Register useful math. functions with the TinyJS interpreter
+extern void registerMathFunctions(CTinyJS *tinyJS);
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,125 @@
+/*
+ * TinyJS for mbed.
+ *
+ * Authored by Takehisa Oneta (ohneta@gmail.com)
+ * 10th Jan. 2013
+ */
+
+#include "mbed.h"
+#include "TinyJS.h"
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+//unsigned char usbArea[1024] __attribute__((section("AHBSRAM0")));
+//unsigned char ethArea[1024] __attribute__((section("AHBSRAM1")));
+
+
+extern int tinyjs_main(int argc, char **argv);
+
+//---------------------------------------------
+
+void mbedDigitalOut(CScriptVar *c, void *)
+{
+    int pinName = c->getParameter("pinName")->getInt();
+    int val = c->getParameter("val")->getInt();
+
+    switch (pinName) {
+        case LED1:
+            led1 = val;
+            break;
+        case LED2:
+            led2 = val;
+            break;
+        case LED3:
+            led3 = val;
+            break;
+        case LED4:
+            led4 = val;
+            break;
+    }
+}
+
+char ledVarStr[32];
+char *mbedLedsVarString(int ledNo)
+{
+  switch (ledNo) {
+      case 1:
+        sprintf(ledVarStr,  "var led1 = %d;", LED1);
+        break;
+      case 2:
+        sprintf(ledVarStr,  "var led2 = %d;", LED2);
+        break;
+      case 3:
+        sprintf(ledVarStr,  "var led3 = %d;", LED3);
+        break;
+      case 4:
+        sprintf(ledVarStr,  "var led4 = %d;", LED4);
+        break;
+      default:
+        sprintf(ledVarStr,  "");
+        break;
+  }
+  return ledVarStr;
+}
+
+//---------------------------------------------
+void mbedMemfree(CScriptVar *c, void *)
+{
+    int i = 0;
+    while(1) {
+        void *p = malloc(i);
+        if (p == NULL)  break;
+        free(p);
+        i++;
+    }
+    c->getReturnVar()->setInt(i);
+}
+
+//---------------------------------------------
+
+int readOneLine(char *buffer, const int bufferSize)
+{
+    int len = 0;
+
+    buffer[0] = '\0';
+    while (true) {
+        char c = pc.getc();
+        pc.putc(c);
+
+        if ('\r' == c) {
+            return len;
+        } else if( '\n' == c ) {
+        } else {
+            buffer[len] = c;
+            buffer[len + 1] = '\0';
+            len++;
+            if (len > bufferSize) {
+                return len;
+            }
+        }
+    }
+
+    return len;
+}
+
+//---------------------------------------------
+//---------------------------------------------
+
+int main() {
+    pc.baud(57600);
+
+    while(1) {
+        printf("\n");
+        printf("--------------------------\n");
+        printf("TinyJS on mbed LPC1768 ported by ohneta.\n");
+
+        tinyjs_main(NULL, NULL);
+
+        printf("--------------------------\n");
+        printf("bye bye\n");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Jan 11 20:19:11 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file