summaryrefslogtreecommitdiffstats
path: root/libacc
diff options
context:
space:
mode:
Diffstat (limited to 'libacc')
-rw-r--r--libacc/Android.mk15
-rw-r--r--libacc/LICENSE21
-rw-r--r--libacc/acc.cpp578
-rwxr-xr-xlibacc/test13
-rwxr-xr-xlibacc/testarm4
-rw-r--r--libacc/tests/.gitignore2
-rw-r--r--libacc/tests/Android.mk15
-rw-r--r--libacc/tests/data/bellard.otccex.c (renamed from libacc/tests/bellard.otccex.c)0
-rw-r--r--libacc/tests/data/expr.c (renamed from libacc/tests/expr.c)0
-rw-r--r--libacc/tests/data/hello.c (renamed from libacc/tests/hello.c)0
-rw-r--r--libacc/tests/data/missing-main.c (renamed from libacc/tests/missing-main.c)0
-rw-r--r--libacc/tests/data/otcc.c (renamed from libacc/tests/otcc.c)0
-rw-r--r--libacc/tests/data/returnval.c (renamed from libacc/tests/returnval.c)0
-rw-r--r--libacc/tests/data/simplest.c (renamed from libacc/tests/simplest.c)0
-rw-r--r--libacc/tests/hello.out-origbin40 -> 0 bytes
-rw-r--r--libacc/tests/main.cpp102
-rw-r--r--libacc/tests/otcc.out-origbin8591 -> 0 bytes
-rwxr-xr-xlibacc/tests/testarm9
-rwxr-xr-xlibacc/tests/testlocal15
19 files changed, 574 insertions, 200 deletions
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 @@ include $(CLEAR_VARS)
# 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 @@ class Compiler {
}
};
+ /**
+ * 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 @@ class Compiler {
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;
-
- virtual void pushEAX() = 0;
+ /* Set R1 to 0.
+ */
+ virtual void clearR1() = 0;
- virtual void popECX() = 0;
+ /* Push R0 onto the stack.
+ */
+ virtual void pushR0() = 0;
- virtual void storeEAXToAddressECX(bool isInt) = 0;
+ /* Pop R1 off of the stack.
+ */
+ virtual void popR1() = 0;
- virtual void loadEAXIndirect(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 leaEAX(int ea) = 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 storeEAX(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 loadEAX(int ea, bool isIncDec, int op) = 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;
+
+ /* 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 @@ class Compiler {
intptr_t getPC() {
return pCodeBuf->getPC();
}
+
+ intptr_t getSize() {
+ return pCodeBuf->getSize();
+ }
private:
CodeBuf* pCodeBuf;
};
@@ -378,23 +482,23 @@ class Compiler {
#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 @@ class Compiler {
}
}
- 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 @@ class Compiler {
}
}
- 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 @@ class Compiler {
}
}
- 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 @@ class Compiler {
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 @@ class Compiler {
}
}
+ 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 @@ class Compiler {
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 @@ class Compiler {
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 @@ class Compiler {
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 @@ class Compiler {
}
virtual int disassemble(FILE* out) {
- return 1;
+ return 0;
}
/* output a symbol and patch all calls to it */
@@ -822,6 +937,10 @@ class Compiler {
}
}
+ virtual int finishCompile() {
+ return 0;
+ }
+
private:
/** Output 1 to 4 bytes.
@@ -868,6 +987,39 @@ class Compiler {
#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 @@ class Compiler {
void* pSymbolBase;
void* pGlobalBase;
void* pVarsBase;
- FILE* file;
+
+ InputStream* file;
CodeBuf codeBuf;
CodeGenerator* pGen;
@@ -957,7 +1110,7 @@ class Compiler {
ch = dch;
}
} else
- ch = fgetc(file);
+ ch = file->get();
/* printf("ch=%c 0x%x\n", ch, ch); */
}
@@ -1108,7 +1261,7 @@ class Compiler {
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 @@ class Compiler {
} else if (c == 2) {
/* -, +, !, ~ */
unary(0);
- pGen->clearECX();
+ pGen->clearR1();
if (t == '!')
pGen->gcmp(a);
else
@@ -1175,15 +1328,15 @@ class Compiler {
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 @@ class Compiler {
/* 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 @@ class Compiler {
/* function call */
if (tok == '(') {
if (n == 1)
- pGen->pushEAX();
+ pGen->pushR0();
/* push args and invert order */
a = pGen->beginFunctionCallArguments();
@@ -1217,7 +1370,7 @@ class Compiler {
l = 0;
while (tok != ')') {
expr();
- pGen->storeEAToArg(l);
+ pGen->storeR0ToArg(l);
if (tok == ',')
next();
l = l + 4;
@@ -1255,9 +1408,9 @@ class Compiler {
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 @@ class Compiler {
delete pGen;
pGen = 0;
}
+ if (file) {
+ delete file;
+ file = 0;
+ }
}
void clear() {
@@ -1470,7 +1627,7 @@ class Compiler {
#endif
}
if (pGen == NULL) {
- fprintf(stderr, "No code generator defined.");
+ fprintf(stderr, "No code generator defined.\n");
}
}
@@ -1490,16 +1647,16 @@ public:
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 @@ public:
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 @@ const int Compiler::X86CodeGenerator::operatorHelper[] = {
};
#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;
- }
+ ACCenum getError() {
+ ACCenum result = accError;
+ accError = ACC_NO_ERROR;
+ return result;
+ }
+
+ 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;
}
- acc::Compiler compiler;
- acc::Compiler::args args;
- if (architecture != NULL) {
- args.architecture = architecture;
+ 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;
}
- int compileResult = compiler.compile(in, args);
- if (in != stdin) {
- fclose(in);
+ 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);
}
- if (compileResult) {
- fprintf(stderr, "Compile failed: %d\n", compileResult);
- return 6;
+}
+
+extern "C"
+void accGetScriptiv(ACCscript* script,
+ ACCenum pname,
+ ACCint * params) {
+ switch (pname) {
+ case ACC_INFO_LOG_LENGTH:
+ *params = 0;
+ break;
}
- if (doDisassemble) {
- compiler.disassemble(stderr);
+}
+
+extern "C"
+void accGetScriptInfoLog(ACCscript* script,
+ ACCsizei maxLength,
+ ACCsizei * length,
+ ACCchar * infoLog) {
+ if (length) {
+ *length = 0;
}
- 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);
- return result;
+ if (maxLength > 0 && infoLog) {
+ *infoLog = 0;
}
+}
- return 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
index e8f0989..e8f0989 100644
--- a/libacc/tests/bellard.otccex.c
+++ b/libacc/tests/data/bellard.otccex.c
diff --git a/libacc/tests/expr.c b/libacc/tests/data/expr.c
index 4f2d2e7..4f2d2e7 100644
--- a/libacc/tests/expr.c
+++ b/libacc/tests/data/expr.c
diff --git a/libacc/tests/hello.c b/libacc/tests/data/hello.c
index 585ce6c..585ce6c 100644
--- a/libacc/tests/hello.c
+++ b/libacc/tests/data/hello.c
diff --git a/libacc/tests/missing-main.c b/libacc/tests/data/missing-main.c
index e73eec4..e73eec4 100644
--- a/libacc/tests/missing-main.c
+++ b/libacc/tests/data/missing-main.c
diff --git a/libacc/tests/otcc.c b/libacc/tests/data/otcc.c
index 577fcf3..577fcf3 100644
--- a/libacc/tests/otcc.c
+++ b/libacc/tests/data/otcc.c
diff --git a/libacc/tests/returnval.c b/libacc/tests/data/returnval.c
index 3142fe2..3142fe2 100644
--- a/libacc/tests/returnval.c
+++ b/libacc/tests/data/returnval.c
diff --git a/libacc/tests/simplest.c b/libacc/tests/data/simplest.c
index bae895a..bae895a 100644
--- a/libacc/tests/simplest.c
+++ b/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