blob: b07a1d809efeedf948c99941577b9ca8c4ad01dc [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040
41#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070042#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070043#endif
Jack Palevicha6535612009-05-13 16:24:17 -070044
Jack Palevich1cdef202009-05-22 12:06:27 -070045#include <acc/acc.h>
46
Jack Palevich09555c72009-05-27 12:25:55 -070047#define LOG_API(...) do {} while(0)
48// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070049// #define ENABLE_ARM_DISASSEMBLY
50
Jack Palevichbbf8ab52009-05-11 11:54:30 -070051namespace acc {
52
Jack Palevichac0e95e2009-05-29 13:53:44 -070053class ErrorSink {
54public:
55 void error(const char *fmt, ...) {
56 va_list ap;
57 va_start(ap, fmt);
58 verror(fmt, ap);
59 va_end(ap);
60 }
61
62 virtual void verror(const char* fmt, va_list ap) = 0;
63};
64
65class Compiler : public ErrorSink {
Jack Palevich21a15a22009-05-11 14:49:29 -070066 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070067 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070068 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070069 ErrorSink* mErrorSink;
70 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -070071 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -070072
Jack Palevich21a15a22009-05-11 14:49:29 -070073 void release() {
74 if (pProgramBase != 0) {
75 free(pProgramBase);
76 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070077 }
Jack Palevich21a15a22009-05-11 14:49:29 -070078 }
79
Jack Palevich0a280a02009-06-11 10:53:51 -070080 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -070081 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -070082 bool overflow = newSize > mSize;
83 if (overflow && !mOverflowed) {
84 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -070085 if (mErrorSink) {
86 mErrorSink->error("Code too large: %d bytes", newSize);
87 }
88 }
Jack Palevich0a280a02009-06-11 10:53:51 -070089 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -070090 }
91
Jack Palevich21a15a22009-05-11 14:49:29 -070092 public:
93 CodeBuf() {
94 pProgramBase = 0;
95 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -070096 mErrorSink = 0;
97 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -070098 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -070099 }
100
101 ~CodeBuf() {
102 release();
103 }
104
105 void init(int size) {
106 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700107 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700108 pProgramBase = (char*) calloc(1, size);
109 ind = pProgramBase;
110 }
111
Jack Palevichac0e95e2009-05-29 13:53:44 -0700112 void setErrorSink(ErrorSink* pErrorSink) {
113 mErrorSink = pErrorSink;
114 }
115
Jack Palevich546b2242009-05-13 15:10:04 -0700116 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700117 if(check(4)) {
118 return 0;
119 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700120 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700121 * (int*) ind = n;
122 ind += 4;
123 return result;
124 }
125
Jack Palevich21a15a22009-05-11 14:49:29 -0700126 /*
127 * Output a byte. Handles all values, 0..ff.
128 */
129 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700130 if(check(1)) {
131 return;
132 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700133 *ind++ = n;
134 }
135
Jack Palevich21a15a22009-05-11 14:49:29 -0700136 inline void* getBase() {
137 return (void*) pProgramBase;
138 }
139
Jack Palevich8b0624c2009-05-20 12:12:06 -0700140 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700141 return ind - pProgramBase;
142 }
143
Jack Palevich8b0624c2009-05-20 12:12:06 -0700144 intptr_t getPC() {
145 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700146 }
147 };
148
Jack Palevich1cdef202009-05-22 12:06:27 -0700149 /**
150 * A code generator creates an in-memory program, generating the code on
151 * the fly. There is one code generator implementation for each supported
152 * architecture.
153 *
154 * The code generator implements the following abstract machine:
155 * R0 - the main accumulator.
156 * R1 - the secondary accumulator.
157 * FP - a frame pointer for accessing function arguments and local
158 * variables.
159 * SP - a stack pointer for storing intermediate results while evaluating
160 * expressions. The stack pointer grows downwards.
161 *
162 * The function calling convention is that all arguments are placed on the
163 * stack such that the first argument has the lowest address.
164 * After the call, the result is in R0. The caller is responsible for
165 * removing the arguments from the stack.
166 * The R0 and R1 registers are not saved across function calls. The
167 * FP and SP registers are saved.
168 */
169
Jack Palevich21a15a22009-05-11 14:49:29 -0700170 class CodeGenerator {
171 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700172 CodeGenerator() {
173 mErrorSink = 0;
174 pCodeBuf = 0;
175 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700176 virtual ~CodeGenerator() {}
177
Jack Palevich22305132009-05-13 10:58:45 -0700178 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700179 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700180 pCodeBuf->setErrorSink(mErrorSink);
181 }
182
183 void setErrorSink(ErrorSink* pErrorSink) {
184 mErrorSink = pErrorSink;
185 if (pCodeBuf) {
186 pCodeBuf->setErrorSink(mErrorSink);
187 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700188 }
189
Jack Palevich1cdef202009-05-22 12:06:27 -0700190 /* Emit a function prolog.
191 * argCount is the number of arguments.
192 * Save the old value of the FP.
193 * Set the new value of the FP.
194 * Convert from the native platform calling convention to
195 * our stack-based calling convention. This may require
196 * pushing arguments from registers to the stack.
197 * Allocate "N" bytes of stack space. N isn't known yet, so
198 * just emit the instructions for adjusting the stack, and return
199 * the address to patch up. The patching will be done in
200 * functionExit().
201 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700202 */
Jack Palevich546b2242009-05-13 15:10:04 -0700203 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700204
Jack Palevich1cdef202009-05-22 12:06:27 -0700205 /* Emit a function epilog.
206 * Restore the old SP and FP register values.
207 * Return to the calling function.
208 * argCount - the number of arguments to the function.
209 * localVariableAddress - returned from functionEntry()
210 * localVariableSize - the size in bytes of the local variables.
211 */
212 virtual void functionExit(int argCount, int localVariableAddress,
213 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700214
Jack Palevich1cdef202009-05-22 12:06:27 -0700215 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700216 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700217
Jack Palevich1cdef202009-05-22 12:06:27 -0700218 /* Jump to a target, and return the address of the word that
219 * holds the target data, in case it needs to be fixed up later.
220 */
Jack Palevich22305132009-05-13 10:58:45 -0700221 virtual int gjmp(int t) = 0;
222
Jack Palevich1cdef202009-05-22 12:06:27 -0700223 /* Test R0 and jump to a target if the test succeeds.
224 * l = 0: je, l == 1: jne
225 * Return the address of the word that holds the targed data, in
226 * case it needs to be fixed up later.
227 */
Jack Palevich22305132009-05-13 10:58:45 -0700228 virtual int gtst(bool l, int t) = 0;
229
Jack Palevich1cdef202009-05-22 12:06:27 -0700230 /* Compare R1 against R0, and store the boolean result in R0.
231 * op specifies the comparison.
232 */
Jack Palevich22305132009-05-13 10:58:45 -0700233 virtual void gcmp(int op) = 0;
234
Jack Palevich1cdef202009-05-22 12:06:27 -0700235 /* Perform the arithmetic op specified by op. R1 is the
236 * left argument, R0 is the right argument.
237 */
Jack Palevich546b2242009-05-13 15:10:04 -0700238 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700239
Jack Palevich1cdef202009-05-22 12:06:27 -0700240 /* Set R1 to 0.
241 */
242 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700243
Jack Palevich1cdef202009-05-22 12:06:27 -0700244 /* Push R0 onto the stack.
245 */
246 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700247
Jack Palevich1cdef202009-05-22 12:06:27 -0700248 /* Pop R1 off of the stack.
249 */
250 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700251
Jack Palevich1cdef202009-05-22 12:06:27 -0700252 /* Store R0 to the address stored in R1.
253 * isInt is true if a whole 4-byte integer value
254 * should be stored, otherwise a 1-byte character
255 * value should be stored.
256 */
257 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700258
Jack Palevich1cdef202009-05-22 12:06:27 -0700259 /* Load R0 from the address stored in R0.
260 * isInt is true if a whole 4-byte integer value
261 * should be loaded, otherwise a 1-byte character
262 * value should be loaded.
263 */
264 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700265
Jack Palevich1cdef202009-05-22 12:06:27 -0700266 /* Load the absolute address of a variable to R0.
267 * If ea <= LOCAL, then this is a local variable, or an
268 * argument, addressed relative to FP.
269 * else it is an absolute global address.
270 */
271 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700272
Jack Palevich1cdef202009-05-22 12:06:27 -0700273 /* Store R0 to a variable.
274 * If ea <= LOCAL, then this is a local variable, or an
275 * argument, addressed relative to FP.
276 * else it is an absolute global address.
277 */
278 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700279
Jack Palevich1cdef202009-05-22 12:06:27 -0700280 /* load R0 from a variable.
281 * If ea <= LOCAL, then this is a local variable, or an
282 * argument, addressed relative to FP.
283 * else it is an absolute global address.
284 * If isIncDec is true, then the stored variable's value
285 * should be post-incremented or post-decremented, based
286 * on the value of op.
287 */
288 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700289
Jack Palevich1cdef202009-05-22 12:06:27 -0700290 /* Emit code to adjust the stack for a function call. Return the
291 * label for the address of the instruction that adjusts the
292 * stack size. This will be passed as argument "a" to
293 * endFunctionCallArguments.
294 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700295 virtual int beginFunctionCallArguments() = 0;
296
Jack Palevich1cdef202009-05-22 12:06:27 -0700297 /* Emit code to store R0 to the stack at byte offset l.
298 */
299 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700300
Jack Palevich1cdef202009-05-22 12:06:27 -0700301 /* Patch the function call preamble.
302 * a is the address returned from beginFunctionCallArguments
303 * l is the number of bytes the arguments took on the stack.
304 * Typically you would also emit code to convert the argument
305 * list into whatever the native function calling convention is.
306 * On ARM for example you would pop the first 5 arguments into
307 * R0..R4
308 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700309 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700310
Jack Palevich1cdef202009-05-22 12:06:27 -0700311 /* Emit a call to an unknown function. The argument "symbol" needs to
312 * be stored in the location where the address should go. It forms
313 * a chain. The address will be patched later.
314 * Return the address of the word that has to be patched.
315 */
Jack Palevich22305132009-05-13 10:58:45 -0700316 virtual int callForward(int symbol) = 0;
317
Jack Palevich1cdef202009-05-22 12:06:27 -0700318 /* Call a function using PC-relative addressing. t is the PC-relative
319 * address of the function. It has already been adjusted for the
320 * architectural jump offset, so just store it as-is.
321 */
Jack Palevich22305132009-05-13 10:58:45 -0700322 virtual void callRelative(int t) = 0;
323
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 /* Call a function pointer. L is the number of bytes the arguments
325 * take on the stack. The address of the function is stored at
326 * location SP + l.
327 */
Jack Palevich22305132009-05-13 10:58:45 -0700328 virtual void callIndirect(int l) = 0;
329
Jack Palevich1cdef202009-05-22 12:06:27 -0700330 /* Adjust SP after returning from a function call. l is the
331 * number of bytes of arguments stored on the stack. isIndirect
332 * is true if this was an indirect call. (In which case the
333 * address of the function is stored at location SP + l.)
334 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700335 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700336
Jack Palevich1cdef202009-05-22 12:06:27 -0700337 /* Print a disassembly of the assembled code to out. Return
338 * non-zero if there is an error.
339 */
Jack Palevicha6535612009-05-13 16:24:17 -0700340 virtual int disassemble(FILE* out) = 0;
341
Jack Palevich1cdef202009-05-22 12:06:27 -0700342 /* Generate a symbol at the current PC. t is the head of a
343 * linked list of addresses to patch.
344 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700345 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700346
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 /*
348 * Do any cleanup work required at the end of a compile.
349 * For example, an instruction cache might need to be
350 * invalidated.
351 * Return non-zero if there is an error.
352 */
353 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700354
Jack Palevicha6535612009-05-13 16:24:17 -0700355 /**
356 * Adjust relative branches by this amount.
357 */
358 virtual int jumpOffset() = 0;
359
Jack Palevich21a15a22009-05-11 14:49:29 -0700360 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700361 /*
362 * Output a byte. Handles all values, 0..ff.
363 */
364 void ob(int n) {
365 pCodeBuf->ob(n);
366 }
367
Jack Palevich8b0624c2009-05-20 12:12:06 -0700368 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700369 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700370 }
371
Jack Palevich8b0624c2009-05-20 12:12:06 -0700372 intptr_t getBase() {
373 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700374 }
375
Jack Palevich8b0624c2009-05-20 12:12:06 -0700376 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700377 return pCodeBuf->getPC();
378 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700379
380 intptr_t getSize() {
381 return pCodeBuf->getSize();
382 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700383
384 void error(const char* fmt,...) {
385 va_list ap;
386 va_start(ap, fmt);
387 mErrorSink->verror(fmt, ap);
388 va_end(ap);
389 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700390 private:
391 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700392 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700393 };
394
Jack Paleviche7b59062009-05-19 17:12:17 -0700395#ifdef PROVIDE_ARM_CODEGEN
396
Jack Palevich22305132009-05-13 10:58:45 -0700397 class ARMCodeGenerator : public CodeGenerator {
398 public:
399 ARMCodeGenerator() {}
400 virtual ~ARMCodeGenerator() {}
401
402 /* returns address to patch with local variable size
403 */
Jack Palevich546b2242009-05-13 15:10:04 -0700404 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700405 LOG_API("functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700406 // sp -> arg4 arg5 ...
407 // Push our register-based arguments back on the stack
408 if (argCount > 0) {
409 int regArgCount = argCount <= 4 ? argCount : 4;
410 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
411 }
412 // sp -> arg0 arg1 ...
413 o4(0xE92D4800); // stmfd sp!, {fp, lr}
414 // sp, fp -> oldfp, retadr, arg0 arg1 ....
415 o4(0xE1A0B00D); // mov fp, sp
416 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700417 }
418
Jack Palevich546b2242009-05-13 15:10:04 -0700419 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700420 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700421 // Patch local variable allocation code:
422 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700423 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700424 }
Jack Palevich69796b62009-05-14 15:42:26 -0700425 *(char*) (localVariableAddress) = localVariableSize;
426
427 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
428 o4(0xE1A0E00B); // mov lr, fp
429 o4(0xE59BB000); // ldr fp, [fp]
430 o4(0xE28ED004); // add sp, lr, #4
431 // sp -> retadr, arg0, ...
432 o4(0xE8BD4000); // ldmfd sp!, {lr}
433 // sp -> arg0 ....
434 if (argCount > 0) {
435 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700436 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700437 // earlier. We don't need to actually store them anywhere,
438 // just adjust the stack.
439 int regArgCount = argCount <= 4 ? argCount : 4;
440 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
441 }
442 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700443 }
444
445 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700446 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700447 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700448 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700449 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700450 } else if (t >= -256 && t < 0) {
451 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700452 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700453 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700454 o4(0xE51F0000); // ldr r0, .L3
455 o4(0xEA000000); // b .L99
456 o4(t); // .L3: .word 0
457 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700458 }
Jack Palevich22305132009-05-13 10:58:45 -0700459 }
460
461 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700462 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700463 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700464 }
465
466 /* l = 0: je, l == 1: jne */
467 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700468 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700469 o4(0xE3500000); // cmp r0,#0
470 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
471 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700472 }
473
474 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700475 LOG_API("gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700476 o4(0xE1510000); // cmp r1, r1
477 switch(op) {
478 case OP_EQUALS:
479 o4(0x03A00001); // moveq r0,#1
480 o4(0x13A00000); // movne r0,#0
481 break;
482 case OP_NOT_EQUALS:
483 o4(0x03A00000); // moveq r0,#0
484 o4(0x13A00001); // movne r0,#1
485 break;
486 case OP_LESS_EQUAL:
487 o4(0xD3A00001); // movle r0,#1
488 o4(0xC3A00000); // movgt r0,#0
489 break;
490 case OP_GREATER:
491 o4(0xD3A00000); // movle r0,#0
492 o4(0xC3A00001); // movgt r0,#1
493 break;
494 case OP_GREATER_EQUAL:
495 o4(0xA3A00001); // movge r0,#1
496 o4(0xB3A00000); // movlt r0,#0
497 break;
498 case OP_LESS:
499 o4(0xA3A00000); // movge r0,#0
500 o4(0xB3A00001); // movlt r0,#1
501 break;
502 default:
503 error("Unknown comparison op %d", op);
504 break;
505 }
Jack Palevich22305132009-05-13 10:58:45 -0700506 }
507
Jack Palevich546b2242009-05-13 15:10:04 -0700508 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700509 LOG_API("genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700510 switch(op) {
511 case OP_MUL:
512 o4(0x0E0000091); // mul r0,r1,r0
513 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700514 case OP_DIV:
515 callRuntime(runtime_DIV);
516 break;
517 case OP_MOD:
518 callRuntime(runtime_MOD);
519 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700520 case OP_PLUS:
521 o4(0xE0810000); // add r0,r1,r0
522 break;
523 case OP_MINUS:
524 o4(0xE0410000); // sub r0,r1,r0
525 break;
526 case OP_SHIFT_LEFT:
527 o4(0xE1A00011); // lsl r0,r1,r0
528 break;
529 case OP_SHIFT_RIGHT:
530 o4(0xE1A00051); // asr r0,r1,r0
531 break;
532 case OP_BIT_AND:
533 o4(0xE0010000); // and r0,r1,r0
534 break;
535 case OP_BIT_XOR:
536 o4(0xE0210000); // eor r0,r1,r0
537 break;
538 case OP_BIT_OR:
539 o4(0xE1810000); // orr r0,r1,r0
540 break;
541 case OP_BIT_NOT:
542 o4(0xE1E00000); // mvn r0, r0
543 break;
544 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700545 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700546 break;
547 }
Jack Palevich22305132009-05-13 10:58:45 -0700548#if 0
549 o(decodeOp(op));
550 if (op == OP_MOD)
551 o(0x92); /* xchg %edx, %eax */
552#endif
553 }
554
Jack Palevich1cdef202009-05-22 12:06:27 -0700555 virtual void clearR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700556 LOG_API("clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700557 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700558 }
559
Jack Palevich1cdef202009-05-22 12:06:27 -0700560 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700561 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700562 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700563 }
564
Jack Palevich1cdef202009-05-22 12:06:27 -0700565 virtual void popR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700566 LOG_API("popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700567 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700568 }
569
Jack Palevich1cdef202009-05-22 12:06:27 -0700570 virtual void storeR0ToR1(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700571 LOG_API("storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700572 if (isInt) {
573 o4(0xE5810000); // str r0, [r1]
574 } else {
575 o4(0xE5C10000); // strb r0, [r1]
576 }
Jack Palevich22305132009-05-13 10:58:45 -0700577 }
578
Jack Palevich1cdef202009-05-22 12:06:27 -0700579 virtual void loadR0FromR0(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700580 LOG_API("loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700581 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700582 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700583 else
Jack Palevich69796b62009-05-14 15:42:26 -0700584 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700585 }
586
Jack Palevich1cdef202009-05-22 12:06:27 -0700587 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700588 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700589 if (ea < LOCAL) {
590 // Local, fp relative
591 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
592 error("Offset out of range: %08x", ea);
593 }
594 if (ea < 0) {
595 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
596 } else {
597 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
598 }
Jack Palevichbd894902009-05-14 19:35:31 -0700599 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700600 // Global, absolute.
601 o4(0xE59F0000); // ldr r0, .L1
602 o4(0xEA000000); // b .L99
603 o4(ea); // .L1: .word 0
604 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700605 }
Jack Palevich22305132009-05-13 10:58:45 -0700606 }
607
Jack Palevich1cdef202009-05-22 12:06:27 -0700608 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700609 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700610 if (ea < LOCAL) {
611 // Local, fp relative
612 if (ea < -4095 || ea > 4095) {
613 error("Offset out of range: %08x", ea);
614 }
615 if (ea < 0) {
616 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
617 } else {
618 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
619 }
620 } else{
621 // Global, absolute
622 o4(0xE59F1000); // ldr r1, .L1
623 o4(0xEA000000); // b .L99
624 o4(ea); // .L1: .word 0
625 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700626 }
Jack Palevich22305132009-05-13 10:58:45 -0700627 }
628
Jack Palevich1cdef202009-05-22 12:06:27 -0700629 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700630 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700631 if (ea < LOCAL) {
632 // Local, fp relative
633 if (ea < -4095 || ea > 4095) {
634 error("Offset out of range: %08x", ea);
635 }
636 if (ea < 0) {
637 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
638 } else {
639 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
640 }
Jack Palevich69796b62009-05-14 15:42:26 -0700641 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700642 // Global, absolute
643 o4(0xE59F2000); // ldr r2, .L1
644 o4(0xEA000000); // b .L99
645 o4(ea); // .L1: .word ea
646 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700647 }
Jack Palevich22305132009-05-13 10:58:45 -0700648
Jack Palevich4d93f302009-05-15 13:30:00 -0700649 if (isIncDec) {
650 switch (op) {
651 case OP_INCREMENT:
652 o4(0xE2801001); // add r1, r0, #1
653 break;
654 case OP_DECREMENT:
655 o4(0xE2401001); // sub r1, r0, #1
656 break;
657 default:
658 error("unknown opcode: %d", op);
659 }
660 if (ea < LOCAL) {
661 // Local, fp relative
662 // Don't need range check, was already checked above
663 if (ea < 0) {
664 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
665 } else {
666 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
667 }
668 } else{
669 // Global, absolute
670 // r2 is already set up from before.
671 o4(0xE5821000); // str r1, [r2]
672 }
Jack Palevichbd894902009-05-14 19:35:31 -0700673 }
Jack Palevich22305132009-05-13 10:58:45 -0700674 }
675
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700676 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700677 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700678 return o4(0xE24DDF00); // Placeholder
679 }
680
Jack Palevich1cdef202009-05-22 12:06:27 -0700681 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700682 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700683 if (l < 0 || l > 4096-4) {
684 error("l out of range for stack offset: 0x%08x", l);
685 }
686 o4(0xE58D0000 + l); // str r0, [sp, #4]
687 }
688
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700689 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700690 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700691 if (l < 0 || l > 0x3FC) {
692 error("L out of range for stack adjustment: 0x%08x", l);
693 }
694 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
695 int argCount = l >> 2;
696 if (argCount > 0) {
697 int regArgCount = argCount > 4 ? 4 : argCount;
698 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
699 }
Jack Palevich22305132009-05-13 10:58:45 -0700700 }
701
Jack Palevich22305132009-05-13 10:58:45 -0700702 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700703 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700704 // Forward calls are always short (local)
705 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700706 }
707
708 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700709 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700710 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700711 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700712 if (t >= - (1 << 25) && t < (1 << 25)) {
713 o4(0xEB000000 | encodeAddress(t));
714 } else {
715 // Long call.
716 o4(0xE59FC000); // ldr r12, .L1
717 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700718 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700719 o4(0xE08CC00F); // .L99: add r12,pc
720 o4(0xE12FFF3C); // blx r12
721 }
Jack Palevich22305132009-05-13 10:58:45 -0700722 }
723
724 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700725 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700726 int argCount = l >> 2;
727 int poppedArgs = argCount > 4 ? 4 : argCount;
728 int adjustedL = l - (poppedArgs << 2);
729 if (adjustedL < 0 || adjustedL > 4096-4) {
730 error("l out of range for stack offset: 0x%08x", l);
731 }
732 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
733 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700734 }
735
Jack Palevich7810bc92009-05-15 14:31:47 -0700736 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700737 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700738 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700739 int stackArgs = argCount > 4 ? argCount - 4 : 0;
740 int stackUse = stackArgs + (isIndirect ? 1 : 0);
741 if (stackUse) {
742 if (stackUse < 0 || stackUse > 255) {
743 error("L out of range for stack adjustment: 0x%08x", l);
744 }
745 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700746 }
Jack Palevich22305132009-05-13 10:58:45 -0700747 }
748
Jack Palevicha6535612009-05-13 16:24:17 -0700749 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700750 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700751 }
752
753 /* output a symbol and patch all calls to it */
754 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700755 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700756 int n;
757 int base = getBase();
758 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700759 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700760 while (t) {
761 int data = * (int*) t;
762 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
763 if (decodedOffset == 0) {
764 n = 0;
765 } else {
766 n = base + decodedOffset; /* next value */
767 }
768 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
769 | encodeRelAddress(pc - t - 8);
770 t = n;
771 }
772 }
773
Jack Palevich1cdef202009-05-22 12:06:27 -0700774 virtual int finishCompile() {
775#if defined(__arm__)
776 const long base = long(getBase());
777 const long curr = long(getPC());
778 int err = cacheflush(base, curr, 0);
779 return err;
780#else
781 return 0;
782#endif
783 }
784
Jack Palevicha6535612009-05-13 16:24:17 -0700785 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700786#ifdef ENABLE_ARM_DISASSEMBLY
787 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700788 disasm_interface_t di;
789 di.di_readword = disassemble_readword;
790 di.di_printaddr = disassemble_printaddr;
791 di.di_printf = disassemble_printf;
792
793 int base = getBase();
794 int pc = getPC();
795 for(int i = base; i < pc; i += 4) {
796 fprintf(out, "%08x: %08x ", i, *(int*) i);
797 ::disasm(&di, i, 0);
798 }
Jack Palevich09555c72009-05-27 12:25:55 -0700799#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700800 return 0;
801 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700802
Jack Palevich22305132009-05-13 10:58:45 -0700803 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700804 static FILE* disasmOut;
805
806 static u_int
807 disassemble_readword(u_int address)
808 {
809 return(*((u_int *)address));
810 }
811
812 static void
813 disassemble_printaddr(u_int address)
814 {
815 fprintf(disasmOut, "0x%08x", address);
816 }
817
818 static void
819 disassemble_printf(const char *fmt, ...) {
820 va_list ap;
821 va_start(ap, fmt);
822 vfprintf(disasmOut, fmt, ap);
823 va_end(ap);
824 }
825
826 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
827
828 /** Encode a relative address that might also be
829 * a label.
830 */
831 int encodeAddress(int value) {
832 int base = getBase();
833 if (value >= base && value <= getPC() ) {
834 // This is a label, encode it relative to the base.
835 value = value - base;
836 }
837 return encodeRelAddress(value);
838 }
839
840 int encodeRelAddress(int value) {
841 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
842 }
Jack Palevich22305132009-05-13 10:58:45 -0700843
Jack Palevich3d474a72009-05-15 15:12:38 -0700844 typedef int (*int2FnPtr)(int a, int b);
845 void callRuntime(int2FnPtr fn) {
846 o4(0xE59F2000); // ldr r2, .L1
847 o4(0xEA000000); // b .L99
848 o4((int) fn); //.L1: .word fn
849 o4(0xE12FFF32); //.L99: blx r2
850 }
851
852 static int runtime_DIV(int a, int b) {
853 return b / a;
854 }
855
856 static int runtime_MOD(int a, int b) {
857 return b % a;
858 }
Jack Palevich22305132009-05-13 10:58:45 -0700859 };
860
Jack Palevich09555c72009-05-27 12:25:55 -0700861#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700862
863#ifdef PROVIDE_X86_CODEGEN
864
Jack Palevich21a15a22009-05-11 14:49:29 -0700865 class X86CodeGenerator : public CodeGenerator {
866 public:
867 X86CodeGenerator() {}
868 virtual ~X86CodeGenerator() {}
869
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700870 /* returns address to patch with local variable size
871 */
Jack Palevich546b2242009-05-13 15:10:04 -0700872 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700873 o(0xe58955); /* push %ebp, mov %esp, %ebp */
874 return oad(0xec81, 0); /* sub $xxx, %esp */
875 }
876
Jack Palevich546b2242009-05-13 15:10:04 -0700877 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700878 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700879 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700880 }
881
Jack Palevich21a15a22009-05-11 14:49:29 -0700882 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700883 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700884 oad(0xb8, t); /* mov $xx, %eax */
885 }
886
Jack Palevich22305132009-05-13 10:58:45 -0700887 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700888 return psym(0xe9, t);
889 }
890
891 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700892 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700893 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
894 return psym(0x84 + l, t);
895 }
896
Jack Palevich22305132009-05-13 10:58:45 -0700897 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700898 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700899 o(0xc139); /* cmp %eax,%ecx */
900 li(0);
901 o(0x0f); /* setxx %al */
902 o(t + 0x90);
903 o(0xc0);
904 }
905
Jack Palevich546b2242009-05-13 15:10:04 -0700906 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700907 o(decodeOp(op));
908 if (op == OP_MOD)
909 o(0x92); /* xchg %edx, %eax */
910 }
911
Jack Palevich1cdef202009-05-22 12:06:27 -0700912 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700913 oad(0xb9, 0); /* movl $0, %ecx */
914 }
915
Jack Palevich1cdef202009-05-22 12:06:27 -0700916 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700917 o(0x50); /* push %eax */
918 }
919
Jack Palevich1cdef202009-05-22 12:06:27 -0700920 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700921 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700922 }
923
Jack Palevich1cdef202009-05-22 12:06:27 -0700924 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700925 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
926 }
927
Jack Palevich1cdef202009-05-22 12:06:27 -0700928 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700929 if (isInt)
930 o(0x8b); /* mov (%eax), %eax */
931 else
932 o(0xbe0f); /* movsbl (%eax), %eax */
933 ob(0); /* add zero in code */
934 }
935
Jack Palevich1cdef202009-05-22 12:06:27 -0700936 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700937 gmov(10, ea); /* leal EA, %eax */
938 }
939
Jack Palevich1cdef202009-05-22 12:06:27 -0700940 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700941 gmov(6, ea); /* mov %eax, EA */
942 }
943
Jack Palevich1cdef202009-05-22 12:06:27 -0700944 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700945 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700946 if (isIncDec) {
947 /* Implement post-increment or post decrement.
948 */
949 gmov(0, ea); /* 83 ADD */
950 o(decodeOp(op));
951 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700952 }
953
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700954 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700955 return oad(0xec81, 0); /* sub $xxx, %esp */
956 }
957
Jack Palevich1cdef202009-05-22 12:06:27 -0700958 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700959 oad(0x248489, l); /* movl %eax, xxx(%esp) */
960 }
961
Jack Palevich7810bc92009-05-15 14:31:47 -0700962 virtual void endFunctionCallArguments(int a, int l) {
963 * (int*) a = l;
964 }
965
Jack Palevich22305132009-05-13 10:58:45 -0700966 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700967 return psym(0xe8, symbol); /* call xxx */
968 }
969
Jack Palevich22305132009-05-13 10:58:45 -0700970 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700971 psym(0xe8, t); /* call xxx */
972 }
973
Jack Palevich22305132009-05-13 10:58:45 -0700974 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700975 oad(0x2494ff, l); /* call *xxx(%esp) */
976 }
977
Jack Palevich7810bc92009-05-15 14:31:47 -0700978 virtual void adjustStackAfterCall(int l, bool isIndirect) {
979 if (isIndirect) {
980 l += 4;
981 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700982 oad(0xc481, l); /* add $xxx, %esp */
983 }
984
Jack Palevicha6535612009-05-13 16:24:17 -0700985 virtual int jumpOffset() {
986 return 5;
987 }
988
989 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -0700990 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -0700991 }
992
Jack Paleviche7b59062009-05-19 17:12:17 -0700993 /* output a symbol and patch all calls to it */
994 virtual void gsym(int t) {
995 int n;
996 int pc = getPC();
997 while (t) {
998 n = *(int *) t; /* next value */
999 *(int *) t = pc - t - 4;
1000 t = n;
1001 }
1002 }
1003
Jack Palevich1cdef202009-05-22 12:06:27 -07001004 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001005 size_t pagesize = 4096;
1006 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1007 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1008 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1009 if (err) {
1010 error("mprotect() failed: %d", errno);
1011 }
1012 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001013 }
1014
Jack Palevich21a15a22009-05-11 14:49:29 -07001015 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001016
1017 /** Output 1 to 4 bytes.
1018 *
1019 */
1020 void o(int n) {
1021 /* cannot use unsigned, so we must do a hack */
1022 while (n && n != -1) {
1023 ob(n & 0xff);
1024 n = n >> 8;
1025 }
1026 }
1027
1028 /* psym is used to put an instruction with a data field which is a
1029 reference to a symbol. It is in fact the same as oad ! */
1030 int psym(int n, int t) {
1031 return oad(n, t);
1032 }
1033
1034 /* instruction + address */
1035 int oad(int n, int t) {
1036 o(n);
1037 int result = getPC();
1038 o4(t);
1039 return result;
1040 }
1041
1042
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001043 static const int operatorHelper[];
1044
1045 int decodeOp(int op) {
1046 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001047 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001048 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001049 }
1050 return operatorHelper[op];
1051 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001052
Jack Palevich546b2242009-05-13 15:10:04 -07001053 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001054 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001055 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001056 }
1057 };
1058
Jack Paleviche7b59062009-05-19 17:12:17 -07001059#endif // PROVIDE_X86_CODEGEN
1060
Jack Palevich1cdef202009-05-22 12:06:27 -07001061 class InputStream {
1062 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001063 int getChar() {
1064 if (bumpLine) {
1065 line++;
1066 bumpLine = false;
1067 }
1068 int ch = get();
1069 if (ch == '\n') {
1070 bumpLine = true;
1071 }
1072 return ch;
1073 }
1074 int getLine() {
1075 return line;
1076 }
1077 protected:
1078 InputStream() :
1079 line(1), bumpLine(false) {
1080 }
1081 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001082 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001083 int line;
1084 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001085 };
1086
1087 class FileInputStream : public InputStream {
1088 public:
1089 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001090 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001091 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001092 FILE* f;
1093 };
1094
1095 class TextInputStream : public InputStream {
1096 public:
1097 TextInputStream(const char* text, size_t textLength)
1098 : pText(text), mTextLength(textLength), mPosition(0) {
1099 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001100
1101 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001102 virtual int get() {
1103 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1104 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001105
Jack Palevich1cdef202009-05-22 12:06:27 -07001106 const char* pText;
1107 size_t mTextLength;
1108 size_t mPosition;
1109 };
1110
Jack Palevicheedf9d22009-06-04 16:23:40 -07001111 class String {
1112 public:
1113 String() {
1114 mpBase = 0;
1115 mUsed = 0;
1116 mSize = 0;
1117 }
1118
Jack Palevich303d8ff2009-06-11 19:06:24 -07001119 String(const char* item, int len, bool adopt) {
1120 if (len < 0) {
1121 len = strlen(item);
1122 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001123 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001124 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001125 mUsed = len;
1126 mSize = len + 1;
1127 } else {
1128 mpBase = 0;
1129 mUsed = 0;
1130 mSize = 0;
1131 appendBytes(item, len);
1132 }
1133 }
1134
Jack Palevich303d8ff2009-06-11 19:06:24 -07001135 String(const String& other) {
1136 mpBase = 0;
1137 mUsed = 0;
1138 mSize = 0;
1139 appendBytes(other.getUnwrapped(), other.len());
1140 }
1141
Jack Palevicheedf9d22009-06-04 16:23:40 -07001142 ~String() {
1143 if (mpBase) {
1144 free(mpBase);
1145 }
1146 }
1147
Jack Palevich303d8ff2009-06-11 19:06:24 -07001148 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001149 return mpBase;
1150 }
1151
Jack Palevich303d8ff2009-06-11 19:06:24 -07001152 void clear() {
1153 mUsed = 0;
1154 if (mSize > 0) {
1155 mpBase[0] = 0;
1156 }
1157 }
1158
Jack Palevicheedf9d22009-06-04 16:23:40 -07001159 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001160 appendBytes(s, strlen(s));
1161 }
1162
1163 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001164 memcpy(ensure(n), s, n + 1);
1165 }
1166
1167 void append(char c) {
1168 * ensure(1) = c;
1169 }
1170
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001171 char* orphan() {
1172 char* result = mpBase;
1173 mpBase = 0;
1174 mUsed = 0;
1175 mSize = 0;
1176 return result;
1177 }
1178
Jack Palevicheedf9d22009-06-04 16:23:40 -07001179 void printf(const char* fmt,...) {
1180 va_list ap;
1181 va_start(ap, fmt);
1182 vprintf(fmt, ap);
1183 va_end(ap);
1184 }
1185
1186 void vprintf(const char* fmt, va_list ap) {
1187 char* temp;
1188 int numChars = vasprintf(&temp, fmt, ap);
1189 memcpy(ensure(numChars), temp, numChars+1);
1190 free(temp);
1191 }
1192
Jack Palevich303d8ff2009-06-11 19:06:24 -07001193 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001194 return mUsed;
1195 }
1196
1197 private:
1198 char* ensure(int n) {
1199 size_t newUsed = mUsed + n;
1200 if (newUsed > mSize) {
1201 size_t newSize = mSize * 2 + 10;
1202 if (newSize < newUsed) {
1203 newSize = newUsed;
1204 }
1205 mpBase = (char*) realloc(mpBase, newSize + 1);
1206 mSize = newSize;
1207 }
1208 mpBase[newUsed] = '\0';
1209 char* result = mpBase + mUsed;
1210 mUsed = newUsed;
1211 return result;
1212 }
1213
1214 char* mpBase;
1215 size_t mUsed;
1216 size_t mSize;
1217 };
1218
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001219 /**
1220 * Wrap an externally allocated string for use as a hash key.
1221 */
1222 class FakeString : public String {
1223 public:
Jack Palevich2db168f2009-06-11 14:29:47 -07001224 FakeString(const char* string, size_t length) :
1225 String((char*) string, length, true) {}
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001226
1227 ~FakeString() {
1228 orphan();
1229 }
1230 };
1231
1232 template<class V> class StringTable {
1233 public:
Jack Palevich303d8ff2009-06-11 19:06:24 -07001234 StringTable() {
1235 init(10);
1236 }
1237
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001238 StringTable(size_t initialCapacity) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001239 init(initialCapacity);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001240 }
1241
1242 ~StringTable() {
1243 clear();
Jack Palevich2db168f2009-06-11 14:29:47 -07001244 hashmapFree(mpMap);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001245 }
1246
1247 void clear() {
1248 hashmapForEach(mpMap, freeKeyValue, this);
1249 }
1250
1251 bool contains(String* pKey) {
1252 bool result = hashmapContainsKey(mpMap, pKey);
1253 return result;
1254 }
1255
1256 V* get(String* pKey) {
1257 V* result = (V*) hashmapGet(mpMap, pKey);
1258 return result;
1259 }
1260
1261 V* remove(String* pKey) {
1262 V* result = (V*) hashmapRemove(mpMap, pKey);
1263 return result;
1264 }
1265
1266 V* put(String* pKey, V* value) {
1267 V* result = (V*) hashmapPut(mpMap, pKey, value);
1268 if (result) {
1269 // The key was not adopted by the map, so delete it here.
1270 delete pKey;
1271 }
1272 return result;
1273 }
1274
1275 protected:
Jack Palevich303d8ff2009-06-11 19:06:24 -07001276
1277 void init(size_t initialCapacity) {
1278 mpMap = hashmapCreate(initialCapacity, hashFn, equalsFn);
1279 }
1280
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001281 static int hashFn(void* pKey) {
1282 String* pString = (String*) pKey;
1283 return hashmapHash(pString->getUnwrapped(), pString->len());
1284 }
1285
1286 static bool equalsFn(void* keyA, void* keyB) {
1287 String* pStringA = (String*) keyA;
1288 String* pStringB = (String*) keyB;
1289 return pStringA->len() == pStringB->len()
1290 && strcmp(pStringA->getUnwrapped(), pStringB->getUnwrapped())
1291 == 0;
1292 }
1293
1294 static bool freeKeyValue(void* key, void* value, void* context) {
1295 delete (String*) key;
1296 delete (V*) value;
1297 return true;
1298 }
1299
1300 Hashmap* mpMap;
1301 };
1302
1303 class MacroTable : public StringTable<String> {
1304 public:
1305 MacroTable() : StringTable<String>(10) {}
1306 };
1307
Jack Palevich2db168f2009-06-11 14:29:47 -07001308 class KeywordTable {
1309 public:
1310
1311 KeywordTable(){
1312 mpMap = hashmapCreate(40, hashFn, equalsFn);
1313 put("int", TOK_INT);
1314 put("char", TOK_CHAR);
1315 put("void", TOK_VOID);
1316 put("if", TOK_IF);
1317 put("else", TOK_ELSE);
1318 put("while", TOK_WHILE);
1319 put("break", TOK_BREAK);
1320 put("return", TOK_RETURN);
1321 put("for", TOK_FOR);
1322 put("pragma", TOK_PRAGMA);
1323 }
1324
1325 ~KeywordTable() {
1326 hashmapFree(mpMap);
1327 }
1328
Jack Palevich303d8ff2009-06-11 19:06:24 -07001329 int get(String* key) {
1330 return (int) hashmapGet(mpMap, key->getUnwrapped());
Jack Palevich2db168f2009-06-11 14:29:47 -07001331 }
1332
1333 const char* lookupKeyFor(int value) {
1334 FindValContext context;
1335 context.key = 0;
1336 hashmapForEach(mpMap, findKeyFn, &context);
1337 return context.key;
1338 }
1339
1340 private:
1341 void put(const char* kw, int val) {
1342 hashmapPut(mpMap, (void*) kw, (void*) val);
1343 }
1344
1345 static int hashFn(void* pKey) {
1346 char* pString = (char*) pKey;
1347 return hashmapHash(pString, strlen(pString));
1348 }
1349
1350 static bool equalsFn(void* keyA, void* keyB) {
1351 const char* pStringA = (const char*) keyA;
1352 const char* pStringB = (const char*) keyB;
1353 return strcmp(pStringA, pStringB) == 0;
1354 }
1355
1356 struct FindValContext {
1357 char* key;
1358 int value;
1359 };
1360
1361 static bool findKeyFn(void* key, void* value, void* context) {
1362 FindValContext* pContext = (FindValContext*) context;
1363 if ((int) value == pContext->value) {
1364 pContext->key = (char*) key;
1365 return false;
1366 }
1367 return true;
1368 }
1369
1370 Hashmap* mpMap;
1371 };
1372
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001373 template<class E> class Array {
1374 public:
1375 Array() {
1376 mpBase = 0;
1377 mUsed = 0;
1378 mSize = 0;
1379 }
1380
1381 ~Array() {
1382 if (mpBase) {
1383 free(mpBase);
1384 }
1385 }
1386
1387 E get(int i) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001388 if (i < 0 || i > (int) mUsed) {
1389 // error("internal error: Index out of range");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001390 return E();
1391 }
1392 return mpBase[i];
1393 }
1394
1395 void set(int i, E val) {
1396 mpBase[i] = val;
1397 }
1398
1399 void pop() {
1400 if (mUsed > 0) {
1401 mUsed -= 1;
Jack Palevich36d94142009-06-08 15:55:32 -07001402 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001403 // error("internal error: Popped empty stack.");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001404 }
1405 }
1406
1407 void push(E item) {
1408 * ensure(1) = item;
1409 }
1410
1411 size_t len() {
1412 return mUsed;
1413 }
1414
1415 private:
1416 E* ensure(int n) {
1417 size_t newUsed = mUsed + n;
1418 if (newUsed > mSize) {
1419 size_t newSize = mSize * 2 + 10;
1420 if (newSize < newUsed) {
1421 newSize = newUsed;
1422 }
1423 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1424 mSize = newSize;
1425 }
1426 E* result = mpBase + mUsed;
1427 mUsed = newUsed;
1428 return result;
1429 }
1430
1431 E* mpBase;
1432 size_t mUsed;
1433 size_t mSize;
1434 };
1435
Jack Palevich36d94142009-06-08 15:55:32 -07001436 struct InputState {
1437 InputStream* pStream;
1438 int oldCh;
1439 };
1440
Jack Palevich2db168f2009-06-11 14:29:47 -07001441 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001442 VariableInfo() {
1443 pAddress = 0;
1444 pForward = 0;
1445 }
1446 void* pAddress;
1447 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich2db168f2009-06-11 14:29:47 -07001448 };
1449
Jack Palevich303d8ff2009-06-11 19:06:24 -07001450 typedef StringTable<VariableInfo> SymbolTable;
1451
1452 class SymbolStack {
1453 public:
1454 SymbolStack() {
1455 mLevel = 0;
1456 addEntry();
1457 }
1458
1459 void pushLevel() {
1460 mLevel++;
1461 }
1462
1463 void popLevel() {
1464 mLevel--;
1465 Entry e = mStack.get(mStack.len()-1);
1466 if (mLevel < e.level) {
1467 mStack.pop();
1468 delete e.pTable;
1469 }
1470 }
1471
1472 VariableInfo* get(String* pName) {
1473 int len = mStack.len();
1474 VariableInfo* v = NULL;
1475 int level = -1;
1476 for (int i = len - 1; i >= 0; i--) {
1477 Entry e = mStack.get(i);
1478 v = e.pTable->get(pName);
1479 if (v) {
1480 level = e.level;
1481 break;
1482 }
1483 }
1484#if 0
1485 fprintf(stderr, "Lookup %s %08x level %d\n", pName->getUnwrapped(), v, level);
1486 if (v) {
1487 fprintf(stderr, " %08x %08x\n", v->pAddress, v->pForward);
1488 }
1489#endif
1490 return v;
1491 }
1492
1493 VariableInfo* addLocal(String* pName) {
1494 int len = mStack.len();
1495 if (mStack.get(len-1).level != mLevel) {
1496 addEntry();
1497 len++;
1498 }
1499 return addImp(len-1, pName);
1500 }
1501
1502 VariableInfo* addGlobal(String* pName) {
1503 return addImp(0, pName);
1504 }
1505
1506 private:
1507 VariableInfo* addImp(int entryIndex, String* pName) {
1508 Entry e = mStack.get(entryIndex);
1509 SymbolTable* pTable = e.pTable;
1510 VariableInfo* v = new VariableInfo();
1511 delete pTable->put(pName, v);
1512#if 0
1513 fprintf(stderr, "Add \"%s\" %08x level %d\n", pName->getUnwrapped(), v, e.level);
1514#endif
1515 return v;
1516 }
1517
1518 void addEntry() {
1519 Entry e;
1520 e.level = mLevel;
1521 e.pTable = new SymbolTable();
1522 mStack.push(e);
1523 }
1524
1525 struct Entry {
1526 Entry() {
1527 level = 0;
1528 pTable = NULL;
1529 }
1530 int level;
1531 SymbolTable* pTable;
1532 };
1533
1534 int mLevel;
1535 Array<Entry> mStack;
1536 };
Jack Palevich36d94142009-06-08 15:55:32 -07001537
1538 int ch; // Current input character, or EOF
1539 intptr_t tok; // token
1540 intptr_t tokc; // token extra info
1541 int tokl; // token operator level
1542 intptr_t rsym; // return symbol
1543 intptr_t loc; // local variable index
1544 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07001545 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07001546 char* dptr; // Macro state: Points to macro text during macro playback.
1547 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07001548 char* pGlobalBase;
Jack Palevich2db168f2009-06-11 14:29:47 -07001549 KeywordTable mKeywords;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001550 SymbolStack mSymbolTable;
Jack Palevich36d94142009-06-08 15:55:32 -07001551 InputStream* file;
1552
1553 CodeBuf codeBuf;
1554 CodeGenerator* pGen;
1555
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001556 MacroTable mMacros;
Jack Palevich36d94142009-06-08 15:55:32 -07001557 Array<InputState> mInputStateStack;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001558
Jack Palevicheedf9d22009-06-04 16:23:40 -07001559 String mErrorBuf;
1560
Jack Palevicheedf9d22009-06-04 16:23:40 -07001561 String mPragmas;
1562 int mPragmaStringCount;
1563
Jack Palevich21a15a22009-05-11 14:49:29 -07001564 static const int ALLOC_SIZE = 99999;
1565
Jack Palevich303d8ff2009-06-11 19:06:24 -07001566 static const int TOK_DUMMY = 1;
1567 static const int TOK_NUM = 2;
1568
1569 // 3..255 are character and/or operators
1570
Jack Palevich2db168f2009-06-11 14:29:47 -07001571 // Keywords start at 0x100 and increase by 1
1572 static const int TOK_KEYWORD = 0x100;
1573 static const int TOK_INT = TOK_KEYWORD + 0;
1574 static const int TOK_CHAR = TOK_KEYWORD + 1;
1575 static const int TOK_VOID = TOK_KEYWORD + 2;
1576 static const int TOK_IF = TOK_KEYWORD + 3;
1577 static const int TOK_ELSE = TOK_KEYWORD + 4;
1578 static const int TOK_WHILE = TOK_KEYWORD + 5;
1579 static const int TOK_BREAK = TOK_KEYWORD + 6;
1580 static const int TOK_RETURN = TOK_KEYWORD + 7;
1581 static const int TOK_FOR = TOK_KEYWORD + 8;
1582 static const int TOK_PRAGMA = TOK_KEYWORD + 9;
1583 static const int TOK_DEFINE = TOK_KEYWORD + 10;
1584
Jack Palevich303d8ff2009-06-11 19:06:24 -07001585 static const int TOK_UNDEFINED_SYMBOL = 0x200;
Jack Palevich21a15a22009-05-11 14:49:29 -07001586
Jack Palevich303d8ff2009-06-11 19:06:24 -07001587 // Symbols start at 0x300, but are really pointers to VariableInfo structs.
1588 static const int TOK_SYMBOL = 0x300;
1589
Jack Palevich21a15a22009-05-11 14:49:29 -07001590
1591 static const int LOCAL = 0x200;
1592
1593 static const int SYM_FORWARD = 0;
1594 static const int SYM_DEFINE = 1;
1595
1596 /* tokens in string heap */
1597 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07001598
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001599 static const int OP_INCREMENT = 0;
1600 static const int OP_DECREMENT = 1;
1601 static const int OP_MUL = 2;
1602 static const int OP_DIV = 3;
1603 static const int OP_MOD = 4;
1604 static const int OP_PLUS = 5;
1605 static const int OP_MINUS = 6;
1606 static const int OP_SHIFT_LEFT = 7;
1607 static const int OP_SHIFT_RIGHT = 8;
1608 static const int OP_LESS_EQUAL = 9;
1609 static const int OP_GREATER_EQUAL = 10;
1610 static const int OP_LESS = 11;
1611 static const int OP_GREATER = 12;
1612 static const int OP_EQUALS = 13;
1613 static const int OP_NOT_EQUALS = 14;
1614 static const int OP_LOGICAL_AND = 15;
1615 static const int OP_LOGICAL_OR = 16;
1616 static const int OP_BIT_AND = 17;
1617 static const int OP_BIT_XOR = 18;
1618 static const int OP_BIT_OR = 19;
1619 static const int OP_BIT_NOT = 20;
1620 static const int OP_LOGICAL_NOT = 21;
1621 static const int OP_COUNT = 22;
1622
1623 /* Operators are searched from front, the two-character operators appear
1624 * before the single-character operators with the same first character.
1625 * @ is used to pad out single-character operators.
1626 */
1627 static const char* operatorChars;
1628 static const char operatorLevel[];
1629
Jack Palevich21a15a22009-05-11 14:49:29 -07001630 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001631 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001632 }
1633
1634 void inp() {
1635 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001636 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001637 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001638 dptr = 0;
1639 ch = dch;
1640 }
1641 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07001642 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001643#if 0
1644 printf("ch='%c' 0x%x\n", ch, ch);
1645#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07001646 }
1647
1648 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07001649 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07001650 }
1651
1652 /* read a character constant */
1653 void getq() {
1654 if (ch == '\\') {
1655 inp();
1656 if (ch == 'n')
1657 ch = '\n';
1658 }
1659 }
1660
1661 void next() {
1662 int l, a;
1663
Jack Palevich546b2242009-05-13 15:10:04 -07001664 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001665 if (ch == '#') {
1666 inp();
1667 next();
1668 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001669 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07001670 } else if (tok == TOK_PRAGMA) {
1671 doPragma();
1672 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001673 error("Unsupported preprocessor directive \"%s\"",
1674 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07001675 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001676 }
1677 inp();
1678 }
1679 tokl = 0;
1680 tok = ch;
1681 /* encode identifiers & numbers */
1682 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001683 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07001684 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001685 pdef(ch);
1686 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001687 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001688 if (isdigit(tok)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001689 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001690 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001691 } else {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001692 // Is this a macro?
Jack Palevich303d8ff2009-06-11 19:06:24 -07001693 String* pValue = mMacros.get(&mTokenString);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001694 if (pValue) {
1695 // Yes, it is a macro
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001696 dptr = pValue->getUnwrapped();
1697 dch = ch;
1698 inp();
1699 next();
1700 } else {
Jack Palevich2db168f2009-06-11 14:29:47 -07001701 // Is this a keyword?
Jack Palevich303d8ff2009-06-11 19:06:24 -07001702 int kwtok = mKeywords.get(&mTokenString);
Jack Palevich2db168f2009-06-11 14:29:47 -07001703 if (kwtok) {
1704 tok = kwtok;
1705 // fprintf(stderr, "tok= keyword %s %x\n", last_id, tok);
1706 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001707 tok = (intptr_t) mSymbolTable.get(&mTokenString);
1708 if (!tok) {
1709 tok = TOK_UNDEFINED_SYMBOL;
1710 }
Jack Palevich2db168f2009-06-11 14:29:47 -07001711 // fprintf(stderr, "tok= symbol %s %x\n", last_id, tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001712 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001713 }
1714 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001715 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001716 inp();
1717 if (tok == '\'') {
1718 tok = TOK_NUM;
1719 getq();
1720 tokc = ch;
1721 inp();
1722 inp();
Jack Palevich546b2242009-05-13 15:10:04 -07001723 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001724 inp();
1725 while (ch) {
1726 while (ch != '*')
1727 inp();
1728 inp();
1729 if (ch == '/')
1730 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001731 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001732 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001733 next();
Jack Palevichbd894902009-05-14 19:35:31 -07001734 } else if ((tok == '/') & (ch == '/')) {
1735 inp();
1736 while (ch && (ch != '\n')) {
1737 inp();
1738 }
1739 inp();
1740 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001741 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001742 const char* t = operatorChars;
1743 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001744 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001745 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001746 tokl = operatorLevel[opIndex];
1747 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07001748 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001749#if 0
1750 printf("%c%c -> tokl=%d tokc=0x%x\n",
1751 l, a, tokl, tokc);
1752#endif
1753 if (a == ch) {
1754 inp();
1755 tok = TOK_DUMMY; /* dummy token for double tokens */
1756 }
1757 break;
1758 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001759 opIndex++;
1760 }
1761 if (l == 0) {
1762 tokl = 0;
1763 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001764 }
1765 }
1766 }
1767#if 0
1768 {
Jack Palevich2db168f2009-06-11 14:29:47 -07001769 const char* p;
Jack Palevich21a15a22009-05-11 14:49:29 -07001770
1771 printf("tok=0x%x ", tok);
Jack Palevich2db168f2009-06-11 14:29:47 -07001772 if (tok >= TOK_KEYWORD) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001773 printf("'");
Jack Palevich2db168f2009-06-11 14:29:47 -07001774 if (tok>= TOK_SYMBOL)
1775 p = sym_stk + 1 + ((char*) tok - (char*) pVarsBase) / 8;
1776 else {
1777 p = mKeywords.lookupKeyFor(tok);
1778 if (!p) {
1779 p = "unknown keyword";
1780 }
1781 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001782 while (*p != TAG_TOK && *p)
1783 printf("%c", *p++);
Jack Palevich21a15a22009-05-11 14:49:29 -07001784 printf("'\n");
1785 } else if (tok == TOK_NUM) {
1786 printf("%d\n", tokc);
1787 } else {
1788 printf("'%c'\n", tok);
1789 }
1790 }
1791#endif
1792 }
1793
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001794 void doDefine() {
1795 String* pName = new String();
1796 while (isspace(ch)) {
1797 inp();
1798 }
1799 while (isid()) {
1800 pName->append(ch);
1801 inp();
1802 }
1803 if (ch == '(') {
1804 delete pName;
1805 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07001806 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001807 }
1808 while (isspace(ch)) {
1809 inp();
1810 }
1811 String* pValue = new String();
1812 while (ch != '\n' && ch != EOF) {
1813 pValue->append(ch);
1814 inp();
1815 }
1816 delete mMacros.put(pName, pValue);
1817 }
1818
Jack Palevicheedf9d22009-06-04 16:23:40 -07001819 void doPragma() {
1820 // # pragma name(val)
1821 int state = 0;
1822 while(ch != EOF && ch != '\n' && state < 10) {
1823 switch(state) {
1824 case 0:
1825 if (isspace(ch)) {
1826 inp();
1827 } else {
1828 state++;
1829 }
1830 break;
1831 case 1:
1832 if (isalnum(ch)) {
1833 mPragmas.append(ch);
1834 inp();
1835 } else if (ch == '(') {
1836 mPragmas.append(0);
1837 inp();
1838 state++;
1839 } else {
1840 state = 11;
1841 }
1842 break;
1843 case 2:
1844 if (isalnum(ch)) {
1845 mPragmas.append(ch);
1846 inp();
1847 } else if (ch == ')') {
1848 mPragmas.append(0);
1849 inp();
1850 state = 10;
1851 } else {
1852 state = 11;
1853 }
1854 break;
1855 }
1856 }
1857 if(state != 10) {
1858 error("Unexpected pragma syntax");
1859 }
1860 mPragmaStringCount += 2;
1861 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001862
Jack Palevichac0e95e2009-05-29 13:53:44 -07001863 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001864 mErrorBuf.printf("%ld: ", file->getLine());
1865 mErrorBuf.vprintf(fmt, ap);
1866 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07001867 }
1868
Jack Palevich8b0624c2009-05-20 12:12:06 -07001869 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001870 if (tok != c) {
1871 error("'%c' expected", c);
1872 }
1873 next();
1874 }
1875
Jack Palevich21a15a22009-05-11 14:49:29 -07001876 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001877 void unary(intptr_t l) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001878 intptr_t n, t, a;
1879 int c;
Jack Palevich546b2242009-05-13 15:10:04 -07001880 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001881 n = 1; /* type of expression 0 = forward, 1 = value, other =
1882 lvalue */
1883 if (tok == '\"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07001884 pGen->li((int) glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001885 while (ch != '\"') {
1886 getq();
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001887 *allocGlobalSpace(1) = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07001888 inp();
1889 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001890 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001891 /* align heap */
1892 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001893 inp();
1894 next();
1895 } else {
1896 c = tokl;
1897 a = tokc;
1898 t = tok;
1899 next();
1900 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001901 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001902 } else if (c == 2) {
1903 /* -, +, !, ~ */
1904 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07001905 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001906 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001907 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001908 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001909 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001910 } else if (t == '(') {
1911 expr();
1912 skip(')');
1913 } else if (t == '*') {
1914 /* parse cast */
1915 skip('(');
1916 t = tok; /* get type */
1917 next(); /* skip int/char/void */
1918 next(); /* skip '*' or '(' */
1919 if (tok == '*') {
1920 /* function type */
1921 skip('*');
1922 skip(')');
1923 skip('(');
1924 skip(')');
1925 t = 0;
1926 }
1927 skip(')');
1928 unary(0);
1929 if (tok == '=') {
1930 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07001931 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001932 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001933 pGen->popR1();
1934 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001935 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001936 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001937 }
1938 } else if (t == '&') {
Jack Palevich1cdef202009-05-22 12:06:27 -07001939 pGen->leaR0(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001940 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07001941 } else if (t == EOF ) {
1942 error("Unexpected EOF.");
1943 } else if (t < TOK_UNDEFINED_SYMBOL) {
1944 error("Unexpected symbol or keyword");
Jack Palevich21a15a22009-05-11 14:49:29 -07001945 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001946 if (t == TOK_UNDEFINED_SYMBOL) {
1947 t = (intptr_t) mSymbolTable.addGlobal(
1948 new String(mTokenString));
1949 }
1950
Jack Palevich21a15a22009-05-11 14:49:29 -07001951 n = *(int *) t;
1952 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001953 if (!n) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001954 n = (intptr_t) dlsym(RTLD_DEFAULT,
1955 mTokenString.getUnwrapped());
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001956 }
Jack Palevich546b2242009-05-13 15:10:04 -07001957 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001958 /* assignment */
1959 next();
1960 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001961 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07001962 } else if (tok != '(') {
1963 /* variable */
Jack Palevich1cdef202009-05-22 12:06:27 -07001964 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001965 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001966 next();
1967 }
1968 }
1969 }
1970 }
1971
1972 /* function call */
1973 if (tok == '(') {
1974 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07001975 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001976
1977 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001978 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07001979 next();
1980 l = 0;
1981 while (tok != ')') {
1982 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001983 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001984 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001985 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001986 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001987 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001988 pGen->endFunctionCallArguments(a, l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001989 next();
1990 if (!n) {
1991 /* forward reference */
1992 t = t + 4;
1993 *(int *) t = pGen->callForward(*(int *) t);
1994 } else if (n == 1) {
1995 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001996 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07001997 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07001998 }
Jack Palevich3d474a72009-05-15 15:12:38 -07001999 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07002000 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002001 }
2002 }
2003
Jack Palevich653f42d2009-05-28 17:15:32 -07002004 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002005 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002006 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002007 if (l-- == 1)
2008 unary(1);
2009 else {
2010 sum(l);
2011 a = 0;
2012 while (l == tokl) {
2013 n = tok;
2014 t = tokc;
2015 next();
2016
2017 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002018 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07002019 sum(l);
2020 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002021 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002022 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07002023 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002024
Jack Palevich546b2242009-05-13 15:10:04 -07002025 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002026 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002027 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002028 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002029 }
2030 }
2031 }
2032 /* && and || output code generation */
2033 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002034 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2035 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002036 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002037 pGen->gsym(a);
2038 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002039 }
2040 }
2041 }
2042
2043 void expr() {
2044 sum(11);
2045 }
2046
2047 int test_expr() {
2048 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002049 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002050 }
2051
Jack Palevich8b0624c2009-05-20 12:12:06 -07002052 void block(intptr_t l) {
2053 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002054
2055 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002056 next();
2057 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002058 a = test_expr();
2059 skip(')');
2060 block(l);
2061 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002062 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002063 n = pGen->gjmp(0); /* jmp */
2064 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002065 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002066 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002067 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002068 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002069 }
Jack Palevich546b2242009-05-13 15:10:04 -07002070 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002071 t = tok;
2072 next();
2073 skip('(');
2074 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002075 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002076 a = test_expr();
2077 } else {
2078 if (tok != ';')
2079 expr();
2080 skip(';');
2081 n = codeBuf.getPC();
2082 a = 0;
2083 if (tok != ';')
2084 a = test_expr();
2085 skip(';');
2086 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002087 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002088 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002089 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002090 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002091 n = t + 4;
2092 }
2093 }
2094 skip(')');
Jack Palevich8b0624c2009-05-20 12:12:06 -07002095 block((intptr_t) &a);
Jack Palevicha6535612009-05-13 16:24:17 -07002096 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002097 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002098 } else if (tok == '{') {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002099 mSymbolTable.pushLevel();
Jack Palevich21a15a22009-05-11 14:49:29 -07002100 next();
2101 /* declarations */
Jack Palevichb7c81e92009-06-04 19:56:13 -07002102 localDeclarations();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002103 while (tok != '}' && tok != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002104 block(l);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002105 skip('}');
2106 mSymbolTable.popLevel();
Jack Palevich21a15a22009-05-11 14:49:29 -07002107 } else {
2108 if (tok == TOK_RETURN) {
2109 next();
2110 if (tok != ';')
2111 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002112 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002113 } else if (tok == TOK_BREAK) {
2114 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002115 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002116 } else if (tok != ';')
2117 expr();
2118 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002119 }
2120 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002121
Jack Palevichb7c81e92009-06-04 19:56:13 -07002122 typedef int Type;
2123 static const Type TY_UNKNOWN = 0;
2124 static const Type TY_INT = 1;
2125 static const Type TY_CHAR = 2;
2126 static const Type TY_VOID = 3;
2127 static const int TY_BASE_TYPE_MASK = 0xf;
2128 static const int TY_INDIRECTION_MASK = 0xf0;
2129 static const int TY_INDIRECTION_SHIFT = 4;
2130 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07002131
Jack Palevichb7c81e92009-06-04 19:56:13 -07002132 Type getBaseType(Type t) {
2133 return t & TY_BASE_TYPE_MASK;
2134 }
2135
2136 int getIndirectionCount(Type t) {
2137 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
2138 }
2139
2140 void setIndirectionCount(Type& t, int count) {
2141 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
2142 | (t & ~TY_INDIRECTION_MASK));
2143 }
2144
2145 bool acceptType(Type& t) {
2146 t = TY_UNKNOWN;
2147 if (tok == TOK_INT) {
2148 t = TY_INT;
2149 } else if (tok == TOK_CHAR) {
2150 t = TY_CHAR;
2151 } else if (tok == TOK_VOID) {
2152 t = TY_VOID;
2153 } else {
2154 return false;
2155 }
2156 next();
2157 return true;
2158 }
2159
2160 Type acceptPointerDeclaration(Type& base) {
2161 Type t = base;
2162 int indirectionCount = 0;
2163 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
2164 next();
2165 indirectionCount++;
2166 }
2167 if (indirectionCount > MAX_INDIRECTION_COUNT) {
2168 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
2169 }
2170 setIndirectionCount(t, indirectionCount);
2171 return t;
2172 }
2173
2174 void expectType(Type& t) {
2175 if (!acceptType(t)) {
2176 error("Expected a type.");
2177 }
2178 }
2179
2180 void checkSymbol() {
Jack Palevich2db168f2009-06-11 14:29:47 -07002181 if (tok < TOK_SYMBOL) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002182 error("Expected a symbol");
2183 }
2184 }
2185
Jack Palevich303d8ff2009-06-11 19:06:24 -07002186 void defineGlobalSymbol() {
2187 if (tok == TOK_UNDEFINED_SYMBOL) {
2188 // TODO: don't allow multiple definitions at same level.
2189 tok = (intptr_t) mSymbolTable.addGlobal(
2190 new String(mTokenString));
2191 }
2192 }
2193
2194 void defineLocalSymbol() {
2195 // TODO: don't allow multiple definitions at same level.
2196 tok = (intptr_t) mSymbolTable.addLocal(
2197 new String(mTokenString));
2198 }
2199
Jack Palevichb7c81e92009-06-04 19:56:13 -07002200 void localDeclarations() {
2201 intptr_t a;
2202 Type base;
2203
2204 while (acceptType(base)) {
2205 while (tok != ';') {
2206 Type t = acceptPointerDeclaration(t);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002207 defineLocalSymbol();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002208 loc = loc + 4;
2209 *(int *) tok = -loc;
2210
Jack Palevich21a15a22009-05-11 14:49:29 -07002211 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002212 if (tok == ',')
2213 next();
2214 }
2215 skip(';');
2216 }
2217 }
2218
2219 void globalDeclarations() {
2220 while (tok != EOF) {
2221 Type base;
2222 expectType(base);
2223 Type t = acceptPointerDeclaration(t);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002224 defineGlobalSymbol();
2225 VariableInfo* name = (VariableInfo*) tok;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002226 next();
2227 if (tok == ',' || tok == ';') {
2228 // it's a variable declaration
2229 for(;;) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002230 name->pAddress = (int*) allocGlobalSpace(4);
Jack Palevichb7c81e92009-06-04 19:56:13 -07002231 if (tok != ',') {
2232 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07002233 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002234 skip(',');
Jack Palevichb7c81e92009-06-04 19:56:13 -07002235 t = acceptPointerDeclaration(t);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002236 defineGlobalSymbol();
2237 name = (VariableInfo*) tok;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002238 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002239 }
2240 skip(';');
2241 } else {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002242 /* patch forward references (XXX: does not work for function
Jack Palevich21a15a22009-05-11 14:49:29 -07002243 pointers) */
Jack Palevich303d8ff2009-06-11 19:06:24 -07002244 pGen->gsym((int) name->pForward);
Jack Palevich21a15a22009-05-11 14:49:29 -07002245 /* put function address */
Jack Palevich303d8ff2009-06-11 19:06:24 -07002246 name->pAddress = (void*) codeBuf.getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07002247 skip('(');
Jack Palevich303d8ff2009-06-11 19:06:24 -07002248 mSymbolTable.pushLevel();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002249 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07002250 int argCount = 0;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002251 while (tok != ')' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002252 Type aType;
2253 expectType(aType);
2254 aType = acceptPointerDeclaration(aType);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002255 defineLocalSymbol();
Jack Palevich21a15a22009-05-11 14:49:29 -07002256 /* read param name and compute offset */
2257 *(int *) tok = a;
2258 a = a + 4;
2259 next();
2260 if (tok == ',')
2261 next();
Jack Palevich546b2242009-05-13 15:10:04 -07002262 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07002263 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002264 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002265 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002266 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07002267 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002268 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07002269 pGen->functionExit(argCount, a, loc);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002270 mSymbolTable.popLevel();
Jack Palevich21a15a22009-05-11 14:49:29 -07002271 }
2272 }
2273 }
2274
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002275 char* allocGlobalSpace(int bytes) {
2276 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
2277 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07002278 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002279 }
2280 char* result = glo;
2281 glo += bytes;
2282 return result;
2283 }
2284
Jack Palevich21a15a22009-05-11 14:49:29 -07002285 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002286 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002287 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07002288 pGlobalBase = 0;
2289 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002290 if (pGen) {
2291 delete pGen;
2292 pGen = 0;
2293 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002294 if (file) {
2295 delete file;
2296 file = 0;
2297 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002298 }
2299
2300 void clear() {
2301 tok = 0;
2302 tokc = 0;
2303 tokl = 0;
2304 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002305 rsym = 0;
2306 loc = 0;
2307 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002308 dptr = 0;
2309 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002310 file = 0;
2311 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002312 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002313 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002314 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002315
Jack Palevich22305132009-05-13 10:58:45 -07002316 void setArchitecture(const char* architecture) {
2317 delete pGen;
2318 pGen = 0;
2319
2320 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002321#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002322 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002323 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002324 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002325#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07002326#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002327 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002328 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002329 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002330#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07002331 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002332 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07002333 }
2334 }
2335
2336 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002337#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07002338 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07002339#elif defined(DEFAULT_X86_CODEGEN)
2340 pGen = new X86CodeGenerator();
2341#endif
2342 }
2343 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002344 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07002345 } else {
2346 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07002347 }
2348 }
2349
Jack Palevich77ae76e2009-05-10 19:59:24 -07002350public:
Jack Palevich22305132009-05-13 10:58:45 -07002351 struct args {
2352 args() {
2353 architecture = 0;
2354 }
2355 const char* architecture;
2356 };
2357
Jack Paleviche7b59062009-05-19 17:12:17 -07002358 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002359 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002360 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002361
Jack Paleviche7b59062009-05-19 17:12:17 -07002362 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002363 cleanup();
2364 }
2365
Jack Palevich1cdef202009-05-22 12:06:27 -07002366 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002367 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07002368
2369 cleanup();
2370 clear();
2371 codeBuf.init(ALLOC_SIZE);
2372 setArchitecture(NULL);
2373 if (!pGen) {
2374 return -1;
2375 }
2376 pGen->init(&codeBuf);
2377 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07002378 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
2379 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07002380 inp();
2381 next();
2382 globalDeclarations();
2383 result = pGen->finishCompile();
2384 if (result == 0) {
2385 if (mErrorBuf.len()) {
2386 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07002387 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07002388 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002389 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07002390 }
2391
Jack Palevich21a15a22009-05-11 14:49:29 -07002392 int dump(FILE* out) {
2393 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
2394 return 0;
2395 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07002396
Jack Palevicha6535612009-05-13 16:24:17 -07002397 int disassemble(FILE* out) {
2398 return pGen->disassemble(out);
2399 }
2400
Jack Palevich1cdef202009-05-22 12:06:27 -07002401 /* Look through the symbol table to find a symbol.
2402 * If found, return its value.
2403 */
2404 void* lookup(const char* name) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002405 String string(name, -1, false);
2406 VariableInfo* pVariableInfo = mSymbolTable.get(&string);
2407 if (pVariableInfo) {
2408 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07002409 }
2410 return NULL;
2411 }
2412
Jack Palevicheedf9d22009-06-04 16:23:40 -07002413 void getPragmas(ACCsizei* actualStringCount,
2414 ACCsizei maxStringCount, ACCchar** strings) {
2415 int stringCount = mPragmaStringCount;
2416 if (actualStringCount) {
2417 *actualStringCount = stringCount;
2418 }
2419 if (stringCount > maxStringCount) {
2420 stringCount = maxStringCount;
2421 }
2422 if (strings) {
2423 char* pPragmas = mPragmas.getUnwrapped();
2424 while (stringCount-- > 0) {
2425 *strings++ = pPragmas;
2426 pPragmas += strlen(pPragmas) + 1;
2427 }
2428 }
2429 }
2430
Jack Palevichac0e95e2009-05-29 13:53:44 -07002431 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002432 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002433 }
2434
Jack Palevich77ae76e2009-05-10 19:59:24 -07002435};
2436
Jack Paleviche7b59062009-05-19 17:12:17 -07002437const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002438 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2439
Jack Paleviche7b59062009-05-19 17:12:17 -07002440const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002441 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2442 5, 5, /* ==, != */
2443 9, 10, /* &&, || */
2444 6, 7, 8, /* & ^ | */
2445 2, 2 /* ~ ! */
2446 };
2447
Jack Palevich8b0624c2009-05-20 12:12:06 -07002448#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002449FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002450#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002451
Jack Palevich8b0624c2009-05-20 12:12:06 -07002452#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002453const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002454 0x1, // ++
2455 0xff, // --
2456 0xc1af0f, // *
2457 0xf9f79991, // /
2458 0xf9f79991, // % (With manual assist to swap results)
2459 0xc801, // +
2460 0xd8f7c829, // -
2461 0xe0d391, // <<
2462 0xf8d391, // >>
2463 0xe, // <=
2464 0xd, // >=
2465 0xc, // <
2466 0xf, // >
2467 0x4, // ==
2468 0x5, // !=
2469 0x0, // &&
2470 0x1, // ||
2471 0xc821, // &
2472 0xc831, // ^
2473 0xc809, // |
2474 0xd0f7, // ~
2475 0x4 // !
2476};
Jack Palevich8b0624c2009-05-20 12:12:06 -07002477#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002478
Jack Palevich1cdef202009-05-22 12:06:27 -07002479struct ACCscript {
2480 ACCscript() {
2481 text = 0;
2482 textLength = 0;
2483 accError = ACC_NO_ERROR;
2484 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002485
Jack Palevich1cdef202009-05-22 12:06:27 -07002486 ~ACCscript() {
2487 delete text;
2488 }
Jack Palevich546b2242009-05-13 15:10:04 -07002489
Jack Palevich1cdef202009-05-22 12:06:27 -07002490 void setError(ACCenum error) {
2491 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
2492 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002493 }
2494 }
2495
Jack Palevich1cdef202009-05-22 12:06:27 -07002496 ACCenum getError() {
2497 ACCenum result = accError;
2498 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07002499 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002500 }
2501
Jack Palevich1cdef202009-05-22 12:06:27 -07002502 Compiler compiler;
2503 char* text;
2504 int textLength;
2505 ACCenum accError;
2506};
2507
2508
2509extern "C"
2510ACCscript* accCreateScript() {
2511 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002512}
Jack Palevich1cdef202009-05-22 12:06:27 -07002513
2514extern "C"
2515ACCenum accGetError( ACCscript* script ) {
2516 return script->getError();
2517}
2518
2519extern "C"
2520void accDeleteScript(ACCscript* script) {
2521 delete script;
2522}
2523
2524extern "C"
2525void accScriptSource(ACCscript* script,
2526 ACCsizei count,
2527 const ACCchar ** string,
2528 const ACCint * length) {
2529 int totalLength = 0;
2530 for(int i = 0; i < count; i++) {
2531 int len = -1;
2532 const ACCchar* s = string[i];
2533 if (length) {
2534 len = length[i];
2535 }
2536 if (len < 0) {
2537 len = strlen(s);
2538 }
2539 totalLength += len;
2540 }
2541 delete script->text;
2542 char* text = new char[totalLength + 1];
2543 script->text = text;
2544 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07002545 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07002546 for(int i = 0; i < count; i++) {
2547 int len = -1;
2548 const ACCchar* s = string[i];
2549 if (length) {
2550 len = length[i];
2551 }
2552 if (len < 0) {
2553 len = strlen(s);
2554 }
Jack Palevich09555c72009-05-27 12:25:55 -07002555 memcpy(dest, s, len);
2556 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07002557 }
2558 text[totalLength] = '\0';
2559}
2560
2561extern "C"
2562void accCompileScript(ACCscript* script) {
2563 int result = script->compiler.compile(script->text, script->textLength);
2564 if (result) {
2565 script->setError(ACC_INVALID_OPERATION);
2566 }
2567}
2568
2569extern "C"
2570void accGetScriptiv(ACCscript* script,
2571 ACCenum pname,
2572 ACCint * params) {
2573 switch (pname) {
2574 case ACC_INFO_LOG_LENGTH:
2575 *params = 0;
2576 break;
2577 }
2578}
2579
2580extern "C"
2581void accGetScriptInfoLog(ACCscript* script,
2582 ACCsizei maxLength,
2583 ACCsizei * length,
2584 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002585 char* message = script->compiler.getErrorMessage();
2586 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07002587 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002588 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07002589 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002590 if (infoLog && maxLength > 0) {
2591 int trimmedLength = maxLength < messageLength ?
2592 maxLength : messageLength;
2593 memcpy(infoLog, message, trimmedLength);
2594 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002595 }
2596}
2597
2598extern "C"
2599void accGetScriptLabel(ACCscript* script, const ACCchar * name,
2600 ACCvoid ** address) {
2601 void* value = script->compiler.lookup(name);
2602 if (value) {
2603 *address = value;
2604 } else {
2605 script->setError(ACC_INVALID_VALUE);
2606 }
2607}
2608
Jack Palevicheedf9d22009-06-04 16:23:40 -07002609extern "C"
2610void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
2611 ACCsizei maxStringCount, ACCchar** strings){
2612 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
2613}
2614
2615
Jack Palevich1cdef202009-05-22 12:06:27 -07002616} // namespace acc
2617