diff options
Diffstat (limited to 'libacc/acc.cpp')
-rw-r--r-- | libacc/acc.cpp | 620 |
1 files changed, 425 insertions, 195 deletions
diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 04d45d5..b7e4594 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,13 @@ #include "disassem.h" #endif +#include <acc/acc.h> + +#define LOG_API(...) do {} while(0) +// #define LOG_API(...) fprintf (stderr, __VA_ARGS__) + +// #define ENABLE_ARM_DISASSEMBLY + namespace acc { class Compiler { @@ -116,6 +100,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 +130,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 +319,10 @@ class Compiler { intptr_t getPC() { return pCodeBuf->getPC(); } + + intptr_t getSize() { + return pCodeBuf->getSize(); + } private: CodeBuf* pCodeBuf; }; @@ -228,7 +337,7 @@ class Compiler { /* returns address to patch with local variable size */ virtual int functionEntry(int argCount) { - fprintf(stderr, "functionEntry(%d);\n", argCount); + LOG_API(stderr, "functionEntry(%d);\n", argCount); // sp -> arg4 arg5 ... // Push our register-based arguments back on the stack if (argCount > 0) { @@ -243,7 +352,7 @@ class Compiler { } virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { - fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize); + LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize); // Patch local variable allocation code: if (localVariableSize < 0 || localVariableSize > 255) { error("localVariables out of range: %d", localVariableSize); @@ -270,7 +379,7 @@ class Compiler { /* load immediate value */ virtual void li(int t) { - fprintf(stderr, "li(%d);\n", t); + LOG_API("li(%d);\n", t); if (t >= 0 && t < 255) { o4(0xE3A00000 + t); // mov r0, #0 } else if (t >= -256 && t < 0) { @@ -285,20 +394,20 @@ class Compiler { } virtual int gjmp(int t) { - fprintf(stderr, "gjmp(%d);\n", t); + LOG_API("gjmp(%d);\n", t); return o4(0xEA000000 | encodeAddress(t)); // b .L33 } /* l = 0: je, l == 1: jne */ virtual int gtst(bool l, int t) { - fprintf(stderr, "gtst(%d, %d);\n", l, t); + LOG_API("gtst(%d, %d);\n", l, t); o4(0xE3500000); // cmp r0,#0 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq return o4(branch | encodeAddress(t)); } virtual void gcmp(int op) { - fprintf(stderr, "gcmp(%d);\n", op); + LOG_API("gcmp(%d);\n", op); o4(0xE1510000); // cmp r1, r1 switch(op) { case OP_EQUALS: @@ -332,7 +441,7 @@ class Compiler { } virtual void genOp(int op) { - fprintf(stderr, "genOp(%d);\n", op); + LOG_API("genOp(%d);\n", op); switch(op) { case OP_MUL: o4(0x0E0000091); // mul r0,r1,r0 @@ -378,23 +487,23 @@ class Compiler { #endif } - virtual void clearECX() { - fprintf(stderr, "clearECX();\n"); + virtual void clearR1() { + LOG_API("clearR1();\n"); o4(0xE3A01000); // mov r1, #0 } - virtual void pushEAX() { - fprintf(stderr, "pushEAX();\n"); + virtual void pushR0() { + LOG_API("pushR0();\n"); o4(0xE92D0001); // stmfd sp!,{r0} } - virtual void popECX() { - fprintf(stderr, "popECX();\n"); + virtual void popR1() { + LOG_API("popR1();\n"); o4(0xE8BD0002); // ldmfd sp!,{r1} } - virtual void storeEAXToAddressECX(bool isInt) { - fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt); + virtual void storeR0ToR1(bool isInt) { + LOG_API("storeR0ToR1(%d);\n", isInt); if (isInt) { o4(0xE5810000); // str r0, [r1] } else { @@ -402,16 +511,16 @@ class Compiler { } } - virtual void loadEAXIndirect(bool isInt) { - fprintf(stderr, "loadEAXIndirect(%d);\n", isInt); + virtual void loadR0FromR0(bool isInt) { + LOG_API("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) { + LOG_API("leaR0(%d);\n", ea); if (ea < LOCAL) { // Local, fp relative if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) { @@ -431,8 +540,8 @@ class Compiler { } } - virtual void storeEAX(int ea) { - fprintf(stderr, "storeEAX(%d);\n", ea); + virtual void storeR0(int ea) { + LOG_API("storeR0(%d);\n", ea); if (ea < LOCAL) { // Local, fp relative if (ea < -4095 || ea > 4095) { @@ -452,8 +561,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) { + LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op); if (ea < LOCAL) { // Local, fp relative if (ea < -4095 || ea > 4095) { @@ -500,12 +609,12 @@ class Compiler { } virtual int beginFunctionCallArguments() { - fprintf(stderr, "beginFunctionCallArguments();\n"); + LOG_API("beginFunctionCallArguments();\n"); return o4(0xE24DDF00); // Placeholder } - virtual void storeEAToArg(int l) { - fprintf(stderr, "storeEAToArg(%d);\n", l); + virtual void storeR0ToArg(int l) { + LOG_API("storeR0ToArg(%d);\n", l); if (l < 0 || l > 4096-4) { error("l out of range for stack offset: 0x%08x", l); } @@ -513,7 +622,7 @@ class Compiler { } virtual void endFunctionCallArguments(int a, int l) { - fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l); + LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l); if (l < 0 || l > 0x3FC) { error("L out of range for stack adjustment: 0x%08x", l); } @@ -526,13 +635,13 @@ class Compiler { } virtual int callForward(int symbol) { - fprintf(stderr, "callForward(%d);\n", symbol); + LOG_API("callForward(%d);\n", symbol); // Forward calls are always short (local) return o4(0xEB000000 | encodeAddress(symbol)); } virtual void callRelative(int t) { - fprintf(stderr, "callRelative(%d);\n", t); + LOG_API("callRelative(%d);\n", t); int abs = t + getPC() + jumpOffset(); fprintf(stderr, "abs=%d (0x%08x)\n", abs, abs); if (t >= - (1 << 25) && t < (1 << 25)) { @@ -548,7 +657,7 @@ class Compiler { } virtual void callIndirect(int l) { - fprintf(stderr, "callIndirect(%d);\n", l); + LOG_API("callIndirect(%d);\n", l); int argCount = l >> 2; int poppedArgs = argCount > 4 ? 4 : argCount; int adjustedL = l - (poppedArgs << 2); @@ -560,7 +669,7 @@ class Compiler { } virtual void adjustStackAfterCall(int l, bool isIndirect) { - fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect); + LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect); int argCount = l >> 2; int stackArgs = argCount > 4 ? argCount - 4 : 0; int stackUse = stackArgs + (isIndirect ? 1 : 0); @@ -578,11 +687,11 @@ class Compiler { /* output a symbol and patch all calls to it */ virtual void gsym(int t) { - fprintf(stderr, "gsym(0x%x)\n", t); + LOG_API("gsym(0x%x)\n", t); int n; int base = getBase(); int pc = getPC(); - fprintf(stderr, "pc = 0x%x\n", pc); + LOG_API("pc = 0x%x\n", pc); while (t) { int data = * (int*) t; int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2); @@ -597,8 +706,20 @@ 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; +#ifdef ENABLE_ARM_DISASSEMBLY + disasmOut = out; disasm_interface_t di; di.di_readword = disassemble_readword; di.di_printaddr = disassemble_printaddr; @@ -610,6 +731,7 @@ class Compiler { fprintf(out, "%08x: %08x ", i, *(int*) i); ::disasm(&di, i, 0); } +#endif return 0; } @@ -679,7 +801,7 @@ class Compiler { } }; -#endif // PROVIDE_X86_CODEGEN +#endif // PROVIDE_ARM_CODEGEN #ifdef PROVIDE_X86_CODEGEN @@ -730,23 +852,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 +876,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 +898,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 +930,7 @@ class Compiler { } virtual int disassemble(FILE* out) { - return 1; + return 0; } /* output a symbol and patch all calls to it */ @@ -822,6 +944,10 @@ class Compiler { } } + virtual int finishCompile() { + return 0; + } + private: /** Output 1 to 4 bytes. @@ -868,6 +994,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 +1041,8 @@ class Compiler { void* pSymbolBase; void* pGlobalBase; void* pVarsBase; - FILE* file; + + InputStream* file; CodeBuf codeBuf; CodeGenerator* pGen; @@ -957,7 +1117,7 @@ class Compiler { ch = dch; } } else - ch = fgetc(file); + ch = file->get(); /* printf("ch=%c 0x%x\n", ch, ch); */ } @@ -1108,7 +1268,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 +1309,7 @@ class Compiler { } else if (c == 2) { /* -, +, !, ~ */ unary(0); - pGen->clearECX(); + pGen->clearR1(); if (t == '!') pGen->gcmp(a); else @@ -1175,15 +1335,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 +1355,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 +1369,7 @@ class Compiler { /* function call */ if (tok == '(') { if (n == 1) - pGen->pushEAX(); + pGen->pushR0(); /* push args and invert order */ a = pGen->beginFunctionCallArguments(); @@ -1217,7 +1377,7 @@ class Compiler { l = 0; while (tok != ')') { expr(); - pGen->storeEAToArg(l); + pGen->storeR0ToArg(l); if (tok == ',') next(); l = l + 4; @@ -1255,9 +1415,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 +1580,10 @@ class Compiler { delete pGen; pGen = 0; } + if (file) { + delete file; + file = 0; + } } void clear() { @@ -1470,7 +1634,7 @@ class Compiler { #endif } if (pGen == NULL) { - fprintf(stderr, "No code generator defined."); + fprintf(stderr, "No code generator defined.\n"); } } @@ -1490,16 +1654,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 +1698,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 +1774,130 @@ 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; } - acc::Compiler compiler; - acc::Compiler::args args; - if (architecture != NULL) { - args.architecture = architecture; + + 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; } - int compileResult = compiler.compile(in, args); - if (in != stdin) { - fclose(in); + delete script->text; + char* text = new char[totalLength + 1]; + script->text = text; + script->textLength = totalLength; + char* dest = text; + 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(dest, s, len); + dest += len; } - if (compileResult) { - fprintf(stderr, "Compile failed: %d\n", compileResult); - return 6; + 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 (doDisassemble) { - compiler.disassemble(stderr); +} + +extern "C" +void accGetScriptiv(ACCscript* script, + ACCenum pname, + ACCint * params) { + switch (pname) { + case ACC_INFO_LOG_LENGTH: + *params = 0; + break; } - 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; +} + +extern "C" +void accGetScriptInfoLog(ACCscript* script, + ACCsizei maxLength, + ACCsizei * length, + ACCchar * infoLog) { + if (length) { + *length = 0; + } + 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 + |