blob: db37ee27cc2967838d46d71e32baa70afef1ea89 [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 Palevichac0e95e2009-05-29 13:53:44 -070013#include <setjmp.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 Palevich546b2242009-05-13 15:10:04 -070021#if defined(__arm__)
22#include <unistd.h>
23#endif
24
Jack Paleviche7b59062009-05-19 17:12:17 -070025#if defined(__arm__)
26#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070027#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070028#elif defined(__i386__)
29#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__x86_64__)
32#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#endif
35
Jack Paleviche7b59062009-05-19 17:12:17 -070036
37#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070038#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070039#endif
Jack Palevicha6535612009-05-13 16:24:17 -070040
Jack Palevich1cdef202009-05-22 12:06:27 -070041#include <acc/acc.h>
42
Jack Palevich09555c72009-05-27 12:25:55 -070043#define LOG_API(...) do {} while(0)
44// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070045// #define ENABLE_ARM_DISASSEMBLY
46
Jack Palevichbbf8ab52009-05-11 11:54:30 -070047namespace acc {
48
Jack Palevichac0e95e2009-05-29 13:53:44 -070049class ErrorSink {
50public:
51 void error(const char *fmt, ...) {
52 va_list ap;
53 va_start(ap, fmt);
54 verror(fmt, ap);
55 va_end(ap);
56 }
57
58 virtual void verror(const char* fmt, va_list ap) = 0;
59};
60
61class Compiler : public ErrorSink {
Jack Palevich21a15a22009-05-11 14:49:29 -070062 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070063 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070064 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070065 ErrorSink* mErrorSink;
66 int mSize;
Jack Palevichf0cbc922009-05-08 16:35:13 -070067
Jack Palevich21a15a22009-05-11 14:49:29 -070068 void release() {
69 if (pProgramBase != 0) {
70 free(pProgramBase);
71 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070072 }
Jack Palevich21a15a22009-05-11 14:49:29 -070073 }
74
Jack Palevichac0e95e2009-05-29 13:53:44 -070075 void check(int n) {
76 int newSize = ind - pProgramBase + n;
77 if (newSize > mSize) {
78 if (mErrorSink) {
79 mErrorSink->error("Code too large: %d bytes", newSize);
80 }
81 }
82 }
83
Jack Palevich21a15a22009-05-11 14:49:29 -070084 public:
85 CodeBuf() {
86 pProgramBase = 0;
87 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -070088 mErrorSink = 0;
89 mSize = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -070090 }
91
92 ~CodeBuf() {
93 release();
94 }
95
96 void init(int size) {
97 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -070098 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -070099 pProgramBase = (char*) calloc(1, size);
100 ind = pProgramBase;
101 }
102
Jack Palevichac0e95e2009-05-29 13:53:44 -0700103 void setErrorSink(ErrorSink* pErrorSink) {
104 mErrorSink = pErrorSink;
105 }
106
Jack Palevich546b2242009-05-13 15:10:04 -0700107 int o4(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700108 check(4);
Jack Palevich8b0624c2009-05-20 12:12:06 -0700109 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700110 * (int*) ind = n;
111 ind += 4;
112 return result;
113 }
114
Jack Palevich21a15a22009-05-11 14:49:29 -0700115 /*
116 * Output a byte. Handles all values, 0..ff.
117 */
118 void ob(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700119 check(1);
Jack Palevich21a15a22009-05-11 14:49:29 -0700120 *ind++ = n;
121 }
122
Jack Palevich21a15a22009-05-11 14:49:29 -0700123 inline void* getBase() {
124 return (void*) pProgramBase;
125 }
126
Jack Palevich8b0624c2009-05-20 12:12:06 -0700127 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700128 return ind - pProgramBase;
129 }
130
Jack Palevich8b0624c2009-05-20 12:12:06 -0700131 intptr_t getPC() {
132 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700133 }
134 };
135
Jack Palevich1cdef202009-05-22 12:06:27 -0700136 /**
137 * A code generator creates an in-memory program, generating the code on
138 * the fly. There is one code generator implementation for each supported
139 * architecture.
140 *
141 * The code generator implements the following abstract machine:
142 * R0 - the main accumulator.
143 * R1 - the secondary accumulator.
144 * FP - a frame pointer for accessing function arguments and local
145 * variables.
146 * SP - a stack pointer for storing intermediate results while evaluating
147 * expressions. The stack pointer grows downwards.
148 *
149 * The function calling convention is that all arguments are placed on the
150 * stack such that the first argument has the lowest address.
151 * After the call, the result is in R0. The caller is responsible for
152 * removing the arguments from the stack.
153 * The R0 and R1 registers are not saved across function calls. The
154 * FP and SP registers are saved.
155 */
156
Jack Palevich21a15a22009-05-11 14:49:29 -0700157 class CodeGenerator {
158 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700159 CodeGenerator() {
160 mErrorSink = 0;
161 pCodeBuf = 0;
162 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700163 virtual ~CodeGenerator() {}
164
Jack Palevich22305132009-05-13 10:58:45 -0700165 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700166 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700167 pCodeBuf->setErrorSink(mErrorSink);
168 }
169
170 void setErrorSink(ErrorSink* pErrorSink) {
171 mErrorSink = pErrorSink;
172 if (pCodeBuf) {
173 pCodeBuf->setErrorSink(mErrorSink);
174 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700175 }
176
Jack Palevich1cdef202009-05-22 12:06:27 -0700177 /* Emit a function prolog.
178 * argCount is the number of arguments.
179 * Save the old value of the FP.
180 * Set the new value of the FP.
181 * Convert from the native platform calling convention to
182 * our stack-based calling convention. This may require
183 * pushing arguments from registers to the stack.
184 * Allocate "N" bytes of stack space. N isn't known yet, so
185 * just emit the instructions for adjusting the stack, and return
186 * the address to patch up. The patching will be done in
187 * functionExit().
188 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700189 */
Jack Palevich546b2242009-05-13 15:10:04 -0700190 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700191
Jack Palevich1cdef202009-05-22 12:06:27 -0700192 /* Emit a function epilog.
193 * Restore the old SP and FP register values.
194 * Return to the calling function.
195 * argCount - the number of arguments to the function.
196 * localVariableAddress - returned from functionEntry()
197 * localVariableSize - the size in bytes of the local variables.
198 */
199 virtual void functionExit(int argCount, int localVariableAddress,
200 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700201
Jack Palevich1cdef202009-05-22 12:06:27 -0700202 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700203 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700204
Jack Palevich1cdef202009-05-22 12:06:27 -0700205 /* Jump to a target, and return the address of the word that
206 * holds the target data, in case it needs to be fixed up later.
207 */
Jack Palevich22305132009-05-13 10:58:45 -0700208 virtual int gjmp(int t) = 0;
209
Jack Palevich1cdef202009-05-22 12:06:27 -0700210 /* Test R0 and jump to a target if the test succeeds.
211 * l = 0: je, l == 1: jne
212 * Return the address of the word that holds the targed data, in
213 * case it needs to be fixed up later.
214 */
Jack Palevich22305132009-05-13 10:58:45 -0700215 virtual int gtst(bool l, int t) = 0;
216
Jack Palevich1cdef202009-05-22 12:06:27 -0700217 /* Compare R1 against R0, and store the boolean result in R0.
218 * op specifies the comparison.
219 */
Jack Palevich22305132009-05-13 10:58:45 -0700220 virtual void gcmp(int op) = 0;
221
Jack Palevich1cdef202009-05-22 12:06:27 -0700222 /* Perform the arithmetic op specified by op. R1 is the
223 * left argument, R0 is the right argument.
224 */
Jack Palevich546b2242009-05-13 15:10:04 -0700225 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700226
Jack Palevich1cdef202009-05-22 12:06:27 -0700227 /* Set R1 to 0.
228 */
229 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700230
Jack Palevich1cdef202009-05-22 12:06:27 -0700231 /* Push R0 onto the stack.
232 */
233 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700234
Jack Palevich1cdef202009-05-22 12:06:27 -0700235 /* Pop R1 off of the stack.
236 */
237 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700238
Jack Palevich1cdef202009-05-22 12:06:27 -0700239 /* Store R0 to the address stored in R1.
240 * isInt is true if a whole 4-byte integer value
241 * should be stored, otherwise a 1-byte character
242 * value should be stored.
243 */
244 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700245
Jack Palevich1cdef202009-05-22 12:06:27 -0700246 /* Load R0 from the address stored in R0.
247 * isInt is true if a whole 4-byte integer value
248 * should be loaded, otherwise a 1-byte character
249 * value should be loaded.
250 */
251 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700252
Jack Palevich1cdef202009-05-22 12:06:27 -0700253 /* Load the absolute address of a variable to R0.
254 * If ea <= LOCAL, then this is a local variable, or an
255 * argument, addressed relative to FP.
256 * else it is an absolute global address.
257 */
258 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700259
Jack Palevich1cdef202009-05-22 12:06:27 -0700260 /* Store R0 to a variable.
261 * If ea <= LOCAL, then this is a local variable, or an
262 * argument, addressed relative to FP.
263 * else it is an absolute global address.
264 */
265 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700266
Jack Palevich1cdef202009-05-22 12:06:27 -0700267 /* load R0 from a variable.
268 * If ea <= LOCAL, then this is a local variable, or an
269 * argument, addressed relative to FP.
270 * else it is an absolute global address.
271 * If isIncDec is true, then the stored variable's value
272 * should be post-incremented or post-decremented, based
273 * on the value of op.
274 */
275 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700276
Jack Palevich1cdef202009-05-22 12:06:27 -0700277 /* Emit code to adjust the stack for a function call. Return the
278 * label for the address of the instruction that adjusts the
279 * stack size. This will be passed as argument "a" to
280 * endFunctionCallArguments.
281 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700282 virtual int beginFunctionCallArguments() = 0;
283
Jack Palevich1cdef202009-05-22 12:06:27 -0700284 /* Emit code to store R0 to the stack at byte offset l.
285 */
286 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700287
Jack Palevich1cdef202009-05-22 12:06:27 -0700288 /* Patch the function call preamble.
289 * a is the address returned from beginFunctionCallArguments
290 * l is the number of bytes the arguments took on the stack.
291 * Typically you would also emit code to convert the argument
292 * list into whatever the native function calling convention is.
293 * On ARM for example you would pop the first 5 arguments into
294 * R0..R4
295 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700296 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700297
Jack Palevich1cdef202009-05-22 12:06:27 -0700298 /* Emit a call to an unknown function. The argument "symbol" needs to
299 * be stored in the location where the address should go. It forms
300 * a chain. The address will be patched later.
301 * Return the address of the word that has to be patched.
302 */
Jack Palevich22305132009-05-13 10:58:45 -0700303 virtual int callForward(int symbol) = 0;
304
Jack Palevich1cdef202009-05-22 12:06:27 -0700305 /* Call a function using PC-relative addressing. t is the PC-relative
306 * address of the function. It has already been adjusted for the
307 * architectural jump offset, so just store it as-is.
308 */
Jack Palevich22305132009-05-13 10:58:45 -0700309 virtual void callRelative(int t) = 0;
310
Jack Palevich1cdef202009-05-22 12:06:27 -0700311 /* Call a function pointer. L is the number of bytes the arguments
312 * take on the stack. The address of the function is stored at
313 * location SP + l.
314 */
Jack Palevich22305132009-05-13 10:58:45 -0700315 virtual void callIndirect(int l) = 0;
316
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 /* Adjust SP after returning from a function call. l is the
318 * number of bytes of arguments stored on the stack. isIndirect
319 * is true if this was an indirect call. (In which case the
320 * address of the function is stored at location SP + l.)
321 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700322 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700323
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 /* Print a disassembly of the assembled code to out. Return
325 * non-zero if there is an error.
326 */
Jack Palevicha6535612009-05-13 16:24:17 -0700327 virtual int disassemble(FILE* out) = 0;
328
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 /* Generate a symbol at the current PC. t is the head of a
330 * linked list of addresses to patch.
331 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700332 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700333
Jack Palevich1cdef202009-05-22 12:06:27 -0700334 /*
335 * Do any cleanup work required at the end of a compile.
336 * For example, an instruction cache might need to be
337 * invalidated.
338 * Return non-zero if there is an error.
339 */
340 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700341
Jack Palevicha6535612009-05-13 16:24:17 -0700342 /**
343 * Adjust relative branches by this amount.
344 */
345 virtual int jumpOffset() = 0;
346
Jack Palevich21a15a22009-05-11 14:49:29 -0700347 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700348 /*
349 * Output a byte. Handles all values, 0..ff.
350 */
351 void ob(int n) {
352 pCodeBuf->ob(n);
353 }
354
Jack Palevich8b0624c2009-05-20 12:12:06 -0700355 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700356 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700357 }
358
Jack Palevich8b0624c2009-05-20 12:12:06 -0700359 intptr_t getBase() {
360 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700361 }
362
Jack Palevich8b0624c2009-05-20 12:12:06 -0700363 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700364 return pCodeBuf->getPC();
365 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700366
367 intptr_t getSize() {
368 return pCodeBuf->getSize();
369 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700370
371 void error(const char* fmt,...) {
372 va_list ap;
373 va_start(ap, fmt);
374 mErrorSink->verror(fmt, ap);
375 va_end(ap);
376 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700377 private:
378 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700379 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700380 };
381
Jack Paleviche7b59062009-05-19 17:12:17 -0700382#ifdef PROVIDE_ARM_CODEGEN
383
Jack Palevich22305132009-05-13 10:58:45 -0700384 class ARMCodeGenerator : public CodeGenerator {
385 public:
386 ARMCodeGenerator() {}
387 virtual ~ARMCodeGenerator() {}
388
389 /* returns address to patch with local variable size
390 */
Jack Palevich546b2242009-05-13 15:10:04 -0700391 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700392 LOG_API("functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700393 // sp -> arg4 arg5 ...
394 // Push our register-based arguments back on the stack
395 if (argCount > 0) {
396 int regArgCount = argCount <= 4 ? argCount : 4;
397 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
398 }
399 // sp -> arg0 arg1 ...
400 o4(0xE92D4800); // stmfd sp!, {fp, lr}
401 // sp, fp -> oldfp, retadr, arg0 arg1 ....
402 o4(0xE1A0B00D); // mov fp, sp
403 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700404 }
405
Jack Palevich546b2242009-05-13 15:10:04 -0700406 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700407 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700408 // Patch local variable allocation code:
409 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700410 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700411 }
Jack Palevich69796b62009-05-14 15:42:26 -0700412 *(char*) (localVariableAddress) = localVariableSize;
413
414 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
415 o4(0xE1A0E00B); // mov lr, fp
416 o4(0xE59BB000); // ldr fp, [fp]
417 o4(0xE28ED004); // add sp, lr, #4
418 // sp -> retadr, arg0, ...
419 o4(0xE8BD4000); // ldmfd sp!, {lr}
420 // sp -> arg0 ....
421 if (argCount > 0) {
422 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700423 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700424 // earlier. We don't need to actually store them anywhere,
425 // just adjust the stack.
426 int regArgCount = argCount <= 4 ? argCount : 4;
427 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
428 }
429 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700430 }
431
432 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700433 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700434 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700435 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700436 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700437 } else if (t >= -256 && t < 0) {
438 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700439 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700440 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700441 o4(0xE51F0000); // ldr r0, .L3
442 o4(0xEA000000); // b .L99
443 o4(t); // .L3: .word 0
444 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700445 }
Jack Palevich22305132009-05-13 10:58:45 -0700446 }
447
448 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700449 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700450 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700451 }
452
453 /* l = 0: je, l == 1: jne */
454 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700455 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700456 o4(0xE3500000); // cmp r0,#0
457 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
458 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700459 }
460
461 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700462 LOG_API("gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700463 o4(0xE1510000); // cmp r1, r1
464 switch(op) {
465 case OP_EQUALS:
466 o4(0x03A00001); // moveq r0,#1
467 o4(0x13A00000); // movne r0,#0
468 break;
469 case OP_NOT_EQUALS:
470 o4(0x03A00000); // moveq r0,#0
471 o4(0x13A00001); // movne r0,#1
472 break;
473 case OP_LESS_EQUAL:
474 o4(0xD3A00001); // movle r0,#1
475 o4(0xC3A00000); // movgt r0,#0
476 break;
477 case OP_GREATER:
478 o4(0xD3A00000); // movle r0,#0
479 o4(0xC3A00001); // movgt r0,#1
480 break;
481 case OP_GREATER_EQUAL:
482 o4(0xA3A00001); // movge r0,#1
483 o4(0xB3A00000); // movlt r0,#0
484 break;
485 case OP_LESS:
486 o4(0xA3A00000); // movge r0,#0
487 o4(0xB3A00001); // movlt r0,#1
488 break;
489 default:
490 error("Unknown comparison op %d", op);
491 break;
492 }
Jack Palevich22305132009-05-13 10:58:45 -0700493 }
494
Jack Palevich546b2242009-05-13 15:10:04 -0700495 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700496 LOG_API("genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700497 switch(op) {
498 case OP_MUL:
499 o4(0x0E0000091); // mul r0,r1,r0
500 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700501 case OP_DIV:
502 callRuntime(runtime_DIV);
503 break;
504 case OP_MOD:
505 callRuntime(runtime_MOD);
506 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700507 case OP_PLUS:
508 o4(0xE0810000); // add r0,r1,r0
509 break;
510 case OP_MINUS:
511 o4(0xE0410000); // sub r0,r1,r0
512 break;
513 case OP_SHIFT_LEFT:
514 o4(0xE1A00011); // lsl r0,r1,r0
515 break;
516 case OP_SHIFT_RIGHT:
517 o4(0xE1A00051); // asr r0,r1,r0
518 break;
519 case OP_BIT_AND:
520 o4(0xE0010000); // and r0,r1,r0
521 break;
522 case OP_BIT_XOR:
523 o4(0xE0210000); // eor r0,r1,r0
524 break;
525 case OP_BIT_OR:
526 o4(0xE1810000); // orr r0,r1,r0
527 break;
528 case OP_BIT_NOT:
529 o4(0xE1E00000); // mvn r0, r0
530 break;
531 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700532 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700533 break;
534 }
Jack Palevich22305132009-05-13 10:58:45 -0700535#if 0
536 o(decodeOp(op));
537 if (op == OP_MOD)
538 o(0x92); /* xchg %edx, %eax */
539#endif
540 }
541
Jack Palevich1cdef202009-05-22 12:06:27 -0700542 virtual void clearR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700543 LOG_API("clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700544 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700545 }
546
Jack Palevich1cdef202009-05-22 12:06:27 -0700547 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700548 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700549 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700550 }
551
Jack Palevich1cdef202009-05-22 12:06:27 -0700552 virtual void popR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700553 LOG_API("popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700554 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700555 }
556
Jack Palevich1cdef202009-05-22 12:06:27 -0700557 virtual void storeR0ToR1(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700558 LOG_API("storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700559 if (isInt) {
560 o4(0xE5810000); // str r0, [r1]
561 } else {
562 o4(0xE5C10000); // strb r0, [r1]
563 }
Jack Palevich22305132009-05-13 10:58:45 -0700564 }
565
Jack Palevich1cdef202009-05-22 12:06:27 -0700566 virtual void loadR0FromR0(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700567 LOG_API("loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700568 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700569 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700570 else
Jack Palevich69796b62009-05-14 15:42:26 -0700571 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700572 }
573
Jack Palevich1cdef202009-05-22 12:06:27 -0700574 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700575 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700576 if (ea < LOCAL) {
577 // Local, fp relative
578 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
579 error("Offset out of range: %08x", ea);
580 }
581 if (ea < 0) {
582 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
583 } else {
584 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
585 }
Jack Palevichbd894902009-05-14 19:35:31 -0700586 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700587 // Global, absolute.
588 o4(0xE59F0000); // ldr r0, .L1
589 o4(0xEA000000); // b .L99
590 o4(ea); // .L1: .word 0
591 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700592 }
Jack Palevich22305132009-05-13 10:58:45 -0700593 }
594
Jack Palevich1cdef202009-05-22 12:06:27 -0700595 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700596 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700597 if (ea < LOCAL) {
598 // Local, fp relative
599 if (ea < -4095 || ea > 4095) {
600 error("Offset out of range: %08x", ea);
601 }
602 if (ea < 0) {
603 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
604 } else {
605 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
606 }
607 } else{
608 // Global, absolute
609 o4(0xE59F1000); // ldr r1, .L1
610 o4(0xEA000000); // b .L99
611 o4(ea); // .L1: .word 0
612 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700613 }
Jack Palevich22305132009-05-13 10:58:45 -0700614 }
615
Jack Palevich1cdef202009-05-22 12:06:27 -0700616 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700617 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700618 if (ea < LOCAL) {
619 // Local, fp relative
620 if (ea < -4095 || ea > 4095) {
621 error("Offset out of range: %08x", ea);
622 }
623 if (ea < 0) {
624 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
625 } else {
626 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
627 }
Jack Palevich69796b62009-05-14 15:42:26 -0700628 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700629 // Global, absolute
630 o4(0xE59F2000); // ldr r2, .L1
631 o4(0xEA000000); // b .L99
632 o4(ea); // .L1: .word ea
633 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700634 }
Jack Palevich22305132009-05-13 10:58:45 -0700635
Jack Palevich4d93f302009-05-15 13:30:00 -0700636 if (isIncDec) {
637 switch (op) {
638 case OP_INCREMENT:
639 o4(0xE2801001); // add r1, r0, #1
640 break;
641 case OP_DECREMENT:
642 o4(0xE2401001); // sub r1, r0, #1
643 break;
644 default:
645 error("unknown opcode: %d", op);
646 }
647 if (ea < LOCAL) {
648 // Local, fp relative
649 // Don't need range check, was already checked above
650 if (ea < 0) {
651 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
652 } else {
653 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
654 }
655 } else{
656 // Global, absolute
657 // r2 is already set up from before.
658 o4(0xE5821000); // str r1, [r2]
659 }
Jack Palevichbd894902009-05-14 19:35:31 -0700660 }
Jack Palevich22305132009-05-13 10:58:45 -0700661 }
662
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700663 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700664 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700665 return o4(0xE24DDF00); // Placeholder
666 }
667
Jack Palevich1cdef202009-05-22 12:06:27 -0700668 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700669 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700670 if (l < 0 || l > 4096-4) {
671 error("l out of range for stack offset: 0x%08x", l);
672 }
673 o4(0xE58D0000 + l); // str r0, [sp, #4]
674 }
675
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700676 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700677 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700678 if (l < 0 || l > 0x3FC) {
679 error("L out of range for stack adjustment: 0x%08x", l);
680 }
681 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
682 int argCount = l >> 2;
683 if (argCount > 0) {
684 int regArgCount = argCount > 4 ? 4 : argCount;
685 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
686 }
Jack Palevich22305132009-05-13 10:58:45 -0700687 }
688
Jack Palevich22305132009-05-13 10:58:45 -0700689 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700690 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700691 // Forward calls are always short (local)
692 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700693 }
694
695 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700696 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700697 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700698 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700699 if (t >= - (1 << 25) && t < (1 << 25)) {
700 o4(0xEB000000 | encodeAddress(t));
701 } else {
702 // Long call.
703 o4(0xE59FC000); // ldr r12, .L1
704 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700705 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700706 o4(0xE08CC00F); // .L99: add r12,pc
707 o4(0xE12FFF3C); // blx r12
708 }
Jack Palevich22305132009-05-13 10:58:45 -0700709 }
710
711 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700712 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700713 int argCount = l >> 2;
714 int poppedArgs = argCount > 4 ? 4 : argCount;
715 int adjustedL = l - (poppedArgs << 2);
716 if (adjustedL < 0 || adjustedL > 4096-4) {
717 error("l out of range for stack offset: 0x%08x", l);
718 }
719 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
720 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700721 }
722
Jack Palevich7810bc92009-05-15 14:31:47 -0700723 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700724 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700725 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700726 int stackArgs = argCount > 4 ? argCount - 4 : 0;
727 int stackUse = stackArgs + (isIndirect ? 1 : 0);
728 if (stackUse) {
729 if (stackUse < 0 || stackUse > 255) {
730 error("L out of range for stack adjustment: 0x%08x", l);
731 }
732 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700733 }
Jack Palevich22305132009-05-13 10:58:45 -0700734 }
735
Jack Palevicha6535612009-05-13 16:24:17 -0700736 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700737 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700738 }
739
740 /* output a symbol and patch all calls to it */
741 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700742 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700743 int n;
744 int base = getBase();
745 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700746 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700747 while (t) {
748 int data = * (int*) t;
749 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
750 if (decodedOffset == 0) {
751 n = 0;
752 } else {
753 n = base + decodedOffset; /* next value */
754 }
755 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
756 | encodeRelAddress(pc - t - 8);
757 t = n;
758 }
759 }
760
Jack Palevich1cdef202009-05-22 12:06:27 -0700761 virtual int finishCompile() {
762#if defined(__arm__)
763 const long base = long(getBase());
764 const long curr = long(getPC());
765 int err = cacheflush(base, curr, 0);
766 return err;
767#else
768 return 0;
769#endif
770 }
771
Jack Palevicha6535612009-05-13 16:24:17 -0700772 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700773#ifdef ENABLE_ARM_DISASSEMBLY
774 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700775 disasm_interface_t di;
776 di.di_readword = disassemble_readword;
777 di.di_printaddr = disassemble_printaddr;
778 di.di_printf = disassemble_printf;
779
780 int base = getBase();
781 int pc = getPC();
782 for(int i = base; i < pc; i += 4) {
783 fprintf(out, "%08x: %08x ", i, *(int*) i);
784 ::disasm(&di, i, 0);
785 }
Jack Palevich09555c72009-05-27 12:25:55 -0700786#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700787 return 0;
788 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700789
Jack Palevich22305132009-05-13 10:58:45 -0700790 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700791 static FILE* disasmOut;
792
793 static u_int
794 disassemble_readword(u_int address)
795 {
796 return(*((u_int *)address));
797 }
798
799 static void
800 disassemble_printaddr(u_int address)
801 {
802 fprintf(disasmOut, "0x%08x", address);
803 }
804
805 static void
806 disassemble_printf(const char *fmt, ...) {
807 va_list ap;
808 va_start(ap, fmt);
809 vfprintf(disasmOut, fmt, ap);
810 va_end(ap);
811 }
812
813 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
814
815 /** Encode a relative address that might also be
816 * a label.
817 */
818 int encodeAddress(int value) {
819 int base = getBase();
820 if (value >= base && value <= getPC() ) {
821 // This is a label, encode it relative to the base.
822 value = value - base;
823 }
824 return encodeRelAddress(value);
825 }
826
827 int encodeRelAddress(int value) {
828 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
829 }
Jack Palevich22305132009-05-13 10:58:45 -0700830
Jack Palevich3d474a72009-05-15 15:12:38 -0700831 typedef int (*int2FnPtr)(int a, int b);
832 void callRuntime(int2FnPtr fn) {
833 o4(0xE59F2000); // ldr r2, .L1
834 o4(0xEA000000); // b .L99
835 o4((int) fn); //.L1: .word fn
836 o4(0xE12FFF32); //.L99: blx r2
837 }
838
839 static int runtime_DIV(int a, int b) {
840 return b / a;
841 }
842
843 static int runtime_MOD(int a, int b) {
844 return b % a;
845 }
Jack Palevich22305132009-05-13 10:58:45 -0700846 };
847
Jack Palevich09555c72009-05-27 12:25:55 -0700848#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700849
850#ifdef PROVIDE_X86_CODEGEN
851
Jack Palevich21a15a22009-05-11 14:49:29 -0700852 class X86CodeGenerator : public CodeGenerator {
853 public:
854 X86CodeGenerator() {}
855 virtual ~X86CodeGenerator() {}
856
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700857 /* returns address to patch with local variable size
858 */
Jack Palevich546b2242009-05-13 15:10:04 -0700859 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700860 o(0xe58955); /* push %ebp, mov %esp, %ebp */
861 return oad(0xec81, 0); /* sub $xxx, %esp */
862 }
863
Jack Palevich546b2242009-05-13 15:10:04 -0700864 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700865 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700866 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700867 }
868
Jack Palevich21a15a22009-05-11 14:49:29 -0700869 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700870 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700871 oad(0xb8, t); /* mov $xx, %eax */
872 }
873
Jack Palevich22305132009-05-13 10:58:45 -0700874 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700875 return psym(0xe9, t);
876 }
877
878 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700879 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700880 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
881 return psym(0x84 + l, t);
882 }
883
Jack Palevich22305132009-05-13 10:58:45 -0700884 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700885 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700886 o(0xc139); /* cmp %eax,%ecx */
887 li(0);
888 o(0x0f); /* setxx %al */
889 o(t + 0x90);
890 o(0xc0);
891 }
892
Jack Palevich546b2242009-05-13 15:10:04 -0700893 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700894 o(decodeOp(op));
895 if (op == OP_MOD)
896 o(0x92); /* xchg %edx, %eax */
897 }
898
Jack Palevich1cdef202009-05-22 12:06:27 -0700899 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700900 oad(0xb9, 0); /* movl $0, %ecx */
901 }
902
Jack Palevich1cdef202009-05-22 12:06:27 -0700903 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700904 o(0x50); /* push %eax */
905 }
906
Jack Palevich1cdef202009-05-22 12:06:27 -0700907 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700908 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700909 }
910
Jack Palevich1cdef202009-05-22 12:06:27 -0700911 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700912 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
913 }
914
Jack Palevich1cdef202009-05-22 12:06:27 -0700915 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700916 if (isInt)
917 o(0x8b); /* mov (%eax), %eax */
918 else
919 o(0xbe0f); /* movsbl (%eax), %eax */
920 ob(0); /* add zero in code */
921 }
922
Jack Palevich1cdef202009-05-22 12:06:27 -0700923 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700924 gmov(10, ea); /* leal EA, %eax */
925 }
926
Jack Palevich1cdef202009-05-22 12:06:27 -0700927 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700928 gmov(6, ea); /* mov %eax, EA */
929 }
930
Jack Palevich1cdef202009-05-22 12:06:27 -0700931 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700932 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700933 if (isIncDec) {
934 /* Implement post-increment or post decrement.
935 */
936 gmov(0, ea); /* 83 ADD */
937 o(decodeOp(op));
938 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700939 }
940
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700941 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700942 return oad(0xec81, 0); /* sub $xxx, %esp */
943 }
944
Jack Palevich1cdef202009-05-22 12:06:27 -0700945 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700946 oad(0x248489, l); /* movl %eax, xxx(%esp) */
947 }
948
Jack Palevich7810bc92009-05-15 14:31:47 -0700949 virtual void endFunctionCallArguments(int a, int l) {
950 * (int*) a = l;
951 }
952
Jack Palevich22305132009-05-13 10:58:45 -0700953 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700954 return psym(0xe8, symbol); /* call xxx */
955 }
956
Jack Palevich22305132009-05-13 10:58:45 -0700957 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700958 psym(0xe8, t); /* call xxx */
959 }
960
Jack Palevich22305132009-05-13 10:58:45 -0700961 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700962 oad(0x2494ff, l); /* call *xxx(%esp) */
963 }
964
Jack Palevich7810bc92009-05-15 14:31:47 -0700965 virtual void adjustStackAfterCall(int l, bool isIndirect) {
966 if (isIndirect) {
967 l += 4;
968 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700969 oad(0xc481, l); /* add $xxx, %esp */
970 }
971
Jack Palevicha6535612009-05-13 16:24:17 -0700972 virtual int jumpOffset() {
973 return 5;
974 }
975
976 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -0700977 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -0700978 }
979
Jack Paleviche7b59062009-05-19 17:12:17 -0700980 /* output a symbol and patch all calls to it */
981 virtual void gsym(int t) {
982 int n;
983 int pc = getPC();
984 while (t) {
985 n = *(int *) t; /* next value */
986 *(int *) t = pc - t - 4;
987 t = n;
988 }
989 }
990
Jack Palevich1cdef202009-05-22 12:06:27 -0700991 virtual int finishCompile() {
992 return 0;
993 }
994
Jack Palevich21a15a22009-05-11 14:49:29 -0700995 private:
Jack Paleviche7b59062009-05-19 17:12:17 -0700996
997 /** Output 1 to 4 bytes.
998 *
999 */
1000 void o(int n) {
1001 /* cannot use unsigned, so we must do a hack */
1002 while (n && n != -1) {
1003 ob(n & 0xff);
1004 n = n >> 8;
1005 }
1006 }
1007
1008 /* psym is used to put an instruction with a data field which is a
1009 reference to a symbol. It is in fact the same as oad ! */
1010 int psym(int n, int t) {
1011 return oad(n, t);
1012 }
1013
1014 /* instruction + address */
1015 int oad(int n, int t) {
1016 o(n);
1017 int result = getPC();
1018 o4(t);
1019 return result;
1020 }
1021
1022
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001023 static const int operatorHelper[];
1024
1025 int decodeOp(int op) {
1026 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001027 error("Out-of-range operator: %d\n", op);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001028 }
1029 return operatorHelper[op];
1030 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001031
Jack Palevich546b2242009-05-13 15:10:04 -07001032 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001033 o(l + 0x83);
1034 oad((t < LOCAL) << 7 | 5, t);
1035 }
1036 };
1037
Jack Paleviche7b59062009-05-19 17:12:17 -07001038#endif // PROVIDE_X86_CODEGEN
1039
Jack Palevich1cdef202009-05-22 12:06:27 -07001040 class InputStream {
1041 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001042 int getChar() {
1043 if (bumpLine) {
1044 line++;
1045 bumpLine = false;
1046 }
1047 int ch = get();
1048 if (ch == '\n') {
1049 bumpLine = true;
1050 }
1051 return ch;
1052 }
1053 int getLine() {
1054 return line;
1055 }
1056 protected:
1057 InputStream() :
1058 line(1), bumpLine(false) {
1059 }
1060 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001061 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001062 int line;
1063 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001064 };
1065
1066 class FileInputStream : public InputStream {
1067 public:
1068 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001069 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001070 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001071 FILE* f;
1072 };
1073
1074 class TextInputStream : public InputStream {
1075 public:
1076 TextInputStream(const char* text, size_t textLength)
1077 : pText(text), mTextLength(textLength), mPosition(0) {
1078 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001079
1080 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001081 virtual int get() {
1082 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1083 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001084
Jack Palevich1cdef202009-05-22 12:06:27 -07001085 const char* pText;
1086 size_t mTextLength;
1087 size_t mPosition;
1088 };
1089
Jack Palevicheedf9d22009-06-04 16:23:40 -07001090 class String {
1091 public:
1092 String() {
1093 mpBase = 0;
1094 mUsed = 0;
1095 mSize = 0;
1096 }
1097
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001098 String(char* item, int len, bool adopt) {
1099 if (adopt) {
1100 mpBase = item;
1101 mUsed = len;
1102 mSize = len + 1;
1103 } else {
1104 mpBase = 0;
1105 mUsed = 0;
1106 mSize = 0;
1107 appendBytes(item, len);
1108 }
1109 }
1110
Jack Palevicheedf9d22009-06-04 16:23:40 -07001111 ~String() {
1112 if (mpBase) {
1113 free(mpBase);
1114 }
1115 }
1116
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001117 inline char* getUnwrapped() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001118 return mpBase;
1119 }
1120
1121 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001122 appendBytes(s, strlen(s));
1123 }
1124
1125 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001126 memcpy(ensure(n), s, n + 1);
1127 }
1128
1129 void append(char c) {
1130 * ensure(1) = c;
1131 }
1132
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001133 char* orphan() {
1134 char* result = mpBase;
1135 mpBase = 0;
1136 mUsed = 0;
1137 mSize = 0;
1138 return result;
1139 }
1140
Jack Palevicheedf9d22009-06-04 16:23:40 -07001141 void printf(const char* fmt,...) {
1142 va_list ap;
1143 va_start(ap, fmt);
1144 vprintf(fmt, ap);
1145 va_end(ap);
1146 }
1147
1148 void vprintf(const char* fmt, va_list ap) {
1149 char* temp;
1150 int numChars = vasprintf(&temp, fmt, ap);
1151 memcpy(ensure(numChars), temp, numChars+1);
1152 free(temp);
1153 }
1154
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001155 inline size_t len() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001156 return mUsed;
1157 }
1158
1159 private:
1160 char* ensure(int n) {
1161 size_t newUsed = mUsed + n;
1162 if (newUsed > mSize) {
1163 size_t newSize = mSize * 2 + 10;
1164 if (newSize < newUsed) {
1165 newSize = newUsed;
1166 }
1167 mpBase = (char*) realloc(mpBase, newSize + 1);
1168 mSize = newSize;
1169 }
1170 mpBase[newUsed] = '\0';
1171 char* result = mpBase + mUsed;
1172 mUsed = newUsed;
1173 return result;
1174 }
1175
1176 char* mpBase;
1177 size_t mUsed;
1178 size_t mSize;
1179 };
1180
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001181 /**
1182 * Wrap an externally allocated string for use as a hash key.
1183 */
1184 class FakeString : public String {
1185 public:
1186 FakeString(char* string, size_t length) :
1187 String(string, length, true) {}
1188
1189 ~FakeString() {
1190 orphan();
1191 }
1192 };
1193
1194 template<class V> class StringTable {
1195 public:
1196 StringTable(size_t initialCapacity) {
1197 mpMap = hashmapCreate(initialCapacity, hashFn, equalsFn);
1198 }
1199
1200 ~StringTable() {
1201 clear();
1202 }
1203
1204 void clear() {
1205 hashmapForEach(mpMap, freeKeyValue, this);
1206 }
1207
1208 bool contains(String* pKey) {
1209 bool result = hashmapContainsKey(mpMap, pKey);
1210 return result;
1211 }
1212
1213 V* get(String* pKey) {
1214 V* result = (V*) hashmapGet(mpMap, pKey);
1215 return result;
1216 }
1217
1218 V* remove(String* pKey) {
1219 V* result = (V*) hashmapRemove(mpMap, pKey);
1220 return result;
1221 }
1222
1223 V* put(String* pKey, V* value) {
1224 V* result = (V*) hashmapPut(mpMap, pKey, value);
1225 if (result) {
1226 // The key was not adopted by the map, so delete it here.
1227 delete pKey;
1228 }
1229 return result;
1230 }
1231
1232 protected:
1233 static int hashFn(void* pKey) {
1234 String* pString = (String*) pKey;
1235 return hashmapHash(pString->getUnwrapped(), pString->len());
1236 }
1237
1238 static bool equalsFn(void* keyA, void* keyB) {
1239 String* pStringA = (String*) keyA;
1240 String* pStringB = (String*) keyB;
1241 return pStringA->len() == pStringB->len()
1242 && strcmp(pStringA->getUnwrapped(), pStringB->getUnwrapped())
1243 == 0;
1244 }
1245
1246 static bool freeKeyValue(void* key, void* value, void* context) {
1247 delete (String*) key;
1248 delete (V*) value;
1249 return true;
1250 }
1251
1252 Hashmap* mpMap;
1253 };
1254
1255 class MacroTable : public StringTable<String> {
1256 public:
1257 MacroTable() : StringTable<String>(10) {}
1258 };
1259
1260 template<class E> class Array {
1261 public:
1262 Array() {
1263 mpBase = 0;
1264 mUsed = 0;
1265 mSize = 0;
1266 }
1267
1268 ~Array() {
1269 if (mpBase) {
1270 free(mpBase);
1271 }
1272 }
1273
1274 E get(int i) {
1275 if (i < 0 || i > mUsed) {
1276 error("internal error: Index out of range");
1277 return E();
1278 }
1279 return mpBase[i];
1280 }
1281
1282 void set(int i, E val) {
1283 mpBase[i] = val;
1284 }
1285
1286 void pop() {
1287 if (mUsed > 0) {
1288 mUsed -= 1;
Jack Palevich36d94142009-06-08 15:55:32 -07001289 } else {
1290 error("internal error: Popped empty stack.");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001291 }
1292 }
1293
1294 void push(E item) {
1295 * ensure(1) = item;
1296 }
1297
1298 size_t len() {
1299 return mUsed;
1300 }
1301
1302 private:
1303 E* ensure(int n) {
1304 size_t newUsed = mUsed + n;
1305 if (newUsed > mSize) {
1306 size_t newSize = mSize * 2 + 10;
1307 if (newSize < newUsed) {
1308 newSize = newUsed;
1309 }
1310 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1311 mSize = newSize;
1312 }
1313 E* result = mpBase + mUsed;
1314 mUsed = newUsed;
1315 return result;
1316 }
1317
1318 E* mpBase;
1319 size_t mUsed;
1320 size_t mSize;
1321 };
1322
Jack Palevich36d94142009-06-08 15:55:32 -07001323 struct InputState {
1324 InputStream* pStream;
1325 int oldCh;
1326 };
1327
1328
1329 int ch; // Current input character, or EOF
1330 intptr_t tok; // token
1331 intptr_t tokc; // token extra info
1332 int tokl; // token operator level
1333 intptr_t rsym; // return symbol
1334 intptr_t loc; // local variable index
1335 char* glo; // global variable index
1336 char* sym_stk;
1337 char* dstk; // Define stack
1338 char* dptr; // Macro state: Points to macro text during macro playback.
1339 int dch; // Macro state: Saves old value of ch during a macro playback.
1340 char* last_id;
1341 char* pGlobalBase;
1342 char* pVarsBase; // Value of variables
1343
1344 InputStream* file;
1345
1346 CodeBuf codeBuf;
1347 CodeGenerator* pGen;
1348
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001349 MacroTable mMacros;
Jack Palevich36d94142009-06-08 15:55:32 -07001350 Array<InputState> mInputStateStack;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001351
Jack Palevicheedf9d22009-06-04 16:23:40 -07001352 String mErrorBuf;
1353
Jack Palevichac0e95e2009-05-29 13:53:44 -07001354 jmp_buf mErrorRecoveryJumpBuf;
1355
Jack Palevicheedf9d22009-06-04 16:23:40 -07001356 String mPragmas;
1357 int mPragmaStringCount;
1358
Jack Palevich21a15a22009-05-11 14:49:29 -07001359 static const int ALLOC_SIZE = 99999;
1360
Jack Palevicheedf9d22009-06-04 16:23:40 -07001361 // Indentifiers start at 0x100 and increase by # (chars + 1) * 8
Jack Palevich21a15a22009-05-11 14:49:29 -07001362 static const int TOK_IDENT = 0x100;
1363 static const int TOK_INT = 0x100;
Jack Palevichb7c81e92009-06-04 19:56:13 -07001364 static const int TOK_CHAR = TOK_INT + 4*8;
1365 static const int TOK_VOID = TOK_CHAR + 5*8;
1366 static const int TOK_IF = TOK_VOID + 5*8;
1367 static const int TOK_ELSE = TOK_IF + 3*8;
1368 static const int TOK_WHILE = TOK_ELSE + 5*8;
1369 static const int TOK_BREAK = TOK_WHILE + 6*8;
1370 static const int TOK_RETURN = TOK_BREAK + 6*8;
1371 static const int TOK_FOR = TOK_RETURN + 7*8;
1372 static const int TOK_PRAGMA = TOK_FOR + 4*8;
1373 static const int TOK_DEFINE = TOK_PRAGMA + 7*8;
1374 static const int TOK_MAIN = TOK_DEFINE + 7*8;
Jack Palevich21a15a22009-05-11 14:49:29 -07001375
1376 static const int TOK_DUMMY = 1;
1377 static const int TOK_NUM = 2;
1378
1379 static const int LOCAL = 0x200;
1380
1381 static const int SYM_FORWARD = 0;
1382 static const int SYM_DEFINE = 1;
1383
1384 /* tokens in string heap */
1385 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07001386
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001387 static const int OP_INCREMENT = 0;
1388 static const int OP_DECREMENT = 1;
1389 static const int OP_MUL = 2;
1390 static const int OP_DIV = 3;
1391 static const int OP_MOD = 4;
1392 static const int OP_PLUS = 5;
1393 static const int OP_MINUS = 6;
1394 static const int OP_SHIFT_LEFT = 7;
1395 static const int OP_SHIFT_RIGHT = 8;
1396 static const int OP_LESS_EQUAL = 9;
1397 static const int OP_GREATER_EQUAL = 10;
1398 static const int OP_LESS = 11;
1399 static const int OP_GREATER = 12;
1400 static const int OP_EQUALS = 13;
1401 static const int OP_NOT_EQUALS = 14;
1402 static const int OP_LOGICAL_AND = 15;
1403 static const int OP_LOGICAL_OR = 16;
1404 static const int OP_BIT_AND = 17;
1405 static const int OP_BIT_XOR = 18;
1406 static const int OP_BIT_OR = 19;
1407 static const int OP_BIT_NOT = 20;
1408 static const int OP_LOGICAL_NOT = 21;
1409 static const int OP_COUNT = 22;
1410
1411 /* Operators are searched from front, the two-character operators appear
1412 * before the single-character operators with the same first character.
1413 * @ is used to pad out single-character operators.
1414 */
1415 static const char* operatorChars;
1416 static const char operatorLevel[];
1417
Jack Palevich21a15a22009-05-11 14:49:29 -07001418 void pdef(int t) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001419 if (dstk - sym_stk >= ALLOC_SIZE) {
1420 error("Symbol table exhausted");
1421 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001422 *dstk++ = t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001423 }
1424
1425 void inp() {
1426 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001427 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001428 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001429 dptr = 0;
1430 ch = dch;
1431 }
1432 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07001433 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001434#if 0
1435 printf("ch='%c' 0x%x\n", ch, ch);
1436#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07001437 }
1438
1439 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07001440 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07001441 }
1442
1443 /* read a character constant */
1444 void getq() {
1445 if (ch == '\\') {
1446 inp();
1447 if (ch == 'n')
1448 ch = '\n';
1449 }
1450 }
1451
1452 void next() {
1453 int l, a;
1454
Jack Palevich546b2242009-05-13 15:10:04 -07001455 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001456 if (ch == '#') {
1457 inp();
1458 next();
1459 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001460 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07001461 } else if (tok == TOK_PRAGMA) {
1462 doPragma();
1463 } else {
1464 error("Unsupported preprocessor directive \"%s\"", last_id);
Jack Palevich21a15a22009-05-11 14:49:29 -07001465 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001466
Jack Palevich21a15a22009-05-11 14:49:29 -07001467 }
1468 inp();
1469 }
1470 tokl = 0;
1471 tok = ch;
1472 /* encode identifiers & numbers */
1473 if (isid()) {
1474 pdef(TAG_TOK);
1475 last_id = dstk;
1476 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001477 pdef(ch);
1478 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001479 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001480 if (isdigit(tok)) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001481 tokc = strtol(last_id, 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001482 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001483 } else {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001484 if (dstk - sym_stk + 1 > ALLOC_SIZE) {
1485 error("symbol stack overflow");
1486 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001487 FakeString token(last_id, dstk-last_id);
1488 // Is this a macro?
1489 String* pValue = mMacros.get(&token);
1490 if (pValue) {
1491 // Yes, it is a macro
1492 dstk = last_id-1;
1493 dptr = pValue->getUnwrapped();
1494 dch = ch;
1495 inp();
1496 next();
1497 } else {
1498 * dstk = TAG_TOK; /* no need to mark end of string (we
1499 suppose data is initialized to zero by calloc) */
1500 tok = (intptr_t) (strstr(sym_stk, (last_id - 1))
1501 - sym_stk);
1502 * dstk = 0; /* mark real end of ident for dlsym() */
1503 tok = tok * 8 + TOK_IDENT;
1504 if (tok > TOK_DEFINE) {
1505 if (tok + 8 > ALLOC_SIZE) {
1506 error("Variable Table overflow.");
1507 }
1508 tok = (intptr_t) (pVarsBase + tok);
1509 /* printf("tok=%s %x\n", last_id, tok); */
Jack Palevich21a15a22009-05-11 14:49:29 -07001510 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001511 }
1512 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001513 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001514 inp();
1515 if (tok == '\'') {
1516 tok = TOK_NUM;
1517 getq();
1518 tokc = ch;
1519 inp();
1520 inp();
Jack Palevich546b2242009-05-13 15:10:04 -07001521 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001522 inp();
1523 while (ch) {
1524 while (ch != '*')
1525 inp();
1526 inp();
1527 if (ch == '/')
1528 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001529 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001530 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001531 next();
Jack Palevichbd894902009-05-14 19:35:31 -07001532 } else if ((tok == '/') & (ch == '/')) {
1533 inp();
1534 while (ch && (ch != '\n')) {
1535 inp();
1536 }
1537 inp();
1538 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001539 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001540 const char* t = operatorChars;
1541 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001542 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001543 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001544 tokl = operatorLevel[opIndex];
1545 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07001546 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001547#if 0
1548 printf("%c%c -> tokl=%d tokc=0x%x\n",
1549 l, a, tokl, tokc);
1550#endif
1551 if (a == ch) {
1552 inp();
1553 tok = TOK_DUMMY; /* dummy token for double tokens */
1554 }
1555 break;
1556 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001557 opIndex++;
1558 }
1559 if (l == 0) {
1560 tokl = 0;
1561 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001562 }
1563 }
1564 }
1565#if 0
1566 {
Jack Palevich653f42d2009-05-28 17:15:32 -07001567 char* p;
Jack Palevich21a15a22009-05-11 14:49:29 -07001568
1569 printf("tok=0x%x ", tok);
1570 if (tok >= TOK_IDENT) {
1571 printf("'");
1572 if (tok> TOK_DEFINE)
Jack Palevich653f42d2009-05-28 17:15:32 -07001573 p = sym_stk + 1 + ((char*) tok - pVarsBase - TOK_IDENT) / 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07001574 else
1575 p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
Jack Palevich653f42d2009-05-28 17:15:32 -07001576 while (*p != TAG_TOK && *p)
1577 printf("%c", *p++);
Jack Palevich21a15a22009-05-11 14:49:29 -07001578 printf("'\n");
1579 } else if (tok == TOK_NUM) {
1580 printf("%d\n", tokc);
1581 } else {
1582 printf("'%c'\n", tok);
1583 }
1584 }
1585#endif
1586 }
1587
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001588 void doDefine() {
1589 String* pName = new String();
1590 while (isspace(ch)) {
1591 inp();
1592 }
1593 while (isid()) {
1594 pName->append(ch);
1595 inp();
1596 }
1597 if (ch == '(') {
1598 delete pName;
1599 error("Defines with arguments not supported");
1600 }
1601 while (isspace(ch)) {
1602 inp();
1603 }
1604 String* pValue = new String();
1605 while (ch != '\n' && ch != EOF) {
1606 pValue->append(ch);
1607 inp();
1608 }
1609 delete mMacros.put(pName, pValue);
1610 }
1611
Jack Palevicheedf9d22009-06-04 16:23:40 -07001612 void doPragma() {
1613 // # pragma name(val)
1614 int state = 0;
1615 while(ch != EOF && ch != '\n' && state < 10) {
1616 switch(state) {
1617 case 0:
1618 if (isspace(ch)) {
1619 inp();
1620 } else {
1621 state++;
1622 }
1623 break;
1624 case 1:
1625 if (isalnum(ch)) {
1626 mPragmas.append(ch);
1627 inp();
1628 } else if (ch == '(') {
1629 mPragmas.append(0);
1630 inp();
1631 state++;
1632 } else {
1633 state = 11;
1634 }
1635 break;
1636 case 2:
1637 if (isalnum(ch)) {
1638 mPragmas.append(ch);
1639 inp();
1640 } else if (ch == ')') {
1641 mPragmas.append(0);
1642 inp();
1643 state = 10;
1644 } else {
1645 state = 11;
1646 }
1647 break;
1648 }
1649 }
1650 if(state != 10) {
1651 error("Unexpected pragma syntax");
1652 }
1653 mPragmaStringCount += 2;
1654 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001655
Jack Palevichac0e95e2009-05-29 13:53:44 -07001656 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001657 mErrorBuf.printf("%ld: ", file->getLine());
1658 mErrorBuf.vprintf(fmt, ap);
1659 mErrorBuf.printf("\n");
Jack Palevichac0e95e2009-05-29 13:53:44 -07001660 longjmp(mErrorRecoveryJumpBuf, 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001661 }
1662
Jack Palevich8b0624c2009-05-20 12:12:06 -07001663 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001664 if (tok != c) {
1665 error("'%c' expected", c);
1666 }
1667 next();
1668 }
1669
Jack Palevich21a15a22009-05-11 14:49:29 -07001670 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001671 void unary(intptr_t l) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001672 intptr_t n, t, a;
1673 int c;
Jack Palevich546b2242009-05-13 15:10:04 -07001674 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001675 n = 1; /* type of expression 0 = forward, 1 = value, other =
1676 lvalue */
1677 if (tok == '\"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07001678 pGen->li((int) glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001679 while (ch != '\"') {
1680 getq();
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001681 *allocGlobalSpace(1) = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07001682 inp();
1683 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001684 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001685 /* align heap */
1686 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001687 inp();
1688 next();
1689 } else {
1690 c = tokl;
1691 a = tokc;
1692 t = tok;
1693 next();
1694 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001695 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001696 } else if (c == 2) {
1697 /* -, +, !, ~ */
1698 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07001699 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001700 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001701 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001702 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001703 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001704 } else if (t == '(') {
1705 expr();
1706 skip(')');
1707 } else if (t == '*') {
1708 /* parse cast */
1709 skip('(');
1710 t = tok; /* get type */
1711 next(); /* skip int/char/void */
1712 next(); /* skip '*' or '(' */
1713 if (tok == '*') {
1714 /* function type */
1715 skip('*');
1716 skip(')');
1717 skip('(');
1718 skip(')');
1719 t = 0;
1720 }
1721 skip(')');
1722 unary(0);
1723 if (tok == '=') {
1724 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07001725 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001726 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001727 pGen->popR1();
1728 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001729 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001730 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001731 }
1732 } else if (t == '&') {
Jack Palevich1cdef202009-05-22 12:06:27 -07001733 pGen->leaR0(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001734 next();
1735 } else {
1736 n = *(int *) t;
1737 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001738 if (!n) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001739 n = (intptr_t) dlsym(RTLD_DEFAULT, last_id);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001740 }
Jack Palevich546b2242009-05-13 15:10:04 -07001741 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001742 /* assignment */
1743 next();
1744 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001745 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07001746 } else if (tok != '(') {
1747 /* variable */
Jack Palevich1cdef202009-05-22 12:06:27 -07001748 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001749 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001750 next();
1751 }
1752 }
1753 }
1754 }
1755
1756 /* function call */
1757 if (tok == '(') {
1758 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07001759 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001760
1761 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001762 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07001763 next();
1764 l = 0;
1765 while (tok != ')') {
1766 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001767 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001768 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001769 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001770 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001771 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001772 pGen->endFunctionCallArguments(a, l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001773 next();
1774 if (!n) {
1775 /* forward reference */
1776 t = t + 4;
1777 *(int *) t = pGen->callForward(*(int *) t);
1778 } else if (n == 1) {
1779 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001780 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07001781 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07001782 }
Jack Palevich3d474a72009-05-15 15:12:38 -07001783 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07001784 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001785 }
1786 }
1787
Jack Palevich653f42d2009-05-28 17:15:32 -07001788 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07001789 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07001790 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001791 if (l-- == 1)
1792 unary(1);
1793 else {
1794 sum(l);
1795 a = 0;
1796 while (l == tokl) {
1797 n = tok;
1798 t = tokc;
1799 next();
1800
1801 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001802 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07001803 sum(l);
1804 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07001805 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001806 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07001807 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001808
Jack Palevich546b2242009-05-13 15:10:04 -07001809 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001810 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001811 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001812 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001813 }
1814 }
1815 }
1816 /* && and || output code generation */
1817 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001818 a = pGen->gtst(t == OP_LOGICAL_OR, a);
1819 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07001820 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001821 pGen->gsym(a);
1822 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07001823 }
1824 }
1825 }
1826
1827 void expr() {
1828 sum(11);
1829 }
1830
1831 int test_expr() {
1832 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001833 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001834 }
1835
Jack Palevich8b0624c2009-05-20 12:12:06 -07001836 void block(intptr_t l) {
1837 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001838
1839 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001840 next();
1841 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07001842 a = test_expr();
1843 skip(')');
1844 block(l);
1845 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001846 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001847 n = pGen->gjmp(0); /* jmp */
1848 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001849 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001850 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001851 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001852 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001853 }
Jack Palevich546b2242009-05-13 15:10:04 -07001854 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001855 t = tok;
1856 next();
1857 skip('(');
1858 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07001859 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07001860 a = test_expr();
1861 } else {
1862 if (tok != ';')
1863 expr();
1864 skip(';');
1865 n = codeBuf.getPC();
1866 a = 0;
1867 if (tok != ';')
1868 a = test_expr();
1869 skip(';');
1870 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001871 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001872 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07001873 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001874 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001875 n = t + 4;
1876 }
1877 }
1878 skip(')');
Jack Palevich8b0624c2009-05-20 12:12:06 -07001879 block((intptr_t) &a);
Jack Palevicha6535612009-05-13 16:24:17 -07001880 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001881 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001882 } else if (tok == '{') {
1883 next();
1884 /* declarations */
Jack Palevichb7c81e92009-06-04 19:56:13 -07001885 localDeclarations();
Jack Palevich21a15a22009-05-11 14:49:29 -07001886 while (tok != '}')
1887 block(l);
1888 next();
1889 } else {
1890 if (tok == TOK_RETURN) {
1891 next();
1892 if (tok != ';')
1893 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001894 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001895 } else if (tok == TOK_BREAK) {
1896 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001897 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001898 } else if (tok != ';')
1899 expr();
1900 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001901 }
1902 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001903
Jack Palevichb7c81e92009-06-04 19:56:13 -07001904 typedef int Type;
1905 static const Type TY_UNKNOWN = 0;
1906 static const Type TY_INT = 1;
1907 static const Type TY_CHAR = 2;
1908 static const Type TY_VOID = 3;
1909 static const int TY_BASE_TYPE_MASK = 0xf;
1910 static const int TY_INDIRECTION_MASK = 0xf0;
1911 static const int TY_INDIRECTION_SHIFT = 4;
1912 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07001913
Jack Palevichb7c81e92009-06-04 19:56:13 -07001914 Type getBaseType(Type t) {
1915 return t & TY_BASE_TYPE_MASK;
1916 }
1917
1918 int getIndirectionCount(Type t) {
1919 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
1920 }
1921
1922 void setIndirectionCount(Type& t, int count) {
1923 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
1924 | (t & ~TY_INDIRECTION_MASK));
1925 }
1926
1927 bool acceptType(Type& t) {
1928 t = TY_UNKNOWN;
1929 if (tok == TOK_INT) {
1930 t = TY_INT;
1931 } else if (tok == TOK_CHAR) {
1932 t = TY_CHAR;
1933 } else if (tok == TOK_VOID) {
1934 t = TY_VOID;
1935 } else {
1936 return false;
1937 }
1938 next();
1939 return true;
1940 }
1941
1942 Type acceptPointerDeclaration(Type& base) {
1943 Type t = base;
1944 int indirectionCount = 0;
1945 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
1946 next();
1947 indirectionCount++;
1948 }
1949 if (indirectionCount > MAX_INDIRECTION_COUNT) {
1950 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
1951 }
1952 setIndirectionCount(t, indirectionCount);
1953 return t;
1954 }
1955
1956 void expectType(Type& t) {
1957 if (!acceptType(t)) {
1958 error("Expected a type.");
1959 }
1960 }
1961
1962 void checkSymbol() {
1963 if (tok <= TOK_DEFINE) {
1964 error("Expected a symbol");
1965 }
1966 }
1967
1968 void localDeclarations() {
1969 intptr_t a;
1970 Type base;
1971
1972 while (acceptType(base)) {
1973 while (tok != ';') {
1974 Type t = acceptPointerDeclaration(t);
1975 checkSymbol();
1976 loc = loc + 4;
1977 *(int *) tok = -loc;
1978
Jack Palevich21a15a22009-05-11 14:49:29 -07001979 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001980 if (tok == ',')
1981 next();
1982 }
1983 skip(';');
1984 }
1985 }
1986
1987 void globalDeclarations() {
1988 while (tok != EOF) {
1989 Type base;
1990 expectType(base);
1991 Type t = acceptPointerDeclaration(t);
1992 checkSymbol();
1993 int name = tok;
1994 next();
1995 if (tok == ',' || tok == ';') {
1996 // it's a variable declaration
1997 for(;;) {
1998 *(int* *) name = (int*) allocGlobalSpace(4);
1999 if (tok != ',') {
2000 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07002001 }
2002 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002003 t = acceptPointerDeclaration(t);
2004 checkSymbol();
2005 name = tok;
2006 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002007 }
2008 skip(';');
2009 } else {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002010 /* patch forward references (XXX: does not work for function
Jack Palevich21a15a22009-05-11 14:49:29 -07002011 pointers) */
Jack Palevichb7c81e92009-06-04 19:56:13 -07002012 pGen->gsym(*(int *) (name + 4));
Jack Palevich21a15a22009-05-11 14:49:29 -07002013 /* put function address */
Jack Palevichb7c81e92009-06-04 19:56:13 -07002014 *(int *) name = codeBuf.getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07002015 skip('(');
Jack Palevichb7c81e92009-06-04 19:56:13 -07002016 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07002017 int argCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002018 while (tok != ')') {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002019 Type aType;
2020 expectType(aType);
2021 aType = acceptPointerDeclaration(aType);
2022 checkSymbol();
Jack Palevich21a15a22009-05-11 14:49:29 -07002023 /* read param name and compute offset */
2024 *(int *) tok = a;
2025 a = a + 4;
2026 next();
2027 if (tok == ',')
2028 next();
Jack Palevich546b2242009-05-13 15:10:04 -07002029 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07002030 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002031 skip(')'); /* skip ')' */
Jack Palevich21a15a22009-05-11 14:49:29 -07002032 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002033 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07002034 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002035 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07002036 pGen->functionExit(argCount, a, loc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002037 }
2038 }
2039 }
2040
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002041 char* allocGlobalSpace(int bytes) {
2042 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
2043 error("Global space exhausted");
2044 }
2045 char* result = glo;
2046 glo += bytes;
2047 return result;
2048 }
2049
Jack Palevich21a15a22009-05-11 14:49:29 -07002050 void cleanup() {
2051 if (sym_stk != 0) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002052 free(sym_stk);
Jack Palevich21a15a22009-05-11 14:49:29 -07002053 sym_stk = 0;
2054 }
2055 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002056 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07002057 pGlobalBase = 0;
2058 }
2059 if (pVarsBase != 0) {
2060 free(pVarsBase);
2061 pVarsBase = 0;
2062 }
2063 if (pGen) {
2064 delete pGen;
2065 pGen = 0;
2066 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002067 if (file) {
2068 delete file;
2069 file = 0;
2070 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002071 }
2072
2073 void clear() {
2074 tok = 0;
2075 tokc = 0;
2076 tokl = 0;
2077 ch = 0;
Jack Palevich653f42d2009-05-28 17:15:32 -07002078 pVarsBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002079 rsym = 0;
2080 loc = 0;
2081 glo = 0;
2082 sym_stk = 0;
2083 dstk = 0;
2084 dptr = 0;
2085 dch = 0;
2086 last_id = 0;
2087 file = 0;
2088 pGlobalBase = 0;
2089 pVarsBase = 0;
2090 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002091 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002092 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002093
Jack Palevich22305132009-05-13 10:58:45 -07002094 void setArchitecture(const char* architecture) {
2095 delete pGen;
2096 pGen = 0;
2097
2098 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002099#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002100 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002101 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002102 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002103#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07002104#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002105 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002106 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002107 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002108#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07002109 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002110 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07002111 }
2112 }
2113
2114 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002115#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07002116 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07002117#elif defined(DEFAULT_X86_CODEGEN)
2118 pGen = new X86CodeGenerator();
2119#endif
2120 }
2121 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002122 error("No code generator defined.");
Jack Palevich22305132009-05-13 10:58:45 -07002123 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002124 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07002125 }
2126
Jack Palevich77ae76e2009-05-10 19:59:24 -07002127public:
Jack Palevich22305132009-05-13 10:58:45 -07002128 struct args {
2129 args() {
2130 architecture = 0;
2131 }
2132 const char* architecture;
2133 };
2134
Jack Paleviche7b59062009-05-19 17:12:17 -07002135 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002136 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002137 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002138
Jack Paleviche7b59062009-05-19 17:12:17 -07002139 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002140 cleanup();
2141 }
2142
Jack Palevich1cdef202009-05-22 12:06:27 -07002143 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002144 int result;
2145 if (! (result = setjmp(mErrorRecoveryJumpBuf))) {
2146 cleanup();
2147 clear();
2148 codeBuf.init(ALLOC_SIZE);
2149 setArchitecture(NULL);
2150 if (!pGen) {
2151 return -1;
2152 }
2153 pGen->init(&codeBuf);
2154 file = new TextInputStream(text, textLength);
2155 sym_stk = (char*) calloc(1, ALLOC_SIZE);
Jack Palevicheedf9d22009-06-04 16:23:40 -07002156 static const char* predefinedSymbols =
Jack Palevichb7c81e92009-06-04 19:56:13 -07002157 " int char void"
2158 " if else while break return for"
2159 " pragma define main ";
Jack Palevicheedf9d22009-06-04 16:23:40 -07002160 dstk = strcpy(sym_stk, predefinedSymbols)
2161 + strlen(predefinedSymbols);
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002162 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
2163 glo = pGlobalBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -07002164 pVarsBase = (char*) calloc(1, ALLOC_SIZE);
2165 inp();
2166 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002167 globalDeclarations();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002168 pGen->finishCompile();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002169 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002170 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07002171 }
2172
2173 int run(int argc, char** argv) {
2174 typedef int (*mainPtr)(int argc, char** argv);
Jack Palevich653f42d2009-05-28 17:15:32 -07002175 mainPtr aMain = (mainPtr) *(int*) (pVarsBase + TOK_MAIN);
Jack Palevich21a15a22009-05-11 14:49:29 -07002176 if (!aMain) {
2177 fprintf(stderr, "Could not find function \"main\".\n");
2178 return -1;
2179 }
2180 return aMain(argc, argv);
2181 }
2182
2183 int dump(FILE* out) {
2184 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
2185 return 0;
2186 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07002187
Jack Palevicha6535612009-05-13 16:24:17 -07002188 int disassemble(FILE* out) {
2189 return pGen->disassemble(out);
2190 }
2191
Jack Palevich1cdef202009-05-22 12:06:27 -07002192 /* Look through the symbol table to find a symbol.
2193 * If found, return its value.
2194 */
2195 void* lookup(const char* name) {
2196 if (!sym_stk) {
2197 return NULL;
2198 }
2199 size_t nameLen = strlen(name);
Jack Palevich653f42d2009-05-28 17:15:32 -07002200 char* pSym = sym_stk;
Jack Palevich1cdef202009-05-22 12:06:27 -07002201 char c;
2202 for(;;) {
2203 c = *pSym++;
2204 if (c == 0) {
2205 break;
2206 }
2207 if (c == TAG_TOK) {
2208 if (memcmp(pSym, name, nameLen) == 0
2209 && pSym[nameLen] == TAG_TOK) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002210 int tok = pSym - 1 - sym_stk;
Jack Palevich1cdef202009-05-22 12:06:27 -07002211 tok = tok * 8 + TOK_IDENT;
2212 if (tok <= TOK_DEFINE) {
2213 return 0;
2214 } else {
Jack Palevich653f42d2009-05-28 17:15:32 -07002215 tok = (intptr_t) (pVarsBase + tok);
Jack Palevich1cdef202009-05-22 12:06:27 -07002216 return * (void**) tok;
2217 }
2218 }
2219 }
2220 }
2221 return NULL;
2222 }
2223
Jack Palevicheedf9d22009-06-04 16:23:40 -07002224 void getPragmas(ACCsizei* actualStringCount,
2225 ACCsizei maxStringCount, ACCchar** strings) {
2226 int stringCount = mPragmaStringCount;
2227 if (actualStringCount) {
2228 *actualStringCount = stringCount;
2229 }
2230 if (stringCount > maxStringCount) {
2231 stringCount = maxStringCount;
2232 }
2233 if (strings) {
2234 char* pPragmas = mPragmas.getUnwrapped();
2235 while (stringCount-- > 0) {
2236 *strings++ = pPragmas;
2237 pPragmas += strlen(pPragmas) + 1;
2238 }
2239 }
2240 }
2241
Jack Palevichac0e95e2009-05-29 13:53:44 -07002242 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002243 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002244 }
2245
Jack Palevich77ae76e2009-05-10 19:59:24 -07002246};
2247
Jack Paleviche7b59062009-05-19 17:12:17 -07002248const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002249 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2250
Jack Paleviche7b59062009-05-19 17:12:17 -07002251const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002252 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2253 5, 5, /* ==, != */
2254 9, 10, /* &&, || */
2255 6, 7, 8, /* & ^ | */
2256 2, 2 /* ~ ! */
2257 };
2258
Jack Palevich8b0624c2009-05-20 12:12:06 -07002259#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002260FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002261#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002262
Jack Palevich8b0624c2009-05-20 12:12:06 -07002263#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002264const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002265 0x1, // ++
2266 0xff, // --
2267 0xc1af0f, // *
2268 0xf9f79991, // /
2269 0xf9f79991, // % (With manual assist to swap results)
2270 0xc801, // +
2271 0xd8f7c829, // -
2272 0xe0d391, // <<
2273 0xf8d391, // >>
2274 0xe, // <=
2275 0xd, // >=
2276 0xc, // <
2277 0xf, // >
2278 0x4, // ==
2279 0x5, // !=
2280 0x0, // &&
2281 0x1, // ||
2282 0xc821, // &
2283 0xc831, // ^
2284 0xc809, // |
2285 0xd0f7, // ~
2286 0x4 // !
2287};
Jack Palevich8b0624c2009-05-20 12:12:06 -07002288#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002289
Jack Palevich1cdef202009-05-22 12:06:27 -07002290struct ACCscript {
2291 ACCscript() {
2292 text = 0;
2293 textLength = 0;
2294 accError = ACC_NO_ERROR;
2295 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002296
Jack Palevich1cdef202009-05-22 12:06:27 -07002297 ~ACCscript() {
2298 delete text;
2299 }
Jack Palevich546b2242009-05-13 15:10:04 -07002300
Jack Palevich1cdef202009-05-22 12:06:27 -07002301 void setError(ACCenum error) {
2302 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
2303 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002304 }
2305 }
2306
Jack Palevich1cdef202009-05-22 12:06:27 -07002307 ACCenum getError() {
2308 ACCenum result = accError;
2309 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07002310 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002311 }
2312
Jack Palevich1cdef202009-05-22 12:06:27 -07002313 Compiler compiler;
2314 char* text;
2315 int textLength;
2316 ACCenum accError;
2317};
2318
2319
2320extern "C"
2321ACCscript* accCreateScript() {
2322 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002323}
Jack Palevich1cdef202009-05-22 12:06:27 -07002324
2325extern "C"
2326ACCenum accGetError( ACCscript* script ) {
2327 return script->getError();
2328}
2329
2330extern "C"
2331void accDeleteScript(ACCscript* script) {
2332 delete script;
2333}
2334
2335extern "C"
2336void accScriptSource(ACCscript* script,
2337 ACCsizei count,
2338 const ACCchar ** string,
2339 const ACCint * length) {
2340 int totalLength = 0;
2341 for(int i = 0; i < count; i++) {
2342 int len = -1;
2343 const ACCchar* s = string[i];
2344 if (length) {
2345 len = length[i];
2346 }
2347 if (len < 0) {
2348 len = strlen(s);
2349 }
2350 totalLength += len;
2351 }
2352 delete script->text;
2353 char* text = new char[totalLength + 1];
2354 script->text = text;
2355 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07002356 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07002357 for(int i = 0; i < count; i++) {
2358 int len = -1;
2359 const ACCchar* s = string[i];
2360 if (length) {
2361 len = length[i];
2362 }
2363 if (len < 0) {
2364 len = strlen(s);
2365 }
Jack Palevich09555c72009-05-27 12:25:55 -07002366 memcpy(dest, s, len);
2367 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07002368 }
2369 text[totalLength] = '\0';
2370}
2371
2372extern "C"
2373void accCompileScript(ACCscript* script) {
2374 int result = script->compiler.compile(script->text, script->textLength);
2375 if (result) {
2376 script->setError(ACC_INVALID_OPERATION);
2377 }
2378}
2379
2380extern "C"
2381void accGetScriptiv(ACCscript* script,
2382 ACCenum pname,
2383 ACCint * params) {
2384 switch (pname) {
2385 case ACC_INFO_LOG_LENGTH:
2386 *params = 0;
2387 break;
2388 }
2389}
2390
2391extern "C"
2392void accGetScriptInfoLog(ACCscript* script,
2393 ACCsizei maxLength,
2394 ACCsizei * length,
2395 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002396 char* message = script->compiler.getErrorMessage();
2397 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07002398 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002399 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07002400 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002401 if (infoLog && maxLength > 0) {
2402 int trimmedLength = maxLength < messageLength ?
2403 maxLength : messageLength;
2404 memcpy(infoLog, message, trimmedLength);
2405 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002406 }
2407}
2408
2409extern "C"
2410void accGetScriptLabel(ACCscript* script, const ACCchar * name,
2411 ACCvoid ** address) {
2412 void* value = script->compiler.lookup(name);
2413 if (value) {
2414 *address = value;
2415 } else {
2416 script->setError(ACC_INVALID_VALUE);
2417 }
2418}
2419
Jack Palevicheedf9d22009-06-04 16:23:40 -07002420extern "C"
2421void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
2422 ACCsizei maxStringCount, ACCchar** strings){
2423 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
2424}
2425
2426
Jack Palevich1cdef202009-05-22 12:06:27 -07002427} // namespace acc
2428