blob: e43728e8ade90e7ce832b7fefef044804d037e61 [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
-b master422972c2009-06-17 19:13:52 -070050#define LOG_STACK(...) do {} while(0)
51// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
52
53// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichbbf8ab52009-05-11 11:54:30 -070056namespace acc {
57
Jack Palevich8df46192009-07-07 14:48:51 -070058// Subset of STL vector.
59template<class E> class Vector {
60 public:
61 Vector() {
62 mpBase = 0;
63 mUsed = 0;
64 mSize = 0;
65 }
66
67 ~Vector() {
68 if (mpBase) {
69 for(size_t i = 0; i < mUsed; i++) {
70 mpBase[mUsed].~E();
71 }
72 free(mpBase);
73 }
74 }
75
76 inline E& operator[](size_t i) {
77 return mpBase[i];
78 }
79
80 inline E& front() {
81 return mpBase[0];
82 }
83
84 inline E& back() {
85 return mpBase[mUsed - 1];
86 }
87
88 void pop_back() {
89 mUsed -= 1;
90 mpBase[mUsed].~E();
91 }
92
93 void push_back(const E& item) {
94 * ensure(1) = item;
95 }
96
97 size_t size() {
98 return mUsed;
99 }
100
101private:
102 E* ensure(int n) {
103 size_t newUsed = mUsed + n;
104 if (newUsed > mSize) {
105 size_t newSize = mSize * 2 + 10;
106 if (newSize < newUsed) {
107 newSize = newUsed;
108 }
109 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
110 mSize = newSize;
111 }
112 E* result = mpBase + mUsed;
113 mUsed = newUsed;
114 return result;
115 }
116
117 E* mpBase;
118 size_t mUsed;
119 size_t mSize;
120};
121
Jack Palevichac0e95e2009-05-29 13:53:44 -0700122class ErrorSink {
123public:
124 void error(const char *fmt, ...) {
125 va_list ap;
126 va_start(ap, fmt);
127 verror(fmt, ap);
128 va_end(ap);
129 }
130
131 virtual void verror(const char* fmt, va_list ap) = 0;
132};
133
134class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700135 typedef int tokenid_t;
136 enum TypeTag {
137 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
138 TY_POINTER, TY_FUNC, TY_PARAM
139 };
140
141 struct Type {
142 TypeTag tag;
143 tokenid_t id; // For function arguments
144 Type* pHead;
145 Type* pTail;
146 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700147
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700149 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700150 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700151 ErrorSink* mErrorSink;
152 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700153 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700154
Jack Palevich21a15a22009-05-11 14:49:29 -0700155 void release() {
156 if (pProgramBase != 0) {
157 free(pProgramBase);
158 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700159 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700160 }
161
Jack Palevich0a280a02009-06-11 10:53:51 -0700162 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700163 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700164 bool overflow = newSize > mSize;
165 if (overflow && !mOverflowed) {
166 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700167 if (mErrorSink) {
168 mErrorSink->error("Code too large: %d bytes", newSize);
169 }
170 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700171 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700172 }
173
Jack Palevich21a15a22009-05-11 14:49:29 -0700174 public:
175 CodeBuf() {
176 pProgramBase = 0;
177 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700178 mErrorSink = 0;
179 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700180 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 }
182
183 ~CodeBuf() {
184 release();
185 }
186
187 void init(int size) {
188 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700190 pProgramBase = (char*) calloc(1, size);
191 ind = pProgramBase;
192 }
193
Jack Palevichac0e95e2009-05-29 13:53:44 -0700194 void setErrorSink(ErrorSink* pErrorSink) {
195 mErrorSink = pErrorSink;
196 }
197
Jack Palevich546b2242009-05-13 15:10:04 -0700198 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700199 if(check(4)) {
200 return 0;
201 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700202 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700203 * (int*) ind = n;
204 ind += 4;
205 return result;
206 }
207
Jack Palevich21a15a22009-05-11 14:49:29 -0700208 /*
209 * Output a byte. Handles all values, 0..ff.
210 */
211 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(1)) {
213 return;
214 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 *ind++ = n;
216 }
217
Jack Palevich21a15a22009-05-11 14:49:29 -0700218 inline void* getBase() {
219 return (void*) pProgramBase;
220 }
221
Jack Palevich8b0624c2009-05-20 12:12:06 -0700222 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700223 return ind - pProgramBase;
224 }
225
Jack Palevich8b0624c2009-05-20 12:12:06 -0700226 intptr_t getPC() {
227 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 }
229 };
230
Jack Palevich1cdef202009-05-22 12:06:27 -0700231 /**
232 * A code generator creates an in-memory program, generating the code on
233 * the fly. There is one code generator implementation for each supported
234 * architecture.
235 *
236 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700237 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700238 * FP - a frame pointer for accessing function arguments and local
239 * variables.
240 * SP - a stack pointer for storing intermediate results while evaluating
241 * expressions. The stack pointer grows downwards.
242 *
243 * The function calling convention is that all arguments are placed on the
244 * stack such that the first argument has the lowest address.
245 * After the call, the result is in R0. The caller is responsible for
246 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700247 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700248 * FP and SP registers are saved.
249 */
250
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 class CodeGenerator {
252 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700253 CodeGenerator() {
254 mErrorSink = 0;
255 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700256 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700257 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 virtual ~CodeGenerator() {}
259
Jack Palevich22305132009-05-13 10:58:45 -0700260 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700262 pCodeBuf->setErrorSink(mErrorSink);
263 }
264
Jack Palevichb67b18f2009-06-11 21:12:23 -0700265 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 mErrorSink = pErrorSink;
267 if (pCodeBuf) {
268 pCodeBuf->setErrorSink(mErrorSink);
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 }
271
Jack Palevich1cdef202009-05-22 12:06:27 -0700272 /* Emit a function prolog.
273 * argCount is the number of arguments.
274 * Save the old value of the FP.
275 * Set the new value of the FP.
276 * Convert from the native platform calling convention to
277 * our stack-based calling convention. This may require
278 * pushing arguments from registers to the stack.
279 * Allocate "N" bytes of stack space. N isn't known yet, so
280 * just emit the instructions for adjusting the stack, and return
281 * the address to patch up. The patching will be done in
282 * functionExit().
283 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700284 */
Jack Palevich546b2242009-05-13 15:10:04 -0700285 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700286
Jack Palevich1cdef202009-05-22 12:06:27 -0700287 /* Emit a function epilog.
288 * Restore the old SP and FP register values.
289 * Return to the calling function.
290 * argCount - the number of arguments to the function.
291 * localVariableAddress - returned from functionEntry()
292 * localVariableSize - the size in bytes of the local variables.
293 */
294 virtual void functionExit(int argCount, int localVariableAddress,
295 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700296
Jack Palevich1cdef202009-05-22 12:06:27 -0700297 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700298 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700299
300 /* load floating point immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700301 virtual void lif(float f, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700302
303 /* load double-precision floating point immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700304 virtual void lid(double d, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700305
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 /* Jump to a target, and return the address of the word that
307 * holds the target data, in case it needs to be fixed up later.
308 */
Jack Palevich22305132009-05-13 10:58:45 -0700309 virtual int gjmp(int t) = 0;
310
Jack Palevich1cdef202009-05-22 12:06:27 -0700311 /* Test R0 and jump to a target if the test succeeds.
312 * l = 0: je, l == 1: jne
313 * Return the address of the word that holds the targed data, in
314 * case it needs to be fixed up later.
315 */
Jack Palevich22305132009-05-13 10:58:45 -0700316 virtual int gtst(bool l, int t) = 0;
317
Jack Palevich9eed7a22009-07-06 17:24:34 -0700318 /* Compare TOS against R0, and store the boolean result in R0.
319 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700320 * op specifies the comparison.
321 */
Jack Palevich22305132009-05-13 10:58:45 -0700322 virtual void gcmp(int op) = 0;
323
Jack Palevich9eed7a22009-07-06 17:24:34 -0700324 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700326 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700327 */
Jack Palevich546b2242009-05-13 15:10:04 -0700328 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700329
Jack Palevich9eed7a22009-07-06 17:24:34 -0700330 /* Compare 0 against R0, and store the boolean result in R0.
331 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700332 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700333 virtual void gUnaryCmp(int op) = 0;
334
335 /* Perform the arithmetic op specified by op. 0 is the
336 * left argument, R0 is the right argument.
337 */
338 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700339
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 /* Push R0 onto the stack.
341 */
342 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700343
Jack Palevich9eed7a22009-07-06 17:24:34 -0700344 /* Store R0 to the address stored in TOS.
345 * The TOS is popped.
346 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700348 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700349
Jack Palevich1cdef202009-05-22 12:06:27 -0700350 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700351 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700352 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700354
Jack Palevich1cdef202009-05-22 12:06:27 -0700355 /* Load the absolute address of a variable to R0.
356 * If ea <= LOCAL, then this is a local variable, or an
357 * argument, addressed relative to FP.
358 * else it is an absolute global address.
359 */
Jack Palevich8df46192009-07-07 14:48:51 -0700360 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700361
Jack Palevich1cdef202009-05-22 12:06:27 -0700362 /* Store R0 to a variable.
363 * If ea <= LOCAL, then this is a local variable, or an
364 * argument, addressed relative to FP.
365 * else it is an absolute global address.
366 */
367 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevich1cdef202009-05-22 12:06:27 -0700369 /* load R0 from a variable.
370 * If ea <= LOCAL, then this is a local variable, or an
371 * argument, addressed relative to FP.
372 * else it is an absolute global address.
373 * If isIncDec is true, then the stored variable's value
374 * should be post-incremented or post-decremented, based
375 * on the value of op.
376 */
Jack Palevich8df46192009-07-07 14:48:51 -0700377 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
378
379 /**
380 * Convert R0 to the given type.
381 */
382 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700383
Jack Palevich1cdef202009-05-22 12:06:27 -0700384 /* Emit code to adjust the stack for a function call. Return the
385 * label for the address of the instruction that adjusts the
386 * stack size. This will be passed as argument "a" to
387 * endFunctionCallArguments.
388 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700389 virtual int beginFunctionCallArguments() = 0;
390
Jack Palevich1cdef202009-05-22 12:06:27 -0700391 /* Emit code to store R0 to the stack at byte offset l.
392 */
393 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700394
Jack Palevich1cdef202009-05-22 12:06:27 -0700395 /* Patch the function call preamble.
396 * a is the address returned from beginFunctionCallArguments
397 * l is the number of bytes the arguments took on the stack.
398 * Typically you would also emit code to convert the argument
399 * list into whatever the native function calling convention is.
400 * On ARM for example you would pop the first 5 arguments into
401 * R0..R4
402 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700403 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700404
Jack Palevich1cdef202009-05-22 12:06:27 -0700405 /* Emit a call to an unknown function. The argument "symbol" needs to
406 * be stored in the location where the address should go. It forms
407 * a chain. The address will be patched later.
408 * Return the address of the word that has to be patched.
409 */
Jack Palevich8df46192009-07-07 14:48:51 -0700410 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700411
Jack Palevich1cdef202009-05-22 12:06:27 -0700412 /* Call a function using PC-relative addressing. t is the PC-relative
413 * address of the function. It has already been adjusted for the
414 * architectural jump offset, so just store it as-is.
415 */
Jack Palevich8df46192009-07-07 14:48:51 -0700416 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700417
Jack Palevich1cdef202009-05-22 12:06:27 -0700418 /* Call a function pointer. L is the number of bytes the arguments
419 * take on the stack. The address of the function is stored at
420 * location SP + l.
421 */
Jack Palevich8df46192009-07-07 14:48:51 -0700422 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700423
Jack Palevich1cdef202009-05-22 12:06:27 -0700424 /* Adjust SP after returning from a function call. l is the
425 * number of bytes of arguments stored on the stack. isIndirect
426 * is true if this was an indirect call. (In which case the
427 * address of the function is stored at location SP + l.)
428 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700429 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700430
Jack Palevich1cdef202009-05-22 12:06:27 -0700431 /* Print a disassembly of the assembled code to out. Return
432 * non-zero if there is an error.
433 */
Jack Palevicha6535612009-05-13 16:24:17 -0700434 virtual int disassemble(FILE* out) = 0;
435
Jack Palevich1cdef202009-05-22 12:06:27 -0700436 /* Generate a symbol at the current PC. t is the head of a
437 * linked list of addresses to patch.
438 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700439 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /*
442 * Do any cleanup work required at the end of a compile.
443 * For example, an instruction cache might need to be
444 * invalidated.
445 * Return non-zero if there is an error.
446 */
447 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700448
Jack Palevicha6535612009-05-13 16:24:17 -0700449 /**
450 * Adjust relative branches by this amount.
451 */
452 virtual int jumpOffset() = 0;
453
Jack Palevich9eed7a22009-07-06 17:24:34 -0700454 /**
455 * Stack alignment (in bytes) for this type of data
456 */
457 virtual size_t stackAlignment(Type* type) = 0;
458
459 /**
460 * Array element alignment (in bytes) for this type of data.
461 */
462 virtual size_t sizeOf(Type* type) = 0;
463
Jack Palevich21a15a22009-05-11 14:49:29 -0700464 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700465 /*
466 * Output a byte. Handles all values, 0..ff.
467 */
468 void ob(int n) {
469 pCodeBuf->ob(n);
470 }
471
Jack Palevich8b0624c2009-05-20 12:12:06 -0700472 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700473 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700474 }
475
Jack Palevich8b0624c2009-05-20 12:12:06 -0700476 intptr_t getBase() {
477 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700478 }
479
Jack Palevich8b0624c2009-05-20 12:12:06 -0700480 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700481 return pCodeBuf->getPC();
482 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700483
484 intptr_t getSize() {
485 return pCodeBuf->getSize();
486 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700487
488 void error(const char* fmt,...) {
489 va_list ap;
490 va_start(ap, fmt);
491 mErrorSink->verror(fmt, ap);
492 va_end(ap);
493 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700494
495 void assert(bool test) {
496 if (!test) {
497 error("code generator assertion failed.");
498 }
499 }
Jack Palevich8df46192009-07-07 14:48:51 -0700500
501 void setR0Type(Type* pType) {
502 mExpressionStack.back() = pType;
503 }
504
505 Type* getR0Type() {
506 return mExpressionStack.back();
507 }
508
509 Type* getTOSType() {
510 return mExpressionStack[mExpressionStack.size()-2];
511 }
512
513 void pushType() {
514 mExpressionStack.push_back(NULL);
515 }
516
517 void popType() {
518 mExpressionStack.pop_back();
519 }
520
521 bool bitsSame(Type* pA, Type* pB) {
522 return collapseType(pA->tag) == collapseType(pB->tag);
523 }
524
525 TypeTag collapseType(TypeTag tag) {
526 static const TypeTag collapsedTag[] = {
527 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
528 TY_VOID, TY_VOID};
529 return collapsedTag[tag];
530 }
531
Jack Palevich21a15a22009-05-11 14:49:29 -0700532 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700533 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700534 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700535 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700536 };
537
Jack Paleviche7b59062009-05-19 17:12:17 -0700538#ifdef PROVIDE_ARM_CODEGEN
539
Jack Palevich22305132009-05-13 10:58:45 -0700540 class ARMCodeGenerator : public CodeGenerator {
541 public:
542 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700543
Jack Palevich22305132009-05-13 10:58:45 -0700544 virtual ~ARMCodeGenerator() {}
545
546 /* returns address to patch with local variable size
547 */
Jack Palevich546b2242009-05-13 15:10:04 -0700548 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700549 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700550 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700551 // sp -> arg4 arg5 ...
552 // Push our register-based arguments back on the stack
553 if (argCount > 0) {
554 int regArgCount = argCount <= 4 ? argCount : 4;
555 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700556 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700557 }
558 // sp -> arg0 arg1 ...
559 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700560 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700561 // sp, fp -> oldfp, retadr, arg0 arg1 ....
562 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700563 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700564 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700565 // We don't know how many local variables we are going to use,
566 // but we will round the allocation up to a multiple of
567 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700568 }
569
Jack Palevich546b2242009-05-13 15:10:04 -0700570 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700571 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700572 // Round local variable size up to a multiple of stack alignment
573 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
574 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700575 // Patch local variable allocation code:
576 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700577 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700578 }
Jack Palevich69796b62009-05-14 15:42:26 -0700579 *(char*) (localVariableAddress) = localVariableSize;
580
581 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
582 o4(0xE1A0E00B); // mov lr, fp
583 o4(0xE59BB000); // ldr fp, [fp]
584 o4(0xE28ED004); // add sp, lr, #4
585 // sp -> retadr, arg0, ...
586 o4(0xE8BD4000); // ldmfd sp!, {lr}
587 // sp -> arg0 ....
588 if (argCount > 0) {
589 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700590 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700591 // earlier. We don't need to actually store them anywhere,
592 // just adjust the stack.
593 int regArgCount = argCount <= 4 ? argCount : 4;
594 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
595 }
596 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700597 }
598
599 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700600 virtual void li(int t, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700601 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700602 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700603 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700604 } else if (t >= -256 && t < 0) {
605 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700606 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700607 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700608 o4(0xE51F0000); // ldr r0, .L3
609 o4(0xEA000000); // b .L99
610 o4(t); // .L3: .word 0
611 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700612 }
Jack Palevich8df46192009-07-07 14:48:51 -0700613 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700614 }
615
Jack Palevich8df46192009-07-07 14:48:51 -0700616 virtual void lif(float f, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700617 union { float f; int i; } converter;
618 converter.f = f;
Jack Palevich8df46192009-07-07 14:48:51 -0700619 li(converter.i, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700620 }
621
Jack Palevich8df46192009-07-07 14:48:51 -0700622 virtual void lid(double d, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700623 union { double d; int i[2]; } converter;
624 converter.d = d;
Jack Palevich8df46192009-07-07 14:48:51 -0700625 error("lid: unimplemented");
626 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700627 }
628
Jack Palevich22305132009-05-13 10:58:45 -0700629 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700630 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700631 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700632 }
633
634 /* l = 0: je, l == 1: jne */
635 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700636 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700637 o4(0xE3500000); // cmp r0,#0
638 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
639 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700640 }
641
642 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700643 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700644 o4(0xE8BD0002); // ldmfd sp!,{r1}
645 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700646 o4(0xE1510000); // cmp r1, r1
647 switch(op) {
648 case OP_EQUALS:
649 o4(0x03A00001); // moveq r0,#1
650 o4(0x13A00000); // movne r0,#0
651 break;
652 case OP_NOT_EQUALS:
653 o4(0x03A00000); // moveq r0,#0
654 o4(0x13A00001); // movne r0,#1
655 break;
656 case OP_LESS_EQUAL:
657 o4(0xD3A00001); // movle r0,#1
658 o4(0xC3A00000); // movgt r0,#0
659 break;
660 case OP_GREATER:
661 o4(0xD3A00000); // movle r0,#0
662 o4(0xC3A00001); // movgt r0,#1
663 break;
664 case OP_GREATER_EQUAL:
665 o4(0xA3A00001); // movge r0,#1
666 o4(0xB3A00000); // movlt r0,#0
667 break;
668 case OP_LESS:
669 o4(0xA3A00000); // movge r0,#0
670 o4(0xB3A00001); // movlt r0,#1
671 break;
672 default:
673 error("Unknown comparison op %d", op);
674 break;
675 }
Jack Palevich8df46192009-07-07 14:48:51 -0700676 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700677 }
678
Jack Palevich546b2242009-05-13 15:10:04 -0700679 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700680 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700681 o4(0xE8BD0002); // ldmfd sp!,{r1}
682 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700683 switch(op) {
684 case OP_MUL:
685 o4(0x0E0000091); // mul r0,r1,r0
686 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700687 case OP_DIV:
688 callRuntime(runtime_DIV);
689 break;
690 case OP_MOD:
691 callRuntime(runtime_MOD);
692 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700693 case OP_PLUS:
694 o4(0xE0810000); // add r0,r1,r0
695 break;
696 case OP_MINUS:
697 o4(0xE0410000); // sub r0,r1,r0
698 break;
699 case OP_SHIFT_LEFT:
700 o4(0xE1A00011); // lsl r0,r1,r0
701 break;
702 case OP_SHIFT_RIGHT:
703 o4(0xE1A00051); // asr r0,r1,r0
704 break;
705 case OP_BIT_AND:
706 o4(0xE0010000); // and r0,r1,r0
707 break;
708 case OP_BIT_XOR:
709 o4(0xE0210000); // eor r0,r1,r0
710 break;
711 case OP_BIT_OR:
712 o4(0xE1810000); // orr r0,r1,r0
713 break;
714 case OP_BIT_NOT:
715 o4(0xE1E00000); // mvn r0, r0
716 break;
717 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700718 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700719 break;
720 }
Jack Palevich8df46192009-07-07 14:48:51 -0700721 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700722 }
723
Jack Palevich9eed7a22009-07-06 17:24:34 -0700724 virtual void gUnaryCmp(int op) {
725 LOG_API("gcmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700726 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700727 o4(0xE1510000); // cmp r1, r1
728 switch(op) {
729 case OP_NOT_EQUALS:
730 o4(0x03A00000); // moveq r0,#0
731 o4(0x13A00001); // movne r0,#1
732 break;
733 default:
734 error("Unknown unary comparison op %d", op);
735 break;
736 }
737 }
738
739 virtual void genUnaryOp(int op) {
740 LOG_API("genOp(%d);\n", op);
741 switch(op) {
742 case OP_PLUS:
743 // Do nothing
744 break;
745 case OP_MINUS:
746 o4(0xE3A01000); // mov r1, #0
747 o4(0xE0410000); // sub r0,r1,r0
748 break;
749 case OP_BIT_NOT:
750 o4(0xE1E00000); // mvn r0, r0
751 break;
752 default:
753 error("Unknown unary op %d\n", op);
754 break;
755 }
Jack Palevich22305132009-05-13 10:58:45 -0700756 }
757
Jack Palevich1cdef202009-05-22 12:06:27 -0700758 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700759 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700760 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700761 mStackUse += 4;
Jack Palevich8df46192009-07-07 14:48:51 -0700762 pushType();
-b master422972c2009-06-17 19:13:52 -0700763 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700764 }
765
Jack Palevich9eed7a22009-07-06 17:24:34 -0700766 virtual void storeR0ToTOS(Type* pPointerType) {
767 LOG_API("storeR0ToTOS(%d);\n", isInt);
768 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700769 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700770 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700771 switch (pPointerType->pHead->tag) {
772 case TY_INT:
773 o4(0xE5810000); // str r0, [r1]
774 break;
775 case TY_CHAR:
776 o4(0xE5C10000); // strb r0, [r1]
777 break;
778 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700779 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700780 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700781 }
Jack Palevich8df46192009-07-07 14:48:51 -0700782 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700783 }
784
Jack Palevich9eed7a22009-07-06 17:24:34 -0700785 virtual void loadR0FromR0(Type* pPointerType) {
786 LOG_API("loadR0FromR0(%d);\n", pPointerType);
787 assert(pPointerType->tag == TY_POINTER);
788 switch (pPointerType->pHead->tag) {
789 case TY_INT:
790 o4(0xE5900000); // ldr r0, [r0]
791 break;
792 case TY_CHAR:
793 o4(0xE5D00000); // ldrb r0, [r0]
794 break;
795 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700796 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700797 break;
798 }
Jack Palevich8df46192009-07-07 14:48:51 -0700799 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -0700800 }
801
Jack Palevich8df46192009-07-07 14:48:51 -0700802 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700803 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700804 if (ea < LOCAL) {
805 // Local, fp relative
806 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
807 error("Offset out of range: %08x", ea);
808 }
809 if (ea < 0) {
810 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
811 } else {
812 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
813 }
Jack Palevichbd894902009-05-14 19:35:31 -0700814 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700815 // Global, absolute.
816 o4(0xE59F0000); // ldr r0, .L1
817 o4(0xEA000000); // b .L99
818 o4(ea); // .L1: .word 0
819 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700820 }
Jack Palevich8df46192009-07-07 14:48:51 -0700821 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -0700822 }
823
Jack Palevich1cdef202009-05-22 12:06:27 -0700824 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700825 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700826 if (ea < LOCAL) {
827 // Local, fp relative
828 if (ea < -4095 || ea > 4095) {
829 error("Offset out of range: %08x", ea);
830 }
831 if (ea < 0) {
832 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
833 } else {
834 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
835 }
836 } else{
837 // Global, absolute
838 o4(0xE59F1000); // ldr r1, .L1
839 o4(0xEA000000); // b .L99
840 o4(ea); // .L1: .word 0
841 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700842 }
Jack Palevich22305132009-05-13 10:58:45 -0700843 }
844
Jack Palevich8df46192009-07-07 14:48:51 -0700845 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700846 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700847 if (ea < LOCAL) {
848 // Local, fp relative
849 if (ea < -4095 || ea > 4095) {
850 error("Offset out of range: %08x", ea);
851 }
852 if (ea < 0) {
853 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
854 } else {
855 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
856 }
Jack Palevich69796b62009-05-14 15:42:26 -0700857 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700858 // Global, absolute
859 o4(0xE59F2000); // ldr r2, .L1
860 o4(0xEA000000); // b .L99
861 o4(ea); // .L1: .word ea
862 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700863 }
Jack Palevich22305132009-05-13 10:58:45 -0700864
Jack Palevich4d93f302009-05-15 13:30:00 -0700865 if (isIncDec) {
866 switch (op) {
867 case OP_INCREMENT:
868 o4(0xE2801001); // add r1, r0, #1
869 break;
870 case OP_DECREMENT:
871 o4(0xE2401001); // sub r1, r0, #1
872 break;
873 default:
874 error("unknown opcode: %d", op);
875 }
876 if (ea < LOCAL) {
877 // Local, fp relative
878 // Don't need range check, was already checked above
879 if (ea < 0) {
880 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
881 } else {
882 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
883 }
884 } else{
885 // Global, absolute
886 // r2 is already set up from before.
887 o4(0xE5821000); // str r1, [r2]
888 }
Jack Palevichbd894902009-05-14 19:35:31 -0700889 }
Jack Palevich8df46192009-07-07 14:48:51 -0700890 setR0Type(pType);
891 }
892
893 virtual void convertR0(Type* pType){
894 if (bitsSame(pType, getR0Type())) {
895 return;
896 }
897 error("Incompatible types");
Jack Palevich22305132009-05-13 10:58:45 -0700898 }
899
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700900 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700901 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700902 return o4(0xE24DDF00); // Placeholder
903 }
904
Jack Palevich1cdef202009-05-22 12:06:27 -0700905 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700906 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700907 if (l < 0 || l > 4096-4) {
908 error("l out of range for stack offset: 0x%08x", l);
909 }
910 o4(0xE58D0000 + l); // str r0, [sp, #4]
911 }
912
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700913 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700914 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700915 int argCount = l >> 2;
916 int argumentStackUse = l;
917 if (argCount > 0) {
918 int regArgCount = argCount > 4 ? 4 : argCount;
919 argumentStackUse -= regArgCount * 4;
920 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
921 }
922 mStackUse += argumentStackUse;
923
924 // Align stack.
925 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
926 * STACK_ALIGNMENT);
927 mStackAlignmentAdjustment = 0;
928 if (missalignment > 0) {
929 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
930 }
931 l += mStackAlignmentAdjustment;
932
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700933 if (l < 0 || l > 0x3FC) {
934 error("L out of range for stack adjustment: 0x%08x", l);
935 }
936 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700937 mStackUse += mStackAlignmentAdjustment;
938 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
939 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700940 }
941
Jack Palevich8df46192009-07-07 14:48:51 -0700942 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700943 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -0700944 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700945 // Forward calls are always short (local)
946 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700947 }
948
Jack Palevich8df46192009-07-07 14:48:51 -0700949 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700950 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -0700951 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700952 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700953 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700954 if (t >= - (1 << 25) && t < (1 << 25)) {
955 o4(0xEB000000 | encodeAddress(t));
956 } else {
957 // Long call.
958 o4(0xE59FC000); // ldr r12, .L1
959 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700960 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700961 o4(0xE08CC00F); // .L99: add r12,pc
962 o4(0xE12FFF3C); // blx r12
963 }
Jack Palevich22305132009-05-13 10:58:45 -0700964 }
965
Jack Palevich8df46192009-07-07 14:48:51 -0700966 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700967 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -0700968 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -0700969 int argCount = l >> 2;
970 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700971 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700972 if (adjustedL < 0 || adjustedL > 4096-4) {
973 error("l out of range for stack offset: 0x%08x", l);
974 }
975 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
976 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700977 }
978
Jack Palevich7810bc92009-05-15 14:31:47 -0700979 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700980 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700981 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700982 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700983 int stackUse = stackArgs + (isIndirect ? 1 : 0)
984 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700985 if (stackUse) {
986 if (stackUse < 0 || stackUse > 255) {
987 error("L out of range for stack adjustment: 0x%08x", l);
988 }
989 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -0700990 mStackUse -= stackUse * 4;
991 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700992 }
Jack Palevich22305132009-05-13 10:58:45 -0700993 }
994
Jack Palevicha6535612009-05-13 16:24:17 -0700995 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700996 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700997 }
998
999 /* output a symbol and patch all calls to it */
1000 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001001 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001002 int n;
1003 int base = getBase();
1004 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001005 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001006 while (t) {
1007 int data = * (int*) t;
1008 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1009 if (decodedOffset == 0) {
1010 n = 0;
1011 } else {
1012 n = base + decodedOffset; /* next value */
1013 }
1014 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1015 | encodeRelAddress(pc - t - 8);
1016 t = n;
1017 }
1018 }
1019
Jack Palevich1cdef202009-05-22 12:06:27 -07001020 virtual int finishCompile() {
1021#if defined(__arm__)
1022 const long base = long(getBase());
1023 const long curr = long(getPC());
1024 int err = cacheflush(base, curr, 0);
1025 return err;
1026#else
1027 return 0;
1028#endif
1029 }
1030
Jack Palevicha6535612009-05-13 16:24:17 -07001031 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001032#ifdef ENABLE_ARM_DISASSEMBLY
1033 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001034 disasm_interface_t di;
1035 di.di_readword = disassemble_readword;
1036 di.di_printaddr = disassemble_printaddr;
1037 di.di_printf = disassemble_printf;
1038
1039 int base = getBase();
1040 int pc = getPC();
1041 for(int i = base; i < pc; i += 4) {
1042 fprintf(out, "%08x: %08x ", i, *(int*) i);
1043 ::disasm(&di, i, 0);
1044 }
Jack Palevich09555c72009-05-27 12:25:55 -07001045#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001046 return 0;
1047 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001048
Jack Palevich9eed7a22009-07-06 17:24:34 -07001049 /**
1050 * Stack alignment (in bytes) for this type of data
1051 */
1052 virtual size_t stackAlignment(Type* pType){
1053 switch(pType->tag) {
1054 case TY_DOUBLE:
1055 return 8;
1056 default:
1057 return 4;
1058 }
1059 }
1060
1061 /**
1062 * Array element alignment (in bytes) for this type of data.
1063 */
1064 virtual size_t sizeOf(Type* pType){
1065 switch(pType->tag) {
1066 case TY_INT:
1067 return 4;
1068 case TY_CHAR:
1069 return 1;
1070 default:
1071 return 0;
1072 case TY_FLOAT:
1073 return 4;
1074 case TY_DOUBLE:
1075 return 8;
1076 case TY_POINTER:
1077 return 4;
1078 }
1079 }
Jack Palevich22305132009-05-13 10:58:45 -07001080 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001081 static FILE* disasmOut;
1082
1083 static u_int
1084 disassemble_readword(u_int address)
1085 {
1086 return(*((u_int *)address));
1087 }
1088
1089 static void
1090 disassemble_printaddr(u_int address)
1091 {
1092 fprintf(disasmOut, "0x%08x", address);
1093 }
1094
1095 static void
1096 disassemble_printf(const char *fmt, ...) {
1097 va_list ap;
1098 va_start(ap, fmt);
1099 vfprintf(disasmOut, fmt, ap);
1100 va_end(ap);
1101 }
1102
1103 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1104
1105 /** Encode a relative address that might also be
1106 * a label.
1107 */
1108 int encodeAddress(int value) {
1109 int base = getBase();
1110 if (value >= base && value <= getPC() ) {
1111 // This is a label, encode it relative to the base.
1112 value = value - base;
1113 }
1114 return encodeRelAddress(value);
1115 }
1116
1117 int encodeRelAddress(int value) {
1118 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1119 }
Jack Palevich22305132009-05-13 10:58:45 -07001120
Jack Palevich3d474a72009-05-15 15:12:38 -07001121 typedef int (*int2FnPtr)(int a, int b);
1122 void callRuntime(int2FnPtr fn) {
1123 o4(0xE59F2000); // ldr r2, .L1
1124 o4(0xEA000000); // b .L99
1125 o4((int) fn); //.L1: .word fn
1126 o4(0xE12FFF32); //.L99: blx r2
1127 }
1128
1129 static int runtime_DIV(int a, int b) {
1130 return b / a;
1131 }
1132
1133 static int runtime_MOD(int a, int b) {
1134 return b % a;
1135 }
-b master422972c2009-06-17 19:13:52 -07001136
1137 static const int STACK_ALIGNMENT = 8;
1138 int mStackUse;
1139 // This variable holds the amount we adjusted the stack in the most
1140 // recent endFunctionCallArguments call. It's examined by the
1141 // following adjustStackAfterCall call.
1142 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001143 };
1144
Jack Palevich09555c72009-05-27 12:25:55 -07001145#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001146
1147#ifdef PROVIDE_X86_CODEGEN
1148
Jack Palevich21a15a22009-05-11 14:49:29 -07001149 class X86CodeGenerator : public CodeGenerator {
1150 public:
1151 X86CodeGenerator() {}
1152 virtual ~X86CodeGenerator() {}
1153
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001154 /* returns address to patch with local variable size
1155 */
Jack Palevich546b2242009-05-13 15:10:04 -07001156 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001157 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1158 return oad(0xec81, 0); /* sub $xxx, %esp */
1159 }
1160
Jack Palevich546b2242009-05-13 15:10:04 -07001161 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001162 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001163 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001164 }
1165
Jack Palevich21a15a22009-05-11 14:49:29 -07001166 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001167 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001168 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001169 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001170 }
1171
Jack Palevich8df46192009-07-07 14:48:51 -07001172 virtual void lif(float f, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001173 union { float f; int i; } converter;
1174 converter.f = f;
Jack Palevich8df46192009-07-07 14:48:51 -07001175 setR0Type(pType);
1176 error("unimplemented: lif");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001177 }
1178
Jack Palevich8df46192009-07-07 14:48:51 -07001179 virtual void lid(double d, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001180 union { double d; int i[2]; } converter;
1181 converter.d = d;
Jack Palevich8df46192009-07-07 14:48:51 -07001182 setR0Type(pType);
1183 error("unimplemented: lid");
Jack Palevich21a15a22009-05-11 14:49:29 -07001184 }
1185
Jack Palevich22305132009-05-13 10:58:45 -07001186 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001187 return psym(0xe9, t);
1188 }
1189
1190 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001191 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001192 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1193 return psym(0x84 + l, t);
1194 }
1195
Jack Palevich22305132009-05-13 10:58:45 -07001196 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001197 int t = decodeOp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001198 o(0x59); /* pop %ecx */
Jack Palevich21a15a22009-05-11 14:49:29 -07001199 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001200 li(0, NULL);
Jack Palevich21a15a22009-05-11 14:49:29 -07001201 o(0x0f); /* setxx %al */
1202 o(t + 0x90);
1203 o(0xc0);
Jack Palevich8df46192009-07-07 14:48:51 -07001204 popType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001205 }
1206
Jack Palevich546b2242009-05-13 15:10:04 -07001207 virtual void genOp(int op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001208 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001209 o(decodeOp(op));
1210 if (op == OP_MOD)
1211 o(0x92); /* xchg %edx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001212 popType();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001213 }
1214
Jack Palevich9eed7a22009-07-06 17:24:34 -07001215 virtual void gUnaryCmp(int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001216 oad(0xb9, 0); /* movl $0, %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001217 int t = decodeOp(op);
1218 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001219 li(0, NULL);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001220 o(0x0f); /* setxx %al */
1221 o(t + 0x90);
1222 o(0xc0);
1223 }
1224
1225 virtual void genUnaryOp(int op) {
1226 oad(0xb9, 0); /* movl $0, %ecx */
1227 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -07001228 }
1229
Jack Palevich1cdef202009-05-22 12:06:27 -07001230 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001231 o(0x50); /* push %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001232 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001233 }
1234
Jack Palevich9eed7a22009-07-06 17:24:34 -07001235 virtual void storeR0ToTOS(Type* pPointerType) {
1236 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001237 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001238 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001239 switch (pPointerType->pHead->tag) {
1240 case TY_INT:
1241 o(0x0189); /* movl %eax/%al, (%ecx) */
1242 break;
1243 case TY_CHAR:
1244 o(0x0188); /* movl %eax/%al, (%ecx) */
1245 break;
1246 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001247 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001248 break;
1249 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001250 }
1251
Jack Palevich9eed7a22009-07-06 17:24:34 -07001252 virtual void loadR0FromR0(Type* pPointerType) {
1253 assert(pPointerType->tag == TY_POINTER);
1254 switch (pPointerType->pHead->tag) {
1255 case TY_INT:
1256 o(0x8b); /* mov (%eax), %eax */
1257 break;
1258 case TY_CHAR:
1259 o(0xbe0f); /* movsbl (%eax), %eax */
1260 break;
1261 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001262 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001263 break;
1264 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001265 ob(0); /* add zero in code */
Jack Palevich8df46192009-07-07 14:48:51 -07001266 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001267 }
1268
Jack Palevich8df46192009-07-07 14:48:51 -07001269 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001270 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001271 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001272 }
1273
Jack Palevich1cdef202009-05-22 12:06:27 -07001274 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001275 gmov(6, ea); /* mov %eax, EA */
1276 }
1277
Jack Palevich8df46192009-07-07 14:48:51 -07001278 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001279 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -07001280 if (isIncDec) {
1281 /* Implement post-increment or post decrement.
1282 */
1283 gmov(0, ea); /* 83 ADD */
1284 o(decodeOp(op));
1285 }
Jack Palevich8df46192009-07-07 14:48:51 -07001286 setR0Type(pType);
1287 }
1288
1289 virtual void convertR0(Type* pType){
1290 if (bitsSame(pType, getR0Type())) {
1291 return;
1292 }
1293 error("convertR0: unsupported conversion %d <- %d", pType->tag,
1294 getR0Type()->tag);
Jack Palevich21a15a22009-05-11 14:49:29 -07001295 }
1296
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001297 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001298 return oad(0xec81, 0); /* sub $xxx, %esp */
1299 }
1300
Jack Palevich1cdef202009-05-22 12:06:27 -07001301 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001302 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1303 }
1304
Jack Palevich7810bc92009-05-15 14:31:47 -07001305 virtual void endFunctionCallArguments(int a, int l) {
1306 * (int*) a = l;
1307 }
1308
Jack Palevich8df46192009-07-07 14:48:51 -07001309 virtual int callForward(int symbol, Type* pFunc) {
1310 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001311 return psym(0xe8, symbol); /* call xxx */
1312 }
1313
Jack Palevich8df46192009-07-07 14:48:51 -07001314 virtual void callRelative(int t, Type* pFunc) {
1315 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001316 psym(0xe8, t); /* call xxx */
1317 }
1318
Jack Palevich8df46192009-07-07 14:48:51 -07001319 virtual void callIndirect(int l, Type* pFunc) {
1320 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001321 oad(0x2494ff, l); /* call *xxx(%esp) */
1322 }
1323
Jack Palevich7810bc92009-05-15 14:31:47 -07001324 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1325 if (isIndirect) {
1326 l += 4;
1327 }
-b master422972c2009-06-17 19:13:52 -07001328 if (l > 0) {
1329 oad(0xc481, l); /* add $xxx, %esp */
1330 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001331 }
1332
Jack Palevicha6535612009-05-13 16:24:17 -07001333 virtual int jumpOffset() {
1334 return 5;
1335 }
1336
1337 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001338 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001339 }
1340
Jack Paleviche7b59062009-05-19 17:12:17 -07001341 /* output a symbol and patch all calls to it */
1342 virtual void gsym(int t) {
1343 int n;
1344 int pc = getPC();
1345 while (t) {
1346 n = *(int *) t; /* next value */
1347 *(int *) t = pc - t - 4;
1348 t = n;
1349 }
1350 }
1351
Jack Palevich1cdef202009-05-22 12:06:27 -07001352 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001353 size_t pagesize = 4096;
1354 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1355 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1356 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1357 if (err) {
1358 error("mprotect() failed: %d", errno);
1359 }
1360 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001361 }
1362
Jack Palevich9eed7a22009-07-06 17:24:34 -07001363 /**
1364 * Stack alignment (in bytes) for this type of data
1365 */
1366 virtual size_t stackAlignment(Type* pType){
1367 switch(pType->tag) {
1368 case TY_DOUBLE:
1369 return 8;
1370 default:
1371 return 4;
1372 }
1373 }
1374
1375 /**
1376 * Array element alignment (in bytes) for this type of data.
1377 */
1378 virtual size_t sizeOf(Type* pType){
1379 switch(pType->tag) {
1380 case TY_INT:
1381 return 4;
1382 case TY_CHAR:
1383 return 1;
1384 default:
1385 return 0;
1386 case TY_FLOAT:
1387 return 4;
1388 case TY_DOUBLE:
1389 return 8;
1390 case TY_POINTER:
1391 return 4;
1392 }
1393 }
1394
Jack Palevich21a15a22009-05-11 14:49:29 -07001395 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001396
1397 /** Output 1 to 4 bytes.
1398 *
1399 */
1400 void o(int n) {
1401 /* cannot use unsigned, so we must do a hack */
1402 while (n && n != -1) {
1403 ob(n & 0xff);
1404 n = n >> 8;
1405 }
1406 }
1407
1408 /* psym is used to put an instruction with a data field which is a
1409 reference to a symbol. It is in fact the same as oad ! */
1410 int psym(int n, int t) {
1411 return oad(n, t);
1412 }
1413
1414 /* instruction + address */
1415 int oad(int n, int t) {
1416 o(n);
1417 int result = getPC();
1418 o4(t);
1419 return result;
1420 }
1421
1422
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001423 static const int operatorHelper[];
1424
1425 int decodeOp(int op) {
1426 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001427 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001428 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001429 }
1430 return operatorHelper[op];
1431 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001432
Jack Palevich546b2242009-05-13 15:10:04 -07001433 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001434 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001435 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001436 }
1437 };
1438
Jack Paleviche7b59062009-05-19 17:12:17 -07001439#endif // PROVIDE_X86_CODEGEN
1440
Jack Palevichb67b18f2009-06-11 21:12:23 -07001441#ifdef PROVIDE_TRACE_CODEGEN
1442 class TraceCodeGenerator : public CodeGenerator {
1443 private:
1444 CodeGenerator* mpBase;
1445
1446 public:
1447 TraceCodeGenerator(CodeGenerator* pBase) {
1448 mpBase = pBase;
1449 }
1450
1451 virtual ~TraceCodeGenerator() {
1452 delete mpBase;
1453 }
1454
1455 virtual void init(CodeBuf* pCodeBuf) {
1456 mpBase->init(pCodeBuf);
1457 }
1458
1459 void setErrorSink(ErrorSink* pErrorSink) {
1460 mpBase->setErrorSink(pErrorSink);
1461 }
1462
1463 /* returns address to patch with local variable size
1464 */
1465 virtual int functionEntry(int argCount) {
1466 int result = mpBase->functionEntry(argCount);
1467 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1468 return result;
1469 }
1470
1471 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1472 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1473 argCount, localVariableAddress, localVariableSize);
1474 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1475 }
1476
1477 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001478 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001479 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001480 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001481 }
1482
Jack Palevich8df46192009-07-07 14:48:51 -07001483 virtual void lif(float f, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001484 fprintf(stderr, "lif(%g)\n", f);
Jack Palevich8df46192009-07-07 14:48:51 -07001485 mpBase->lif(f, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001486 }
1487
Jack Palevich8df46192009-07-07 14:48:51 -07001488 virtual void lid(double d, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001489 fprintf(stderr, "lid(%g)\n", d);
Jack Palevich8df46192009-07-07 14:48:51 -07001490 mpBase->lid(d, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001491 }
1492
Jack Palevichb67b18f2009-06-11 21:12:23 -07001493 virtual int gjmp(int t) {
1494 int result = mpBase->gjmp(t);
1495 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1496 return result;
1497 }
1498
1499 /* l = 0: je, l == 1: jne */
1500 virtual int gtst(bool l, int t) {
1501 int result = mpBase->gtst(l, t);
1502 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1503 return result;
1504 }
1505
1506 virtual void gcmp(int op) {
1507 fprintf(stderr, "gcmp(%d)\n", op);
1508 mpBase->gcmp(op);
1509 }
1510
1511 virtual void genOp(int op) {
1512 fprintf(stderr, "genOp(%d)\n", op);
1513 mpBase->genOp(op);
1514 }
1515
Jack Palevich9eed7a22009-07-06 17:24:34 -07001516
1517 virtual void gUnaryCmp(int op) {
1518 fprintf(stderr, "gUnaryCmp(%d)\n", op);
1519 mpBase->gUnaryCmp(op);
1520 }
1521
1522 virtual void genUnaryOp(int op) {
1523 fprintf(stderr, "genUnaryOp(%d)\n", op);
1524 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001525 }
1526
1527 virtual void pushR0() {
1528 fprintf(stderr, "pushR0()\n");
1529 mpBase->pushR0();
1530 }
1531
Jack Palevich9eed7a22009-07-06 17:24:34 -07001532 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001533 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001534 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001535 }
1536
Jack Palevich9eed7a22009-07-06 17:24:34 -07001537 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001538 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001539 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001540 }
1541
Jack Palevich8df46192009-07-07 14:48:51 -07001542 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001543 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001544 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001545 }
1546
1547 virtual void storeR0(int ea) {
1548 fprintf(stderr, "storeR0(%d)\n", ea);
1549 mpBase->storeR0(ea);
1550 }
1551
Jack Palevich8df46192009-07-07 14:48:51 -07001552 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001553 fprintf(stderr, "loadR0(%d, %d, %d)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001554 mpBase->loadR0(ea, isIncDec, op, pType);
1555 }
1556
1557 virtual void convertR0(Type* pType){
1558 fprintf(stderr, "convertR0(pType)\n");
1559 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001560 }
1561
1562 virtual int beginFunctionCallArguments() {
1563 int result = mpBase->beginFunctionCallArguments();
1564 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1565 return result;
1566 }
1567
1568 virtual void storeR0ToArg(int l) {
1569 fprintf(stderr, "storeR0ToArg(%d)\n", l);
1570 mpBase->storeR0ToArg(l);
1571 }
1572
1573 virtual void endFunctionCallArguments(int a, int l) {
1574 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1575 mpBase->endFunctionCallArguments(a, l);
1576 }
1577
Jack Palevich8df46192009-07-07 14:48:51 -07001578 virtual int callForward(int symbol, Type* pFunc) {
1579 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001580 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1581 return result;
1582 }
1583
Jack Palevich8df46192009-07-07 14:48:51 -07001584 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001585 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001586 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001587 }
1588
Jack Palevich8df46192009-07-07 14:48:51 -07001589 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001590 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001591 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001592 }
1593
1594 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1595 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1596 mpBase->adjustStackAfterCall(l, isIndirect);
1597 }
1598
1599 virtual int jumpOffset() {
1600 return mpBase->jumpOffset();
1601 }
1602
1603 virtual int disassemble(FILE* out) {
1604 return mpBase->disassemble(out);
1605 }
1606
1607 /* output a symbol and patch all calls to it */
1608 virtual void gsym(int t) {
1609 fprintf(stderr, "gsym(%d)\n", t);
1610 mpBase->gsym(t);
1611 }
1612
1613 virtual int finishCompile() {
1614 int result = mpBase->finishCompile();
1615 fprintf(stderr, "finishCompile() = %d\n", result);
1616 return result;
1617 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001618
1619 /**
1620 * Stack alignment (in bytes) for this type of data
1621 */
1622 virtual size_t stackAlignment(Type* pType){
1623 return mpBase->stackAlignment(pType);
1624 }
1625
1626 /**
1627 * Array element alignment (in bytes) for this type of data.
1628 */
1629 virtual size_t sizeOf(Type* pType){
1630 return mpBase->sizeOf(pType);
1631 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001632 };
1633
1634#endif // PROVIDE_TRACE_CODEGEN
1635
Jack Palevich569f1352009-06-29 14:29:08 -07001636 class Arena {
1637 public:
1638 // Used to record a given allocation amount.
1639 // Used:
1640 // Mark mark = arena.mark();
1641 // ... lots of arena.allocate()
1642 // arena.free(mark);
1643
1644 struct Mark {
1645 size_t chunk;
1646 size_t offset;
1647 };
1648
1649 Arena() {
1650 mCurrentChunk = 0;
1651 Chunk start(CHUNK_SIZE);
1652 mData.push_back(start);
1653 }
1654
1655 ~Arena() {
1656 for(size_t i = 0; i < mData.size(); i++) {
1657 mData[i].free();
1658 }
1659 }
1660
1661 // Alloc using the standard alignment size safe for any variable
1662 void* alloc(size_t size) {
1663 return alloc(size, 8);
1664 }
1665
1666 Mark mark(){
1667 Mark result;
1668 result.chunk = mCurrentChunk;
1669 result.offset = mData[mCurrentChunk].mOffset;
1670 return result;
1671 }
1672
1673 void freeToMark(const Mark& mark) {
1674 mCurrentChunk = mark.chunk;
1675 mData[mCurrentChunk].mOffset = mark.offset;
1676 }
1677
1678 private:
1679 // Allocate memory aligned to a given size
1680 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1681 // Memory is not zero filled.
1682
1683 void* alloc(size_t size, size_t alignment) {
1684 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1685 if (mCurrentChunk + 1 < mData.size()) {
1686 mCurrentChunk++;
1687 } else {
1688 size_t allocSize = CHUNK_SIZE;
1689 if (allocSize < size + alignment - 1) {
1690 allocSize = size + alignment - 1;
1691 }
1692 Chunk chunk(allocSize);
1693 mData.push_back(chunk);
1694 mCurrentChunk++;
1695 }
1696 }
1697 return mData[mCurrentChunk].allocate(size, alignment);
1698 }
1699
1700 static const size_t CHUNK_SIZE = 128*1024;
1701 // Note: this class does not deallocate its
1702 // memory when it's destroyed. It depends upon
1703 // its parent to deallocate the memory.
1704 struct Chunk {
1705 Chunk() {
1706 mpData = 0;
1707 mSize = 0;
1708 mOffset = 0;
1709 }
1710
1711 Chunk(size_t size) {
1712 mSize = size;
1713 mpData = (char*) malloc(size);
1714 mOffset = 0;
1715 }
1716
1717 ~Chunk() {
1718 // Doesn't deallocate memory.
1719 }
1720
1721 void* allocate(size_t size, size_t alignment) {
1722 size_t alignedOffset = aligned(mOffset, alignment);
1723 void* result = mpData + alignedOffset;
1724 mOffset = alignedOffset + size;
1725 return result;
1726 }
1727
1728 void free() {
1729 if (mpData) {
1730 ::free(mpData);
1731 mpData = 0;
1732 }
1733 }
1734
1735 size_t remainingCapacity(size_t alignment) {
1736 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1737 }
1738
1739 // Assume alignment is a power of two
1740 inline size_t aligned(size_t v, size_t alignment) {
1741 size_t mask = alignment-1;
1742 return (v + mask) & ~mask;
1743 }
1744
1745 char* mpData;
1746 size_t mSize;
1747 size_t mOffset;
1748 };
1749
1750 size_t mCurrentChunk;
1751
1752 Vector<Chunk> mData;
1753 };
1754
Jack Palevich569f1352009-06-29 14:29:08 -07001755 struct VariableInfo;
1756
1757 struct Token {
1758 int hash;
1759 size_t length;
1760 char* pText;
1761 tokenid_t id;
1762
1763 // Current values for the token
1764 char* mpMacroDefinition;
1765 VariableInfo* mpVariableInfo;
1766 };
1767
1768 class TokenTable {
1769 public:
1770 // Don't use 0..0xff, allows characters and operators to be tokens too.
1771
1772 static const int TOKEN_BASE = 0x100;
1773 TokenTable() {
1774 mpMap = hashmapCreate(128, hashFn, equalsFn);
1775 }
1776
1777 ~TokenTable() {
1778 hashmapFree(mpMap);
1779 }
1780
1781 void setArena(Arena* pArena) {
1782 mpArena = pArena;
1783 }
1784
1785 // Returns a token for a given string of characters.
1786 tokenid_t intern(const char* pText, size_t length) {
1787 Token probe;
1788 int hash = hashmapHash((void*) pText, length);
1789 {
1790 Token probe;
1791 probe.hash = hash;
1792 probe.length = length;
1793 probe.pText = (char*) pText;
1794 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1795 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001796 return pValue->id;
1797 }
1798 }
1799
1800 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1801 memset(pToken, 0, sizeof(*pToken));
1802 pToken->hash = hash;
1803 pToken->length = length;
1804 pToken->pText = (char*) mpArena->alloc(length + 1);
1805 memcpy(pToken->pText, pText, length);
1806 pToken->pText[length] = 0;
1807 pToken->id = mTokens.size() + TOKEN_BASE;
1808 mTokens.push_back(pToken);
1809 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001810 return pToken->id;
1811 }
1812
1813 // Return the Token for a given tokenid.
1814 Token& operator[](tokenid_t id) {
1815 return *mTokens[id - TOKEN_BASE];
1816 }
1817
1818 inline size_t size() {
1819 return mTokens.size();
1820 }
1821
1822 private:
1823
1824 static int hashFn(void* pKey) {
1825 Token* pToken = (Token*) pKey;
1826 return pToken->hash;
1827 }
1828
1829 static bool equalsFn(void* keyA, void* keyB) {
1830 Token* pTokenA = (Token*) keyA;
1831 Token* pTokenB = (Token*) keyB;
1832 // Don't need to compare hash values, they should always be equal
1833 return pTokenA->length == pTokenB->length
1834 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1835 }
1836
1837 Hashmap* mpMap;
1838 Vector<Token*> mTokens;
1839 Arena* mpArena;
1840 };
1841
Jack Palevich1cdef202009-05-22 12:06:27 -07001842 class InputStream {
1843 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001844 int getChar() {
1845 if (bumpLine) {
1846 line++;
1847 bumpLine = false;
1848 }
1849 int ch = get();
1850 if (ch == '\n') {
1851 bumpLine = true;
1852 }
1853 return ch;
1854 }
1855 int getLine() {
1856 return line;
1857 }
1858 protected:
1859 InputStream() :
1860 line(1), bumpLine(false) {
1861 }
1862 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001863 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001864 int line;
1865 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001866 };
1867
1868 class FileInputStream : public InputStream {
1869 public:
1870 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001871 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001872 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001873 FILE* f;
1874 };
1875
1876 class TextInputStream : public InputStream {
1877 public:
1878 TextInputStream(const char* text, size_t textLength)
1879 : pText(text), mTextLength(textLength), mPosition(0) {
1880 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001881
1882 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001883 virtual int get() {
1884 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1885 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001886
Jack Palevich1cdef202009-05-22 12:06:27 -07001887 const char* pText;
1888 size_t mTextLength;
1889 size_t mPosition;
1890 };
1891
Jack Palevicheedf9d22009-06-04 16:23:40 -07001892 class String {
1893 public:
1894 String() {
1895 mpBase = 0;
1896 mUsed = 0;
1897 mSize = 0;
1898 }
1899
Jack Palevich303d8ff2009-06-11 19:06:24 -07001900 String(const char* item, int len, bool adopt) {
1901 if (len < 0) {
1902 len = strlen(item);
1903 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001904 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001905 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001906 mUsed = len;
1907 mSize = len + 1;
1908 } else {
1909 mpBase = 0;
1910 mUsed = 0;
1911 mSize = 0;
1912 appendBytes(item, len);
1913 }
1914 }
1915
Jack Palevich303d8ff2009-06-11 19:06:24 -07001916 String(const String& other) {
1917 mpBase = 0;
1918 mUsed = 0;
1919 mSize = 0;
1920 appendBytes(other.getUnwrapped(), other.len());
1921 }
1922
Jack Palevicheedf9d22009-06-04 16:23:40 -07001923 ~String() {
1924 if (mpBase) {
1925 free(mpBase);
1926 }
1927 }
1928
Jack Palevicha6baa232009-06-12 11:25:59 -07001929 String& operator=(const String& other) {
1930 clear();
1931 appendBytes(other.getUnwrapped(), other.len());
1932 return *this;
1933 }
1934
Jack Palevich303d8ff2009-06-11 19:06:24 -07001935 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001936 return mpBase;
1937 }
1938
Jack Palevich303d8ff2009-06-11 19:06:24 -07001939 void clear() {
1940 mUsed = 0;
1941 if (mSize > 0) {
1942 mpBase[0] = 0;
1943 }
1944 }
1945
Jack Palevicheedf9d22009-06-04 16:23:40 -07001946 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001947 appendBytes(s, strlen(s));
1948 }
1949
1950 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001951 memcpy(ensure(n), s, n + 1);
1952 }
1953
1954 void append(char c) {
1955 * ensure(1) = c;
1956 }
1957
Jack Palevich86351982009-06-30 18:09:56 -07001958 void append(String& other) {
1959 appendBytes(other.getUnwrapped(), other.len());
1960 }
1961
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001962 char* orphan() {
1963 char* result = mpBase;
1964 mpBase = 0;
1965 mUsed = 0;
1966 mSize = 0;
1967 return result;
1968 }
1969
Jack Palevicheedf9d22009-06-04 16:23:40 -07001970 void printf(const char* fmt,...) {
1971 va_list ap;
1972 va_start(ap, fmt);
1973 vprintf(fmt, ap);
1974 va_end(ap);
1975 }
1976
1977 void vprintf(const char* fmt, va_list ap) {
1978 char* temp;
1979 int numChars = vasprintf(&temp, fmt, ap);
1980 memcpy(ensure(numChars), temp, numChars+1);
1981 free(temp);
1982 }
1983
Jack Palevich303d8ff2009-06-11 19:06:24 -07001984 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001985 return mUsed;
1986 }
1987
1988 private:
1989 char* ensure(int n) {
1990 size_t newUsed = mUsed + n;
1991 if (newUsed > mSize) {
1992 size_t newSize = mSize * 2 + 10;
1993 if (newSize < newUsed) {
1994 newSize = newUsed;
1995 }
1996 mpBase = (char*) realloc(mpBase, newSize + 1);
1997 mSize = newSize;
1998 }
1999 mpBase[newUsed] = '\0';
2000 char* result = mpBase + mUsed;
2001 mUsed = newUsed;
2002 return result;
2003 }
2004
2005 char* mpBase;
2006 size_t mUsed;
2007 size_t mSize;
2008 };
2009
Jack Palevich569f1352009-06-29 14:29:08 -07002010 void internKeywords() {
2011 // Note: order has to match TOK_ constants
2012 static const char* keywords[] = {
2013 "int",
2014 "char",
2015 "void",
2016 "if",
2017 "else",
2018 "while",
2019 "break",
2020 "return",
2021 "for",
2022 "pragma",
2023 "define",
2024 "auto",
2025 "case",
2026 "const",
2027 "continue",
2028 "default",
2029 "do",
2030 "double",
2031 "enum",
2032 "extern",
2033 "float",
2034 "goto",
2035 "long",
2036 "register",
2037 "short",
2038 "signed",
2039 "sizeof",
2040 "static",
2041 "struct",
2042 "switch",
2043 "typedef",
2044 "union",
2045 "unsigned",
2046 "volatile",
2047 "_Bool",
2048 "_Complex",
2049 "_Imaginary",
2050 "inline",
2051 "restrict",
2052 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002053
Jack Palevich569f1352009-06-29 14:29:08 -07002054 for(int i = 0; keywords[i]; i++) {
2055 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002056 }
Jack Palevich569f1352009-06-29 14:29:08 -07002057 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002058
Jack Palevich36d94142009-06-08 15:55:32 -07002059 struct InputState {
2060 InputStream* pStream;
2061 int oldCh;
2062 };
2063
Jack Palevich2db168f2009-06-11 14:29:47 -07002064 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002065 void* pAddress;
2066 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002067 tokenid_t tok;
2068 size_t level;
2069 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002070 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002071 };
2072
Jack Palevich303d8ff2009-06-11 19:06:24 -07002073 class SymbolStack {
2074 public:
2075 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002076 mpArena = 0;
2077 mpTokenTable = 0;
2078 }
2079
2080 void setArena(Arena* pArena) {
2081 mpArena = pArena;
2082 }
2083
2084 void setTokenTable(TokenTable* pTokenTable) {
2085 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002086 }
2087
2088 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002089 Mark mark;
2090 mark.mArenaMark = mpArena->mark();
2091 mark.mSymbolHead = mStack.size();
2092 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002093 }
2094
2095 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002096 // Undo any shadowing that was done:
2097 Mark mark = mLevelStack.back();
2098 mLevelStack.pop_back();
2099 while (mStack.size() > mark.mSymbolHead) {
2100 VariableInfo* pV = mStack.back();
2101 mStack.pop_back();
2102 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002103 }
Jack Palevich569f1352009-06-29 14:29:08 -07002104 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002105 }
2106
Jack Palevich569f1352009-06-29 14:29:08 -07002107 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2108 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2109 return pV && pV->level == level();
2110 }
2111
2112 VariableInfo* add(tokenid_t tok) {
2113 Token& token = (*mpTokenTable)[tok];
2114 VariableInfo* pOldV = token.mpVariableInfo;
2115 VariableInfo* pNewV =
2116 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2117 memset(pNewV, 0, sizeof(VariableInfo));
2118 pNewV->tok = tok;
2119 pNewV->level = level();
2120 pNewV->pOldDefinition = pOldV;
2121 token.mpVariableInfo = pNewV;
2122 mStack.push_back(pNewV);
2123 return pNewV;
2124 }
2125
Jack Palevich86351982009-06-30 18:09:56 -07002126 VariableInfo* add(Type* pType) {
2127 VariableInfo* pVI = add(pType->id);
2128 pVI->pType = pType;
2129 return pVI;
2130 }
2131
Jack Palevich569f1352009-06-29 14:29:08 -07002132 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2133 for (size_t i = 0; i < mStack.size(); i++) {
2134 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002135 break;
2136 }
2137 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002138 }
2139
Jack Palevich303d8ff2009-06-11 19:06:24 -07002140 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002141 inline size_t level() {
2142 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002143 }
2144
Jack Palevich569f1352009-06-29 14:29:08 -07002145 struct Mark {
2146 Arena::Mark mArenaMark;
2147 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002148 };
2149
Jack Palevich569f1352009-06-29 14:29:08 -07002150 Arena* mpArena;
2151 TokenTable* mpTokenTable;
2152 Vector<VariableInfo*> mStack;
2153 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002154 };
Jack Palevich36d94142009-06-08 15:55:32 -07002155
2156 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002157 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002158 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002159 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002160 int tokl; // token operator level
2161 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002162 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002163 intptr_t loc; // local variable index
2164 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002165 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002166 char* dptr; // Macro state: Points to macro text during macro playback.
2167 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002168 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002169
2170 // Arena for the duration of the compile
2171 Arena mGlobalArena;
2172 // Arena for data that's only needed when compiling a single function
2173 Arena mLocalArena;
2174
2175 TokenTable mTokenTable;
2176 SymbolStack mGlobals;
2177 SymbolStack mLocals;
2178
Jack Palevich40600de2009-07-01 15:32:35 -07002179 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002180 Type* mkpInt; // int
2181 Type* mkpChar; // char
2182 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002183 Type* mkpFloat;
2184 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002185 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002186 Type* mkpIntPtr;
2187 Type* mkpCharPtr;
2188 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002189
Jack Palevich36d94142009-06-08 15:55:32 -07002190 InputStream* file;
2191
2192 CodeBuf codeBuf;
2193 CodeGenerator* pGen;
2194
Jack Palevicheedf9d22009-06-04 16:23:40 -07002195 String mErrorBuf;
2196
Jack Palevicheedf9d22009-06-04 16:23:40 -07002197 String mPragmas;
2198 int mPragmaStringCount;
2199
Jack Palevich21a15a22009-05-11 14:49:29 -07002200 static const int ALLOC_SIZE = 99999;
2201
Jack Palevich303d8ff2009-06-11 19:06:24 -07002202 static const int TOK_DUMMY = 1;
2203 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002204 static const int TOK_NUM_FLOAT = 3;
2205 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002206
2207 // 3..255 are character and/or operators
2208
Jack Palevich2db168f2009-06-11 14:29:47 -07002209 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002210 // Order has to match string list in "internKeywords".
2211 enum {
2212 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2213 TOK_INT = TOK_KEYWORD,
2214 TOK_CHAR,
2215 TOK_VOID,
2216 TOK_IF,
2217 TOK_ELSE,
2218 TOK_WHILE,
2219 TOK_BREAK,
2220 TOK_RETURN,
2221 TOK_FOR,
2222 TOK_PRAGMA,
2223 TOK_DEFINE,
2224 TOK_AUTO,
2225 TOK_CASE,
2226 TOK_CONST,
2227 TOK_CONTINUE,
2228 TOK_DEFAULT,
2229 TOK_DO,
2230 TOK_DOUBLE,
2231 TOK_ENUM,
2232 TOK_EXTERN,
2233 TOK_FLOAT,
2234 TOK_GOTO,
2235 TOK_LONG,
2236 TOK_REGISTER,
2237 TOK_SHORT,
2238 TOK_SIGNED,
2239 TOK_SIZEOF,
2240 TOK_STATIC,
2241 TOK_STRUCT,
2242 TOK_SWITCH,
2243 TOK_TYPEDEF,
2244 TOK_UNION,
2245 TOK_UNSIGNED,
2246 TOK_VOLATILE,
2247 TOK__BOOL,
2248 TOK__COMPLEX,
2249 TOK__IMAGINARY,
2250 TOK_INLINE,
2251 TOK_RESTRICT,
2252 // Symbols start after tokens
2253 TOK_SYMBOL
2254 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002255
2256 static const int LOCAL = 0x200;
2257
2258 static const int SYM_FORWARD = 0;
2259 static const int SYM_DEFINE = 1;
2260
2261 /* tokens in string heap */
2262 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002263
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002264 static const int OP_INCREMENT = 0;
2265 static const int OP_DECREMENT = 1;
2266 static const int OP_MUL = 2;
2267 static const int OP_DIV = 3;
2268 static const int OP_MOD = 4;
2269 static const int OP_PLUS = 5;
2270 static const int OP_MINUS = 6;
2271 static const int OP_SHIFT_LEFT = 7;
2272 static const int OP_SHIFT_RIGHT = 8;
2273 static const int OP_LESS_EQUAL = 9;
2274 static const int OP_GREATER_EQUAL = 10;
2275 static const int OP_LESS = 11;
2276 static const int OP_GREATER = 12;
2277 static const int OP_EQUALS = 13;
2278 static const int OP_NOT_EQUALS = 14;
2279 static const int OP_LOGICAL_AND = 15;
2280 static const int OP_LOGICAL_OR = 16;
2281 static const int OP_BIT_AND = 17;
2282 static const int OP_BIT_XOR = 18;
2283 static const int OP_BIT_OR = 19;
2284 static const int OP_BIT_NOT = 20;
2285 static const int OP_LOGICAL_NOT = 21;
2286 static const int OP_COUNT = 22;
2287
2288 /* Operators are searched from front, the two-character operators appear
2289 * before the single-character operators with the same first character.
2290 * @ is used to pad out single-character operators.
2291 */
2292 static const char* operatorChars;
2293 static const char operatorLevel[];
2294
Jack Palevich569f1352009-06-29 14:29:08 -07002295 /* Called when we detect an internal problem. Does nothing in production.
2296 *
2297 */
2298 void internalError() {
2299 * (char*) 0 = 0;
2300 }
2301
Jack Palevich86351982009-06-30 18:09:56 -07002302 void assert(bool isTrue) {
2303 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002304 internalError();
2305 }
Jack Palevich86351982009-06-30 18:09:56 -07002306 }
2307
Jack Palevich40600de2009-07-01 15:32:35 -07002308 bool isSymbol(tokenid_t t) {
2309 return t >= TOK_SYMBOL &&
2310 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2311 }
2312
2313 bool isSymbolOrKeyword(tokenid_t t) {
2314 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002315 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002316 }
2317
Jack Palevich86351982009-06-30 18:09:56 -07002318 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002319 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002320 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2321 if (pV && pV->tok != t) {
2322 internalError();
2323 }
2324 return pV;
2325 }
2326
2327 inline bool isDefined(tokenid_t t) {
2328 return t >= TOK_SYMBOL && VI(t) != 0;
2329 }
2330
Jack Palevich40600de2009-07-01 15:32:35 -07002331 const char* nameof(tokenid_t t) {
2332 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002333 return mTokenTable[t].pText;
2334 }
2335
Jack Palevich21a15a22009-05-11 14:49:29 -07002336 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002337 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002338 }
2339
2340 void inp() {
2341 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002342 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002343 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002344 dptr = 0;
2345 ch = dch;
2346 }
2347 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002348 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002349#if 0
2350 printf("ch='%c' 0x%x\n", ch, ch);
2351#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002352 }
2353
2354 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002355 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002356 }
2357
Jack Palevichb4758ff2009-06-12 12:49:14 -07002358 /* read a character constant, advances ch to after end of constant */
2359 int getq() {
2360 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002361 if (ch == '\\') {
2362 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002363 if (isoctal(ch)) {
2364 // 1 to 3 octal characters.
2365 val = 0;
2366 for(int i = 0; i < 3; i++) {
2367 if (isoctal(ch)) {
2368 val = (val << 3) + ch - '0';
2369 inp();
2370 }
2371 }
2372 return val;
2373 } else if (ch == 'x' || ch == 'X') {
2374 // N hex chars
2375 inp();
2376 if (! isxdigit(ch)) {
2377 error("'x' character escape requires at least one digit.");
2378 } else {
2379 val = 0;
2380 while (isxdigit(ch)) {
2381 int d = ch;
2382 if (isdigit(d)) {
2383 d -= '0';
2384 } else if (d <= 'F') {
2385 d = d - 'A' + 10;
2386 } else {
2387 d = d - 'a' + 10;
2388 }
2389 val = (val << 4) + d;
2390 inp();
2391 }
2392 }
2393 } else {
2394 int val = ch;
2395 switch (ch) {
2396 case 'a':
2397 val = '\a';
2398 break;
2399 case 'b':
2400 val = '\b';
2401 break;
2402 case 'f':
2403 val = '\f';
2404 break;
2405 case 'n':
2406 val = '\n';
2407 break;
2408 case 'r':
2409 val = '\r';
2410 break;
2411 case 't':
2412 val = '\t';
2413 break;
2414 case 'v':
2415 val = '\v';
2416 break;
2417 case '\\':
2418 val = '\\';
2419 break;
2420 case '\'':
2421 val = '\'';
2422 break;
2423 case '"':
2424 val = '"';
2425 break;
2426 case '?':
2427 val = '?';
2428 break;
2429 default:
2430 error("Undefined character escape %c", ch);
2431 break;
2432 }
2433 inp();
2434 return val;
2435 }
2436 } else {
2437 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002438 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002439 return val;
2440 }
2441
2442 static bool isoctal(int ch) {
2443 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002444 }
2445
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002446 bool acceptCh(int c) {
2447 bool result = c == ch;
2448 if (result) {
2449 pdef(ch);
2450 inp();
2451 }
2452 return result;
2453 }
2454
2455 bool acceptDigitsCh() {
2456 bool result = false;
2457 while (isdigit(ch)) {
2458 result = true;
2459 pdef(ch);
2460 inp();
2461 }
2462 return result;
2463 }
2464
2465 void parseFloat() {
2466 tok = TOK_NUM_DOUBLE;
2467 // mTokenString already has the integral part of the number.
2468 acceptCh('.');
2469 acceptDigitsCh();
2470 bool doExp = true;
2471 if (acceptCh('e') || acceptCh('E')) {
2472 // Don't need to do any extra work
2473 } else if (ch == 'f' || ch == 'F') {
2474 pdef('e'); // So it can be parsed by strtof.
2475 inp();
2476 tok = TOK_NUM_FLOAT;
2477 } else {
2478 doExp = false;
2479 }
2480 if (doExp) {
2481 bool digitsRequired = acceptCh('-');
2482 bool digitsFound = acceptDigitsCh();
2483 if (digitsRequired && ! digitsFound) {
2484 error("malformed exponent");
2485 }
2486 }
2487 char* pText = mTokenString.getUnwrapped();
2488 if (tok == TOK_NUM_FLOAT) {
2489 tokd = strtof(pText, 0);
2490 } else {
2491 tokd = strtod(pText, 0);
2492 }
2493 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2494 }
2495
Jack Palevich21a15a22009-05-11 14:49:29 -07002496 void next() {
2497 int l, a;
2498
Jack Palevich546b2242009-05-13 15:10:04 -07002499 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002500 if (ch == '#') {
2501 inp();
2502 next();
2503 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002504 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002505 } else if (tok == TOK_PRAGMA) {
2506 doPragma();
2507 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002508 error("Unsupported preprocessor directive \"%s\"",
2509 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002510 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002511 }
2512 inp();
2513 }
2514 tokl = 0;
2515 tok = ch;
2516 /* encode identifiers & numbers */
2517 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002518 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002519 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002520 pdef(ch);
2521 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002522 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002523 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002524 // Start of a numeric constant. Could be integer, float, or
2525 // double, won't know until we look further.
2526 if (ch == '.' || ch == 'e' || ch == 'e'
2527 || ch == 'f' || ch == 'F') {
2528 parseFloat();
2529 } else {
2530 // It's an integer constant
2531 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2532 tok = TOK_NUM;
2533 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002534 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002535 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2536 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002537 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002538 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2539 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002540 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002541 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002542 dch = ch;
2543 inp();
2544 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002545 }
2546 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002547 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002548 inp();
2549 if (tok == '\'') {
2550 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002551 tokc = getq();
2552 if (ch != '\'') {
2553 error("Expected a ' character, got %c", ch);
2554 } else {
2555 inp();
2556 }
Jack Palevich546b2242009-05-13 15:10:04 -07002557 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002558 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002559 while (ch && ch != EOF) {
2560 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002561 inp();
2562 inp();
2563 if (ch == '/')
2564 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002565 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002566 if (ch == EOF) {
2567 error("End of file inside comment.");
2568 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002569 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002570 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002571 } else if ((tok == '/') & (ch == '/')) {
2572 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002573 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002574 inp();
2575 }
2576 inp();
2577 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002578 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002579 const char* t = operatorChars;
2580 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002581 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002582 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002583 tokl = operatorLevel[opIndex];
2584 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002585 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002586#if 0
2587 printf("%c%c -> tokl=%d tokc=0x%x\n",
2588 l, a, tokl, tokc);
2589#endif
2590 if (a == ch) {
2591 inp();
2592 tok = TOK_DUMMY; /* dummy token for double tokens */
2593 }
2594 break;
2595 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002596 opIndex++;
2597 }
2598 if (l == 0) {
2599 tokl = 0;
2600 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002601 }
2602 }
2603 }
2604#if 0
2605 {
Jack Palevich569f1352009-06-29 14:29:08 -07002606 String buf;
2607 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002608 fprintf(stderr, "%s\n", buf.getUnwrapped());
2609 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002610#endif
2611 }
2612
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002613 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002614 next();
2615 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002616 String* pName = new String();
2617 while (isspace(ch)) {
2618 inp();
2619 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002620 if (ch == '(') {
2621 delete pName;
2622 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002623 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002624 }
2625 while (isspace(ch)) {
2626 inp();
2627 }
Jack Palevich569f1352009-06-29 14:29:08 -07002628 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002629 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002630 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002631 inp();
2632 }
Jack Palevich569f1352009-06-29 14:29:08 -07002633 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2634 memcpy(pDefn, value.getUnwrapped(), value.len());
2635 pDefn[value.len()] = 0;
2636 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002637 }
2638
Jack Palevicheedf9d22009-06-04 16:23:40 -07002639 void doPragma() {
2640 // # pragma name(val)
2641 int state = 0;
2642 while(ch != EOF && ch != '\n' && state < 10) {
2643 switch(state) {
2644 case 0:
2645 if (isspace(ch)) {
2646 inp();
2647 } else {
2648 state++;
2649 }
2650 break;
2651 case 1:
2652 if (isalnum(ch)) {
2653 mPragmas.append(ch);
2654 inp();
2655 } else if (ch == '(') {
2656 mPragmas.append(0);
2657 inp();
2658 state++;
2659 } else {
2660 state = 11;
2661 }
2662 break;
2663 case 2:
2664 if (isalnum(ch)) {
2665 mPragmas.append(ch);
2666 inp();
2667 } else if (ch == ')') {
2668 mPragmas.append(0);
2669 inp();
2670 state = 10;
2671 } else {
2672 state = 11;
2673 }
2674 break;
2675 }
2676 }
2677 if(state != 10) {
2678 error("Unexpected pragma syntax");
2679 }
2680 mPragmaStringCount += 2;
2681 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002682
Jack Palevichac0e95e2009-05-29 13:53:44 -07002683 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002684 mErrorBuf.printf("%ld: ", file->getLine());
2685 mErrorBuf.vprintf(fmt, ap);
2686 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002687 }
2688
Jack Palevich8b0624c2009-05-20 12:12:06 -07002689 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002690 if (tok != c) {
2691 error("'%c' expected", c);
2692 }
2693 next();
2694 }
2695
Jack Palevich86351982009-06-30 18:09:56 -07002696 bool accept(intptr_t c) {
2697 if (tok == c) {
2698 next();
2699 return true;
2700 }
2701 return false;
2702 }
2703
Jack Palevich40600de2009-07-01 15:32:35 -07002704 bool acceptStringLiteral() {
2705 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07002706 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07002707 // This while loop merges multiple adjacent string constants.
2708 while (tok == '"') {
2709 while (ch != '"' && ch != EOF) {
2710 *allocGlobalSpace(1) = getq();
2711 }
2712 if (ch != '"') {
2713 error("Unterminated string constant.");
2714 }
2715 inp();
2716 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002717 }
Jack Palevich40600de2009-07-01 15:32:35 -07002718 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002719 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002720 /* align heap */
2721 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002722
2723 return true;
2724 }
2725 return false;
2726 }
2727 /* Parse and evaluate a unary expression.
2728 * allowAssignment is true if '=' parsing wanted (quick hack)
2729 */
2730 void unary(bool allowAssignment) {
2731 intptr_t n, t, a;
2732 t = 0;
2733 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2734 if (acceptStringLiteral()) {
2735 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002736 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002737 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002738 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002739 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07002740 t = tok;
2741 next();
2742 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07002743 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002744 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich8df46192009-07-07 14:48:51 -07002745 pGen->lif(ad, mkpFloat);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002746 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich8df46192009-07-07 14:48:51 -07002747 pGen->lid(ad, mkpDouble);
Jack Palevich21a15a22009-05-11 14:49:29 -07002748 } else if (c == 2) {
2749 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002750 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002751 if (t == '!')
Jack Palevich9eed7a22009-07-06 17:24:34 -07002752 pGen->gUnaryCmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002753 else
Jack Palevich9eed7a22009-07-06 17:24:34 -07002754 pGen->genUnaryOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002755 } else if (t == '(') {
2756 expr();
2757 skip(')');
2758 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002759 /* This is a pointer dereference, but we currently only
2760 * support a pointer dereference if it's immediately
2761 * in front of a cast. So parse the cast right here.
2762 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002763 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002764 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2765 // We currently only handle 3 types of cast:
2766 // (int*), (char*) , (int (*)())
2767 if(typeEqual(pCast, mkpIntPtr)) {
2768 t = TOK_INT;
2769 } else if (typeEqual(pCast, mkpCharPtr)) {
2770 t = TOK_CHAR;
2771 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002772 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002773 } else {
2774 String buffer;
2775 decodeType(buffer, pCast);
2776 error("Unsupported cast type %s", buffer.getUnwrapped());
2777 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002778 }
2779 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002780 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002781 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002782 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002783 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002784 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002785 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002786 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002787 }
Jack Palevich3f226492009-07-02 14:46:19 -07002788 // Else we fall through to the function call below, with
2789 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002790 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07002791 VariableInfo* pVI = VI(tok);
2792 pGen->leaR0((int) pVI->pAddress,
2793 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07002794 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002795 } else if (t == EOF ) {
2796 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002797 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002798 // Don't have to do anything special here, the error
2799 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002800 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002801 if (!isDefined(t)) {
2802 mGlobals.add(t);
2803 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002804 }
Jack Palevich8df46192009-07-07 14:48:51 -07002805 VariableInfo* pVI = VI(t);
2806 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002807 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002808 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002809 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich8df46192009-07-07 14:48:51 -07002810 pVI->pType = mkpIntFn;
2811 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002812 }
Jack Palevich40600de2009-07-01 15:32:35 -07002813 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002814 /* assignment */
2815 next();
2816 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002817 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002818 } else if (tok != '(') {
2819 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002820 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002821 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07002822 }
Jack Palevich8df46192009-07-07 14:48:51 -07002823 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002824 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002825 next();
2826 }
2827 }
2828 }
2829 }
2830
2831 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07002832 if (accept('(')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002833 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002834 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002835
2836 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002837 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07002838 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002839 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002840 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002841 pGen->storeR0ToArg(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002842 l = l + 4;
Jack Palevich95727a02009-07-06 12:07:15 -07002843 if (accept(',')) {
2844 // fine
2845 } else if ( tok != ')') {
2846 error("Expected ',' or ')'");
2847 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002848 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002849 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002850 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002851 if (!n) {
2852 /* forward reference */
Jack Palevich569f1352009-06-29 14:29:08 -07002853 VariableInfo* pVI = VI(t);
Jack Palevich8df46192009-07-07 14:48:51 -07002854 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
2855 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002856 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07002857 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002858 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07002859 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
2860 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002861 }
-b master422972c2009-06-17 19:13:52 -07002862 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002863 }
2864 }
2865
Jack Palevich40600de2009-07-01 15:32:35 -07002866 /* Recursive descent parser for binary operations.
2867 */
2868 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002869 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002870 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002871 if (level-- == 1)
2872 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07002873 else {
Jack Palevich40600de2009-07-01 15:32:35 -07002874 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002875 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002876 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002877 n = tok;
2878 t = tokc;
2879 next();
2880
Jack Palevich40600de2009-07-01 15:32:35 -07002881 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002882 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002883 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002884 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002885 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07002886 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002887
Jack Palevich40600de2009-07-01 15:32:35 -07002888 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002889 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002890 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002891 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002892 }
2893 }
2894 }
2895 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002896 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002897 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07002898 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07002899 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002900 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07002901 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002902 }
2903 }
2904 }
2905
2906 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07002907 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07002908 }
2909
2910 int test_expr() {
2911 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002912 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002913 }
2914
Jack Palevicha6baa232009-06-12 11:25:59 -07002915 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002916 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002917
Jack Palevich95727a02009-07-06 12:07:15 -07002918 Type* pBaseType;
2919 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002920 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07002921 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07002922 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002923 next();
2924 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002925 a = test_expr();
2926 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002927 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002928 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002929 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002930 n = pGen->gjmp(0); /* jmp */
2931 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002932 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002933 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002934 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002935 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002936 }
Jack Palevich546b2242009-05-13 15:10:04 -07002937 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002938 t = tok;
2939 next();
2940 skip('(');
2941 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002942 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002943 a = test_expr();
2944 } else {
2945 if (tok != ';')
2946 expr();
2947 skip(';');
2948 n = codeBuf.getPC();
2949 a = 0;
2950 if (tok != ';')
2951 a = test_expr();
2952 skip(';');
2953 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002954 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002955 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002956 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002957 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002958 n = t + 4;
2959 }
2960 }
2961 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002962 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002963 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002964 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002965 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002966 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002967 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002968 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002969 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002970 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002971 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002972 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002973 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002974 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002975 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002976 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07002977 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07002978 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07002979 expr();
Jack Palevich8df46192009-07-07 14:48:51 -07002980 pGen->convertR0(pReturnType);
2981 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002982 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07002983 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002984 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002985 } else if (tok != ';')
2986 expr();
2987 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002988 }
2989 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002990
Jack Palevich3f226492009-07-02 14:46:19 -07002991 bool typeEqual(Type* a, Type* b) {
2992 if (a == b) {
2993 return true;
2994 }
2995 if (a == NULL || b == NULL) {
2996 return false;
2997 }
2998 TypeTag at = a->tag;
2999 if (at != b->tag) {
3000 return false;
3001 }
3002 if (at == TY_POINTER) {
3003 return typeEqual(a->pHead, b->pHead);
3004 } else if (at == TY_FUNC || at == TY_PARAM) {
3005 return typeEqual(a->pHead, b->pHead)
3006 && typeEqual(a->pTail, b->pTail);
3007 }
3008 return true;
3009 }
3010
Jack Palevich86351982009-06-30 18:09:56 -07003011 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3012 assert(tag >= TY_INT && tag <= TY_PARAM);
3013 Type* pType = (Type*) arena.alloc(sizeof(Type));
3014 memset(pType, 0, sizeof(*pType));
3015 pType->tag = tag;
3016 pType->pHead = pHead;
3017 pType->pTail = pTail;
3018 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003019 }
3020
Jack Palevich3f226492009-07-02 14:46:19 -07003021 Type* createPtrType(Type* pType, Arena& arena) {
3022 return createType(TY_POINTER, pType, NULL, arena);
3023 }
3024
3025 /**
3026 * Try to print a type in declaration order
3027 */
Jack Palevich86351982009-06-30 18:09:56 -07003028 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003029 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003030 if (pType == NULL) {
3031 buffer.appendCStr("null");
3032 return;
3033 }
Jack Palevich3f226492009-07-02 14:46:19 -07003034 decodeTypeImp(buffer, pType);
3035 }
3036
3037 void decodeTypeImp(String& buffer, Type* pType) {
3038 decodeTypeImpPrefix(buffer, pType);
3039
Jack Palevich86351982009-06-30 18:09:56 -07003040 String temp;
3041 if (pType->id != 0) {
3042 decodeToken(temp, pType->id);
3043 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003044 }
3045
3046 decodeTypeImpPostfix(buffer, pType);
3047 }
3048
3049 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3050 TypeTag tag = pType->tag;
3051
3052 if (tag >= TY_INT && tag <= TY_VOID) {
3053 switch (tag) {
3054 case TY_INT:
3055 buffer.appendCStr("int");
3056 break;
3057 case TY_CHAR:
3058 buffer.appendCStr("char");
3059 break;
3060 case TY_VOID:
3061 buffer.appendCStr("void");
3062 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003063 case TY_FLOAT:
3064 buffer.appendCStr("float");
3065 break;
3066 case TY_DOUBLE:
3067 buffer.appendCStr("double");
3068 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003069 default:
3070 break;
3071 }
Jack Palevich86351982009-06-30 18:09:56 -07003072 buffer.append(' ');
3073 }
Jack Palevich3f226492009-07-02 14:46:19 -07003074
3075 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003076 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003077 break;
3078 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003079 break;
3080 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003081 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003082 case TY_FLOAT:
3083 break;
3084 case TY_DOUBLE:
3085 break;
Jack Palevich86351982009-06-30 18:09:56 -07003086 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003087 decodeTypeImpPrefix(buffer, pType->pHead);
3088 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3089 buffer.append('(');
3090 }
3091 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003092 break;
3093 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003094 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003095 break;
3096 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003097 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003098 break;
3099 default:
3100 String temp;
3101 temp.printf("Unknown tag %d", pType->tag);
3102 buffer.append(temp);
3103 break;
3104 }
Jack Palevich3f226492009-07-02 14:46:19 -07003105 }
3106
3107 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3108 TypeTag tag = pType->tag;
3109
3110 switch(tag) {
3111 case TY_POINTER:
3112 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3113 buffer.append(')');
3114 }
3115 decodeTypeImpPostfix(buffer, pType->pHead);
3116 break;
3117 case TY_FUNC:
3118 buffer.append('(');
3119 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3120 decodeTypeImp(buffer, pArg);
3121 if (pArg->pTail) {
3122 buffer.appendCStr(", ");
3123 }
3124 }
3125 buffer.append(')');
3126 break;
3127 default:
3128 break;
Jack Palevich86351982009-06-30 18:09:56 -07003129 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003130 }
3131
Jack Palevich86351982009-06-30 18:09:56 -07003132 void printType(Type* pType) {
3133 String buffer;
3134 decodeType(buffer, pType);
3135 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003136 }
3137
Jack Palevich86351982009-06-30 18:09:56 -07003138 Type* acceptPrimitiveType(Arena& arena) {
3139 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003140 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003141 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003142 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003143 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003144 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003145 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003146 } else if (tok == TOK_FLOAT) {
3147 pType = mkpFloat;
3148 } else if (tok == TOK_DOUBLE) {
3149 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003150 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003151 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003152 }
3153 next();
Jack Palevich86351982009-06-30 18:09:56 -07003154 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003155 }
3156
Jack Palevich3f226492009-07-02 14:46:19 -07003157 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3158 Arena& arena) {
3159 tokenid_t declName = 0;
3160 pType = acceptDecl2(pType, declName, nameAllowed,
3161 nameRequired, arena);
3162 if (declName) {
3163 // Clone the parent type so we can set a unique ID
3164 pType = createType(pType->tag, pType->pHead,
3165 pType->pTail, arena);
3166
Jack Palevich86351982009-06-30 18:09:56 -07003167 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003168 }
Jack Palevich3f226492009-07-02 14:46:19 -07003169 // fprintf(stderr, "Parsed a declaration: ");
3170 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003171 return pType;
3172 }
3173
Jack Palevich3f226492009-07-02 14:46:19 -07003174 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3175 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003176 if (! pType) {
3177 error("Expected a declaration");
3178 }
3179 return pType;
3180 }
3181
Jack Palevich3f226492009-07-02 14:46:19 -07003182 /* Used for accepting types that appear in casts */
3183 Type* acceptCastTypeDeclaration(Arena& arena) {
3184 Type* pType = acceptPrimitiveType(arena);
3185 if (pType) {
3186 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003187 }
Jack Palevich86351982009-06-30 18:09:56 -07003188 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003189 }
3190
Jack Palevich3f226492009-07-02 14:46:19 -07003191 Type* expectCastTypeDeclaration(Arena& arena) {
3192 Type* pType = acceptCastTypeDeclaration(arena);
3193 if (! pType) {
3194 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003195 }
Jack Palevich3f226492009-07-02 14:46:19 -07003196 return pType;
3197 }
3198
3199 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3200 bool nameAllowed, bool nameRequired, Arena& arena) {
3201 int ptrCounter = 0;
3202 while (accept('*')) {
3203 ptrCounter++;
3204 }
3205 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3206 while (ptrCounter-- > 0) {
3207 pType = createType(TY_POINTER, pType, NULL, arena);
3208 }
3209 return pType;
3210 }
3211
3212 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3213 bool nameAllowed, bool nameRequired, Arena& arena) {
3214 // direct-dcl :
3215 // name
3216 // (dcl)
3217 // direct-dcl()
3218 // direct-dcl[]
3219 Type* pNewHead = NULL;
3220 if (accept('(')) {
3221 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3222 nameRequired, arena);
3223 skip(')');
3224 } else if ((declName = acceptSymbol()) != 0) {
3225 if (nameAllowed == false && declName) {
3226 error("Symbol %s not allowed here", nameof(declName));
3227 } else if (nameRequired && ! declName) {
3228 String temp;
3229 decodeToken(temp, tok);
3230 error("Expected symbol. Got %s", temp.getUnwrapped());
3231 }
3232 }
3233 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003234 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003235 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003236 pType = createType(TY_FUNC, pType, pTail, arena);
3237 skip(')');
3238 }
Jack Palevich3f226492009-07-02 14:46:19 -07003239
3240 if (pNewHead) {
3241 Type* pA = pNewHead;
3242 while (pA->pHead) {
3243 pA = pA->pHead;
3244 }
3245 pA->pHead = pType;
3246 pType = pNewHead;
3247 }
Jack Palevich86351982009-06-30 18:09:56 -07003248 return pType;
3249 }
3250
Jack Palevich3f226492009-07-02 14:46:19 -07003251 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003252 Type* pHead = NULL;
3253 Type* pTail = NULL;
3254 for(;;) {
3255 Type* pBaseArg = acceptPrimitiveType(arena);
3256 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003257 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3258 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003259 if (pArg) {
3260 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3261 if (!pHead) {
3262 pHead = pParam;
3263 pTail = pParam;
3264 } else {
3265 pTail->pTail = pParam;
3266 pTail = pParam;
3267 }
3268 }
3269 }
3270 if (! accept(',')) {
3271 break;
3272 }
3273 }
3274 return pHead;
3275 }
3276
3277 Type* expectPrimitiveType(Arena& arena) {
3278 Type* pType = acceptPrimitiveType(arena);
3279 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003280 String buf;
3281 decodeToken(buf, tok);
3282 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003283 }
Jack Palevich86351982009-06-30 18:09:56 -07003284 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003285 }
3286
Jack Palevich86351982009-06-30 18:09:56 -07003287 void addGlobalSymbol(Type* pDecl) {
3288 tokenid_t t = pDecl->id;
3289 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003290 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003291 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003292 }
Jack Palevich86351982009-06-30 18:09:56 -07003293 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003294 }
3295
Jack Palevich86351982009-06-30 18:09:56 -07003296 void reportDuplicate(tokenid_t t) {
3297 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003298 }
3299
Jack Palevich86351982009-06-30 18:09:56 -07003300 void addLocalSymbol(Type* pDecl) {
3301 tokenid_t t = pDecl->id;
3302 if (mLocals.isDefinedAtCurrentLevel(t)) {
3303 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003304 }
Jack Palevich86351982009-06-30 18:09:56 -07003305 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003306 }
3307
Jack Palevich95727a02009-07-06 12:07:15 -07003308 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003309 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003310
Jack Palevich95727a02009-07-06 12:07:15 -07003311 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003312 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003313 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3314 if (!pDecl) {
3315 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003316 }
Jack Palevich86351982009-06-30 18:09:56 -07003317 int variableAddress = 0;
3318 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003319 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003320 loc = loc + 4;
3321 variableAddress = -loc;
3322 VI(pDecl->id)->pAddress = (void*) variableAddress;
3323 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003324 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003325 expr();
3326 pGen->storeR0(variableAddress);
3327 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003328 if (tok == ',')
3329 next();
3330 }
3331 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003332 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003333 }
3334 }
3335
Jack Palevichf1728be2009-06-12 13:53:51 -07003336 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003337 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003338 }
3339
Jack Palevich569f1352009-06-29 14:29:08 -07003340 void decodeToken(String& buffer, tokenid_t token) {
3341 if (token == EOF ) {
3342 buffer.printf("EOF");
3343 } else if (token == TOK_NUM) {
3344 buffer.printf("numeric constant");
3345 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003346 if (token < 32) {
3347 buffer.printf("'\\x%02x'", token);
3348 } else {
3349 buffer.printf("'%c'", token);
3350 }
Jack Palevich569f1352009-06-29 14:29:08 -07003351 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3352 buffer.printf("keyword \"%s\"", nameof(token));
3353 } else {
3354 buffer.printf("symbol \"%s\"", nameof(token));
3355 }
3356 }
3357
Jack Palevich40600de2009-07-01 15:32:35 -07003358 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003359 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003360 if (!result) {
3361 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003362 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003363 error("Expected symbol. Got %s", temp.getUnwrapped());
3364 }
3365 return result;
3366 }
3367
Jack Palevich86351982009-06-30 18:09:56 -07003368 tokenid_t acceptSymbol() {
3369 tokenid_t result = 0;
3370 if (tok >= TOK_SYMBOL) {
3371 result = tok;
3372 next();
Jack Palevich86351982009-06-30 18:09:56 -07003373 }
3374 return result;
3375 }
3376
Jack Palevichb7c81e92009-06-04 19:56:13 -07003377 void globalDeclarations() {
3378 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003379 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3380 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003381 break;
3382 }
Jack Palevich86351982009-06-30 18:09:56 -07003383 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3384 if (!pDecl) {
3385 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003386 }
Jack Palevich86351982009-06-30 18:09:56 -07003387 if (! isDefined(pDecl->id)) {
3388 addGlobalSymbol(pDecl);
3389 }
3390 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003391 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003392 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003393 }
Jack Palevich86351982009-06-30 18:09:56 -07003394 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003395 // it's a variable declaration
3396 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003397 if (name && !name->pAddress) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003398 name->pAddress = (int*) allocGlobalSpace(4);
3399 }
Jack Palevich86351982009-06-30 18:09:56 -07003400 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003401 if (tok == TOK_NUM) {
3402 if (name) {
3403 * (int*) name->pAddress = tokc;
3404 }
3405 next();
3406 } else {
3407 error("Expected an integer constant");
3408 }
3409 }
Jack Palevich86351982009-06-30 18:09:56 -07003410 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003411 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003412 }
Jack Palevich86351982009-06-30 18:09:56 -07003413 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3414 if (!pDecl) {
3415 break;
3416 }
3417 if (! isDefined(pDecl->id)) {
3418 addGlobalSymbol(pDecl);
3419 }
3420 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003421 }
3422 skip(';');
3423 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003424 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003425 if (accept(';')) {
3426 // forward declaration.
3427 } else {
3428 if (name) {
3429 /* patch forward references (XXX: does not work for function
3430 pointers) */
3431 pGen->gsym((int) name->pForward);
3432 /* put function address */
3433 name->pAddress = (void*) codeBuf.getPC();
3434 }
3435 // Calculate stack offsets for parameters
3436 mLocals.pushLevel();
3437 intptr_t a = 8;
3438 int argCount = 0;
3439 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3440 Type* pArg = pP->pHead;
3441 addLocalSymbol(pArg);
3442 /* read param name and compute offset */
3443 VI(pArg->id)->pAddress = (void*) a;
3444 a = a + 4;
3445 argCount++;
3446 }
3447 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003448 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003449 a = pGen->functionEntry(argCount);
3450 block(0, true);
3451 pGen->gsym(rsym);
3452 pGen->functionExit(argCount, a, loc);
3453 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003454 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003455 }
3456 }
3457 }
3458
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003459 char* allocGlobalSpace(int bytes) {
3460 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
3461 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003462 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003463 }
3464 char* result = glo;
3465 glo += bytes;
3466 return result;
3467 }
3468
Jack Palevich21a15a22009-05-11 14:49:29 -07003469 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003470 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003471 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003472 pGlobalBase = 0;
3473 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003474 if (pGen) {
3475 delete pGen;
3476 pGen = 0;
3477 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003478 if (file) {
3479 delete file;
3480 file = 0;
3481 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003482 }
3483
3484 void clear() {
3485 tok = 0;
3486 tokc = 0;
3487 tokl = 0;
3488 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003489 rsym = 0;
3490 loc = 0;
3491 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003492 dptr = 0;
3493 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003494 file = 0;
3495 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003496 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003497 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003498 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003499
Jack Palevich22305132009-05-13 10:58:45 -07003500 void setArchitecture(const char* architecture) {
3501 delete pGen;
3502 pGen = 0;
3503
3504 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003505#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003506 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003507 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003508 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003509#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003510#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003511 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003512 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003513 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003514#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003515 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003516 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003517 }
3518 }
3519
3520 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003521#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003522 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003523#elif defined(DEFAULT_X86_CODEGEN)
3524 pGen = new X86CodeGenerator();
3525#endif
3526 }
3527 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003528 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003529 } else {
3530 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003531 }
3532 }
3533
Jack Palevich77ae76e2009-05-10 19:59:24 -07003534public:
Jack Palevich22305132009-05-13 10:58:45 -07003535 struct args {
3536 args() {
3537 architecture = 0;
3538 }
3539 const char* architecture;
3540 };
3541
Jack Paleviche7b59062009-05-19 17:12:17 -07003542 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003543 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003544 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003545
Jack Paleviche7b59062009-05-19 17:12:17 -07003546 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003547 cleanup();
3548 }
3549
Jack Palevich1cdef202009-05-22 12:06:27 -07003550 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003551 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003552
3553 cleanup();
3554 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003555 mTokenTable.setArena(&mGlobalArena);
3556 mGlobals.setArena(&mGlobalArena);
3557 mGlobals.setTokenTable(&mTokenTable);
3558 mLocals.setArena(&mLocalArena);
3559 mLocals.setTokenTable(&mTokenTable);
3560
3561 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003562 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003563 codeBuf.init(ALLOC_SIZE);
3564 setArchitecture(NULL);
3565 if (!pGen) {
3566 return -1;
3567 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003568#ifdef PROVIDE_TRACE_CODEGEN
3569 pGen = new TraceCodeGenerator(pGen);
3570#endif
3571 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003572 pGen->init(&codeBuf);
3573 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003574 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3575 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003576 inp();
3577 next();
3578 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003579 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003580 result = pGen->finishCompile();
3581 if (result == 0) {
3582 if (mErrorBuf.len()) {
3583 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003584 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003585 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003586 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003587 }
3588
Jack Palevich86351982009-06-30 18:09:56 -07003589 void createPrimitiveTypes() {
3590 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3591 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3592 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003593 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3594 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003595 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003596 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3597 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003598 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003599 }
3600
Jack Palevicha6baa232009-06-12 11:25:59 -07003601 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003602 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003603 }
3604
Jack Palevich569f1352009-06-29 14:29:08 -07003605 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003606 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003607 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003608 }
3609
Jack Palevich569f1352009-06-29 14:29:08 -07003610 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003611 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003612 error("Undefined forward reference: %s",
3613 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003614 }
3615 return true;
3616 }
3617
Jack Palevich21a15a22009-05-11 14:49:29 -07003618 int dump(FILE* out) {
3619 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3620 return 0;
3621 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003622
Jack Palevicha6535612009-05-13 16:24:17 -07003623 int disassemble(FILE* out) {
3624 return pGen->disassemble(out);
3625 }
3626
Jack Palevich1cdef202009-05-22 12:06:27 -07003627 /* Look through the symbol table to find a symbol.
3628 * If found, return its value.
3629 */
3630 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003631 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3632 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003633 if (pVariableInfo) {
3634 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003635 }
3636 return NULL;
3637 }
3638
Jack Palevicheedf9d22009-06-04 16:23:40 -07003639 void getPragmas(ACCsizei* actualStringCount,
3640 ACCsizei maxStringCount, ACCchar** strings) {
3641 int stringCount = mPragmaStringCount;
3642 if (actualStringCount) {
3643 *actualStringCount = stringCount;
3644 }
3645 if (stringCount > maxStringCount) {
3646 stringCount = maxStringCount;
3647 }
3648 if (strings) {
3649 char* pPragmas = mPragmas.getUnwrapped();
3650 while (stringCount-- > 0) {
3651 *strings++ = pPragmas;
3652 pPragmas += strlen(pPragmas) + 1;
3653 }
3654 }
3655 }
3656
Jack Palevichac0e95e2009-05-29 13:53:44 -07003657 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003658 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003659 }
3660
Jack Palevich77ae76e2009-05-10 19:59:24 -07003661};
3662
Jack Paleviche7b59062009-05-19 17:12:17 -07003663const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003664 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3665
Jack Paleviche7b59062009-05-19 17:12:17 -07003666const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003667 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3668 5, 5, /* ==, != */
3669 9, 10, /* &&, || */
3670 6, 7, 8, /* & ^ | */
3671 2, 2 /* ~ ! */
3672 };
3673
Jack Palevich8b0624c2009-05-20 12:12:06 -07003674#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003675FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003676#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003677
Jack Palevich8b0624c2009-05-20 12:12:06 -07003678#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003679const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003680 0x1, // ++
3681 0xff, // --
3682 0xc1af0f, // *
3683 0xf9f79991, // /
3684 0xf9f79991, // % (With manual assist to swap results)
3685 0xc801, // +
3686 0xd8f7c829, // -
3687 0xe0d391, // <<
3688 0xf8d391, // >>
3689 0xe, // <=
3690 0xd, // >=
3691 0xc, // <
3692 0xf, // >
3693 0x4, // ==
3694 0x5, // !=
3695 0x0, // &&
3696 0x1, // ||
3697 0xc821, // &
3698 0xc831, // ^
3699 0xc809, // |
3700 0xd0f7, // ~
3701 0x4 // !
3702};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003703#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003704
Jack Palevich1cdef202009-05-22 12:06:27 -07003705struct ACCscript {
3706 ACCscript() {
3707 text = 0;
3708 textLength = 0;
3709 accError = ACC_NO_ERROR;
3710 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003711
Jack Palevich1cdef202009-05-22 12:06:27 -07003712 ~ACCscript() {
3713 delete text;
3714 }
Jack Palevich546b2242009-05-13 15:10:04 -07003715
Jack Palevich1cdef202009-05-22 12:06:27 -07003716 void setError(ACCenum error) {
3717 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3718 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003719 }
3720 }
3721
Jack Palevich1cdef202009-05-22 12:06:27 -07003722 ACCenum getError() {
3723 ACCenum result = accError;
3724 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003725 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003726 }
3727
Jack Palevich1cdef202009-05-22 12:06:27 -07003728 Compiler compiler;
3729 char* text;
3730 int textLength;
3731 ACCenum accError;
3732};
3733
3734
3735extern "C"
3736ACCscript* accCreateScript() {
3737 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003738}
Jack Palevich1cdef202009-05-22 12:06:27 -07003739
3740extern "C"
3741ACCenum accGetError( ACCscript* script ) {
3742 return script->getError();
3743}
3744
3745extern "C"
3746void accDeleteScript(ACCscript* script) {
3747 delete script;
3748}
3749
3750extern "C"
3751void accScriptSource(ACCscript* script,
3752 ACCsizei count,
3753 const ACCchar ** string,
3754 const ACCint * length) {
3755 int totalLength = 0;
3756 for(int i = 0; i < count; i++) {
3757 int len = -1;
3758 const ACCchar* s = string[i];
3759 if (length) {
3760 len = length[i];
3761 }
3762 if (len < 0) {
3763 len = strlen(s);
3764 }
3765 totalLength += len;
3766 }
3767 delete script->text;
3768 char* text = new char[totalLength + 1];
3769 script->text = text;
3770 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003771 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003772 for(int i = 0; i < count; i++) {
3773 int len = -1;
3774 const ACCchar* s = string[i];
3775 if (length) {
3776 len = length[i];
3777 }
3778 if (len < 0) {
3779 len = strlen(s);
3780 }
Jack Palevich09555c72009-05-27 12:25:55 -07003781 memcpy(dest, s, len);
3782 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003783 }
3784 text[totalLength] = '\0';
3785}
3786
3787extern "C"
3788void accCompileScript(ACCscript* script) {
3789 int result = script->compiler.compile(script->text, script->textLength);
3790 if (result) {
3791 script->setError(ACC_INVALID_OPERATION);
3792 }
3793}
3794
3795extern "C"
3796void accGetScriptiv(ACCscript* script,
3797 ACCenum pname,
3798 ACCint * params) {
3799 switch (pname) {
3800 case ACC_INFO_LOG_LENGTH:
3801 *params = 0;
3802 break;
3803 }
3804}
3805
3806extern "C"
3807void accGetScriptInfoLog(ACCscript* script,
3808 ACCsizei maxLength,
3809 ACCsizei * length,
3810 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003811 char* message = script->compiler.getErrorMessage();
3812 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003813 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003814 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003815 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003816 if (infoLog && maxLength > 0) {
3817 int trimmedLength = maxLength < messageLength ?
3818 maxLength : messageLength;
3819 memcpy(infoLog, message, trimmedLength);
3820 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003821 }
3822}
3823
3824extern "C"
3825void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3826 ACCvoid ** address) {
3827 void* value = script->compiler.lookup(name);
3828 if (value) {
3829 *address = value;
3830 } else {
3831 script->setError(ACC_INVALID_VALUE);
3832 }
3833}
3834
Jack Palevicheedf9d22009-06-04 16:23:40 -07003835extern "C"
3836void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3837 ACCsizei maxStringCount, ACCchar** strings){
3838 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3839}
3840
-b master422972c2009-06-17 19:13:52 -07003841extern "C"
3842void accDisassemble(ACCscript* script) {
3843 script->compiler.disassemble(stderr);
3844}
3845
Jack Palevicheedf9d22009-06-04 16:23:40 -07003846
Jack Palevich1cdef202009-05-22 12:06:27 -07003847} // namespace acc
3848