blob: 8b3765a3d3c71bcd8f4e3fd16dade0e2493c03a6 [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 Palevichb67b18f2009-06-11 21:12:23 -070051// #define PROVIDE_TRACE_CODEGEN
52
Jack Palevichbbf8ab52009-05-11 11:54:30 -070053namespace acc {
54
Jack Palevichac0e95e2009-05-29 13:53:44 -070055class ErrorSink {
56public:
57 void error(const char *fmt, ...) {
58 va_list ap;
59 va_start(ap, fmt);
60 verror(fmt, ap);
61 va_end(ap);
62 }
63
64 virtual void verror(const char* fmt, va_list ap) = 0;
65};
66
67class Compiler : public ErrorSink {
Jack Palevich21a15a22009-05-11 14:49:29 -070068 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070069 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070070 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070071 ErrorSink* mErrorSink;
72 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -070073 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -070074
Jack Palevich21a15a22009-05-11 14:49:29 -070075 void release() {
76 if (pProgramBase != 0) {
77 free(pProgramBase);
78 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070079 }
Jack Palevich21a15a22009-05-11 14:49:29 -070080 }
81
Jack Palevich0a280a02009-06-11 10:53:51 -070082 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -070083 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -070084 bool overflow = newSize > mSize;
85 if (overflow && !mOverflowed) {
86 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -070087 if (mErrorSink) {
88 mErrorSink->error("Code too large: %d bytes", newSize);
89 }
90 }
Jack Palevich0a280a02009-06-11 10:53:51 -070091 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -070092 }
93
Jack Palevich21a15a22009-05-11 14:49:29 -070094 public:
95 CodeBuf() {
96 pProgramBase = 0;
97 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -070098 mErrorSink = 0;
99 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700100 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700101 }
102
103 ~CodeBuf() {
104 release();
105 }
106
107 void init(int size) {
108 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700109 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700110 pProgramBase = (char*) calloc(1, size);
111 ind = pProgramBase;
112 }
113
Jack Palevichac0e95e2009-05-29 13:53:44 -0700114 void setErrorSink(ErrorSink* pErrorSink) {
115 mErrorSink = pErrorSink;
116 }
117
Jack Palevich546b2242009-05-13 15:10:04 -0700118 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700119 if(check(4)) {
120 return 0;
121 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700122 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700123 * (int*) ind = n;
124 ind += 4;
125 return result;
126 }
127
Jack Palevich21a15a22009-05-11 14:49:29 -0700128 /*
129 * Output a byte. Handles all values, 0..ff.
130 */
131 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700132 if(check(1)) {
133 return;
134 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700135 *ind++ = n;
136 }
137
Jack Palevich21a15a22009-05-11 14:49:29 -0700138 inline void* getBase() {
139 return (void*) pProgramBase;
140 }
141
Jack Palevich8b0624c2009-05-20 12:12:06 -0700142 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700143 return ind - pProgramBase;
144 }
145
Jack Palevich8b0624c2009-05-20 12:12:06 -0700146 intptr_t getPC() {
147 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 }
149 };
150
Jack Palevich1cdef202009-05-22 12:06:27 -0700151 /**
152 * A code generator creates an in-memory program, generating the code on
153 * the fly. There is one code generator implementation for each supported
154 * architecture.
155 *
156 * The code generator implements the following abstract machine:
157 * R0 - the main accumulator.
158 * R1 - the secondary accumulator.
159 * FP - a frame pointer for accessing function arguments and local
160 * variables.
161 * SP - a stack pointer for storing intermediate results while evaluating
162 * expressions. The stack pointer grows downwards.
163 *
164 * The function calling convention is that all arguments are placed on the
165 * stack such that the first argument has the lowest address.
166 * After the call, the result is in R0. The caller is responsible for
167 * removing the arguments from the stack.
168 * The R0 and R1 registers are not saved across function calls. The
169 * FP and SP registers are saved.
170 */
171
Jack Palevich21a15a22009-05-11 14:49:29 -0700172 class CodeGenerator {
173 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700174 CodeGenerator() {
175 mErrorSink = 0;
176 pCodeBuf = 0;
177 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700178 virtual ~CodeGenerator() {}
179
Jack Palevich22305132009-05-13 10:58:45 -0700180 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700182 pCodeBuf->setErrorSink(mErrorSink);
183 }
184
Jack Palevichb67b18f2009-06-11 21:12:23 -0700185 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700186 mErrorSink = pErrorSink;
187 if (pCodeBuf) {
188 pCodeBuf->setErrorSink(mErrorSink);
189 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700190 }
191
Jack Palevich1cdef202009-05-22 12:06:27 -0700192 /* Emit a function prolog.
193 * argCount is the number of arguments.
194 * Save the old value of the FP.
195 * Set the new value of the FP.
196 * Convert from the native platform calling convention to
197 * our stack-based calling convention. This may require
198 * pushing arguments from registers to the stack.
199 * Allocate "N" bytes of stack space. N isn't known yet, so
200 * just emit the instructions for adjusting the stack, and return
201 * the address to patch up. The patching will be done in
202 * functionExit().
203 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700204 */
Jack Palevich546b2242009-05-13 15:10:04 -0700205 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700206
Jack Palevich1cdef202009-05-22 12:06:27 -0700207 /* Emit a function epilog.
208 * Restore the old SP and FP register values.
209 * Return to the calling function.
210 * argCount - the number of arguments to the function.
211 * localVariableAddress - returned from functionEntry()
212 * localVariableSize - the size in bytes of the local variables.
213 */
214 virtual void functionExit(int argCount, int localVariableAddress,
215 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700216
Jack Palevich1cdef202009-05-22 12:06:27 -0700217 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700218 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700219
Jack Palevich1cdef202009-05-22 12:06:27 -0700220 /* Jump to a target, and return the address of the word that
221 * holds the target data, in case it needs to be fixed up later.
222 */
Jack Palevich22305132009-05-13 10:58:45 -0700223 virtual int gjmp(int t) = 0;
224
Jack Palevich1cdef202009-05-22 12:06:27 -0700225 /* Test R0 and jump to a target if the test succeeds.
226 * l = 0: je, l == 1: jne
227 * Return the address of the word that holds the targed data, in
228 * case it needs to be fixed up later.
229 */
Jack Palevich22305132009-05-13 10:58:45 -0700230 virtual int gtst(bool l, int t) = 0;
231
Jack Palevich1cdef202009-05-22 12:06:27 -0700232 /* Compare R1 against R0, and store the boolean result in R0.
233 * op specifies the comparison.
234 */
Jack Palevich22305132009-05-13 10:58:45 -0700235 virtual void gcmp(int op) = 0;
236
Jack Palevich1cdef202009-05-22 12:06:27 -0700237 /* Perform the arithmetic op specified by op. R1 is the
238 * left argument, R0 is the right argument.
239 */
Jack Palevich546b2242009-05-13 15:10:04 -0700240 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700241
Jack Palevich1cdef202009-05-22 12:06:27 -0700242 /* Set R1 to 0.
243 */
244 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700245
Jack Palevich1cdef202009-05-22 12:06:27 -0700246 /* Push R0 onto the stack.
247 */
248 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700249
Jack Palevich1cdef202009-05-22 12:06:27 -0700250 /* Pop R1 off of the stack.
251 */
252 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700253
Jack Palevich1cdef202009-05-22 12:06:27 -0700254 /* Store R0 to the address stored in R1.
255 * isInt is true if a whole 4-byte integer value
256 * should be stored, otherwise a 1-byte character
257 * value should be stored.
258 */
259 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700260
Jack Palevich1cdef202009-05-22 12:06:27 -0700261 /* Load R0 from the address stored in R0.
262 * isInt is true if a whole 4-byte integer value
263 * should be loaded, otherwise a 1-byte character
264 * value should be loaded.
265 */
266 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700267
Jack Palevich1cdef202009-05-22 12:06:27 -0700268 /* Load the absolute address of a variable to R0.
269 * If ea <= LOCAL, then this is a local variable, or an
270 * argument, addressed relative to FP.
271 * else it is an absolute global address.
272 */
273 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700274
Jack Palevich1cdef202009-05-22 12:06:27 -0700275 /* Store R0 to a variable.
276 * If ea <= LOCAL, then this is a local variable, or an
277 * argument, addressed relative to FP.
278 * else it is an absolute global address.
279 */
280 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700281
Jack Palevich1cdef202009-05-22 12:06:27 -0700282 /* load R0 from a variable.
283 * If ea <= LOCAL, then this is a local variable, or an
284 * argument, addressed relative to FP.
285 * else it is an absolute global address.
286 * If isIncDec is true, then the stored variable's value
287 * should be post-incremented or post-decremented, based
288 * on the value of op.
289 */
290 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700291
Jack Palevich1cdef202009-05-22 12:06:27 -0700292 /* Emit code to adjust the stack for a function call. Return the
293 * label for the address of the instruction that adjusts the
294 * stack size. This will be passed as argument "a" to
295 * endFunctionCallArguments.
296 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700297 virtual int beginFunctionCallArguments() = 0;
298
Jack Palevich1cdef202009-05-22 12:06:27 -0700299 /* Emit code to store R0 to the stack at byte offset l.
300 */
301 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700302
Jack Palevich1cdef202009-05-22 12:06:27 -0700303 /* Patch the function call preamble.
304 * a is the address returned from beginFunctionCallArguments
305 * l is the number of bytes the arguments took on the stack.
306 * Typically you would also emit code to convert the argument
307 * list into whatever the native function calling convention is.
308 * On ARM for example you would pop the first 5 arguments into
309 * R0..R4
310 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700311 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700312
Jack Palevich1cdef202009-05-22 12:06:27 -0700313 /* Emit a call to an unknown function. The argument "symbol" needs to
314 * be stored in the location where the address should go. It forms
315 * a chain. The address will be patched later.
316 * Return the address of the word that has to be patched.
317 */
Jack Palevich22305132009-05-13 10:58:45 -0700318 virtual int callForward(int symbol) = 0;
319
Jack Palevich1cdef202009-05-22 12:06:27 -0700320 /* Call a function using PC-relative addressing. t is the PC-relative
321 * address of the function. It has already been adjusted for the
322 * architectural jump offset, so just store it as-is.
323 */
Jack Palevich22305132009-05-13 10:58:45 -0700324 virtual void callRelative(int t) = 0;
325
Jack Palevich1cdef202009-05-22 12:06:27 -0700326 /* Call a function pointer. L is the number of bytes the arguments
327 * take on the stack. The address of the function is stored at
328 * location SP + l.
329 */
Jack Palevich22305132009-05-13 10:58:45 -0700330 virtual void callIndirect(int l) = 0;
331
Jack Palevich1cdef202009-05-22 12:06:27 -0700332 /* Adjust SP after returning from a function call. l is the
333 * number of bytes of arguments stored on the stack. isIndirect
334 * is true if this was an indirect call. (In which case the
335 * address of the function is stored at location SP + l.)
336 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700337 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700338
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 /* Print a disassembly of the assembled code to out. Return
340 * non-zero if there is an error.
341 */
Jack Palevicha6535612009-05-13 16:24:17 -0700342 virtual int disassemble(FILE* out) = 0;
343
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 /* Generate a symbol at the current PC. t is the head of a
345 * linked list of addresses to patch.
346 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700347 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700348
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 /*
350 * Do any cleanup work required at the end of a compile.
351 * For example, an instruction cache might need to be
352 * invalidated.
353 * Return non-zero if there is an error.
354 */
355 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700356
Jack Palevicha6535612009-05-13 16:24:17 -0700357 /**
358 * Adjust relative branches by this amount.
359 */
360 virtual int jumpOffset() = 0;
361
Jack Palevich21a15a22009-05-11 14:49:29 -0700362 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700363 /*
364 * Output a byte. Handles all values, 0..ff.
365 */
366 void ob(int n) {
367 pCodeBuf->ob(n);
368 }
369
Jack Palevich8b0624c2009-05-20 12:12:06 -0700370 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700371 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700372 }
373
Jack Palevich8b0624c2009-05-20 12:12:06 -0700374 intptr_t getBase() {
375 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700376 }
377
Jack Palevich8b0624c2009-05-20 12:12:06 -0700378 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700379 return pCodeBuf->getPC();
380 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700381
382 intptr_t getSize() {
383 return pCodeBuf->getSize();
384 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700385
386 void error(const char* fmt,...) {
387 va_list ap;
388 va_start(ap, fmt);
389 mErrorSink->verror(fmt, ap);
390 va_end(ap);
391 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700392 private:
393 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700394 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700395 };
396
Jack Paleviche7b59062009-05-19 17:12:17 -0700397#ifdef PROVIDE_ARM_CODEGEN
398
Jack Palevich22305132009-05-13 10:58:45 -0700399 class ARMCodeGenerator : public CodeGenerator {
400 public:
401 ARMCodeGenerator() {}
402 virtual ~ARMCodeGenerator() {}
403
404 /* returns address to patch with local variable size
405 */
Jack Palevich546b2242009-05-13 15:10:04 -0700406 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700407 LOG_API("functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700408 // sp -> arg4 arg5 ...
409 // Push our register-based arguments back on the stack
410 if (argCount > 0) {
411 int regArgCount = argCount <= 4 ? argCount : 4;
412 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
413 }
414 // sp -> arg0 arg1 ...
415 o4(0xE92D4800); // stmfd sp!, {fp, lr}
416 // sp, fp -> oldfp, retadr, arg0 arg1 ....
417 o4(0xE1A0B00D); // mov fp, sp
418 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700419 }
420
Jack Palevich546b2242009-05-13 15:10:04 -0700421 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700422 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700423 // Patch local variable allocation code:
424 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700425 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700426 }
Jack Palevich69796b62009-05-14 15:42:26 -0700427 *(char*) (localVariableAddress) = localVariableSize;
428
429 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
430 o4(0xE1A0E00B); // mov lr, fp
431 o4(0xE59BB000); // ldr fp, [fp]
432 o4(0xE28ED004); // add sp, lr, #4
433 // sp -> retadr, arg0, ...
434 o4(0xE8BD4000); // ldmfd sp!, {lr}
435 // sp -> arg0 ....
436 if (argCount > 0) {
437 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700438 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700439 // earlier. We don't need to actually store them anywhere,
440 // just adjust the stack.
441 int regArgCount = argCount <= 4 ? argCount : 4;
442 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
443 }
444 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700445 }
446
447 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700448 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700449 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700450 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700451 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700452 } else if (t >= -256 && t < 0) {
453 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700454 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700455 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700456 o4(0xE51F0000); // ldr r0, .L3
457 o4(0xEA000000); // b .L99
458 o4(t); // .L3: .word 0
459 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700460 }
Jack Palevich22305132009-05-13 10:58:45 -0700461 }
462
463 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700464 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700465 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700466 }
467
468 /* l = 0: je, l == 1: jne */
469 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700470 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700471 o4(0xE3500000); // cmp r0,#0
472 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
473 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700474 }
475
476 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700477 LOG_API("gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700478 o4(0xE1510000); // cmp r1, r1
479 switch(op) {
480 case OP_EQUALS:
481 o4(0x03A00001); // moveq r0,#1
482 o4(0x13A00000); // movne r0,#0
483 break;
484 case OP_NOT_EQUALS:
485 o4(0x03A00000); // moveq r0,#0
486 o4(0x13A00001); // movne r0,#1
487 break;
488 case OP_LESS_EQUAL:
489 o4(0xD3A00001); // movle r0,#1
490 o4(0xC3A00000); // movgt r0,#0
491 break;
492 case OP_GREATER:
493 o4(0xD3A00000); // movle r0,#0
494 o4(0xC3A00001); // movgt r0,#1
495 break;
496 case OP_GREATER_EQUAL:
497 o4(0xA3A00001); // movge r0,#1
498 o4(0xB3A00000); // movlt r0,#0
499 break;
500 case OP_LESS:
501 o4(0xA3A00000); // movge r0,#0
502 o4(0xB3A00001); // movlt r0,#1
503 break;
504 default:
505 error("Unknown comparison op %d", op);
506 break;
507 }
Jack Palevich22305132009-05-13 10:58:45 -0700508 }
509
Jack Palevich546b2242009-05-13 15:10:04 -0700510 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700511 LOG_API("genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700512 switch(op) {
513 case OP_MUL:
514 o4(0x0E0000091); // mul r0,r1,r0
515 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700516 case OP_DIV:
517 callRuntime(runtime_DIV);
518 break;
519 case OP_MOD:
520 callRuntime(runtime_MOD);
521 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700522 case OP_PLUS:
523 o4(0xE0810000); // add r0,r1,r0
524 break;
525 case OP_MINUS:
526 o4(0xE0410000); // sub r0,r1,r0
527 break;
528 case OP_SHIFT_LEFT:
529 o4(0xE1A00011); // lsl r0,r1,r0
530 break;
531 case OP_SHIFT_RIGHT:
532 o4(0xE1A00051); // asr r0,r1,r0
533 break;
534 case OP_BIT_AND:
535 o4(0xE0010000); // and r0,r1,r0
536 break;
537 case OP_BIT_XOR:
538 o4(0xE0210000); // eor r0,r1,r0
539 break;
540 case OP_BIT_OR:
541 o4(0xE1810000); // orr r0,r1,r0
542 break;
543 case OP_BIT_NOT:
544 o4(0xE1E00000); // mvn r0, r0
545 break;
546 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700547 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700548 break;
549 }
Jack Palevich22305132009-05-13 10:58:45 -0700550#if 0
551 o(decodeOp(op));
552 if (op == OP_MOD)
553 o(0x92); /* xchg %edx, %eax */
554#endif
555 }
556
Jack Palevich1cdef202009-05-22 12:06:27 -0700557 virtual void clearR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700558 LOG_API("clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700559 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700560 }
561
Jack Palevich1cdef202009-05-22 12:06:27 -0700562 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700563 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700564 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700565 }
566
Jack Palevich1cdef202009-05-22 12:06:27 -0700567 virtual void popR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700568 LOG_API("popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700569 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700570 }
571
Jack Palevich1cdef202009-05-22 12:06:27 -0700572 virtual void storeR0ToR1(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700573 LOG_API("storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700574 if (isInt) {
575 o4(0xE5810000); // str r0, [r1]
576 } else {
577 o4(0xE5C10000); // strb r0, [r1]
578 }
Jack Palevich22305132009-05-13 10:58:45 -0700579 }
580
Jack Palevich1cdef202009-05-22 12:06:27 -0700581 virtual void loadR0FromR0(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700582 LOG_API("loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700583 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700584 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700585 else
Jack Palevich69796b62009-05-14 15:42:26 -0700586 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700587 }
588
Jack Palevich1cdef202009-05-22 12:06:27 -0700589 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700590 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700591 if (ea < LOCAL) {
592 // Local, fp relative
593 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
594 error("Offset out of range: %08x", ea);
595 }
596 if (ea < 0) {
597 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
598 } else {
599 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
600 }
Jack Palevichbd894902009-05-14 19:35:31 -0700601 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700602 // Global, absolute.
603 o4(0xE59F0000); // ldr r0, .L1
604 o4(0xEA000000); // b .L99
605 o4(ea); // .L1: .word 0
606 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700607 }
Jack Palevich22305132009-05-13 10:58:45 -0700608 }
609
Jack Palevich1cdef202009-05-22 12:06:27 -0700610 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700611 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700612 if (ea < LOCAL) {
613 // Local, fp relative
614 if (ea < -4095 || ea > 4095) {
615 error("Offset out of range: %08x", ea);
616 }
617 if (ea < 0) {
618 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
619 } else {
620 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
621 }
622 } else{
623 // Global, absolute
624 o4(0xE59F1000); // ldr r1, .L1
625 o4(0xEA000000); // b .L99
626 o4(ea); // .L1: .word 0
627 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700628 }
Jack Palevich22305132009-05-13 10:58:45 -0700629 }
630
Jack Palevich1cdef202009-05-22 12:06:27 -0700631 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700632 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700633 if (ea < LOCAL) {
634 // Local, fp relative
635 if (ea < -4095 || ea > 4095) {
636 error("Offset out of range: %08x", ea);
637 }
638 if (ea < 0) {
639 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
640 } else {
641 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
642 }
Jack Palevich69796b62009-05-14 15:42:26 -0700643 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700644 // Global, absolute
645 o4(0xE59F2000); // ldr r2, .L1
646 o4(0xEA000000); // b .L99
647 o4(ea); // .L1: .word ea
648 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700649 }
Jack Palevich22305132009-05-13 10:58:45 -0700650
Jack Palevich4d93f302009-05-15 13:30:00 -0700651 if (isIncDec) {
652 switch (op) {
653 case OP_INCREMENT:
654 o4(0xE2801001); // add r1, r0, #1
655 break;
656 case OP_DECREMENT:
657 o4(0xE2401001); // sub r1, r0, #1
658 break;
659 default:
660 error("unknown opcode: %d", op);
661 }
662 if (ea < LOCAL) {
663 // Local, fp relative
664 // Don't need range check, was already checked above
665 if (ea < 0) {
666 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
667 } else {
668 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
669 }
670 } else{
671 // Global, absolute
672 // r2 is already set up from before.
673 o4(0xE5821000); // str r1, [r2]
674 }
Jack Palevichbd894902009-05-14 19:35:31 -0700675 }
Jack Palevich22305132009-05-13 10:58:45 -0700676 }
677
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700678 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700679 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700680 return o4(0xE24DDF00); // Placeholder
681 }
682
Jack Palevich1cdef202009-05-22 12:06:27 -0700683 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700684 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700685 if (l < 0 || l > 4096-4) {
686 error("l out of range for stack offset: 0x%08x", l);
687 }
688 o4(0xE58D0000 + l); // str r0, [sp, #4]
689 }
690
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700691 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700692 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700693 if (l < 0 || l > 0x3FC) {
694 error("L out of range for stack adjustment: 0x%08x", l);
695 }
696 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
697 int argCount = l >> 2;
698 if (argCount > 0) {
699 int regArgCount = argCount > 4 ? 4 : argCount;
700 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
701 }
Jack Palevich22305132009-05-13 10:58:45 -0700702 }
703
Jack Palevich22305132009-05-13 10:58:45 -0700704 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700705 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700706 // Forward calls are always short (local)
707 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700708 }
709
710 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700711 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700712 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700713 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700714 if (t >= - (1 << 25) && t < (1 << 25)) {
715 o4(0xEB000000 | encodeAddress(t));
716 } else {
717 // Long call.
718 o4(0xE59FC000); // ldr r12, .L1
719 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700720 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700721 o4(0xE08CC00F); // .L99: add r12,pc
722 o4(0xE12FFF3C); // blx r12
723 }
Jack Palevich22305132009-05-13 10:58:45 -0700724 }
725
726 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700727 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700728 int argCount = l >> 2;
729 int poppedArgs = argCount > 4 ? 4 : argCount;
730 int adjustedL = l - (poppedArgs << 2);
731 if (adjustedL < 0 || adjustedL > 4096-4) {
732 error("l out of range for stack offset: 0x%08x", l);
733 }
734 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
735 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700736 }
737
Jack Palevich7810bc92009-05-15 14:31:47 -0700738 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700739 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700740 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700741 int stackArgs = argCount > 4 ? argCount - 4 : 0;
742 int stackUse = stackArgs + (isIndirect ? 1 : 0);
743 if (stackUse) {
744 if (stackUse < 0 || stackUse > 255) {
745 error("L out of range for stack adjustment: 0x%08x", l);
746 }
747 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700748 }
Jack Palevich22305132009-05-13 10:58:45 -0700749 }
750
Jack Palevicha6535612009-05-13 16:24:17 -0700751 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700752 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700753 }
754
755 /* output a symbol and patch all calls to it */
756 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700757 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700758 int n;
759 int base = getBase();
760 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700761 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700762 while (t) {
763 int data = * (int*) t;
764 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
765 if (decodedOffset == 0) {
766 n = 0;
767 } else {
768 n = base + decodedOffset; /* next value */
769 }
770 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
771 | encodeRelAddress(pc - t - 8);
772 t = n;
773 }
774 }
775
Jack Palevich1cdef202009-05-22 12:06:27 -0700776 virtual int finishCompile() {
777#if defined(__arm__)
778 const long base = long(getBase());
779 const long curr = long(getPC());
780 int err = cacheflush(base, curr, 0);
781 return err;
782#else
783 return 0;
784#endif
785 }
786
Jack Palevicha6535612009-05-13 16:24:17 -0700787 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700788#ifdef ENABLE_ARM_DISASSEMBLY
789 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700790 disasm_interface_t di;
791 di.di_readword = disassemble_readword;
792 di.di_printaddr = disassemble_printaddr;
793 di.di_printf = disassemble_printf;
794
795 int base = getBase();
796 int pc = getPC();
797 for(int i = base; i < pc; i += 4) {
798 fprintf(out, "%08x: %08x ", i, *(int*) i);
799 ::disasm(&di, i, 0);
800 }
Jack Palevich09555c72009-05-27 12:25:55 -0700801#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700802 return 0;
803 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700804
Jack Palevich22305132009-05-13 10:58:45 -0700805 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700806 static FILE* disasmOut;
807
808 static u_int
809 disassemble_readword(u_int address)
810 {
811 return(*((u_int *)address));
812 }
813
814 static void
815 disassemble_printaddr(u_int address)
816 {
817 fprintf(disasmOut, "0x%08x", address);
818 }
819
820 static void
821 disassemble_printf(const char *fmt, ...) {
822 va_list ap;
823 va_start(ap, fmt);
824 vfprintf(disasmOut, fmt, ap);
825 va_end(ap);
826 }
827
828 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
829
830 /** Encode a relative address that might also be
831 * a label.
832 */
833 int encodeAddress(int value) {
834 int base = getBase();
835 if (value >= base && value <= getPC() ) {
836 // This is a label, encode it relative to the base.
837 value = value - base;
838 }
839 return encodeRelAddress(value);
840 }
841
842 int encodeRelAddress(int value) {
843 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
844 }
Jack Palevich22305132009-05-13 10:58:45 -0700845
Jack Palevich3d474a72009-05-15 15:12:38 -0700846 typedef int (*int2FnPtr)(int a, int b);
847 void callRuntime(int2FnPtr fn) {
848 o4(0xE59F2000); // ldr r2, .L1
849 o4(0xEA000000); // b .L99
850 o4((int) fn); //.L1: .word fn
851 o4(0xE12FFF32); //.L99: blx r2
852 }
853
854 static int runtime_DIV(int a, int b) {
855 return b / a;
856 }
857
858 static int runtime_MOD(int a, int b) {
859 return b % a;
860 }
Jack Palevich22305132009-05-13 10:58:45 -0700861 };
862
Jack Palevich09555c72009-05-27 12:25:55 -0700863#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700864
865#ifdef PROVIDE_X86_CODEGEN
866
Jack Palevich21a15a22009-05-11 14:49:29 -0700867 class X86CodeGenerator : public CodeGenerator {
868 public:
869 X86CodeGenerator() {}
870 virtual ~X86CodeGenerator() {}
871
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700872 /* returns address to patch with local variable size
873 */
Jack Palevich546b2242009-05-13 15:10:04 -0700874 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700875 o(0xe58955); /* push %ebp, mov %esp, %ebp */
876 return oad(0xec81, 0); /* sub $xxx, %esp */
877 }
878
Jack Palevich546b2242009-05-13 15:10:04 -0700879 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700880 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700881 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700882 }
883
Jack Palevich21a15a22009-05-11 14:49:29 -0700884 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700885 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700886 oad(0xb8, t); /* mov $xx, %eax */
887 }
888
Jack Palevich22305132009-05-13 10:58:45 -0700889 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700890 return psym(0xe9, t);
891 }
892
893 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700894 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700895 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
896 return psym(0x84 + l, t);
897 }
898
Jack Palevich22305132009-05-13 10:58:45 -0700899 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700900 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700901 o(0xc139); /* cmp %eax,%ecx */
902 li(0);
903 o(0x0f); /* setxx %al */
904 o(t + 0x90);
905 o(0xc0);
906 }
907
Jack Palevich546b2242009-05-13 15:10:04 -0700908 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700909 o(decodeOp(op));
910 if (op == OP_MOD)
911 o(0x92); /* xchg %edx, %eax */
912 }
913
Jack Palevich1cdef202009-05-22 12:06:27 -0700914 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700915 oad(0xb9, 0); /* movl $0, %ecx */
916 }
917
Jack Palevich1cdef202009-05-22 12:06:27 -0700918 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700919 o(0x50); /* push %eax */
920 }
921
Jack Palevich1cdef202009-05-22 12:06:27 -0700922 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700923 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700924 }
925
Jack Palevich1cdef202009-05-22 12:06:27 -0700926 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700927 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
928 }
929
Jack Palevich1cdef202009-05-22 12:06:27 -0700930 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700931 if (isInt)
932 o(0x8b); /* mov (%eax), %eax */
933 else
934 o(0xbe0f); /* movsbl (%eax), %eax */
935 ob(0); /* add zero in code */
936 }
937
Jack Palevich1cdef202009-05-22 12:06:27 -0700938 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700939 gmov(10, ea); /* leal EA, %eax */
940 }
941
Jack Palevich1cdef202009-05-22 12:06:27 -0700942 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700943 gmov(6, ea); /* mov %eax, EA */
944 }
945
Jack Palevich1cdef202009-05-22 12:06:27 -0700946 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700947 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700948 if (isIncDec) {
949 /* Implement post-increment or post decrement.
950 */
951 gmov(0, ea); /* 83 ADD */
952 o(decodeOp(op));
953 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700954 }
955
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700956 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700957 return oad(0xec81, 0); /* sub $xxx, %esp */
958 }
959
Jack Palevich1cdef202009-05-22 12:06:27 -0700960 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700961 oad(0x248489, l); /* movl %eax, xxx(%esp) */
962 }
963
Jack Palevich7810bc92009-05-15 14:31:47 -0700964 virtual void endFunctionCallArguments(int a, int l) {
965 * (int*) a = l;
966 }
967
Jack Palevich22305132009-05-13 10:58:45 -0700968 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700969 return psym(0xe8, symbol); /* call xxx */
970 }
971
Jack Palevich22305132009-05-13 10:58:45 -0700972 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700973 psym(0xe8, t); /* call xxx */
974 }
975
Jack Palevich22305132009-05-13 10:58:45 -0700976 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700977 oad(0x2494ff, l); /* call *xxx(%esp) */
978 }
979
Jack Palevich7810bc92009-05-15 14:31:47 -0700980 virtual void adjustStackAfterCall(int l, bool isIndirect) {
981 if (isIndirect) {
982 l += 4;
983 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700984 oad(0xc481, l); /* add $xxx, %esp */
985 }
986
Jack Palevicha6535612009-05-13 16:24:17 -0700987 virtual int jumpOffset() {
988 return 5;
989 }
990
991 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -0700992 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -0700993 }
994
Jack Paleviche7b59062009-05-19 17:12:17 -0700995 /* output a symbol and patch all calls to it */
996 virtual void gsym(int t) {
997 int n;
998 int pc = getPC();
999 while (t) {
1000 n = *(int *) t; /* next value */
1001 *(int *) t = pc - t - 4;
1002 t = n;
1003 }
1004 }
1005
Jack Palevich1cdef202009-05-22 12:06:27 -07001006 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001007 size_t pagesize = 4096;
1008 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1009 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1010 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1011 if (err) {
1012 error("mprotect() failed: %d", errno);
1013 }
1014 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001015 }
1016
Jack Palevich21a15a22009-05-11 14:49:29 -07001017 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001018
1019 /** Output 1 to 4 bytes.
1020 *
1021 */
1022 void o(int n) {
1023 /* cannot use unsigned, so we must do a hack */
1024 while (n && n != -1) {
1025 ob(n & 0xff);
1026 n = n >> 8;
1027 }
1028 }
1029
1030 /* psym is used to put an instruction with a data field which is a
1031 reference to a symbol. It is in fact the same as oad ! */
1032 int psym(int n, int t) {
1033 return oad(n, t);
1034 }
1035
1036 /* instruction + address */
1037 int oad(int n, int t) {
1038 o(n);
1039 int result = getPC();
1040 o4(t);
1041 return result;
1042 }
1043
1044
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001045 static const int operatorHelper[];
1046
1047 int decodeOp(int op) {
1048 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001049 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001050 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001051 }
1052 return operatorHelper[op];
1053 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001054
Jack Palevich546b2242009-05-13 15:10:04 -07001055 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001056 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001057 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001058 }
1059 };
1060
Jack Paleviche7b59062009-05-19 17:12:17 -07001061#endif // PROVIDE_X86_CODEGEN
1062
Jack Palevichb67b18f2009-06-11 21:12:23 -07001063#ifdef PROVIDE_TRACE_CODEGEN
1064 class TraceCodeGenerator : public CodeGenerator {
1065 private:
1066 CodeGenerator* mpBase;
1067
1068 public:
1069 TraceCodeGenerator(CodeGenerator* pBase) {
1070 mpBase = pBase;
1071 }
1072
1073 virtual ~TraceCodeGenerator() {
1074 delete mpBase;
1075 }
1076
1077 virtual void init(CodeBuf* pCodeBuf) {
1078 mpBase->init(pCodeBuf);
1079 }
1080
1081 void setErrorSink(ErrorSink* pErrorSink) {
1082 mpBase->setErrorSink(pErrorSink);
1083 }
1084
1085 /* returns address to patch with local variable size
1086 */
1087 virtual int functionEntry(int argCount) {
1088 int result = mpBase->functionEntry(argCount);
1089 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1090 return result;
1091 }
1092
1093 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1094 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1095 argCount, localVariableAddress, localVariableSize);
1096 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1097 }
1098
1099 /* load immediate value */
1100 virtual void li(int t) {
1101 fprintf(stderr, "li(%d)\n", t);
1102 mpBase->li(t);
1103 }
1104
1105 virtual int gjmp(int t) {
1106 int result = mpBase->gjmp(t);
1107 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1108 return result;
1109 }
1110
1111 /* l = 0: je, l == 1: jne */
1112 virtual int gtst(bool l, int t) {
1113 int result = mpBase->gtst(l, t);
1114 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1115 return result;
1116 }
1117
1118 virtual void gcmp(int op) {
1119 fprintf(stderr, "gcmp(%d)\n", op);
1120 mpBase->gcmp(op);
1121 }
1122
1123 virtual void genOp(int op) {
1124 fprintf(stderr, "genOp(%d)\n", op);
1125 mpBase->genOp(op);
1126 }
1127
1128 virtual void clearR1() {
1129 fprintf(stderr, "clearR1()\n");
1130 mpBase->clearR1();
1131 }
1132
1133 virtual void pushR0() {
1134 fprintf(stderr, "pushR0()\n");
1135 mpBase->pushR0();
1136 }
1137
1138 virtual void popR1() {
1139 fprintf(stderr, "popR1()\n");
1140 mpBase->popR1();
1141 }
1142
1143 virtual void storeR0ToR1(bool isInt) {
1144 fprintf(stderr, "storeR0ToR1(%d)\n", isInt);
1145 mpBase->storeR0ToR1(isInt);
1146 }
1147
1148 virtual void loadR0FromR0(bool isInt) {
1149 fprintf(stderr, "loadR0FromR0(%d)\n", isInt);
1150 mpBase->loadR0FromR0(isInt);
1151 }
1152
1153 virtual void leaR0(int ea) {
1154 fprintf(stderr, "leaR0(%d)\n", ea);
1155 mpBase->leaR0(ea);
1156 }
1157
1158 virtual void storeR0(int ea) {
1159 fprintf(stderr, "storeR0(%d)\n", ea);
1160 mpBase->storeR0(ea);
1161 }
1162
1163 virtual void loadR0(int ea, bool isIncDec, int op) {
1164 fprintf(stderr, "loadR0(%d, %d, %d)\n", ea, isIncDec, op);
1165 mpBase->loadR0(ea, isIncDec, op);
1166 }
1167
1168 virtual int beginFunctionCallArguments() {
1169 int result = mpBase->beginFunctionCallArguments();
1170 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1171 return result;
1172 }
1173
1174 virtual void storeR0ToArg(int l) {
1175 fprintf(stderr, "storeR0ToArg(%d)\n", l);
1176 mpBase->storeR0ToArg(l);
1177 }
1178
1179 virtual void endFunctionCallArguments(int a, int l) {
1180 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1181 mpBase->endFunctionCallArguments(a, l);
1182 }
1183
1184 virtual int callForward(int symbol) {
1185 int result = mpBase->callForward(symbol);
1186 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1187 return result;
1188 }
1189
1190 virtual void callRelative(int t) {
1191 fprintf(stderr, "callRelative(%d)\n", t);
1192 mpBase->callRelative(t);
1193 }
1194
1195 virtual void callIndirect(int l) {
1196 fprintf(stderr, "callIndirect(%d)\n", l);
1197 mpBase->callIndirect(l);
1198 }
1199
1200 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1201 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1202 mpBase->adjustStackAfterCall(l, isIndirect);
1203 }
1204
1205 virtual int jumpOffset() {
1206 return mpBase->jumpOffset();
1207 }
1208
1209 virtual int disassemble(FILE* out) {
1210 return mpBase->disassemble(out);
1211 }
1212
1213 /* output a symbol and patch all calls to it */
1214 virtual void gsym(int t) {
1215 fprintf(stderr, "gsym(%d)\n", t);
1216 mpBase->gsym(t);
1217 }
1218
1219 virtual int finishCompile() {
1220 int result = mpBase->finishCompile();
1221 fprintf(stderr, "finishCompile() = %d\n", result);
1222 return result;
1223 }
1224 };
1225
1226#endif // PROVIDE_TRACE_CODEGEN
1227
Jack Palevich1cdef202009-05-22 12:06:27 -07001228 class InputStream {
1229 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001230 int getChar() {
1231 if (bumpLine) {
1232 line++;
1233 bumpLine = false;
1234 }
1235 int ch = get();
1236 if (ch == '\n') {
1237 bumpLine = true;
1238 }
1239 return ch;
1240 }
1241 int getLine() {
1242 return line;
1243 }
1244 protected:
1245 InputStream() :
1246 line(1), bumpLine(false) {
1247 }
1248 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001249 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001250 int line;
1251 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001252 };
1253
1254 class FileInputStream : public InputStream {
1255 public:
1256 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001257 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001258 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001259 FILE* f;
1260 };
1261
1262 class TextInputStream : public InputStream {
1263 public:
1264 TextInputStream(const char* text, size_t textLength)
1265 : pText(text), mTextLength(textLength), mPosition(0) {
1266 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001267
1268 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001269 virtual int get() {
1270 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1271 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001272
Jack Palevich1cdef202009-05-22 12:06:27 -07001273 const char* pText;
1274 size_t mTextLength;
1275 size_t mPosition;
1276 };
1277
Jack Palevicheedf9d22009-06-04 16:23:40 -07001278 class String {
1279 public:
1280 String() {
1281 mpBase = 0;
1282 mUsed = 0;
1283 mSize = 0;
1284 }
1285
Jack Palevich303d8ff2009-06-11 19:06:24 -07001286 String(const char* item, int len, bool adopt) {
1287 if (len < 0) {
1288 len = strlen(item);
1289 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001290 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001291 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001292 mUsed = len;
1293 mSize = len + 1;
1294 } else {
1295 mpBase = 0;
1296 mUsed = 0;
1297 mSize = 0;
1298 appendBytes(item, len);
1299 }
1300 }
1301
Jack Palevich303d8ff2009-06-11 19:06:24 -07001302 String(const String& other) {
1303 mpBase = 0;
1304 mUsed = 0;
1305 mSize = 0;
1306 appendBytes(other.getUnwrapped(), other.len());
1307 }
1308
Jack Palevicheedf9d22009-06-04 16:23:40 -07001309 ~String() {
1310 if (mpBase) {
1311 free(mpBase);
1312 }
1313 }
1314
Jack Palevicha6baa232009-06-12 11:25:59 -07001315 String& operator=(const String& other) {
1316 clear();
1317 appendBytes(other.getUnwrapped(), other.len());
1318 return *this;
1319 }
1320
Jack Palevich303d8ff2009-06-11 19:06:24 -07001321 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001322 return mpBase;
1323 }
1324
Jack Palevich303d8ff2009-06-11 19:06:24 -07001325 void clear() {
1326 mUsed = 0;
1327 if (mSize > 0) {
1328 mpBase[0] = 0;
1329 }
1330 }
1331
Jack Palevicheedf9d22009-06-04 16:23:40 -07001332 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001333 appendBytes(s, strlen(s));
1334 }
1335
1336 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001337 memcpy(ensure(n), s, n + 1);
1338 }
1339
1340 void append(char c) {
1341 * ensure(1) = c;
1342 }
1343
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001344 char* orphan() {
1345 char* result = mpBase;
1346 mpBase = 0;
1347 mUsed = 0;
1348 mSize = 0;
1349 return result;
1350 }
1351
Jack Palevicheedf9d22009-06-04 16:23:40 -07001352 void printf(const char* fmt,...) {
1353 va_list ap;
1354 va_start(ap, fmt);
1355 vprintf(fmt, ap);
1356 va_end(ap);
1357 }
1358
1359 void vprintf(const char* fmt, va_list ap) {
1360 char* temp;
1361 int numChars = vasprintf(&temp, fmt, ap);
1362 memcpy(ensure(numChars), temp, numChars+1);
1363 free(temp);
1364 }
1365
Jack Palevich303d8ff2009-06-11 19:06:24 -07001366 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001367 return mUsed;
1368 }
1369
1370 private:
1371 char* ensure(int n) {
1372 size_t newUsed = mUsed + n;
1373 if (newUsed > mSize) {
1374 size_t newSize = mSize * 2 + 10;
1375 if (newSize < newUsed) {
1376 newSize = newUsed;
1377 }
1378 mpBase = (char*) realloc(mpBase, newSize + 1);
1379 mSize = newSize;
1380 }
1381 mpBase[newUsed] = '\0';
1382 char* result = mpBase + mUsed;
1383 mUsed = newUsed;
1384 return result;
1385 }
1386
1387 char* mpBase;
1388 size_t mUsed;
1389 size_t mSize;
1390 };
1391
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001392 /**
1393 * Wrap an externally allocated string for use as a hash key.
1394 */
1395 class FakeString : public String {
1396 public:
Jack Palevich2db168f2009-06-11 14:29:47 -07001397 FakeString(const char* string, size_t length) :
1398 String((char*) string, length, true) {}
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001399
1400 ~FakeString() {
1401 orphan();
1402 }
1403 };
1404
1405 template<class V> class StringTable {
1406 public:
Jack Palevich303d8ff2009-06-11 19:06:24 -07001407 StringTable() {
1408 init(10);
1409 }
1410
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001411 StringTable(size_t initialCapacity) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001412 init(initialCapacity);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001413 }
1414
1415 ~StringTable() {
1416 clear();
Jack Palevich2db168f2009-06-11 14:29:47 -07001417 hashmapFree(mpMap);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001418 }
1419
1420 void clear() {
1421 hashmapForEach(mpMap, freeKeyValue, this);
1422 }
1423
1424 bool contains(String* pKey) {
1425 bool result = hashmapContainsKey(mpMap, pKey);
1426 return result;
1427 }
1428
1429 V* get(String* pKey) {
1430 V* result = (V*) hashmapGet(mpMap, pKey);
1431 return result;
1432 }
1433
1434 V* remove(String* pKey) {
1435 V* result = (V*) hashmapRemove(mpMap, pKey);
1436 return result;
1437 }
1438
1439 V* put(String* pKey, V* value) {
1440 V* result = (V*) hashmapPut(mpMap, pKey, value);
1441 if (result) {
1442 // The key was not adopted by the map, so delete it here.
1443 delete pKey;
1444 }
1445 return result;
1446 }
1447
Jack Palevicha6baa232009-06-12 11:25:59 -07001448 void forEach(bool (*callback)(String* key, V* value, void* context),
1449 void* context) {
1450 hashmapForEach(mpMap, (bool (*)(void*, void*, void*)) callback,
1451 context);
1452 }
1453
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001454 protected:
Jack Palevich303d8ff2009-06-11 19:06:24 -07001455
1456 void init(size_t initialCapacity) {
1457 mpMap = hashmapCreate(initialCapacity, hashFn, equalsFn);
1458 }
1459
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001460 static int hashFn(void* pKey) {
1461 String* pString = (String*) pKey;
1462 return hashmapHash(pString->getUnwrapped(), pString->len());
1463 }
1464
1465 static bool equalsFn(void* keyA, void* keyB) {
1466 String* pStringA = (String*) keyA;
1467 String* pStringB = (String*) keyB;
1468 return pStringA->len() == pStringB->len()
1469 && strcmp(pStringA->getUnwrapped(), pStringB->getUnwrapped())
1470 == 0;
1471 }
1472
1473 static bool freeKeyValue(void* key, void* value, void* context) {
1474 delete (String*) key;
1475 delete (V*) value;
1476 return true;
1477 }
1478
1479 Hashmap* mpMap;
1480 };
1481
1482 class MacroTable : public StringTable<String> {
1483 public:
1484 MacroTable() : StringTable<String>(10) {}
1485 };
1486
Jack Palevich2db168f2009-06-11 14:29:47 -07001487 class KeywordTable {
1488 public:
1489
1490 KeywordTable(){
1491 mpMap = hashmapCreate(40, hashFn, equalsFn);
1492 put("int", TOK_INT);
1493 put("char", TOK_CHAR);
1494 put("void", TOK_VOID);
1495 put("if", TOK_IF);
1496 put("else", TOK_ELSE);
1497 put("while", TOK_WHILE);
1498 put("break", TOK_BREAK);
1499 put("return", TOK_RETURN);
1500 put("for", TOK_FOR);
Jack Palevich2ccc40d2009-06-12 11:53:07 -07001501 // TODO: remove these preprocessor-specific keywords. You should
1502 // be able to have symbols named pragma or define.
Jack Palevich2db168f2009-06-11 14:29:47 -07001503 put("pragma", TOK_PRAGMA);
Jack Palevich2ccc40d2009-06-12 11:53:07 -07001504 put("define", TOK_DEFINE);
Jack Palevichf1728be2009-06-12 13:53:51 -07001505
1506 const char* unsupported[] = {
1507 "auto",
1508 "case",
1509 "const",
1510 "continue",
1511 "default",
1512 "do",
1513 "double",
1514 "enum",
1515 "extern",
1516 "float",
1517 "goto",
1518 "long",
1519 "register",
1520 "short",
1521 "signed",
1522 "sizeof",
1523 "static",
1524 "struct",
1525 "switch",
1526 "typedef",
1527 "union",
1528 "unsigned",
1529 "volatile",
1530 "_Bool",
1531 "_Complex",
1532 "_Imaginary",
1533 "inline",
1534 "restrict",
1535 0};
1536
1537 for(int i = 0; unsupported[i]; i++) {
1538 put(unsupported[i], TOK_UNSUPPORTED_KEYWORD);
1539 }
Jack Palevich2db168f2009-06-11 14:29:47 -07001540 }
1541
1542 ~KeywordTable() {
1543 hashmapFree(mpMap);
1544 }
1545
Jack Palevich303d8ff2009-06-11 19:06:24 -07001546 int get(String* key) {
1547 return (int) hashmapGet(mpMap, key->getUnwrapped());
Jack Palevich2db168f2009-06-11 14:29:47 -07001548 }
1549
1550 const char* lookupKeyFor(int value) {
1551 FindValContext context;
1552 context.key = 0;
1553 hashmapForEach(mpMap, findKeyFn, &context);
1554 return context.key;
1555 }
1556
1557 private:
1558 void put(const char* kw, int val) {
1559 hashmapPut(mpMap, (void*) kw, (void*) val);
1560 }
1561
1562 static int hashFn(void* pKey) {
1563 char* pString = (char*) pKey;
1564 return hashmapHash(pString, strlen(pString));
1565 }
1566
1567 static bool equalsFn(void* keyA, void* keyB) {
1568 const char* pStringA = (const char*) keyA;
1569 const char* pStringB = (const char*) keyB;
1570 return strcmp(pStringA, pStringB) == 0;
1571 }
1572
1573 struct FindValContext {
1574 char* key;
1575 int value;
1576 };
1577
1578 static bool findKeyFn(void* key, void* value, void* context) {
1579 FindValContext* pContext = (FindValContext*) context;
1580 if ((int) value == pContext->value) {
1581 pContext->key = (char*) key;
1582 return false;
1583 }
1584 return true;
1585 }
1586
1587 Hashmap* mpMap;
1588 };
1589
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001590 template<class E> class Array {
1591 public:
1592 Array() {
1593 mpBase = 0;
1594 mUsed = 0;
1595 mSize = 0;
1596 }
1597
1598 ~Array() {
1599 if (mpBase) {
1600 free(mpBase);
1601 }
1602 }
1603
1604 E get(int i) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001605 if (i < 0 || i > (int) mUsed) {
1606 // error("internal error: Index out of range");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001607 return E();
1608 }
1609 return mpBase[i];
1610 }
1611
1612 void set(int i, E val) {
1613 mpBase[i] = val;
1614 }
1615
1616 void pop() {
1617 if (mUsed > 0) {
1618 mUsed -= 1;
Jack Palevich36d94142009-06-08 15:55:32 -07001619 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001620 // error("internal error: Popped empty stack.");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001621 }
1622 }
1623
1624 void push(E item) {
1625 * ensure(1) = item;
1626 }
1627
1628 size_t len() {
1629 return mUsed;
1630 }
1631
1632 private:
1633 E* ensure(int n) {
1634 size_t newUsed = mUsed + n;
1635 if (newUsed > mSize) {
1636 size_t newSize = mSize * 2 + 10;
1637 if (newSize < newUsed) {
1638 newSize = newUsed;
1639 }
1640 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1641 mSize = newSize;
1642 }
1643 E* result = mpBase + mUsed;
1644 mUsed = newUsed;
1645 return result;
1646 }
1647
1648 E* mpBase;
1649 size_t mUsed;
1650 size_t mSize;
1651 };
1652
Jack Palevich36d94142009-06-08 15:55:32 -07001653 struct InputState {
1654 InputStream* pStream;
1655 int oldCh;
1656 };
1657
Jack Palevich2db168f2009-06-11 14:29:47 -07001658 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001659 VariableInfo() {
1660 pAddress = 0;
1661 pForward = 0;
1662 }
1663 void* pAddress;
1664 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich2db168f2009-06-11 14:29:47 -07001665 };
1666
Jack Palevich303d8ff2009-06-11 19:06:24 -07001667 typedef StringTable<VariableInfo> SymbolTable;
1668
1669 class SymbolStack {
1670 public:
1671 SymbolStack() {
1672 mLevel = 0;
1673 addEntry();
1674 }
1675
1676 void pushLevel() {
1677 mLevel++;
1678 }
1679
1680 void popLevel() {
1681 mLevel--;
1682 Entry e = mStack.get(mStack.len()-1);
1683 if (mLevel < e.level) {
1684 mStack.pop();
1685 delete e.pTable;
1686 }
1687 }
1688
1689 VariableInfo* get(String* pName) {
1690 int len = mStack.len();
1691 VariableInfo* v = NULL;
1692 int level = -1;
1693 for (int i = len - 1; i >= 0; i--) {
1694 Entry e = mStack.get(i);
1695 v = e.pTable->get(pName);
1696 if (v) {
1697 level = e.level;
1698 break;
1699 }
1700 }
1701#if 0
1702 fprintf(stderr, "Lookup %s %08x level %d\n", pName->getUnwrapped(), v, level);
1703 if (v) {
1704 fprintf(stderr, " %08x %08x\n", v->pAddress, v->pForward);
1705 }
1706#endif
1707 return v;
1708 }
1709
1710 VariableInfo* addLocal(String* pName) {
1711 int len = mStack.len();
1712 if (mStack.get(len-1).level != mLevel) {
1713 addEntry();
1714 len++;
1715 }
1716 return addImp(len-1, pName);
1717 }
1718
1719 VariableInfo* addGlobal(String* pName) {
1720 return addImp(0, pName);
1721 }
1722
Jack Palevicha6baa232009-06-12 11:25:59 -07001723 void forEachGlobal(
1724 bool (*callback)(String* key, VariableInfo* value, void* context),
1725 void* context) {
1726 mStack.get(0).pTable->forEach(callback, context);
1727 }
1728
Jack Palevich303d8ff2009-06-11 19:06:24 -07001729 private:
1730 VariableInfo* addImp(int entryIndex, String* pName) {
1731 Entry e = mStack.get(entryIndex);
1732 SymbolTable* pTable = e.pTable;
Jack Palevicha6baa232009-06-12 11:25:59 -07001733 if (pTable->contains(pName)) {
1734 return NULL;
1735 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07001736 VariableInfo* v = new VariableInfo();
Jack Palevicha6baa232009-06-12 11:25:59 -07001737
Jack Palevich303d8ff2009-06-11 19:06:24 -07001738 delete pTable->put(pName, v);
1739#if 0
1740 fprintf(stderr, "Add \"%s\" %08x level %d\n", pName->getUnwrapped(), v, e.level);
1741#endif
1742 return v;
1743 }
1744
1745 void addEntry() {
1746 Entry e;
1747 e.level = mLevel;
1748 e.pTable = new SymbolTable();
1749 mStack.push(e);
1750 }
1751
1752 struct Entry {
1753 Entry() {
1754 level = 0;
1755 pTable = NULL;
1756 }
1757 int level;
1758 SymbolTable* pTable;
1759 };
1760
1761 int mLevel;
1762 Array<Entry> mStack;
1763 };
Jack Palevich36d94142009-06-08 15:55:32 -07001764
1765 int ch; // Current input character, or EOF
1766 intptr_t tok; // token
1767 intptr_t tokc; // token extra info
1768 int tokl; // token operator level
1769 intptr_t rsym; // return symbol
1770 intptr_t loc; // local variable index
1771 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07001772 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07001773 char* dptr; // Macro state: Points to macro text during macro playback.
1774 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07001775 char* pGlobalBase;
Jack Palevich2db168f2009-06-11 14:29:47 -07001776 KeywordTable mKeywords;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001777 SymbolStack mSymbolTable;
Jack Palevich36d94142009-06-08 15:55:32 -07001778 InputStream* file;
1779
1780 CodeBuf codeBuf;
1781 CodeGenerator* pGen;
1782
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001783 MacroTable mMacros;
Jack Palevich36d94142009-06-08 15:55:32 -07001784 Array<InputState> mInputStateStack;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001785
Jack Palevicheedf9d22009-06-04 16:23:40 -07001786 String mErrorBuf;
1787
Jack Palevicheedf9d22009-06-04 16:23:40 -07001788 String mPragmas;
1789 int mPragmaStringCount;
1790
Jack Palevich21a15a22009-05-11 14:49:29 -07001791 static const int ALLOC_SIZE = 99999;
1792
Jack Palevich303d8ff2009-06-11 19:06:24 -07001793 static const int TOK_DUMMY = 1;
1794 static const int TOK_NUM = 2;
1795
1796 // 3..255 are character and/or operators
1797
Jack Palevich2db168f2009-06-11 14:29:47 -07001798 // Keywords start at 0x100 and increase by 1
1799 static const int TOK_KEYWORD = 0x100;
1800 static const int TOK_INT = TOK_KEYWORD + 0;
1801 static const int TOK_CHAR = TOK_KEYWORD + 1;
1802 static const int TOK_VOID = TOK_KEYWORD + 2;
1803 static const int TOK_IF = TOK_KEYWORD + 3;
1804 static const int TOK_ELSE = TOK_KEYWORD + 4;
1805 static const int TOK_WHILE = TOK_KEYWORD + 5;
1806 static const int TOK_BREAK = TOK_KEYWORD + 6;
1807 static const int TOK_RETURN = TOK_KEYWORD + 7;
1808 static const int TOK_FOR = TOK_KEYWORD + 8;
1809 static const int TOK_PRAGMA = TOK_KEYWORD + 9;
1810 static const int TOK_DEFINE = TOK_KEYWORD + 10;
Jack Palevichf1728be2009-06-12 13:53:51 -07001811 static const int TOK_UNSUPPORTED_KEYWORD = TOK_KEYWORD + 0xff;
Jack Palevich2db168f2009-06-11 14:29:47 -07001812
Jack Palevich303d8ff2009-06-11 19:06:24 -07001813 static const int TOK_UNDEFINED_SYMBOL = 0x200;
Jack Palevich21a15a22009-05-11 14:49:29 -07001814
Jack Palevich303d8ff2009-06-11 19:06:24 -07001815 // Symbols start at 0x300, but are really pointers to VariableInfo structs.
1816 static const int TOK_SYMBOL = 0x300;
1817
Jack Palevich21a15a22009-05-11 14:49:29 -07001818
1819 static const int LOCAL = 0x200;
1820
1821 static const int SYM_FORWARD = 0;
1822 static const int SYM_DEFINE = 1;
1823
1824 /* tokens in string heap */
1825 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07001826
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001827 static const int OP_INCREMENT = 0;
1828 static const int OP_DECREMENT = 1;
1829 static const int OP_MUL = 2;
1830 static const int OP_DIV = 3;
1831 static const int OP_MOD = 4;
1832 static const int OP_PLUS = 5;
1833 static const int OP_MINUS = 6;
1834 static const int OP_SHIFT_LEFT = 7;
1835 static const int OP_SHIFT_RIGHT = 8;
1836 static const int OP_LESS_EQUAL = 9;
1837 static const int OP_GREATER_EQUAL = 10;
1838 static const int OP_LESS = 11;
1839 static const int OP_GREATER = 12;
1840 static const int OP_EQUALS = 13;
1841 static const int OP_NOT_EQUALS = 14;
1842 static const int OP_LOGICAL_AND = 15;
1843 static const int OP_LOGICAL_OR = 16;
1844 static const int OP_BIT_AND = 17;
1845 static const int OP_BIT_XOR = 18;
1846 static const int OP_BIT_OR = 19;
1847 static const int OP_BIT_NOT = 20;
1848 static const int OP_LOGICAL_NOT = 21;
1849 static const int OP_COUNT = 22;
1850
1851 /* Operators are searched from front, the two-character operators appear
1852 * before the single-character operators with the same first character.
1853 * @ is used to pad out single-character operators.
1854 */
1855 static const char* operatorChars;
1856 static const char operatorLevel[];
1857
Jack Palevich21a15a22009-05-11 14:49:29 -07001858 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001859 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001860 }
1861
1862 void inp() {
1863 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001864 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001865 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001866 dptr = 0;
1867 ch = dch;
1868 }
1869 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07001870 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001871#if 0
1872 printf("ch='%c' 0x%x\n", ch, ch);
1873#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07001874 }
1875
1876 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07001877 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07001878 }
1879
Jack Palevichb4758ff2009-06-12 12:49:14 -07001880 /* read a character constant, advances ch to after end of constant */
1881 int getq() {
1882 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07001883 if (ch == '\\') {
1884 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07001885 if (isoctal(ch)) {
1886 // 1 to 3 octal characters.
1887 val = 0;
1888 for(int i = 0; i < 3; i++) {
1889 if (isoctal(ch)) {
1890 val = (val << 3) + ch - '0';
1891 inp();
1892 }
1893 }
1894 return val;
1895 } else if (ch == 'x' || ch == 'X') {
1896 // N hex chars
1897 inp();
1898 if (! isxdigit(ch)) {
1899 error("'x' character escape requires at least one digit.");
1900 } else {
1901 val = 0;
1902 while (isxdigit(ch)) {
1903 int d = ch;
1904 if (isdigit(d)) {
1905 d -= '0';
1906 } else if (d <= 'F') {
1907 d = d - 'A' + 10;
1908 } else {
1909 d = d - 'a' + 10;
1910 }
1911 val = (val << 4) + d;
1912 inp();
1913 }
1914 }
1915 } else {
1916 int val = ch;
1917 switch (ch) {
1918 case 'a':
1919 val = '\a';
1920 break;
1921 case 'b':
1922 val = '\b';
1923 break;
1924 case 'f':
1925 val = '\f';
1926 break;
1927 case 'n':
1928 val = '\n';
1929 break;
1930 case 'r':
1931 val = '\r';
1932 break;
1933 case 't':
1934 val = '\t';
1935 break;
1936 case 'v':
1937 val = '\v';
1938 break;
1939 case '\\':
1940 val = '\\';
1941 break;
1942 case '\'':
1943 val = '\'';
1944 break;
1945 case '"':
1946 val = '"';
1947 break;
1948 case '?':
1949 val = '?';
1950 break;
1951 default:
1952 error("Undefined character escape %c", ch);
1953 break;
1954 }
1955 inp();
1956 return val;
1957 }
1958 } else {
1959 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07001960 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07001961 return val;
1962 }
1963
1964 static bool isoctal(int ch) {
1965 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07001966 }
1967
1968 void next() {
1969 int l, a;
1970
Jack Palevich546b2242009-05-13 15:10:04 -07001971 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001972 if (ch == '#') {
1973 inp();
1974 next();
1975 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001976 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07001977 } else if (tok == TOK_PRAGMA) {
1978 doPragma();
1979 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001980 error("Unsupported preprocessor directive \"%s\"",
1981 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07001982 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001983 }
1984 inp();
1985 }
1986 tokl = 0;
1987 tok = ch;
1988 /* encode identifiers & numbers */
1989 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001990 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07001991 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001992 pdef(ch);
1993 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001994 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001995 if (isdigit(tok)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001996 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001997 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001998 } else {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001999 // Is this a macro?
Jack Palevich303d8ff2009-06-11 19:06:24 -07002000 String* pValue = mMacros.get(&mTokenString);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002001 if (pValue) {
2002 // Yes, it is a macro
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002003 dptr = pValue->getUnwrapped();
2004 dch = ch;
2005 inp();
2006 next();
2007 } else {
Jack Palevich2db168f2009-06-11 14:29:47 -07002008 // Is this a keyword?
Jack Palevich303d8ff2009-06-11 19:06:24 -07002009 int kwtok = mKeywords.get(&mTokenString);
Jack Palevich2db168f2009-06-11 14:29:47 -07002010 if (kwtok) {
2011 tok = kwtok;
2012 // fprintf(stderr, "tok= keyword %s %x\n", last_id, tok);
2013 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002014 tok = (intptr_t) mSymbolTable.get(&mTokenString);
2015 if (!tok) {
2016 tok = TOK_UNDEFINED_SYMBOL;
2017 }
Jack Palevich2db168f2009-06-11 14:29:47 -07002018 // fprintf(stderr, "tok= symbol %s %x\n", last_id, tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07002019 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002020 }
2021 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002022 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002023 inp();
2024 if (tok == '\'') {
2025 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002026 tokc = getq();
2027 if (ch != '\'') {
2028 error("Expected a ' character, got %c", ch);
2029 } else {
2030 inp();
2031 }
Jack Palevich546b2242009-05-13 15:10:04 -07002032 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002033 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002034 while (ch && ch != EOF) {
2035 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002036 inp();
2037 inp();
2038 if (ch == '/')
2039 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002040 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002041 if (ch == EOF) {
2042 error("End of file inside comment.");
2043 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002044 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002045 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002046 } else if ((tok == '/') & (ch == '/')) {
2047 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002048 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002049 inp();
2050 }
2051 inp();
2052 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002053 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002054 const char* t = operatorChars;
2055 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002056 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002057 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002058 tokl = operatorLevel[opIndex];
2059 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002060 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002061#if 0
2062 printf("%c%c -> tokl=%d tokc=0x%x\n",
2063 l, a, tokl, tokc);
2064#endif
2065 if (a == ch) {
2066 inp();
2067 tok = TOK_DUMMY; /* dummy token for double tokens */
2068 }
2069 break;
2070 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002071 opIndex++;
2072 }
2073 if (l == 0) {
2074 tokl = 0;
2075 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002076 }
2077 }
2078 }
2079#if 0
2080 {
Jack Palevich2db168f2009-06-11 14:29:47 -07002081 const char* p;
Jack Palevich21a15a22009-05-11 14:49:29 -07002082
2083 printf("tok=0x%x ", tok);
Jack Palevich2db168f2009-06-11 14:29:47 -07002084 if (tok >= TOK_KEYWORD) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002085 printf("'");
Jack Palevich2db168f2009-06-11 14:29:47 -07002086 if (tok>= TOK_SYMBOL)
2087 p = sym_stk + 1 + ((char*) tok - (char*) pVarsBase) / 8;
2088 else {
2089 p = mKeywords.lookupKeyFor(tok);
2090 if (!p) {
2091 p = "unknown keyword";
2092 }
2093 }
Jack Palevich653f42d2009-05-28 17:15:32 -07002094 while (*p != TAG_TOK && *p)
2095 printf("%c", *p++);
Jack Palevich21a15a22009-05-11 14:49:29 -07002096 printf("'\n");
2097 } else if (tok == TOK_NUM) {
2098 printf("%d\n", tokc);
2099 } else {
2100 printf("'%c'\n", tok);
2101 }
2102 }
2103#endif
2104 }
2105
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002106 void doDefine() {
2107 String* pName = new String();
2108 while (isspace(ch)) {
2109 inp();
2110 }
2111 while (isid()) {
2112 pName->append(ch);
2113 inp();
2114 }
2115 if (ch == '(') {
2116 delete pName;
2117 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002118 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002119 }
2120 while (isspace(ch)) {
2121 inp();
2122 }
2123 String* pValue = new String();
2124 while (ch != '\n' && ch != EOF) {
2125 pValue->append(ch);
2126 inp();
2127 }
2128 delete mMacros.put(pName, pValue);
2129 }
2130
Jack Palevicheedf9d22009-06-04 16:23:40 -07002131 void doPragma() {
2132 // # pragma name(val)
2133 int state = 0;
2134 while(ch != EOF && ch != '\n' && state < 10) {
2135 switch(state) {
2136 case 0:
2137 if (isspace(ch)) {
2138 inp();
2139 } else {
2140 state++;
2141 }
2142 break;
2143 case 1:
2144 if (isalnum(ch)) {
2145 mPragmas.append(ch);
2146 inp();
2147 } else if (ch == '(') {
2148 mPragmas.append(0);
2149 inp();
2150 state++;
2151 } else {
2152 state = 11;
2153 }
2154 break;
2155 case 2:
2156 if (isalnum(ch)) {
2157 mPragmas.append(ch);
2158 inp();
2159 } else if (ch == ')') {
2160 mPragmas.append(0);
2161 inp();
2162 state = 10;
2163 } else {
2164 state = 11;
2165 }
2166 break;
2167 }
2168 }
2169 if(state != 10) {
2170 error("Unexpected pragma syntax");
2171 }
2172 mPragmaStringCount += 2;
2173 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002174
Jack Palevichac0e95e2009-05-29 13:53:44 -07002175 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002176 mErrorBuf.printf("%ld: ", file->getLine());
2177 mErrorBuf.vprintf(fmt, ap);
2178 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002179 }
2180
Jack Palevich8b0624c2009-05-20 12:12:06 -07002181 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002182 if (tok != c) {
2183 error("'%c' expected", c);
2184 }
2185 next();
2186 }
2187
Jack Palevich21a15a22009-05-11 14:49:29 -07002188 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07002189 void unary(intptr_t l) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002190 intptr_t n, t, a;
2191 int c;
Jack Palevicha6baa232009-06-12 11:25:59 -07002192 String tString;
Jack Palevich546b2242009-05-13 15:10:04 -07002193 t = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002194 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
Jack Palevich21a15a22009-05-11 14:49:29 -07002195 if (tok == '\"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07002196 pGen->li((int) glo);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002197 while (ch != '\"' && ch != EOF) {
2198 *allocGlobalSpace(1) = getq();
2199 }
2200 if (ch != '\"') {
2201 error("Unterminated string constant.");
Jack Palevich21a15a22009-05-11 14:49:29 -07002202 }
Jack Palevich653f42d2009-05-28 17:15:32 -07002203 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002204 /* align heap */
2205 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07002206 inp();
2207 next();
2208 } else {
2209 c = tokl;
2210 a = tokc;
2211 t = tok;
Jack Palevicha6baa232009-06-12 11:25:59 -07002212 tString = mTokenString;
Jack Palevich21a15a22009-05-11 14:49:29 -07002213 next();
2214 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002215 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002216 } else if (c == 2) {
2217 /* -, +, !, ~ */
2218 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07002219 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002220 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002221 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002222 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002223 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002224 } else if (t == '(') {
2225 expr();
2226 skip(')');
2227 } else if (t == '*') {
2228 /* parse cast */
2229 skip('(');
2230 t = tok; /* get type */
2231 next(); /* skip int/char/void */
2232 next(); /* skip '*' or '(' */
2233 if (tok == '*') {
2234 /* function type */
2235 skip('*');
2236 skip(')');
2237 skip('(');
2238 skip(')');
2239 t = 0;
2240 }
2241 skip(')');
2242 unary(0);
2243 if (tok == '=') {
2244 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07002245 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002246 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002247 pGen->popR1();
2248 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002249 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002250 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002251 }
2252 } else if (t == '&') {
Jack Palevich1cdef202009-05-22 12:06:27 -07002253 pGen->leaR0(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07002254 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002255 } else if (t == EOF ) {
2256 error("Unexpected EOF.");
2257 } else if (t < TOK_UNDEFINED_SYMBOL) {
2258 error("Unexpected symbol or keyword");
Jack Palevich21a15a22009-05-11 14:49:29 -07002259 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002260 if (t == TOK_UNDEFINED_SYMBOL) {
2261 t = (intptr_t) mSymbolTable.addGlobal(
Jack Palevicha6baa232009-06-12 11:25:59 -07002262 new String(tString));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002263 }
2264
Jack Palevicha6baa232009-06-12 11:25:59 -07002265 n = (intptr_t) ((VariableInfo*) t)->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002266 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002267 if (!n) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002268 n = (intptr_t) dlsym(RTLD_DEFAULT,
Jack Palevicha6baa232009-06-12 11:25:59 -07002269 tString.getUnwrapped());
2270 ((VariableInfo*) t)->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002271 }
Jack Palevich546b2242009-05-13 15:10:04 -07002272 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002273 /* assignment */
2274 next();
2275 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002276 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002277 } else if (tok != '(') {
2278 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002279 if (!n) {
2280 error("Undefined variable %s", tString.getUnwrapped());
2281 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002282 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002283 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002284 next();
2285 }
2286 }
2287 }
2288 }
2289
2290 /* function call */
2291 if (tok == '(') {
2292 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002293 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002294
2295 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002296 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07002297 next();
2298 l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002299 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002300 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002301 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002302 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002303 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002304 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002305 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002306 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002307 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002308 if (!n) {
2309 /* forward reference */
2310 t = t + 4;
2311 *(int *) t = pGen->callForward(*(int *) t);
2312 } else if (n == 1) {
2313 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002314 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07002315 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07002316 }
Jack Palevich3d474a72009-05-15 15:12:38 -07002317 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07002318 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002319 }
2320 }
2321
Jack Palevich653f42d2009-05-28 17:15:32 -07002322 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002323 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002324 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002325 if (l-- == 1)
2326 unary(1);
2327 else {
2328 sum(l);
2329 a = 0;
2330 while (l == tokl) {
2331 n = tok;
2332 t = tokc;
2333 next();
2334
2335 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002336 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07002337 sum(l);
2338 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002339 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002340 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07002341 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002342
Jack Palevich546b2242009-05-13 15:10:04 -07002343 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002344 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002345 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002346 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002347 }
2348 }
2349 }
2350 /* && and || output code generation */
2351 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002352 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2353 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002354 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002355 pGen->gsym(a);
2356 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002357 }
2358 }
2359 }
2360
2361 void expr() {
2362 sum(11);
2363 }
2364
2365 int test_expr() {
2366 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002367 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002368 }
2369
Jack Palevicha6baa232009-06-12 11:25:59 -07002370 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002371 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002372
2373 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002374 next();
2375 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002376 a = test_expr();
2377 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002378 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002379 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002380 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002381 n = pGen->gjmp(0); /* jmp */
2382 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002383 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002384 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002385 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002386 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002387 }
Jack Palevich546b2242009-05-13 15:10:04 -07002388 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002389 t = tok;
2390 next();
2391 skip('(');
2392 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002393 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002394 a = test_expr();
2395 } else {
2396 if (tok != ';')
2397 expr();
2398 skip(';');
2399 n = codeBuf.getPC();
2400 a = 0;
2401 if (tok != ';')
2402 a = test_expr();
2403 skip(';');
2404 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002405 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002406 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002407 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002408 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002409 n = t + 4;
2410 }
2411 }
2412 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002413 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002414 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002415 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002416 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002417 if (! outermostFunctionBlock) {
2418 mSymbolTable.pushLevel();
2419 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 next();
2421 /* declarations */
Jack Palevichb7c81e92009-06-04 19:56:13 -07002422 localDeclarations();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002423 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002424 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002425 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002426 if (! outermostFunctionBlock) {
2427 mSymbolTable.popLevel();
2428 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002429 } else {
2430 if (tok == TOK_RETURN) {
2431 next();
2432 if (tok != ';')
2433 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002434 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002435 } else if (tok == TOK_BREAK) {
2436 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002437 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002438 } else if (tok != ';')
2439 expr();
2440 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002441 }
2442 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002443
Jack Palevichb7c81e92009-06-04 19:56:13 -07002444 typedef int Type;
2445 static const Type TY_UNKNOWN = 0;
2446 static const Type TY_INT = 1;
2447 static const Type TY_CHAR = 2;
2448 static const Type TY_VOID = 3;
2449 static const int TY_BASE_TYPE_MASK = 0xf;
2450 static const int TY_INDIRECTION_MASK = 0xf0;
2451 static const int TY_INDIRECTION_SHIFT = 4;
2452 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07002453
Jack Palevichb7c81e92009-06-04 19:56:13 -07002454 Type getBaseType(Type t) {
2455 return t & TY_BASE_TYPE_MASK;
2456 }
2457
2458 int getIndirectionCount(Type t) {
2459 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
2460 }
2461
2462 void setIndirectionCount(Type& t, int count) {
2463 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
2464 | (t & ~TY_INDIRECTION_MASK));
2465 }
2466
2467 bool acceptType(Type& t) {
2468 t = TY_UNKNOWN;
2469 if (tok == TOK_INT) {
2470 t = TY_INT;
2471 } else if (tok == TOK_CHAR) {
2472 t = TY_CHAR;
2473 } else if (tok == TOK_VOID) {
2474 t = TY_VOID;
2475 } else {
2476 return false;
2477 }
2478 next();
2479 return true;
2480 }
2481
2482 Type acceptPointerDeclaration(Type& base) {
2483 Type t = base;
2484 int indirectionCount = 0;
2485 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
2486 next();
2487 indirectionCount++;
2488 }
2489 if (indirectionCount > MAX_INDIRECTION_COUNT) {
2490 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
2491 }
2492 setIndirectionCount(t, indirectionCount);
2493 return t;
2494 }
2495
2496 void expectType(Type& t) {
2497 if (!acceptType(t)) {
2498 error("Expected a type.");
2499 }
2500 }
2501
Jack Palevicha6baa232009-06-12 11:25:59 -07002502 void addGlobalSymbol() {
2503 tok = (intptr_t) mSymbolTable.addGlobal(
2504 new String(mTokenString));
2505 reportIfDuplicate();
2506 }
2507
2508 void reportIfDuplicate() {
2509 if (!tok) {
2510 error("Duplicate definition of %s", mTokenString.getUnwrapped());
Jack Palevich303d8ff2009-06-11 19:06:24 -07002511 }
2512 }
2513
Jack Palevicha6baa232009-06-12 11:25:59 -07002514 void addLocalSymbol() {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002515 tok = (intptr_t) mSymbolTable.addLocal(
2516 new String(mTokenString));
Jack Palevicha6baa232009-06-12 11:25:59 -07002517 reportIfDuplicate();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002518 }
2519
Jack Palevichb7c81e92009-06-04 19:56:13 -07002520 void localDeclarations() {
2521 intptr_t a;
2522 Type base;
2523
2524 while (acceptType(base)) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002525 while (tok != ';' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002526 Type t = acceptPointerDeclaration(t);
Jack Palevichf1728be2009-06-12 13:53:51 -07002527 if (checkSymbol()) {
2528 addLocalSymbol();
2529 if (tok) {
2530 loc = loc + 4;
2531 *(int *) tok = -loc;
2532 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002533 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002534 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002535 if (tok == ',')
2536 next();
2537 }
2538 skip(';');
2539 }
2540 }
2541
Jack Palevichf1728be2009-06-12 13:53:51 -07002542 bool checkSymbol() {
2543 bool result = isSymbol();
2544 if (!result) {
2545 String temp;
2546 if (tok >= 0 && tok < 256) {
2547 temp.printf("char \'%c\'", tok);
2548 } else if (tok >= TOK_KEYWORD && tok < TOK_UNSUPPORTED_KEYWORD) {
2549 temp.printf("keyword \"%s\"", mTokenString.getUnwrapped());
2550 } else {
2551 temp.printf("reserved keyword \"%s\"",
2552 mTokenString.getUnwrapped());
2553 }
2554 error("Expected symbol. Got %s", temp.getUnwrapped());
2555 }
2556 return result;
2557 }
2558
2559 /* Is a possibly undefined symbol */
2560 bool isSymbol() {
2561 return tok < EOF || tok >= TOK_UNDEFINED_SYMBOL;
2562 }
2563
Jack Palevichb7c81e92009-06-04 19:56:13 -07002564 void globalDeclarations() {
2565 while (tok != EOF) {
2566 Type base;
2567 expectType(base);
2568 Type t = acceptPointerDeclaration(t);
Jack Palevichf1728be2009-06-12 13:53:51 -07002569 if (tok >= 0 && tok < TOK_UNDEFINED_SYMBOL) {
2570 error("Unexpected token %d", tok);
2571 break;
2572 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002573 if (tok == TOK_UNDEFINED_SYMBOL) {
2574 addGlobalSymbol();
2575 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002576 VariableInfo* name = (VariableInfo*) tok;
Jack Palevicha6baa232009-06-12 11:25:59 -07002577 if (name && name->pAddress) {
2578 error("Already defined global %s",
2579 mTokenString.getUnwrapped());
2580 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002581 next();
2582 if (tok == ',' || tok == ';') {
2583 // it's a variable declaration
2584 for(;;) {
Jack Palevicha6baa232009-06-12 11:25:59 -07002585 if (name) {
2586 name->pAddress = (int*) allocGlobalSpace(4);
2587 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002588 if (tok != ',') {
2589 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07002590 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002591 skip(',');
Jack Palevichb7c81e92009-06-04 19:56:13 -07002592 t = acceptPointerDeclaration(t);
Jack Palevicha6baa232009-06-12 11:25:59 -07002593 addGlobalSymbol();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002594 name = (VariableInfo*) tok;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002595 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002596 }
2597 skip(';');
2598 } else {
Jack Palevicha6baa232009-06-12 11:25:59 -07002599 if (name) {
2600 /* patch forward references (XXX: does not work for function
2601 pointers) */
2602 pGen->gsym((int) name->pForward);
2603 /* put function address */
2604 name->pAddress = (void*) codeBuf.getPC();
2605 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002606 skip('(');
Jack Palevich303d8ff2009-06-11 19:06:24 -07002607 mSymbolTable.pushLevel();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002608 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07002609 int argCount = 0;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002610 while (tok != ')' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002611 Type aType;
2612 expectType(aType);
2613 aType = acceptPointerDeclaration(aType);
Jack Palevichf1728be2009-06-12 13:53:51 -07002614 if (checkSymbol()) {
2615 addLocalSymbol();
2616 if (tok) {
2617 /* read param name and compute offset */
2618 *(int *) tok = a;
2619 a = a + 4;
2620 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002621 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002622 next();
2623 if (tok == ',')
2624 next();
Jack Palevich546b2242009-05-13 15:10:04 -07002625 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07002626 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002627 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002628 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002629 a = pGen->functionEntry(argCount);
Jack Palevicha6baa232009-06-12 11:25:59 -07002630 block(0, true);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002631 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07002632 pGen->functionExit(argCount, a, loc);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002633 mSymbolTable.popLevel();
Jack Palevich21a15a22009-05-11 14:49:29 -07002634 }
2635 }
2636 }
2637
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002638 char* allocGlobalSpace(int bytes) {
2639 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
2640 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07002641 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002642 }
2643 char* result = glo;
2644 glo += bytes;
2645 return result;
2646 }
2647
Jack Palevich21a15a22009-05-11 14:49:29 -07002648 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002649 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002650 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07002651 pGlobalBase = 0;
2652 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002653 if (pGen) {
2654 delete pGen;
2655 pGen = 0;
2656 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002657 if (file) {
2658 delete file;
2659 file = 0;
2660 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002661 }
2662
2663 void clear() {
2664 tok = 0;
2665 tokc = 0;
2666 tokl = 0;
2667 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002668 rsym = 0;
2669 loc = 0;
2670 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002671 dptr = 0;
2672 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002673 file = 0;
2674 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002675 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002676 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002677 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002678
Jack Palevich22305132009-05-13 10:58:45 -07002679 void setArchitecture(const char* architecture) {
2680 delete pGen;
2681 pGen = 0;
2682
2683 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002684#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002685 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002686 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002687 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002688#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07002689#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002690 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002691 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002692 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002693#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07002694 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002695 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07002696 }
2697 }
2698
2699 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002700#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07002701 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07002702#elif defined(DEFAULT_X86_CODEGEN)
2703 pGen = new X86CodeGenerator();
2704#endif
2705 }
2706 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002707 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07002708 } else {
2709 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07002710 }
2711 }
2712
Jack Palevich77ae76e2009-05-10 19:59:24 -07002713public:
Jack Palevich22305132009-05-13 10:58:45 -07002714 struct args {
2715 args() {
2716 architecture = 0;
2717 }
2718 const char* architecture;
2719 };
2720
Jack Paleviche7b59062009-05-19 17:12:17 -07002721 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002722 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002723 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002724
Jack Paleviche7b59062009-05-19 17:12:17 -07002725 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002726 cleanup();
2727 }
2728
Jack Palevich1cdef202009-05-22 12:06:27 -07002729 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002730 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07002731
2732 cleanup();
2733 clear();
2734 codeBuf.init(ALLOC_SIZE);
2735 setArchitecture(NULL);
2736 if (!pGen) {
2737 return -1;
2738 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002739#ifdef PROVIDE_TRACE_CODEGEN
2740 pGen = new TraceCodeGenerator(pGen);
2741#endif
2742 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07002743 pGen->init(&codeBuf);
2744 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07002745 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
2746 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07002747 inp();
2748 next();
2749 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07002750 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07002751 result = pGen->finishCompile();
2752 if (result == 0) {
2753 if (mErrorBuf.len()) {
2754 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07002755 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07002756 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002757 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07002758 }
2759
Jack Palevicha6baa232009-06-12 11:25:59 -07002760 void checkForUndefinedForwardReferences() {
2761 mSymbolTable.forEachGlobal(static_ufrcFn, this);
2762 }
2763
2764 static bool static_ufrcFn(String* key, VariableInfo* value,
2765 void* context) {
2766 Compiler* pCompiler = (Compiler*) context;
2767 return pCompiler->undefinedForwardReferenceCheck(key, value);
2768 }
2769
2770 bool undefinedForwardReferenceCheck(String* key, VariableInfo* value) {
2771#if 0
2772 fprintf(stderr, "%s 0x%8x 0x%08x\n", key->getUnwrapped(),
2773 value->pAddress, value->pForward);
2774#endif
2775 if (!value->pAddress && value->pForward) {
2776 error("Undefined forward reference: %s", key->getUnwrapped());
2777 }
2778 return true;
2779 }
2780
Jack Palevich21a15a22009-05-11 14:49:29 -07002781 int dump(FILE* out) {
2782 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
2783 return 0;
2784 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07002785
Jack Palevicha6535612009-05-13 16:24:17 -07002786 int disassemble(FILE* out) {
2787 return pGen->disassemble(out);
2788 }
2789
Jack Palevich1cdef202009-05-22 12:06:27 -07002790 /* Look through the symbol table to find a symbol.
2791 * If found, return its value.
2792 */
2793 void* lookup(const char* name) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002794 String string(name, -1, false);
2795 VariableInfo* pVariableInfo = mSymbolTable.get(&string);
2796 if (pVariableInfo) {
2797 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07002798 }
2799 return NULL;
2800 }
2801
Jack Palevicheedf9d22009-06-04 16:23:40 -07002802 void getPragmas(ACCsizei* actualStringCount,
2803 ACCsizei maxStringCount, ACCchar** strings) {
2804 int stringCount = mPragmaStringCount;
2805 if (actualStringCount) {
2806 *actualStringCount = stringCount;
2807 }
2808 if (stringCount > maxStringCount) {
2809 stringCount = maxStringCount;
2810 }
2811 if (strings) {
2812 char* pPragmas = mPragmas.getUnwrapped();
2813 while (stringCount-- > 0) {
2814 *strings++ = pPragmas;
2815 pPragmas += strlen(pPragmas) + 1;
2816 }
2817 }
2818 }
2819
Jack Palevichac0e95e2009-05-29 13:53:44 -07002820 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002821 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002822 }
2823
Jack Palevich77ae76e2009-05-10 19:59:24 -07002824};
2825
Jack Paleviche7b59062009-05-19 17:12:17 -07002826const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002827 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2828
Jack Paleviche7b59062009-05-19 17:12:17 -07002829const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002830 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2831 5, 5, /* ==, != */
2832 9, 10, /* &&, || */
2833 6, 7, 8, /* & ^ | */
2834 2, 2 /* ~ ! */
2835 };
2836
Jack Palevich8b0624c2009-05-20 12:12:06 -07002837#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002838FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002839#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002840
Jack Palevich8b0624c2009-05-20 12:12:06 -07002841#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002842const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002843 0x1, // ++
2844 0xff, // --
2845 0xc1af0f, // *
2846 0xf9f79991, // /
2847 0xf9f79991, // % (With manual assist to swap results)
2848 0xc801, // +
2849 0xd8f7c829, // -
2850 0xe0d391, // <<
2851 0xf8d391, // >>
2852 0xe, // <=
2853 0xd, // >=
2854 0xc, // <
2855 0xf, // >
2856 0x4, // ==
2857 0x5, // !=
2858 0x0, // &&
2859 0x1, // ||
2860 0xc821, // &
2861 0xc831, // ^
2862 0xc809, // |
2863 0xd0f7, // ~
2864 0x4 // !
2865};
Jack Palevich8b0624c2009-05-20 12:12:06 -07002866#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002867
Jack Palevich1cdef202009-05-22 12:06:27 -07002868struct ACCscript {
2869 ACCscript() {
2870 text = 0;
2871 textLength = 0;
2872 accError = ACC_NO_ERROR;
2873 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002874
Jack Palevich1cdef202009-05-22 12:06:27 -07002875 ~ACCscript() {
2876 delete text;
2877 }
Jack Palevich546b2242009-05-13 15:10:04 -07002878
Jack Palevich1cdef202009-05-22 12:06:27 -07002879 void setError(ACCenum error) {
2880 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
2881 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002882 }
2883 }
2884
Jack Palevich1cdef202009-05-22 12:06:27 -07002885 ACCenum getError() {
2886 ACCenum result = accError;
2887 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07002888 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002889 }
2890
Jack Palevich1cdef202009-05-22 12:06:27 -07002891 Compiler compiler;
2892 char* text;
2893 int textLength;
2894 ACCenum accError;
2895};
2896
2897
2898extern "C"
2899ACCscript* accCreateScript() {
2900 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002901}
Jack Palevich1cdef202009-05-22 12:06:27 -07002902
2903extern "C"
2904ACCenum accGetError( ACCscript* script ) {
2905 return script->getError();
2906}
2907
2908extern "C"
2909void accDeleteScript(ACCscript* script) {
2910 delete script;
2911}
2912
2913extern "C"
2914void accScriptSource(ACCscript* script,
2915 ACCsizei count,
2916 const ACCchar ** string,
2917 const ACCint * length) {
2918 int totalLength = 0;
2919 for(int i = 0; i < count; i++) {
2920 int len = -1;
2921 const ACCchar* s = string[i];
2922 if (length) {
2923 len = length[i];
2924 }
2925 if (len < 0) {
2926 len = strlen(s);
2927 }
2928 totalLength += len;
2929 }
2930 delete script->text;
2931 char* text = new char[totalLength + 1];
2932 script->text = text;
2933 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07002934 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07002935 for(int i = 0; i < count; i++) {
2936 int len = -1;
2937 const ACCchar* s = string[i];
2938 if (length) {
2939 len = length[i];
2940 }
2941 if (len < 0) {
2942 len = strlen(s);
2943 }
Jack Palevich09555c72009-05-27 12:25:55 -07002944 memcpy(dest, s, len);
2945 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07002946 }
2947 text[totalLength] = '\0';
2948}
2949
2950extern "C"
2951void accCompileScript(ACCscript* script) {
2952 int result = script->compiler.compile(script->text, script->textLength);
2953 if (result) {
2954 script->setError(ACC_INVALID_OPERATION);
2955 }
2956}
2957
2958extern "C"
2959void accGetScriptiv(ACCscript* script,
2960 ACCenum pname,
2961 ACCint * params) {
2962 switch (pname) {
2963 case ACC_INFO_LOG_LENGTH:
2964 *params = 0;
2965 break;
2966 }
2967}
2968
2969extern "C"
2970void accGetScriptInfoLog(ACCscript* script,
2971 ACCsizei maxLength,
2972 ACCsizei * length,
2973 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002974 char* message = script->compiler.getErrorMessage();
2975 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07002976 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002977 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07002978 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002979 if (infoLog && maxLength > 0) {
2980 int trimmedLength = maxLength < messageLength ?
2981 maxLength : messageLength;
2982 memcpy(infoLog, message, trimmedLength);
2983 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002984 }
2985}
2986
2987extern "C"
2988void accGetScriptLabel(ACCscript* script, const ACCchar * name,
2989 ACCvoid ** address) {
2990 void* value = script->compiler.lookup(name);
2991 if (value) {
2992 *address = value;
2993 } else {
2994 script->setError(ACC_INVALID_VALUE);
2995 }
2996}
2997
Jack Palevicheedf9d22009-06-04 16:23:40 -07002998extern "C"
2999void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3000 ACCsizei maxStringCount, ACCchar** strings){
3001 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3002}
3003
3004
Jack Palevich1cdef202009-05-22 12:06:27 -07003005} // namespace acc
3006