blob: 7d14e3fdfa878623d03724128ca609b17621a558 [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.");
Jack Palevicha1804dd2009-06-12 14:40:04 -07002257 } else if (!checkSymbol(t, &tString)) {
2258 // Don't have to do anything special here, the error
2259 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002260 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002261 if (t == TOK_UNDEFINED_SYMBOL) {
2262 t = (intptr_t) mSymbolTable.addGlobal(
Jack Palevicha6baa232009-06-12 11:25:59 -07002263 new String(tString));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002264 }
2265
Jack Palevicha6baa232009-06-12 11:25:59 -07002266 n = (intptr_t) ((VariableInfo*) t)->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002267 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002268 if (!n) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002269 n = (intptr_t) dlsym(RTLD_DEFAULT,
Jack Palevicha6baa232009-06-12 11:25:59 -07002270 tString.getUnwrapped());
2271 ((VariableInfo*) t)->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002272 }
Jack Palevich546b2242009-05-13 15:10:04 -07002273 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002274 /* assignment */
2275 next();
2276 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002277 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002278 } else if (tok != '(') {
2279 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002280 if (!n) {
2281 error("Undefined variable %s", tString.getUnwrapped());
2282 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002283 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002284 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002285 next();
2286 }
2287 }
2288 }
2289 }
2290
2291 /* function call */
2292 if (tok == '(') {
2293 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002294 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002295
2296 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002297 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07002298 next();
2299 l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002300 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002301 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002302 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002303 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002304 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002305 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002306 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002307 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002308 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002309 if (!n) {
2310 /* forward reference */
2311 t = t + 4;
2312 *(int *) t = pGen->callForward(*(int *) t);
2313 } else if (n == 1) {
2314 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002315 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07002316 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07002317 }
Jack Palevich3d474a72009-05-15 15:12:38 -07002318 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07002319 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002320 }
2321 }
2322
Jack Palevich653f42d2009-05-28 17:15:32 -07002323 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002324 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002325 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002326 if (l-- == 1)
2327 unary(1);
2328 else {
2329 sum(l);
2330 a = 0;
2331 while (l == tokl) {
2332 n = tok;
2333 t = tokc;
2334 next();
2335
2336 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002337 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07002338 sum(l);
2339 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002340 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002341 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07002342 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002343
Jack Palevich546b2242009-05-13 15:10:04 -07002344 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002345 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002346 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002347 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002348 }
2349 }
2350 }
2351 /* && and || output code generation */
2352 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002353 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2354 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002355 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002356 pGen->gsym(a);
2357 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002358 }
2359 }
2360 }
2361
2362 void expr() {
2363 sum(11);
2364 }
2365
2366 int test_expr() {
2367 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002368 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002369 }
2370
Jack Palevicha6baa232009-06-12 11:25:59 -07002371 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002372 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002373
Jack Palevicha1804dd2009-06-12 14:40:04 -07002374 if (tok == TOK_INT || tok == TOK_CHAR) {
2375 /* declarations */
2376 localDeclarations();
2377 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002378 next();
2379 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002380 a = test_expr();
2381 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002382 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002383 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002384 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002385 n = pGen->gjmp(0); /* jmp */
2386 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002387 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002388 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002389 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002390 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002391 }
Jack Palevich546b2242009-05-13 15:10:04 -07002392 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002393 t = tok;
2394 next();
2395 skip('(');
2396 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002397 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002398 a = test_expr();
2399 } else {
2400 if (tok != ';')
2401 expr();
2402 skip(';');
2403 n = codeBuf.getPC();
2404 a = 0;
2405 if (tok != ';')
2406 a = test_expr();
2407 skip(';');
2408 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002409 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002410 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002411 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002412 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002413 n = t + 4;
2414 }
2415 }
2416 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002417 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002418 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002419 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002421 if (! outermostFunctionBlock) {
2422 mSymbolTable.pushLevel();
2423 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002424 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002425 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002426 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002427 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002428 if (! outermostFunctionBlock) {
2429 mSymbolTable.popLevel();
2430 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002431 } else {
2432 if (tok == TOK_RETURN) {
2433 next();
2434 if (tok != ';')
2435 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002436 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002437 } else if (tok == TOK_BREAK) {
2438 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002439 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002440 } else if (tok != ';')
2441 expr();
2442 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002443 }
2444 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002445
Jack Palevichb7c81e92009-06-04 19:56:13 -07002446 typedef int Type;
2447 static const Type TY_UNKNOWN = 0;
2448 static const Type TY_INT = 1;
2449 static const Type TY_CHAR = 2;
2450 static const Type TY_VOID = 3;
2451 static const int TY_BASE_TYPE_MASK = 0xf;
2452 static const int TY_INDIRECTION_MASK = 0xf0;
2453 static const int TY_INDIRECTION_SHIFT = 4;
2454 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07002455
Jack Palevichb7c81e92009-06-04 19:56:13 -07002456 Type getBaseType(Type t) {
2457 return t & TY_BASE_TYPE_MASK;
2458 }
2459
2460 int getIndirectionCount(Type t) {
2461 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
2462 }
2463
2464 void setIndirectionCount(Type& t, int count) {
2465 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
2466 | (t & ~TY_INDIRECTION_MASK));
2467 }
2468
2469 bool acceptType(Type& t) {
2470 t = TY_UNKNOWN;
2471 if (tok == TOK_INT) {
2472 t = TY_INT;
2473 } else if (tok == TOK_CHAR) {
2474 t = TY_CHAR;
2475 } else if (tok == TOK_VOID) {
2476 t = TY_VOID;
2477 } else {
2478 return false;
2479 }
2480 next();
2481 return true;
2482 }
2483
2484 Type acceptPointerDeclaration(Type& base) {
2485 Type t = base;
2486 int indirectionCount = 0;
2487 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
2488 next();
2489 indirectionCount++;
2490 }
2491 if (indirectionCount > MAX_INDIRECTION_COUNT) {
2492 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
2493 }
2494 setIndirectionCount(t, indirectionCount);
2495 return t;
2496 }
2497
2498 void expectType(Type& t) {
2499 if (!acceptType(t)) {
2500 error("Expected a type.");
2501 }
2502 }
2503
Jack Palevicha6baa232009-06-12 11:25:59 -07002504 void addGlobalSymbol() {
2505 tok = (intptr_t) mSymbolTable.addGlobal(
2506 new String(mTokenString));
2507 reportIfDuplicate();
2508 }
2509
2510 void reportIfDuplicate() {
2511 if (!tok) {
2512 error("Duplicate definition of %s", mTokenString.getUnwrapped());
Jack Palevich303d8ff2009-06-11 19:06:24 -07002513 }
2514 }
2515
Jack Palevicha6baa232009-06-12 11:25:59 -07002516 void addLocalSymbol() {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002517 tok = (intptr_t) mSymbolTable.addLocal(
2518 new String(mTokenString));
Jack Palevicha6baa232009-06-12 11:25:59 -07002519 reportIfDuplicate();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002520 }
2521
Jack Palevichb7c81e92009-06-04 19:56:13 -07002522 void localDeclarations() {
2523 intptr_t a;
2524 Type base;
2525
2526 while (acceptType(base)) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002527 while (tok != ';' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002528 Type t = acceptPointerDeclaration(t);
Jack Palevichd7461a72009-06-12 14:26:58 -07002529 int variableAddress = 0;
Jack Palevichf1728be2009-06-12 13:53:51 -07002530 if (checkSymbol()) {
2531 addLocalSymbol();
2532 if (tok) {
2533 loc = loc + 4;
Jack Palevichd7461a72009-06-12 14:26:58 -07002534 variableAddress = -loc;
2535 ((VariableInfo*) tok)->pAddress = (void*) variableAddress;
Jack Palevichf1728be2009-06-12 13:53:51 -07002536 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002537 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002538 next();
Jack Palevichd7461a72009-06-12 14:26:58 -07002539 if (tok == '=') {
2540 /* assignment */
2541 next();
2542 expr();
2543 pGen->storeR0(variableAddress);
2544 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002545 if (tok == ',')
2546 next();
2547 }
2548 skip(';');
2549 }
2550 }
2551
Jack Palevichf1728be2009-06-12 13:53:51 -07002552 bool checkSymbol() {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002553 return checkSymbol(tok, &mTokenString);
2554 }
2555
2556 bool checkSymbol(int token, String* pText) {
2557 bool result = token < EOF || token >= TOK_UNDEFINED_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07002558 if (!result) {
2559 String temp;
Jack Palevicha1804dd2009-06-12 14:40:04 -07002560 if (token == EOF ) {
Jack Palevichd7461a72009-06-12 14:26:58 -07002561 temp.printf("EOF");
Jack Palevicha1804dd2009-06-12 14:40:04 -07002562 } else if (token == TOK_NUM) {
Jack Palevichd7461a72009-06-12 14:26:58 -07002563 temp.printf("numeric constant");
Jack Palevicha1804dd2009-06-12 14:40:04 -07002564 } else if (token >= 0 && token < 256) {
2565 temp.printf("char \'%c\'", token);
2566 } else if (token >= TOK_KEYWORD && token < TOK_UNSUPPORTED_KEYWORD) {
2567 temp.printf("keyword \"%s\"", pText->getUnwrapped());
Jack Palevichf1728be2009-06-12 13:53:51 -07002568 } else {
2569 temp.printf("reserved keyword \"%s\"",
Jack Palevicha1804dd2009-06-12 14:40:04 -07002570 pText->getUnwrapped());
Jack Palevichf1728be2009-06-12 13:53:51 -07002571 }
2572 error("Expected symbol. Got %s", temp.getUnwrapped());
2573 }
2574 return result;
2575 }
2576
Jack Palevichb7c81e92009-06-04 19:56:13 -07002577 void globalDeclarations() {
2578 while (tok != EOF) {
2579 Type base;
2580 expectType(base);
2581 Type t = acceptPointerDeclaration(t);
Jack Palevichf1728be2009-06-12 13:53:51 -07002582 if (tok >= 0 && tok < TOK_UNDEFINED_SYMBOL) {
2583 error("Unexpected token %d", tok);
2584 break;
2585 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002586 if (tok == TOK_UNDEFINED_SYMBOL) {
2587 addGlobalSymbol();
2588 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002589 VariableInfo* name = (VariableInfo*) tok;
Jack Palevicha6baa232009-06-12 11:25:59 -07002590 if (name && name->pAddress) {
2591 error("Already defined global %s",
2592 mTokenString.getUnwrapped());
2593 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002594 next();
Jack Palevichd7461a72009-06-12 14:26:58 -07002595 if (tok == ',' || tok == ';' || tok == '=') {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002596 // it's a variable declaration
2597 for(;;) {
Jack Palevicha6baa232009-06-12 11:25:59 -07002598 if (name) {
2599 name->pAddress = (int*) allocGlobalSpace(4);
2600 }
Jack Palevichd7461a72009-06-12 14:26:58 -07002601 if (tok == '=') {
2602 next();
2603 if (tok == TOK_NUM) {
2604 if (name) {
2605 * (int*) name->pAddress = tokc;
2606 }
2607 next();
2608 } else {
2609 error("Expected an integer constant");
2610 }
2611 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002612 if (tok != ',') {
2613 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07002614 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002615 skip(',');
Jack Palevichb7c81e92009-06-04 19:56:13 -07002616 t = acceptPointerDeclaration(t);
Jack Palevicha6baa232009-06-12 11:25:59 -07002617 addGlobalSymbol();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002618 name = (VariableInfo*) tok;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002619 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002620 }
2621 skip(';');
2622 } else {
Jack Palevicha6baa232009-06-12 11:25:59 -07002623 if (name) {
2624 /* patch forward references (XXX: does not work for function
2625 pointers) */
2626 pGen->gsym((int) name->pForward);
2627 /* put function address */
2628 name->pAddress = (void*) codeBuf.getPC();
2629 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002630 skip('(');
Jack Palevich303d8ff2009-06-11 19:06:24 -07002631 mSymbolTable.pushLevel();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002632 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07002633 int argCount = 0;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002634 while (tok != ')' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002635 Type aType;
2636 expectType(aType);
2637 aType = acceptPointerDeclaration(aType);
Jack Palevichf1728be2009-06-12 13:53:51 -07002638 if (checkSymbol()) {
2639 addLocalSymbol();
2640 if (tok) {
2641 /* read param name and compute offset */
2642 *(int *) tok = a;
2643 a = a + 4;
2644 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002645 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002646 next();
2647 if (tok == ',')
2648 next();
Jack Palevich546b2242009-05-13 15:10:04 -07002649 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07002650 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002651 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002652 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002653 a = pGen->functionEntry(argCount);
Jack Palevicha6baa232009-06-12 11:25:59 -07002654 block(0, true);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002655 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07002656 pGen->functionExit(argCount, a, loc);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002657 mSymbolTable.popLevel();
Jack Palevich21a15a22009-05-11 14:49:29 -07002658 }
2659 }
2660 }
2661
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002662 char* allocGlobalSpace(int bytes) {
2663 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
2664 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07002665 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002666 }
2667 char* result = glo;
2668 glo += bytes;
2669 return result;
2670 }
2671
Jack Palevich21a15a22009-05-11 14:49:29 -07002672 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002673 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002674 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07002675 pGlobalBase = 0;
2676 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002677 if (pGen) {
2678 delete pGen;
2679 pGen = 0;
2680 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002681 if (file) {
2682 delete file;
2683 file = 0;
2684 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002685 }
2686
2687 void clear() {
2688 tok = 0;
2689 tokc = 0;
2690 tokl = 0;
2691 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002692 rsym = 0;
2693 loc = 0;
2694 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002695 dptr = 0;
2696 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002697 file = 0;
2698 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002699 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002700 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002701 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002702
Jack Palevich22305132009-05-13 10:58:45 -07002703 void setArchitecture(const char* architecture) {
2704 delete pGen;
2705 pGen = 0;
2706
2707 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002708#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002709 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002710 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002711 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002712#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07002713#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002714 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002715 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002716 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002717#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07002718 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002719 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07002720 }
2721 }
2722
2723 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002724#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07002725 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07002726#elif defined(DEFAULT_X86_CODEGEN)
2727 pGen = new X86CodeGenerator();
2728#endif
2729 }
2730 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002731 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07002732 } else {
2733 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07002734 }
2735 }
2736
Jack Palevich77ae76e2009-05-10 19:59:24 -07002737public:
Jack Palevich22305132009-05-13 10:58:45 -07002738 struct args {
2739 args() {
2740 architecture = 0;
2741 }
2742 const char* architecture;
2743 };
2744
Jack Paleviche7b59062009-05-19 17:12:17 -07002745 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002746 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002747 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002748
Jack Paleviche7b59062009-05-19 17:12:17 -07002749 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002750 cleanup();
2751 }
2752
Jack Palevich1cdef202009-05-22 12:06:27 -07002753 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002754 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07002755
2756 cleanup();
2757 clear();
2758 codeBuf.init(ALLOC_SIZE);
2759 setArchitecture(NULL);
2760 if (!pGen) {
2761 return -1;
2762 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002763#ifdef PROVIDE_TRACE_CODEGEN
2764 pGen = new TraceCodeGenerator(pGen);
2765#endif
2766 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07002767 pGen->init(&codeBuf);
2768 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07002769 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
2770 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07002771 inp();
2772 next();
2773 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07002774 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07002775 result = pGen->finishCompile();
2776 if (result == 0) {
2777 if (mErrorBuf.len()) {
2778 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07002779 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07002780 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002781 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07002782 }
2783
Jack Palevicha6baa232009-06-12 11:25:59 -07002784 void checkForUndefinedForwardReferences() {
2785 mSymbolTable.forEachGlobal(static_ufrcFn, this);
2786 }
2787
2788 static bool static_ufrcFn(String* key, VariableInfo* value,
2789 void* context) {
2790 Compiler* pCompiler = (Compiler*) context;
2791 return pCompiler->undefinedForwardReferenceCheck(key, value);
2792 }
2793
2794 bool undefinedForwardReferenceCheck(String* key, VariableInfo* value) {
2795#if 0
2796 fprintf(stderr, "%s 0x%8x 0x%08x\n", key->getUnwrapped(),
2797 value->pAddress, value->pForward);
2798#endif
2799 if (!value->pAddress && value->pForward) {
2800 error("Undefined forward reference: %s", key->getUnwrapped());
2801 }
2802 return true;
2803 }
2804
Jack Palevich21a15a22009-05-11 14:49:29 -07002805 int dump(FILE* out) {
2806 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
2807 return 0;
2808 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07002809
Jack Palevicha6535612009-05-13 16:24:17 -07002810 int disassemble(FILE* out) {
2811 return pGen->disassemble(out);
2812 }
2813
Jack Palevich1cdef202009-05-22 12:06:27 -07002814 /* Look through the symbol table to find a symbol.
2815 * If found, return its value.
2816 */
2817 void* lookup(const char* name) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002818 String string(name, -1, false);
2819 VariableInfo* pVariableInfo = mSymbolTable.get(&string);
2820 if (pVariableInfo) {
2821 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07002822 }
2823 return NULL;
2824 }
2825
Jack Palevicheedf9d22009-06-04 16:23:40 -07002826 void getPragmas(ACCsizei* actualStringCount,
2827 ACCsizei maxStringCount, ACCchar** strings) {
2828 int stringCount = mPragmaStringCount;
2829 if (actualStringCount) {
2830 *actualStringCount = stringCount;
2831 }
2832 if (stringCount > maxStringCount) {
2833 stringCount = maxStringCount;
2834 }
2835 if (strings) {
2836 char* pPragmas = mPragmas.getUnwrapped();
2837 while (stringCount-- > 0) {
2838 *strings++ = pPragmas;
2839 pPragmas += strlen(pPragmas) + 1;
2840 }
2841 }
2842 }
2843
Jack Palevichac0e95e2009-05-29 13:53:44 -07002844 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002845 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002846 }
2847
Jack Palevich77ae76e2009-05-10 19:59:24 -07002848};
2849
Jack Paleviche7b59062009-05-19 17:12:17 -07002850const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002851 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2852
Jack Paleviche7b59062009-05-19 17:12:17 -07002853const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002854 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2855 5, 5, /* ==, != */
2856 9, 10, /* &&, || */
2857 6, 7, 8, /* & ^ | */
2858 2, 2 /* ~ ! */
2859 };
2860
Jack Palevich8b0624c2009-05-20 12:12:06 -07002861#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002862FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002863#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002864
Jack Palevich8b0624c2009-05-20 12:12:06 -07002865#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002866const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002867 0x1, // ++
2868 0xff, // --
2869 0xc1af0f, // *
2870 0xf9f79991, // /
2871 0xf9f79991, // % (With manual assist to swap results)
2872 0xc801, // +
2873 0xd8f7c829, // -
2874 0xe0d391, // <<
2875 0xf8d391, // >>
2876 0xe, // <=
2877 0xd, // >=
2878 0xc, // <
2879 0xf, // >
2880 0x4, // ==
2881 0x5, // !=
2882 0x0, // &&
2883 0x1, // ||
2884 0xc821, // &
2885 0xc831, // ^
2886 0xc809, // |
2887 0xd0f7, // ~
2888 0x4 // !
2889};
Jack Palevich8b0624c2009-05-20 12:12:06 -07002890#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002891
Jack Palevich1cdef202009-05-22 12:06:27 -07002892struct ACCscript {
2893 ACCscript() {
2894 text = 0;
2895 textLength = 0;
2896 accError = ACC_NO_ERROR;
2897 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002898
Jack Palevich1cdef202009-05-22 12:06:27 -07002899 ~ACCscript() {
2900 delete text;
2901 }
Jack Palevich546b2242009-05-13 15:10:04 -07002902
Jack Palevich1cdef202009-05-22 12:06:27 -07002903 void setError(ACCenum error) {
2904 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
2905 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002906 }
2907 }
2908
Jack Palevich1cdef202009-05-22 12:06:27 -07002909 ACCenum getError() {
2910 ACCenum result = accError;
2911 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07002912 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002913 }
2914
Jack Palevich1cdef202009-05-22 12:06:27 -07002915 Compiler compiler;
2916 char* text;
2917 int textLength;
2918 ACCenum accError;
2919};
2920
2921
2922extern "C"
2923ACCscript* accCreateScript() {
2924 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002925}
Jack Palevich1cdef202009-05-22 12:06:27 -07002926
2927extern "C"
2928ACCenum accGetError( ACCscript* script ) {
2929 return script->getError();
2930}
2931
2932extern "C"
2933void accDeleteScript(ACCscript* script) {
2934 delete script;
2935}
2936
2937extern "C"
2938void accScriptSource(ACCscript* script,
2939 ACCsizei count,
2940 const ACCchar ** string,
2941 const ACCint * length) {
2942 int totalLength = 0;
2943 for(int i = 0; i < count; i++) {
2944 int len = -1;
2945 const ACCchar* s = string[i];
2946 if (length) {
2947 len = length[i];
2948 }
2949 if (len < 0) {
2950 len = strlen(s);
2951 }
2952 totalLength += len;
2953 }
2954 delete script->text;
2955 char* text = new char[totalLength + 1];
2956 script->text = text;
2957 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07002958 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07002959 for(int i = 0; i < count; i++) {
2960 int len = -1;
2961 const ACCchar* s = string[i];
2962 if (length) {
2963 len = length[i];
2964 }
2965 if (len < 0) {
2966 len = strlen(s);
2967 }
Jack Palevich09555c72009-05-27 12:25:55 -07002968 memcpy(dest, s, len);
2969 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07002970 }
2971 text[totalLength] = '\0';
2972}
2973
2974extern "C"
2975void accCompileScript(ACCscript* script) {
2976 int result = script->compiler.compile(script->text, script->textLength);
2977 if (result) {
2978 script->setError(ACC_INVALID_OPERATION);
2979 }
2980}
2981
2982extern "C"
2983void accGetScriptiv(ACCscript* script,
2984 ACCenum pname,
2985 ACCint * params) {
2986 switch (pname) {
2987 case ACC_INFO_LOG_LENGTH:
2988 *params = 0;
2989 break;
2990 }
2991}
2992
2993extern "C"
2994void accGetScriptInfoLog(ACCscript* script,
2995 ACCsizei maxLength,
2996 ACCsizei * length,
2997 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002998 char* message = script->compiler.getErrorMessage();
2999 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003000 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003001 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003002 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003003 if (infoLog && maxLength > 0) {
3004 int trimmedLength = maxLength < messageLength ?
3005 maxLength : messageLength;
3006 memcpy(infoLog, message, trimmedLength);
3007 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003008 }
3009}
3010
3011extern "C"
3012void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3013 ACCvoid ** address) {
3014 void* value = script->compiler.lookup(name);
3015 if (value) {
3016 *address = value;
3017 } else {
3018 script->setError(ACC_INVALID_VALUE);
3019 }
3020}
3021
Jack Palevicheedf9d22009-06-04 16:23:40 -07003022extern "C"
3023void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3024 ACCsizei maxStringCount, ACCchar** strings){
3025 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3026}
3027
3028
Jack Palevich1cdef202009-05-22 12:06:27 -07003029} // namespace acc
3030