11cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich/*
21cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich * Android "Almost" C Compiler.
31cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich * This is a compiler for a small subset of the C language, intended for use
41cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich * in scripting environments where speed and memory footprint are important.
51cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich *
61cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich * This code is based upon the "unobfuscated" version of the
71cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich * Obfuscated Tiny C compiler, see the file LICENSE for details.
81cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich *
91cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich */
101cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
111cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <ctype.h>
121cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <dlfcn.h>
131cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <stdarg.h>
141cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <stdint.h>
151cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <stdio.h>
161cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <stdlib.h>
171cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <string.h>
181cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
191cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#if defined(__arm__)
201cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <unistd.h>
211cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#endif
221cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
23d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#if defined(__arm__)
24d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#define PROVIDE_ARM_DISASSEMBLY
25d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#endif
26d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
27d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#ifdef PROVIDE_ARM_DISASSEMBLY
28d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#include "disassem.h"
29d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#endif
30d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
311cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich#include <acc/acc.h>
321cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
331cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
341cdef20774b2cd30f1a509227c86845337f63f11Jack Palevichtypedef int (*MainPtr)(int, char**);
351cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich// This is a separate function so it can easily be set by breakpoint in gdb.
361cdef20774b2cd30f1a509227c86845337f63f11Jack Palevichint run(MainPtr mainFunc, int argc, char** argv) {
371cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    return mainFunc(argc, argv);
381cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich}
391cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
408c246a9dc294760f2a981cf5144fe4939d1554e6Jack PalevichACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) {
41188a5a7a3af54bd45383c72e452d627d33e63391Jack Palevich    return (ACCvoid*) dlsym(RTLD_DEFAULT, name);
428c246a9dc294760f2a981cf5144fe4939d1554e6Jack Palevich}
438c246a9dc294760f2a981cf5144fe4939d1554e6Jack Palevich
44d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#ifdef PROVIDE_ARM_DISASSEMBLY
45d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
46d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichstatic FILE* disasmOut;
47d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
48d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichstatic u_int
49d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichdisassemble_readword(u_int address)
50d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich{
51d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    return(*((u_int *)address));
52d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich}
53d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
54d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichstatic void
55d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichdisassemble_printaddr(u_int address)
56d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich{
57d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    fprintf(disasmOut, "0x%08x", address);
58d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich}
59d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
60d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichstatic void
61d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichdisassemble_printf(const char *fmt, ...) {
62d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    va_list ap;
63d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    va_start(ap, fmt);
64d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    vfprintf(disasmOut, fmt, ap);
65d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    va_end(ap);
66d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich}
67d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
68d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevichstatic int disassemble(ACCscript* script, FILE* out) {
69d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    disasmOut = out;
70d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    disasm_interface_t  di;
71d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    di.di_readword = disassemble_readword;
72d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    di.di_printaddr = disassemble_printaddr;
73d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    di.di_printf = disassemble_printf;
74d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
75d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    ACCvoid* base;
76d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    ACCsizei length;
77d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
78d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    accGetProgramBinary(script, &base, &length);
79d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    unsigned long* pBase = (unsigned long*) base;
80d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    unsigned long* pEnd = (unsigned long*) (((unsigned char*) base) + length);
81d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
82d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) {
831c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich        fprintf(out, "%08x: %08x  ", (int) pInstruction, (int) *pInstruction);
84d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich        ::disasm(&di, (uint) pInstruction, 0);
85d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    }
86d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich    return 0;
87d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich}
88d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
89d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#endif // PROVIDE_ARM_DISASSEMBLY
90d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich
911cdef20774b2cd30f1a509227c86845337f63f11Jack Palevichint main(int argc, char** argv) {
921cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    const char* inFile = NULL;
931cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    bool printListing;
9436d9414f72b629dacc2c972e93d16cec08ef44b6Jack Palevich    bool runResults = false;
951cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    FILE* in = stdin;
961cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    int i;
971cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    for (i = 1; i < argc; i++) {
981cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        char* arg = argv[i];
991cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        if (arg[0] == '-') {
1001cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich            switch (arg[1]) {
1011cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich                case 'S':
1021cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich                    printListing = true;
1031cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich                    break;
10436d9414f72b629dacc2c972e93d16cec08ef44b6Jack Palevich                case 'R':
10536d9414f72b629dacc2c972e93d16cec08ef44b6Jack Palevich                    runResults = true;
10636d9414f72b629dacc2c972e93d16cec08ef44b6Jack Palevich                    break;
1071cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich            default:
1081cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich                fprintf(stderr, "Unrecognized flag %s\n", arg);
1091cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich                return 3;
1101cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich            }
1111cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        } else if (inFile == NULL) {
1121cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich            inFile = arg;
1131cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        } else {
1141cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich            break;
1151cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        }
1161cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    }
1171cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
1181cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    if (! inFile) {
1191cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        fprintf(stderr, "input file required\n");
1201cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        return 2;
1211cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    }
1221cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
1231cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    if (inFile) {
1241cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        in = fopen(inFile, "r");
1251cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        if (!in) {
1261cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich            fprintf(stderr, "Could not open input file %s\n", inFile);
1271cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich            return 1;
1281cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        }
1291cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    }
1301cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
1311cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    fseek(in, 0, SEEK_END);
1321cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    size_t fileSize = (size_t) ftell(in);
1331cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    rewind(in);
134b7c81e99522fbc5256f20e826eae18f2a33ea76aJack Palevich    ACCchar* text = new ACCchar[fileSize + 1];
1351cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    size_t bytesRead = fread(text, 1, fileSize, in);
1361cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    if (bytesRead != fileSize) {
1371cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich        fprintf(stderr, "Could not read all of file %s\n", inFile);
1381cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    }
1391cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
140b7c81e99522fbc5256f20e826eae18f2a33ea76aJack Palevich    text[fileSize] = '\0';
141b7c81e99522fbc5256f20e826eae18f2a33ea76aJack Palevich
1421cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    ACCscript* script = accCreateScript();
1431cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
1441cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    const ACCchar* scriptSource[] = {text};
1451cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    accScriptSource(script, 1, scriptSource, NULL);
1461cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    delete[] text;
1471cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
1488c246a9dc294760f2a981cf5144fe4939d1554e6Jack Palevich    accRegisterSymbolCallback(script, symbolLookup, NULL);
1498c246a9dc294760f2a981cf5144fe4939d1554e6Jack Palevich
1501cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    accCompileScript(script);
151ac0e95eb60fc8f8ef3281f9183630d1515bd12a7Jack Palevich    int result = accGetError(script);
1521cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    MainPtr mainPointer = 0;
153ac0e95eb60fc8f8ef3281f9183630d1515bd12a7Jack Palevich    if (result != 0) {
1541c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich        ACCsizei bufferLength;
1551c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich        accGetScriptInfoLog(script, 0, &bufferLength, NULL);
1561c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich        char* buf = (char*) malloc(bufferLength + 1);
1571c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich        if (buf != NULL) {
1581c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich            accGetScriptInfoLog(script, bufferLength + 1, NULL, buf);
1591c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich            fprintf(stderr, "%s", buf);
1601c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich            free(buf);
1611c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich        } else {
1621c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich            fprintf(stderr, "Out of memory.\n");
1631c60e46e0e5a20426e235eaede8f1cf7395f4cc0Jack Palevich        }
164ac0e95eb60fc8f8ef3281f9183630d1515bd12a7Jack Palevich        goto exit;
165ac0e95eb60fc8f8ef3281f9183630d1515bd12a7Jack Palevich    }
1661cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
167eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich    {
168eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich        ACCsizei numPragmaStrings;
169eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich        accGetPragmas(script, &numPragmaStrings, 0, NULL);
170eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich        if (numPragmaStrings) {
171eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich            char** strings = new char*[numPragmaStrings];
172eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich            accGetPragmas(script, NULL, numPragmaStrings, strings);
173eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich            for(ACCsizei i = 0; i < numPragmaStrings; i += 2) {
174eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich                fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]);
175eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich            }
176eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich            delete[] strings;
177eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich        }
178eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich    }
179eedf9d20832f1af3a4bd362819be6eace54240b5Jack Palevich
180422972cb127c229a38e79bb5d2d8df44aebeeeea-b master    if (printListing) {
181d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#ifdef PROVIDE_ARM_DISASSEMBLY
182d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich        disassemble(script, stderr);
183d5315573d792c8441482b1cbe9ac7e93d3f730d1Jack Palevich#endif
184422972cb127c229a38e79bb5d2d8df44aebeeeea-b master    }
185422972cb127c229a38e79bb5d2d8df44aebeeeea-b master
1862db168f12feb0e25209b4aee385af074ef87157aJack Palevich    if (runResults) {
1872db168f12feb0e25209b4aee385af074ef87157aJack Palevich        accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer);
1882db168f12feb0e25209b4aee385af074ef87157aJack Palevich
1892db168f12feb0e25209b4aee385af074ef87157aJack Palevich        result = accGetError(script);
1902db168f12feb0e25209b4aee385af074ef87157aJack Palevich        if (result != ACC_NO_ERROR) {
1912db168f12feb0e25209b4aee385af074ef87157aJack Palevich            fprintf(stderr, "Could not find main: %d\n", result);
1922db168f12feb0e25209b4aee385af074ef87157aJack Palevich        } else {
1932db168f12feb0e25209b4aee385af074ef87157aJack Palevich            fprintf(stderr, "Executing compiled code:\n");
1942db168f12feb0e25209b4aee385af074ef87157aJack Palevich            int codeArgc = argc - i + 1;
1952db168f12feb0e25209b4aee385af074ef87157aJack Palevich            char** codeArgv = argv + i - 1;
1962db168f12feb0e25209b4aee385af074ef87157aJack Palevich            codeArgv[0] = (char*) (inFile ? inFile : "stdin");
1972db168f12feb0e25209b4aee385af074ef87157aJack Palevich            result = run(mainPointer, codeArgc, codeArgv);
1982db168f12feb0e25209b4aee385af074ef87157aJack Palevich            fprintf(stderr, "result: %d\n", result);
1992db168f12feb0e25209b4aee385af074ef87157aJack Palevich        }
2001cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    }
2011cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
202ac0e95eb60fc8f8ef3281f9183630d1515bd12a7Jack Palevichexit:
203ac0e95eb60fc8f8ef3281f9183630d1515bd12a7Jack Palevich
2041cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    accDeleteScript(script);
2051cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich
2061cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich    return result;
2071cdef20774b2cd30f1a509227c86845337f63f11Jack Palevich}
208