Merge change 2341

* changes:
  Convert libacc into a shared library.
diff --git a/include/acc/acc.h b/include/acc/acc.h
new file mode 100644
index 0000000..054d6a0
--- /dev/null
+++ b/include/acc/acc.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ACC_ACC_H
+#define ANDROID_ACC_ACC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef char                        ACCchar;
+typedef int32_t                     ACCint;
+typedef uint32_t                    ACCuint;
+typedef ssize_t                     ACCsizei;
+typedef unsigned int                ACCenum;
+typedef void                        ACCvoid;
+typedef struct ACCscript            ACCscript;
+
+#define ACC_NO_ERROR                0x0000
+#define ACC_INVALID_ENUM            0x0500
+#define ACC_INVALID_OPERATION       0x0502
+#define ACC_INVALID_VALUE           0x0501
+#define ACC_OUT_OF_MEMORY           0x0505
+
+#define ACC_COMPILE_STATUS          0x8B81
+#define ACC_INFO_LOG_LENGTH         0x8B84
+
+
+// ----------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ACCscript* accCreateScript();
+
+void accDeleteScript(ACCscript* script);
+
+ACCenum accGetError( ACCscript* script );
+
+void accScriptSource(ACCscript* script,
+    ACCsizei count,
+    const ACCchar** string,
+    const ACCint* length);
+
+void accCompileScript(ACCscript* script);
+
+void accGetScriptiv(ACCscript* script,
+    ACCenum pname,
+    ACCint* params);
+
+void accGetScriptInfoLog(ACCscript* script,
+    ACCsizei maxLength,
+    ACCsizei* length,
+    ACCchar* infoLog);
+
+void accGetScriptLabel(ACCscript* script, const ACCchar * name,
+                       ACCvoid** address);
+
+#ifdef __cplusplus
+};
+#endif
+
+// ----------------------------------------------------------------------------
+
+#endif
diff --git a/libacc/Android.mk b/libacc/Android.mk
index c3207cc..77c71c6 100644
--- a/libacc/Android.mk
+++ b/libacc/Android.mk
@@ -5,8 +5,15 @@
 # Shared library
 #
 
-LOCAL_MODULE:= acc
-LOCAL_SRC_FILES := acc.cpp disassem.cpp
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libacc
+LOCAL_SRC_FILES := acc.cpp
 
-include $(BUILD_EXECUTABLE)
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SRC_FILES += disassem.cpp
+endif
+
+LOCAL_SHARED_LIBRARIES := libdl
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/libacc/LICENSE b/libacc/LICENSE
new file mode 100644
index 0000000..aea41e0
--- /dev/null
+++ b/libacc/LICENSE
@@ -0,0 +1,21 @@
+ Obfuscated Tiny C Compiler
+
+ Copyright (C) 2001-2003 Fabrice Bellard
+
+ This software is provided 'as-is', without any express or implied
+ warranty.  In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product and its documentation
+ *is* required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 04d45d5..db208cc 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -4,33 +4,10 @@
  * in scripting environments where speed and memory footprint are important.
  *
  * This code is based upon the "unobfuscated" version of the
- * Obfuscated Tiny C compiler, and retains the
- * original copyright notice and license from that compiler, see below.
+ * Obfuscated Tiny C compiler, see the file LICENSE for details.
  *
  */
 
-/*
- Obfuscated Tiny C Compiler
-
- Copyright (C) 2001-2003 Fabrice Bellard
-
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product and its documentation
- *is* required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
-
 #include <ctype.h>
 #include <dlfcn.h>
 #include <stdarg.h>
@@ -59,6 +36,8 @@
 #include "disassem.h"
 #endif
 
+#include <acc/acc.h>
+
 namespace acc {
 
 class Compiler {
@@ -116,6 +95,27 @@
         }
     };
 
+    /**
+     * A code generator creates an in-memory program, generating the code on
+     * the fly. There is one code generator implementation for each supported
+     * architecture.
+     *
+     * The code generator implements the following abstract machine:
+     * R0 - the main accumulator.
+     * R1 - the secondary accumulator.
+     * FP - a frame pointer for accessing function arguments and local
+     *      variables.
+     * SP - a stack pointer for storing intermediate results while evaluating
+     *      expressions. The stack pointer grows downwards.
+     *
+     * The function calling convention is that all arguments are placed on the
+     * stack such that the first argument has the lowest address.
+     * After the call, the result is in R0. The caller is responsible for
+     * removing the arguments from the stack.
+     * The R0 and R1 registers are not saved across function calls. The
+     * FP and SP registers are saved.
+     */
+
     class CodeGenerator {
     public:
         CodeGenerator() {}
@@ -125,70 +125,170 @@
             this->pCodeBuf = pCodeBuf;
         }
 
-        /* returns address to patch with local variable size
+        /* Emit a function prolog.
+         * argCount is the number of arguments.
+         * Save the old value of the FP.
+         * Set the new value of the FP.
+         * Convert from the native platform calling convention to
+         * our stack-based calling convention. This may require
+         * pushing arguments from registers to the stack.
+         * Allocate "N" bytes of stack space. N isn't known yet, so
+         * just emit the instructions for adjusting the stack, and return
+         * the address to patch up. The patching will be done in
+         * functionExit().
+         * returns address to patch with local variable size.
         */
         virtual int functionEntry(int argCount) = 0;
 
-        virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) = 0;
+        /* Emit a function epilog.
+         * Restore the old SP and FP register values.
+         * Return to the calling function.
+         * argCount - the number of arguments to the function.
+         * localVariableAddress - returned from functionEntry()
+         * localVariableSize - the size in bytes of the local variables.
+         */
+        virtual void functionExit(int argCount, int localVariableAddress,
+                                  int localVariableSize) = 0;
 
-        /* load immediate value */
+        /* load immediate value to R0 */
         virtual void li(int t) = 0;
 
+        /* Jump to a target, and return the address of the word that
+         * holds the target data, in case it needs to be fixed up later.
+         */
         virtual int gjmp(int t) = 0;
 
-        /* l = 0: je, l == 1: jne */
+        /* Test R0 and jump to a target if the test succeeds.
+         * l = 0: je, l == 1: jne
+         * Return the address of the word that holds the targed data, in
+         * case it needs to be fixed up later.
+         */
         virtual int gtst(bool l, int t) = 0;
 
+        /* Compare R1 against R0, and store the boolean result in R0.
+         * op specifies the comparison.
+         */
         virtual void gcmp(int op) = 0;
 
+        /* Perform the arithmetic op specified by op. R1 is the
+         * left argument, R0 is the right argument.
+         */
         virtual void genOp(int op) = 0;
 
-        virtual void clearECX() = 0;
+        /* Set R1 to 0.
+         */
+        virtual void clearR1() = 0;
 
-        virtual void pushEAX() = 0;
+        /* Push R0 onto the stack.
+         */
+        virtual void pushR0() = 0;
 
-        virtual void popECX() = 0;
+        /* Pop R1 off of the stack.
+         */
+        virtual void popR1() = 0;
 
-        virtual void storeEAXToAddressECX(bool isInt) = 0;
+        /* Store R0 to the address stored in R1.
+         * isInt is true if a whole 4-byte integer value
+         * should be stored, otherwise a 1-byte character
+         * value should be stored.
+         */
+        virtual void storeR0ToR1(bool isInt) = 0;
 
-        virtual void loadEAXIndirect(bool isInt) = 0;
+        /* Load R0 from the address stored in R0.
+         * isInt is true if a whole 4-byte integer value
+         * should be loaded, otherwise a 1-byte character
+         * value should be loaded.
+         */
+        virtual void loadR0FromR0(bool isInt) = 0;
 
-        virtual void leaEAX(int ea) = 0;
+        /* Load the absolute address of a variable to R0.
+         * If ea <= LOCAL, then this is a local variable, or an
+         * argument, addressed relative to FP.
+         * else it is an absolute global address.
+         */
+        virtual void leaR0(int ea) = 0;
 
-        virtual void storeEAX(int ea) = 0;
+        /* Store R0 to a variable.
+         * If ea <= LOCAL, then this is a local variable, or an
+         * argument, addressed relative to FP.
+         * else it is an absolute global address.
+         */
+        virtual void storeR0(int ea) = 0;
 
-        virtual void loadEAX(int ea, bool isIncDec, int op) = 0;
+        /* load R0 from a variable.
+         * If ea <= LOCAL, then this is a local variable, or an
+         * argument, addressed relative to FP.
+         * else it is an absolute global address.
+         * If isIncDec is true, then the stored variable's value
+         * should be post-incremented or post-decremented, based
+         * on the value of op.
+         */
+        virtual void loadR0(int ea, bool isIncDec, int op) = 0;
 
+        /* Emit code to adjust the stack for a function call. Return the
+         * label for the address of the instruction that adjusts the
+         * stack size. This will be passed as argument "a" to
+         * endFunctionCallArguments.
+         */
         virtual int beginFunctionCallArguments() = 0;
 
-        virtual void storeEAToArg(int l) = 0;
+        /* Emit code to store R0 to the stack at byte offset l.
+         */
+        virtual void storeR0ToArg(int l) = 0;
 
+        /* Patch the function call preamble.
+         * a is the address returned from beginFunctionCallArguments
+         * l is the number of bytes the arguments took on the stack.
+         * Typically you would also emit code to convert the argument
+         * list into whatever the native function calling convention is.
+         * On ARM for example you would pop the first 5 arguments into
+         * R0..R4
+         */
         virtual void endFunctionCallArguments(int a, int l) = 0;
 
-
+        /* Emit a call to an unknown function. The argument "symbol" needs to
+         * be stored in the location where the address should go. It forms
+         * a chain. The address will be patched later.
+         * Return the address of the word that has to be patched.
+         */
         virtual int callForward(int symbol) = 0;
 
+        /* Call a function using PC-relative addressing. t is the PC-relative
+         * address of the function. It has already been adjusted for the
+         * architectural jump offset, so just store it as-is.
+         */
         virtual void callRelative(int t) = 0;
 
+        /* Call a function pointer. L is the number of bytes the arguments
+         * take on the stack. The address of the function is stored at
+         * location SP + l.
+         */
         virtual void callIndirect(int l) = 0;
 
+        /* Adjust SP after returning from a function call. l is the
+         * number of bytes of arguments stored on the stack. isIndirect
+         * is true if this was an indirect call. (In which case the
+         * address of the function is stored at location SP + l.)
+         */
         virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
 
+        /* Print a disassembly of the assembled code to out. Return
+         * non-zero if there is an error.
+         */
         virtual int disassemble(FILE* out) = 0;
 
-        /* output a symbol and patch all calls to it */
+        /* Generate a symbol at the current PC. t is the head of a
+         * linked list of addresses to patch.
+         */
         virtual void gsym(int t) = 0;
 
-        virtual int finishCompile() {
-#if defined(__arm__)
-            const long base = long(pCodeBuf->getBase());
-            const long curr = base + long(pCodeBuf->getSize());
-            int err = cacheflush(base, curr, 0);
-            return err;
-#else
-            return 0;
-#endif
-        }
+        /*
+         * Do any cleanup work required at the end of a compile.
+         * For example, an instruction cache might need to be
+         * invalidated.
+         * Return non-zero if there is an error.
+         */
+        virtual int finishCompile() = 0;
 
         /**
          * Adjust relative branches by this amount.
@@ -214,6 +314,10 @@
         intptr_t getPC() {
             return pCodeBuf->getPC();
         }
+
+        intptr_t getSize() {
+            return pCodeBuf->getSize();
+        }
     private:
         CodeBuf* pCodeBuf;
     };
@@ -378,23 +482,23 @@
 #endif
         }
 
-        virtual void clearECX() {
-            fprintf(stderr, "clearECX();\n");
+        virtual void clearR1() {
+            fprintf(stderr, "clearR1();\n");
             o4(0xE3A01000);  // mov    r1, #0
         }
 
-        virtual void pushEAX() {
-            fprintf(stderr, "pushEAX();\n");
+        virtual void pushR0() {
+            fprintf(stderr, "pushR0();\n");
             o4(0xE92D0001);  // stmfd   sp!,{r0}
         }
 
-        virtual void popECX() {
-            fprintf(stderr, "popECX();\n");
+        virtual void popR1() {
+            fprintf(stderr, "popR1();\n");
             o4(0xE8BD0002);  // ldmfd   sp!,{r1}
         }
 
-        virtual void storeEAXToAddressECX(bool isInt) {
-            fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt);
+        virtual void storeR0ToR1(bool isInt) {
+            fprintf(stderr, "storeR0ToR1(%d);\n", isInt);
             if (isInt) {
                 o4(0xE5810000); // str r0, [r1]
             } else {
@@ -402,16 +506,16 @@
             }
         }
 
-        virtual void loadEAXIndirect(bool isInt) {
-            fprintf(stderr, "loadEAXIndirect(%d);\n", isInt);
+        virtual void loadR0FromR0(bool isInt) {
+            fprintf(stderr, "loadR0FromR0(%d);\n", isInt);
             if (isInt)
                 o4(0xE5900000); // ldr r0, [r0]
             else
                 o4(0xE5D00000); // ldrb r0, [r0]
         }
 
-        virtual void leaEAX(int ea) {
-            fprintf(stderr, "leaEAX(%d);\n", ea);
+        virtual void leaR0(int ea) {
+            fprintf(stderr, "leaR0(%d);\n", ea);
             if (ea < LOCAL) {
                 // Local, fp relative
                 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
@@ -431,8 +535,8 @@
             }
         }
 
-        virtual void storeEAX(int ea) {
-            fprintf(stderr, "storeEAX(%d);\n", ea);
+        virtual void storeR0(int ea) {
+            fprintf(stderr, "storeR0(%d);\n", ea);
             if (ea < LOCAL) {
                 // Local, fp relative
                 if (ea < -4095 || ea > 4095) {
@@ -452,8 +556,8 @@
             }
         }
 
-        virtual void loadEAX(int ea, bool isIncDec, int op) {
-            fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op);
+        virtual void loadR0(int ea, bool isIncDec, int op) {
+            fprintf(stderr, "loadR0(%d, %d, %d);\n", ea, isIncDec, op);
             if (ea < LOCAL) {
                 // Local, fp relative
                 if (ea < -4095 || ea > 4095) {
@@ -504,8 +608,8 @@
             return o4(0xE24DDF00); // Placeholder
         }
 
-        virtual void storeEAToArg(int l) {
-            fprintf(stderr, "storeEAToArg(%d);\n", l);
+        virtual void storeR0ToArg(int l) {
+            fprintf(stderr, "storeR0ToArg(%d);\n", l);
             if (l < 0 || l > 4096-4) {
                 error("l out of range for stack offset: 0x%08x", l);
             }
@@ -597,6 +701,17 @@
             }
         }
 
+        virtual int finishCompile() {
+#if defined(__arm__)
+            const long base = long(getBase());
+            const long curr = long(getPC());
+            int err = cacheflush(base, curr, 0);
+            return err;
+#else
+            return 0;
+#endif
+        }
+
         virtual int disassemble(FILE* out) {
                disasmOut = out;
             disasm_interface_t  di;
@@ -730,23 +845,23 @@
                 o(0x92); /* xchg %edx, %eax */
         }
 
-        virtual void clearECX() {
+        virtual void clearR1() {
             oad(0xb9, 0); /* movl $0, %ecx */
         }
 
-        virtual void pushEAX() {
+        virtual void pushR0() {
             o(0x50); /* push %eax */
         }
 
-        virtual void popECX() {
+        virtual void popR1() {
             o(0x59); /* pop %ecx */
         }
 
-        virtual void storeEAXToAddressECX(bool isInt) {
+        virtual void storeR0ToR1(bool isInt) {
             o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
         }
 
-        virtual void loadEAXIndirect(bool isInt) {
+        virtual void loadR0FromR0(bool isInt) {
             if (isInt)
                 o(0x8b); /* mov (%eax), %eax */
             else
@@ -754,15 +869,15 @@
             ob(0); /* add zero in code */
         }
 
-        virtual void leaEAX(int ea) {
+        virtual void leaR0(int ea) {
             gmov(10, ea); /* leal EA, %eax */
         }
 
-        virtual void storeEAX(int ea) {
+        virtual void storeR0(int ea) {
             gmov(6, ea); /* mov %eax, EA */
         }
 
-        virtual void loadEAX(int ea, bool isIncDec, int op) {
+        virtual void loadR0(int ea, bool isIncDec, int op) {
             gmov(8, ea); /* mov EA, %eax */
             if (isIncDec) {
                 /* Implement post-increment or post decrement.
@@ -776,7 +891,7 @@
             return oad(0xec81, 0); /* sub $xxx, %esp */
         }
 
-        virtual void storeEAToArg(int l) {
+        virtual void storeR0ToArg(int l) {
             oad(0x248489, l); /* movl %eax, xxx(%esp) */
         }
 
@@ -808,7 +923,7 @@
         }
 
         virtual int disassemble(FILE* out) {
-            return 1;
+            return 0;
         }
 
         /* output a symbol and patch all calls to it */
@@ -822,6 +937,10 @@
             }
         }
 
+        virtual int finishCompile() {
+            return 0;
+        }
+
     private:
 
         /** Output 1 to 4 bytes.
@@ -868,6 +987,39 @@
 
 #endif // PROVIDE_X86_CODEGEN
 
+    class InputStream {
+    public:
+        virtual int get() = 0;
+        virtual long tell() = 0;
+    };
+
+    class FileInputStream : public InputStream {
+    public:
+        FileInputStream(FILE* in) : f(in) {}
+        virtual int get() { return fgetc(f); }
+        virtual long tell() { return ftell(f); }
+    private:
+        FILE* f;
+    };
+
+    class TextInputStream : public InputStream {
+    public:
+        TextInputStream(const char* text, size_t textLength)
+            : pText(text), mTextLength(textLength), mPosition(0) {
+        }
+        virtual int get() {
+            return mPosition < mTextLength ? pText[mPosition++] : EOF;
+        }
+        virtual long tell() {
+            return mPosition;
+        }
+
+    private:
+        const char* pText;
+        size_t mTextLength;
+        size_t mPosition;
+    };
+
     /* vars: value of variables
      loc : local variable index
      glo : global variable index
@@ -882,7 +1034,8 @@
     void* pSymbolBase;
     void* pGlobalBase;
     void* pVarsBase;
-    FILE* file;
+
+    InputStream* file;
 
     CodeBuf codeBuf;
     CodeGenerator* pGen;
@@ -957,7 +1110,7 @@
                 ch = dch;
             }
         } else
-            ch = fgetc(file);
+            ch = file->get();
         /*    printf("ch=%c 0x%x\n", ch, ch); */
     }
 
@@ -1108,7 +1261,7 @@
         va_list ap;
 
         va_start(ap, fmt);
-        fprintf(stderr, "%ld: ", ftell((FILE *) file));
+        fprintf(stderr, "%ld: ", file->tell());
         vfprintf(stderr, fmt, ap);
         fprintf(stderr, "\n");
         va_end(ap);
@@ -1149,7 +1302,7 @@
             } else if (c == 2) {
                 /* -, +, !, ~ */
                 unary(0);
-                pGen->clearECX();
+                pGen->clearR1();
                 if (t == '!')
                     pGen->gcmp(a);
                 else
@@ -1175,15 +1328,15 @@
                 unary(0);
                 if (tok == '=') {
                     next();
-                    pGen->pushEAX();
+                    pGen->pushR0();
                     expr();
-                    pGen->popECX();
-                    pGen->storeEAXToAddressECX(t == TOK_INT);
+                    pGen->popR1();
+                    pGen->storeR0ToR1(t == TOK_INT);
                 } else if (t) {
-                    pGen->loadEAXIndirect(t == TOK_INT);
+                    pGen->loadR0FromR0(t == TOK_INT);
                 }
             } else if (t == '&') {
-                pGen->leaEAX(*(int *) tok);
+                pGen->leaR0(*(int *) tok);
                 next();
             } else {
                 n = *(int *) t;
@@ -1195,10 +1348,10 @@
                     /* assignment */
                     next();
                     expr();
-                    pGen->storeEAX(n);
+                    pGen->storeR0(n);
                 } else if (tok != '(') {
                     /* variable */
-                    pGen->loadEAX(n, tokl == 11, tokc);
+                    pGen->loadR0(n, tokl == 11, tokc);
                     if (tokl == 11) {
                         next();
                     }
@@ -1209,7 +1362,7 @@
         /* function call */
         if (tok == '(') {
             if (n == 1)
-                pGen->pushEAX();
+                pGen->pushR0();
 
             /* push args and invert order */
             a = pGen->beginFunctionCallArguments();
@@ -1217,7 +1370,7 @@
             l = 0;
             while (tok != ')') {
                 expr();
-                pGen->storeEAToArg(l);
+                pGen->storeR0ToArg(l);
                 if (tok == ',')
                     next();
                 l = l + 4;
@@ -1255,9 +1408,9 @@
                     a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
                     sum(l);
                 } else {
-                    pGen->pushEAX();
+                    pGen->pushR0();
                     sum(l);
-                    pGen->popECX();
+                    pGen->popR1();
 
                     if ((l == 4) | (l == 5)) {
                         pGen->gcmp(t);
@@ -1420,6 +1573,10 @@
             delete pGen;
             pGen = 0;
         }
+        if (file) {
+            delete file;
+            file = 0;
+        }
     }
 
     void clear() {
@@ -1470,7 +1627,7 @@
 #endif
         }
         if (pGen == NULL) {
-            fprintf(stderr, "No code generator defined.");
+            fprintf(stderr, "No code generator defined.\n");
         }
     }
 
@@ -1490,16 +1647,16 @@
         cleanup();
     }
 
-    int compile(FILE* in, args& args) {
+    int compile(const char* text, size_t textLength) {
         cleanup();
         clear();
         codeBuf.init(ALLOC_SIZE);
-        setArchitecture(args.architecture);
+        setArchitecture(NULL);
         if (!pGen) {
             return -1;
         }
         pGen->init(&codeBuf);
-        file = in;
+        file = new TextInputStream(text, textLength);
         sym_stk = (intptr_t) calloc(1, ALLOC_SIZE);
         dstk = (intptr_t) strcpy((char*) sym_stk,
                 " int if else while break return for define main ")
@@ -1534,6 +1691,38 @@
         return pGen->disassemble(out);
     }
 
+    /* Look through the symbol table to find a symbol.
+     * If found, return its value.
+     */
+    void* lookup(const char* name) {
+        if (!sym_stk) {
+            return NULL;
+        }
+        size_t nameLen = strlen(name);
+        char* pSym = (char*) sym_stk;
+        char c;
+        for(;;) {
+            c = *pSym++;
+            if (c == 0) {
+                break;
+            }
+            if (c == TAG_TOK) {
+                if (memcmp(pSym, name, nameLen) == 0
+                        && pSym[nameLen] == TAG_TOK) {
+                    int tok = pSym - 1 - (char*) sym_stk;
+                    tok = tok * 8 + TOK_IDENT;
+                    if (tok <= TOK_DEFINE) {
+                        return 0;
+                    } else {
+                        tok = vars + tok;
+                        return * (void**) tok;
+                    }
+                }
+            }
+        }
+        return NULL;
+    }
+
 };
 
 const char* Compiler::operatorChars =
@@ -1578,96 +1767,129 @@
 };
 #endif
 
-} // namespace acc
+struct ACCscript {
+    ACCscript() {
+        text = 0;
+        textLength = 0;
+        accError = ACC_NO_ERROR;
+    }
 
-// This is a separate function so it can easily be set by breakpoint in gdb.
-int run(acc::Compiler& c, int argc, char** argv) {
-    return c.run(argc, argv);
-}
+    ~ACCscript() {
+        delete text;
+    }
 
-int main(int argc, char** argv) {
-    bool doDump = false;
-    bool doDisassemble = false;
-    const char* inFile = NULL;
-    const char* outFile = NULL;
-    const char* architecture = NULL;
-    int i;
-    for (i = 1; i < argc; i++) {
-        char* arg = argv[i];
-        if (arg[0] == '-') {
-            switch (arg[1]) {
-            case 'a':
-                if (i + 1 >= argc) {
-                    fprintf(stderr, "Expected architecture after -a\n");
-                    return 2;
-                }
-                architecture = argv[i+1];
-                i += 1;
-                break;
-            case 'd':
-                if (i + 1 >= argc) {
-                    fprintf(stderr, "Expected filename after -d\n");
-                    return 2;
-                }
-                doDump = true;
-                outFile = argv[i + 1];
-                i += 1;
-                break;
-            case 'S':
-                doDisassemble = true;
-                break;
-            default:
-                fprintf(stderr, "Unrecognized flag %s\n", arg);
-                return 3;
-            }
-        } else if (inFile == NULL) {
-            inFile = arg;
-        } else {
-            break;
+    void setError(ACCenum error) {
+        if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
+            accError = error;
         }
     }
 
-    FILE* in = stdin;
-    if (inFile) {
-        in = fopen(inFile, "r");
-        if (!in) {
-            fprintf(stderr, "Could not open input file %s\n", inFile);
-            return 1;
-        }
-    }
-    acc::Compiler compiler;
-    acc::Compiler::args args;
-    if (architecture != NULL) {
-        args.architecture = architecture;
-    }
-    int compileResult = compiler.compile(in, args);
-    if (in != stdin) {
-        fclose(in);
-    }
-    if (compileResult) {
-        fprintf(stderr, "Compile failed: %d\n", compileResult);
-        return 6;
-    }
-    if (doDisassemble) {
-        compiler.disassemble(stderr);
-    }
-    if (doDump) {
-        FILE* save = fopen(outFile, "w");
-        if (!save) {
-            fprintf(stderr, "Could not open output file %s\n", outFile);
-            return 5;
-        }
-        compiler.dump(save);
-        fclose(save);
-    } else {
-        fprintf(stderr, "Executing compiled code:\n");
-        int codeArgc = argc - i + 1;
-        char** codeArgv = argv + i - 1;
-        codeArgv[0] = (char*) (inFile ? inFile : "stdin");
-        int result = run(compiler, codeArgc, codeArgv);
-        fprintf(stderr, "result: %d\n", result);
+    ACCenum getError() {
+        ACCenum result = accError;
+        accError = ACC_NO_ERROR;
         return result;
     }
 
-    return 0;
+    Compiler compiler;
+    char* text;
+    int textLength;
+    ACCenum accError;
+};
+
+
+extern "C"
+ACCscript* accCreateScript() {
+    return new ACCscript();
 }
+
+extern "C"
+ACCenum accGetError( ACCscript* script ) {
+    return script->getError();
+}
+
+extern "C"
+void accDeleteScript(ACCscript* script) {
+    delete script;
+}
+
+extern "C"
+void accScriptSource(ACCscript* script,
+    ACCsizei count,
+    const ACCchar ** string,
+    const ACCint * length) {
+    int totalLength = 0;
+    for(int i = 0; i < count; i++) {
+        int len = -1;
+        const ACCchar* s = string[i];
+        if (length) {
+            len = length[i];
+        }
+        if (len < 0) {
+            len = strlen(s);
+        }
+        totalLength += len;
+    }
+    delete script->text;
+    char* text = new char[totalLength + 1];
+    script->text = text;
+    script->textLength = totalLength;
+    for(int i = 0; i < count; i++) {
+        int len = -1;
+        const ACCchar* s = string[i];
+        if (length) {
+            len = length[i];
+        }
+        if (len < 0) {
+            len = strlen(s);
+        }
+        memcpy(text, s, len);
+        text += len;
+    }
+    text[totalLength] = '\0';
+}
+
+extern "C"
+void accCompileScript(ACCscript* script) {
+    int result = script->compiler.compile(script->text, script->textLength);
+    if (result) {
+        script->setError(ACC_INVALID_OPERATION);
+    }
+}
+
+extern "C"
+void accGetScriptiv(ACCscript* script,
+    ACCenum pname,
+    ACCint * params) {
+    switch (pname) {
+        case ACC_INFO_LOG_LENGTH:
+            *params = 0;
+            break;
+    }
+}
+
+extern "C"
+void accGetScriptInfoLog(ACCscript* script,
+    ACCsizei maxLength,
+    ACCsizei * length,
+    ACCchar * infoLog) {
+    if (length) {
+        *length = 0;
+    }
+    if (maxLength > 0 && infoLog) {
+        *infoLog = 0;
+    }
+}
+
+extern "C"
+void accGetScriptLabel(ACCscript* script, const ACCchar * name,
+                       ACCvoid ** address) {
+    void* value = script->compiler.lookup(name);
+    if (value) {
+        *address = value;
+    } else {
+        script->setError(ACC_INVALID_VALUE);
+    }
+}
+
+} // namespace acc
+
diff --git a/libacc/test b/libacc/test
deleted file mode 100755
index 28b7655..0000000
--- a/libacc/test
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-rm -f tests/acc
-g++ acc.cpp disassem.cpp -g -ldl -o tests/acc && tests/acc tests/otcc.c -a x86 -d tests/otcc.out && diff tests/otcc.out tests/otcc.out-orig
-if [ -x "tests/acc" ]; then
-  tests/acc -S tests/returnval.c
-
-  if [ "$(uname)" = "Linux" ]; then
-    if [ "$(uname -m)" = "i686" ]; then
-      echo "Linux i686. Testing otcc.c"
-      tests/acc tests/otcc.c tests/otcc.c tests/returnval.c
-    fi
-  fi
-fi
diff --git a/libacc/testarm b/libacc/testarm
deleted file mode 100755
index d1a442e..0000000
--- a/libacc/testarm
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-adb remount
-adb push tests/returnval.c /system/bin/returnval.c
-mm -j8 && adb sync && adb shell /system/bin/acc -S /system/bin/returnval.c
diff --git a/libacc/tests/.gitignore b/libacc/tests/.gitignore
index 9974532..a26b298 100644
--- a/libacc/tests/.gitignore
+++ b/libacc/tests/.gitignore
@@ -1,2 +1,2 @@
-acc
+test-acc
 *.out
diff --git a/libacc/tests/Android.mk b/libacc/tests/Android.mk
new file mode 100644
index 0000000..2cff9d3
--- /dev/null
+++ b/libacc/tests/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libacc
+
+LOCAL_MODULE:= acc
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/libacc/tests/bellard.otccex.c b/libacc/tests/data/bellard.otccex.c
similarity index 100%
rename from libacc/tests/bellard.otccex.c
rename to libacc/tests/data/bellard.otccex.c
diff --git a/libacc/tests/expr.c b/libacc/tests/data/expr.c
similarity index 100%
rename from libacc/tests/expr.c
rename to libacc/tests/data/expr.c
diff --git a/libacc/tests/hello.c b/libacc/tests/data/hello.c
similarity index 100%
rename from libacc/tests/hello.c
rename to libacc/tests/data/hello.c
diff --git a/libacc/tests/missing-main.c b/libacc/tests/data/missing-main.c
similarity index 100%
rename from libacc/tests/missing-main.c
rename to libacc/tests/data/missing-main.c
diff --git a/libacc/tests/otcc.c b/libacc/tests/data/otcc.c
similarity index 100%
rename from libacc/tests/otcc.c
rename to libacc/tests/data/otcc.c
diff --git a/libacc/tests/returnval.c b/libacc/tests/data/returnval.c
similarity index 100%
rename from libacc/tests/returnval.c
rename to libacc/tests/data/returnval.c
diff --git a/libacc/tests/simplest.c b/libacc/tests/data/simplest.c
similarity index 100%
rename from libacc/tests/simplest.c
rename to libacc/tests/data/simplest.c
diff --git a/libacc/tests/hello.out-orig b/libacc/tests/hello.out-orig
deleted file mode 100644
index 1fb7bf5..0000000
--- a/libacc/tests/hello.out-orig
+++ /dev/null
Binary files differ
diff --git a/libacc/tests/main.cpp b/libacc/tests/main.cpp
new file mode 100644
index 0000000..8cfc196
--- /dev/null
+++ b/libacc/tests/main.cpp
@@ -0,0 +1,102 @@
+/*
+ * Android "Almost" C Compiler.
+ * This is a compiler for a small subset of the C language, intended for use
+ * in scripting environments where speed and memory footprint are important.
+ *
+ * This code is based upon the "unobfuscated" version of the
+ * Obfuscated Tiny C compiler, see the file LICENSE for details.
+ *
+ */
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__arm__)
+#include <unistd.h>
+#endif
+
+#include <acc/acc.h>
+
+
+typedef int (*MainPtr)(int, char**);
+// This is a separate function so it can easily be set by breakpoint in gdb.
+int run(MainPtr mainFunc, int argc, char** argv) {
+    return mainFunc(argc, argv);
+}
+
+int main(int argc, char** argv) {
+    const char* inFile = NULL;
+    bool printListing;
+    FILE* in = stdin;
+    int i;
+    for (i = 1; i < argc; i++) {
+        char* arg = argv[i];
+        if (arg[0] == '-') {
+            switch (arg[1]) {
+                case 'S':
+                    printListing = true;
+                    break;
+            default:
+                fprintf(stderr, "Unrecognized flag %s\n", arg);
+                return 3;
+            }
+        } else if (inFile == NULL) {
+            inFile = arg;
+        } else {
+            break;
+        }
+    }
+
+    if (! inFile) {
+        fprintf(stderr, "input file required\n");
+        return 2;
+    }
+
+    if (inFile) {
+        in = fopen(inFile, "r");
+        if (!in) {
+            fprintf(stderr, "Could not open input file %s\n", inFile);
+            return 1;
+        }
+    }
+
+    fseek(in, 0, SEEK_END);
+    size_t fileSize = (size_t) ftell(in);
+    rewind(in);
+    ACCchar* text = new ACCchar[fileSize];
+    size_t bytesRead = fread(text, 1, fileSize, in);
+    if (bytesRead != fileSize) {
+        fprintf(stderr, "Could not read all of file %s\n", inFile);
+    }
+
+    ACCscript* script = accCreateScript();
+
+    const ACCchar* scriptSource[] = {text};
+    accScriptSource(script, 1, scriptSource, NULL);
+    delete[] text;
+
+    accCompileScript(script);
+
+    MainPtr mainPointer = 0;
+
+    accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer);
+
+    int result = accGetError(script);
+    if (result == ACC_NO_ERROR) {
+        fprintf(stderr, "Executing compiled code:\n");
+        int codeArgc = argc - i + 1;
+        char** codeArgv = argv + i - 1;
+        codeArgv[0] = (char*) (inFile ? inFile : "stdin");
+        result = run(mainPointer, codeArgc, codeArgv);
+        fprintf(stderr, "result: %d\n", result);
+    }
+
+    accDeleteScript(script);
+
+    return result;
+}
diff --git a/libacc/tests/otcc.out-orig b/libacc/tests/otcc.out-orig
deleted file mode 100644
index fa14c72..0000000
--- a/libacc/tests/otcc.out-orig
+++ /dev/null
Binary files differ
diff --git a/libacc/tests/testarm b/libacc/tests/testarm
new file mode 100755
index 0000000..db7ebe5
--- /dev/null
+++ b/libacc/tests/testarm
@@ -0,0 +1,9 @@
+#!/bin/sh
+adb remount
+adb shell rm /system/bin/acc
+adb push data/returnval.c /system/bin/returnval.c
+cd ..
+mm -j8
+cd tests
+adb sync
+adb shell /system/bin/acc -S /system/bin/returnval.c
diff --git a/libacc/tests/testlocal b/libacc/tests/testlocal
new file mode 100755
index 0000000..a76322b
--- /dev/null
+++ b/libacc/tests/testlocal
@@ -0,0 +1,15 @@
+#!/bin/sh
+rm -f test-acc
+cd ..
+g++ -I../include acc.cpp disassem.cpp tests/main.cpp -g -ldl -o tests/test-acc
+cd tests
+if [ -x "test-acc" ]; then
+  ./test-acc -S data/returnval.c
+
+  if [ "$(uname)" = "Linux" ]; then
+    if [ "$(uname -m)" = "i686" ]; then
+      echo "Linux i686. Testing otcc.c"
+      ./test-acc data/otcc.c data/otcc.c data/returnval.c
+    fi
+  fi
+fi