blob: 65b0b3917500b070e3ab926d01e36ff9242d1aa6 [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#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070041#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070042#endif
Jack Palevicha6535612009-05-13 16:24:17 -070043
Jack Palevich1cdef202009-05-22 12:06:27 -070044#include <acc/acc.h>
45
Jack Palevich09555c72009-05-27 12:25:55 -070046#define LOG_API(...) do {} while(0)
47// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070048
-b master422972c2009-06-17 19:13:52 -070049#define LOG_STACK(...) do {} while(0)
50// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
51
52// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070053// #define PROVIDE_TRACE_CODEGEN
54
Jack Palevichbbf8ab52009-05-11 11:54:30 -070055namespace acc {
56
Jack Palevich8df46192009-07-07 14:48:51 -070057// Subset of STL vector.
58template<class E> class Vector {
59 public:
60 Vector() {
61 mpBase = 0;
62 mUsed = 0;
63 mSize = 0;
64 }
65
66 ~Vector() {
67 if (mpBase) {
68 for(size_t i = 0; i < mUsed; i++) {
69 mpBase[mUsed].~E();
70 }
71 free(mpBase);
72 }
73 }
74
75 inline E& operator[](size_t i) {
76 return mpBase[i];
77 }
78
79 inline E& front() {
80 return mpBase[0];
81 }
82
83 inline E& back() {
84 return mpBase[mUsed - 1];
85 }
86
87 void pop_back() {
88 mUsed -= 1;
89 mpBase[mUsed].~E();
90 }
91
92 void push_back(const E& item) {
93 * ensure(1) = item;
94 }
95
96 size_t size() {
97 return mUsed;
98 }
99
100private:
101 E* ensure(int n) {
102 size_t newUsed = mUsed + n;
103 if (newUsed > mSize) {
104 size_t newSize = mSize * 2 + 10;
105 if (newSize < newUsed) {
106 newSize = newUsed;
107 }
108 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
109 mSize = newSize;
110 }
111 E* result = mpBase + mUsed;
112 mUsed = newUsed;
113 return result;
114 }
115
116 E* mpBase;
117 size_t mUsed;
118 size_t mSize;
119};
120
Jack Palevichac0e95e2009-05-29 13:53:44 -0700121class ErrorSink {
122public:
123 void error(const char *fmt, ...) {
124 va_list ap;
125 va_start(ap, fmt);
126 verror(fmt, ap);
127 va_end(ap);
128 }
129
130 virtual void verror(const char* fmt, va_list ap) = 0;
131};
132
133class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700134 typedef int tokenid_t;
135 enum TypeTag {
136 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
137 TY_POINTER, TY_FUNC, TY_PARAM
138 };
139
140 struct Type {
141 TypeTag tag;
142 tokenid_t id; // For function arguments
143 Type* pHead;
144 Type* pTail;
145 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700146
Jack Palevich21a15a22009-05-11 14:49:29 -0700147 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700148 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700149 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700150 ErrorSink* mErrorSink;
151 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700152 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700153
Jack Palevich21a15a22009-05-11 14:49:29 -0700154 void release() {
155 if (pProgramBase != 0) {
156 free(pProgramBase);
157 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700158 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700159 }
160
Jack Palevich0a280a02009-06-11 10:53:51 -0700161 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700162 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700163 bool overflow = newSize > mSize;
164 if (overflow && !mOverflowed) {
165 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700166 if (mErrorSink) {
167 mErrorSink->error("Code too large: %d bytes", newSize);
168 }
169 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700170 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700171 }
172
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 public:
174 CodeBuf() {
175 pProgramBase = 0;
176 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700177 mErrorSink = 0;
178 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700179 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700180 }
181
182 ~CodeBuf() {
183 release();
184 }
185
186 void init(int size) {
187 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700188 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700189 pProgramBase = (char*) calloc(1, size);
190 ind = pProgramBase;
191 }
192
Jack Palevichac0e95e2009-05-29 13:53:44 -0700193 void setErrorSink(ErrorSink* pErrorSink) {
194 mErrorSink = pErrorSink;
195 }
196
Jack Palevich546b2242009-05-13 15:10:04 -0700197 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700198 if(check(4)) {
199 return 0;
200 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700201 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700202 * (int*) ind = n;
203 ind += 4;
204 return result;
205 }
206
Jack Palevich21a15a22009-05-11 14:49:29 -0700207 /*
208 * Output a byte. Handles all values, 0..ff.
209 */
210 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700211 if(check(1)) {
212 return;
213 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700214 *ind++ = n;
215 }
216
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 inline void* getBase() {
218 return (void*) pProgramBase;
219 }
220
Jack Palevich8b0624c2009-05-20 12:12:06 -0700221 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700222 return ind - pProgramBase;
223 }
224
Jack Palevich8b0624c2009-05-20 12:12:06 -0700225 intptr_t getPC() {
226 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700227 }
228 };
229
Jack Palevich1cdef202009-05-22 12:06:27 -0700230 /**
231 * A code generator creates an in-memory program, generating the code on
232 * the fly. There is one code generator implementation for each supported
233 * architecture.
234 *
235 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700236 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700237 * FP - a frame pointer for accessing function arguments and local
238 * variables.
239 * SP - a stack pointer for storing intermediate results while evaluating
240 * expressions. The stack pointer grows downwards.
241 *
242 * The function calling convention is that all arguments are placed on the
243 * stack such that the first argument has the lowest address.
244 * After the call, the result is in R0. The caller is responsible for
245 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700246 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700247 * FP and SP registers are saved.
248 */
249
Jack Palevich21a15a22009-05-11 14:49:29 -0700250 class CodeGenerator {
251 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700252 CodeGenerator() {
253 mErrorSink = 0;
254 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700255 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700256 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700257 virtual ~CodeGenerator() {}
258
Jack Palevich22305132009-05-13 10:58:45 -0700259 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700260 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700261 pCodeBuf->setErrorSink(mErrorSink);
262 }
263
Jack Palevichb67b18f2009-06-11 21:12:23 -0700264 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700265 mErrorSink = pErrorSink;
266 if (pCodeBuf) {
267 pCodeBuf->setErrorSink(mErrorSink);
268 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700269 }
270
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 /* Emit a function prolog.
272 * argCount is the number of arguments.
273 * Save the old value of the FP.
274 * Set the new value of the FP.
275 * Convert from the native platform calling convention to
276 * our stack-based calling convention. This may require
277 * pushing arguments from registers to the stack.
278 * Allocate "N" bytes of stack space. N isn't known yet, so
279 * just emit the instructions for adjusting the stack, and return
280 * the address to patch up. The patching will be done in
281 * functionExit().
282 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700283 */
Jack Palevich546b2242009-05-13 15:10:04 -0700284 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700285
Jack Palevich1cdef202009-05-22 12:06:27 -0700286 /* Emit a function epilog.
287 * Restore the old SP and FP register values.
288 * Return to the calling function.
289 * argCount - the number of arguments to the function.
290 * localVariableAddress - returned from functionEntry()
291 * localVariableSize - the size in bytes of the local variables.
292 */
293 virtual void functionExit(int argCount, int localVariableAddress,
294 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700295
Jack Palevich1cdef202009-05-22 12:06:27 -0700296 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700297 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700298
Jack Palevich1a539db2009-07-08 13:04:41 -0700299 /* Load floating point value from global address. */
300 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700301
Jack Palevich1cdef202009-05-22 12:06:27 -0700302 /* Jump to a target, and return the address of the word that
303 * holds the target data, in case it needs to be fixed up later.
304 */
Jack Palevich22305132009-05-13 10:58:45 -0700305 virtual int gjmp(int t) = 0;
306
Jack Palevich1cdef202009-05-22 12:06:27 -0700307 /* Test R0 and jump to a target if the test succeeds.
308 * l = 0: je, l == 1: jne
309 * Return the address of the word that holds the targed data, in
310 * case it needs to be fixed up later.
311 */
Jack Palevich22305132009-05-13 10:58:45 -0700312 virtual int gtst(bool l, int t) = 0;
313
Jack Palevich9eed7a22009-07-06 17:24:34 -0700314 /* Compare TOS against R0, and store the boolean result in R0.
315 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700316 * op specifies the comparison.
317 */
Jack Palevich22305132009-05-13 10:58:45 -0700318 virtual void gcmp(int op) = 0;
319
Jack Palevich9eed7a22009-07-06 17:24:34 -0700320 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700321 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700322 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700323 */
Jack Palevich546b2242009-05-13 15:10:04 -0700324 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700325
Jack Palevich9eed7a22009-07-06 17:24:34 -0700326 /* Compare 0 against R0, and store the boolean result in R0.
327 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700329 virtual void gUnaryCmp(int op) = 0;
330
331 /* Perform the arithmetic op specified by op. 0 is the
332 * left argument, R0 is the right argument.
333 */
334 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700335
Jack Palevich1cdef202009-05-22 12:06:27 -0700336 /* Push R0 onto the stack.
337 */
338 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700339
Jack Palevich9eed7a22009-07-06 17:24:34 -0700340 /* Store R0 to the address stored in TOS.
341 * The TOS is popped.
342 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700343 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700344 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700345
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700347 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700348 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700350
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 /* Load the absolute address of a variable to R0.
352 * If ea <= LOCAL, then this is a local variable, or an
353 * argument, addressed relative to FP.
354 * else it is an absolute global address.
355 */
Jack Palevich8df46192009-07-07 14:48:51 -0700356 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700357
Jack Palevich1cdef202009-05-22 12:06:27 -0700358 /* Store R0 to a variable.
359 * If ea <= LOCAL, then this is a local variable, or an
360 * argument, addressed relative to FP.
361 * else it is an absolute global address.
362 */
363 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700364
Jack Palevich1cdef202009-05-22 12:06:27 -0700365 /* load R0 from a variable.
366 * If ea <= LOCAL, then this is a local variable, or an
367 * argument, addressed relative to FP.
368 * else it is an absolute global address.
369 * If isIncDec is true, then the stored variable's value
370 * should be post-incremented or post-decremented, based
371 * on the value of op.
372 */
Jack Palevich8df46192009-07-07 14:48:51 -0700373 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
374
375 /**
376 * Convert R0 to the given type.
377 */
378 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700379
Jack Palevich1cdef202009-05-22 12:06:27 -0700380 /* Emit code to adjust the stack for a function call. Return the
381 * label for the address of the instruction that adjusts the
382 * stack size. This will be passed as argument "a" to
383 * endFunctionCallArguments.
384 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700385 virtual int beginFunctionCallArguments() = 0;
386
Jack Palevich1cdef202009-05-22 12:06:27 -0700387 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700388 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700389 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700390 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700391
Jack Palevich1cdef202009-05-22 12:06:27 -0700392 /* Patch the function call preamble.
393 * a is the address returned from beginFunctionCallArguments
394 * l is the number of bytes the arguments took on the stack.
395 * Typically you would also emit code to convert the argument
396 * list into whatever the native function calling convention is.
397 * On ARM for example you would pop the first 5 arguments into
398 * R0..R4
399 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700400 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700401
Jack Palevich1cdef202009-05-22 12:06:27 -0700402 /* Emit a call to an unknown function. The argument "symbol" needs to
403 * be stored in the location where the address should go. It forms
404 * a chain. The address will be patched later.
405 * Return the address of the word that has to be patched.
406 */
Jack Palevich8df46192009-07-07 14:48:51 -0700407 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700408
Jack Palevich1cdef202009-05-22 12:06:27 -0700409 /* Call a function using PC-relative addressing. t is the PC-relative
410 * address of the function. It has already been adjusted for the
411 * architectural jump offset, so just store it as-is.
412 */
Jack Palevich8df46192009-07-07 14:48:51 -0700413 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700414
Jack Palevich1cdef202009-05-22 12:06:27 -0700415 /* Call a function pointer. L is the number of bytes the arguments
416 * take on the stack. The address of the function is stored at
417 * location SP + l.
418 */
Jack Palevich8df46192009-07-07 14:48:51 -0700419 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700420
Jack Palevich1cdef202009-05-22 12:06:27 -0700421 /* Adjust SP after returning from a function call. l is the
422 * number of bytes of arguments stored on the stack. isIndirect
423 * is true if this was an indirect call. (In which case the
424 * address of the function is stored at location SP + l.)
425 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700426 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevich1cdef202009-05-22 12:06:27 -0700428 /* Print a disassembly of the assembled code to out. Return
429 * non-zero if there is an error.
430 */
Jack Palevicha6535612009-05-13 16:24:17 -0700431 virtual int disassemble(FILE* out) = 0;
432
Jack Palevich1cdef202009-05-22 12:06:27 -0700433 /* Generate a symbol at the current PC. t is the head of a
434 * linked list of addresses to patch.
435 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700436 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700437
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 /*
439 * Do any cleanup work required at the end of a compile.
440 * For example, an instruction cache might need to be
441 * invalidated.
442 * Return non-zero if there is an error.
443 */
444 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700445
Jack Palevicha6535612009-05-13 16:24:17 -0700446 /**
447 * Adjust relative branches by this amount.
448 */
449 virtual int jumpOffset() = 0;
450
Jack Palevich9eed7a22009-07-06 17:24:34 -0700451 /**
452 * Stack alignment (in bytes) for this type of data
453 */
454 virtual size_t stackAlignment(Type* type) = 0;
455
456 /**
457 * Array element alignment (in bytes) for this type of data.
458 */
459 virtual size_t sizeOf(Type* type) = 0;
460
Jack Palevich1a539db2009-07-08 13:04:41 -0700461 virtual Type* getR0Type() {
462 return mExpressionStack.back();
463 }
464
Jack Palevich21a15a22009-05-11 14:49:29 -0700465 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700466 /*
467 * Output a byte. Handles all values, 0..ff.
468 */
469 void ob(int n) {
470 pCodeBuf->ob(n);
471 }
472
Jack Palevich8b0624c2009-05-20 12:12:06 -0700473 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700474 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700475 }
476
Jack Palevich8b0624c2009-05-20 12:12:06 -0700477 intptr_t getBase() {
478 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700479 }
480
Jack Palevich8b0624c2009-05-20 12:12:06 -0700481 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700482 return pCodeBuf->getPC();
483 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700484
485 intptr_t getSize() {
486 return pCodeBuf->getSize();
487 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700488
489 void error(const char* fmt,...) {
490 va_list ap;
491 va_start(ap, fmt);
492 mErrorSink->verror(fmt, ap);
493 va_end(ap);
494 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700495
496 void assert(bool test) {
497 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700498 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700499 error("code generator assertion failed.");
500 }
501 }
Jack Palevich8df46192009-07-07 14:48:51 -0700502
503 void setR0Type(Type* pType) {
504 mExpressionStack.back() = pType;
505 }
506
Jack Palevich8df46192009-07-07 14:48:51 -0700507 Type* getTOSType() {
508 return mExpressionStack[mExpressionStack.size()-2];
509 }
510
511 void pushType() {
512 mExpressionStack.push_back(NULL);
513 }
514
515 void popType() {
516 mExpressionStack.pop_back();
517 }
518
519 bool bitsSame(Type* pA, Type* pB) {
520 return collapseType(pA->tag) == collapseType(pB->tag);
521 }
522
523 TypeTag collapseType(TypeTag tag) {
524 static const TypeTag collapsedTag[] = {
525 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
526 TY_VOID, TY_VOID};
527 return collapsedTag[tag];
528 }
529
Jack Palevich1a539db2009-07-08 13:04:41 -0700530 TypeTag collapseTypeR0() {
531 return collapseType(getR0Type()->tag);
532 }
533
534 bool isFloatType(Type* pType) {
535 TypeTag tag = pType->tag;
536 return tag == TY_FLOAT || tag == TY_DOUBLE;
537 }
538
Jack Palevich21a15a22009-05-11 14:49:29 -0700539 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700540 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700541 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700542 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700543 };
544
Jack Paleviche7b59062009-05-19 17:12:17 -0700545#ifdef PROVIDE_ARM_CODEGEN
546
Jack Palevich22305132009-05-13 10:58:45 -0700547 class ARMCodeGenerator : public CodeGenerator {
548 public:
549 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700550
Jack Palevich22305132009-05-13 10:58:45 -0700551 virtual ~ARMCodeGenerator() {}
552
553 /* returns address to patch with local variable size
554 */
Jack Palevich546b2242009-05-13 15:10:04 -0700555 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700556 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700557 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700558 // sp -> arg4 arg5 ...
559 // Push our register-based arguments back on the stack
560 if (argCount > 0) {
561 int regArgCount = argCount <= 4 ? argCount : 4;
562 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700563 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700564 }
565 // sp -> arg0 arg1 ...
566 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700567 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700568 // sp, fp -> oldfp, retadr, arg0 arg1 ....
569 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700570 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700571 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700572 // We don't know how many local variables we are going to use,
573 // but we will round the allocation up to a multiple of
574 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700575 }
576
Jack Palevich546b2242009-05-13 15:10:04 -0700577 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700578 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700579 // Round local variable size up to a multiple of stack alignment
580 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
581 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700582 // Patch local variable allocation code:
583 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700584 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700585 }
Jack Palevich69796b62009-05-14 15:42:26 -0700586 *(char*) (localVariableAddress) = localVariableSize;
587
588 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
589 o4(0xE1A0E00B); // mov lr, fp
590 o4(0xE59BB000); // ldr fp, [fp]
591 o4(0xE28ED004); // add sp, lr, #4
592 // sp -> retadr, arg0, ...
593 o4(0xE8BD4000); // ldmfd sp!, {lr}
594 // sp -> arg0 ....
595 if (argCount > 0) {
596 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700597 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700598 // earlier. We don't need to actually store them anywhere,
599 // just adjust the stack.
600 int regArgCount = argCount <= 4 ? argCount : 4;
601 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
602 }
603 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700604 }
605
606 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700607 virtual void li(int t, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700608 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700609 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700610 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700611 } else if (t >= -256 && t < 0) {
612 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700613 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700614 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700615 o4(0xE51F0000); // ldr r0, .L3
616 o4(0xEA000000); // b .L99
617 o4(t); // .L3: .word 0
618 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700619 }
Jack Palevich8df46192009-07-07 14:48:51 -0700620 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700621 }
622
Jack Palevich1a539db2009-07-08 13:04:41 -0700623 virtual void loadFloat(int address, Type* pType) {
624 error("Unimplemented.\n");
Jack Palevich8df46192009-07-07 14:48:51 -0700625 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700626 }
627
Jack Palevich22305132009-05-13 10:58:45 -0700628 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700629 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700630 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700631 }
632
633 /* l = 0: je, l == 1: jne */
634 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700635 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700636 o4(0xE3500000); // cmp r0,#0
637 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
638 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700639 }
640
641 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700642 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700643 o4(0xE8BD0002); // ldmfd sp!,{r1}
644 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700645 o4(0xE1510000); // cmp r1, r1
646 switch(op) {
647 case OP_EQUALS:
648 o4(0x03A00001); // moveq r0,#1
649 o4(0x13A00000); // movne r0,#0
650 break;
651 case OP_NOT_EQUALS:
652 o4(0x03A00000); // moveq r0,#0
653 o4(0x13A00001); // movne r0,#1
654 break;
655 case OP_LESS_EQUAL:
656 o4(0xD3A00001); // movle r0,#1
657 o4(0xC3A00000); // movgt r0,#0
658 break;
659 case OP_GREATER:
660 o4(0xD3A00000); // movle r0,#0
661 o4(0xC3A00001); // movgt r0,#1
662 break;
663 case OP_GREATER_EQUAL:
664 o4(0xA3A00001); // movge r0,#1
665 o4(0xB3A00000); // movlt r0,#0
666 break;
667 case OP_LESS:
668 o4(0xA3A00000); // movge r0,#0
669 o4(0xB3A00001); // movlt r0,#1
670 break;
671 default:
672 error("Unknown comparison op %d", op);
673 break;
674 }
Jack Palevich8df46192009-07-07 14:48:51 -0700675 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700676 }
677
Jack Palevich546b2242009-05-13 15:10:04 -0700678 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700679 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700680 o4(0xE8BD0002); // ldmfd sp!,{r1}
681 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700682 switch(op) {
683 case OP_MUL:
684 o4(0x0E0000091); // mul r0,r1,r0
685 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700686 case OP_DIV:
687 callRuntime(runtime_DIV);
688 break;
689 case OP_MOD:
690 callRuntime(runtime_MOD);
691 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700692 case OP_PLUS:
693 o4(0xE0810000); // add r0,r1,r0
694 break;
695 case OP_MINUS:
696 o4(0xE0410000); // sub r0,r1,r0
697 break;
698 case OP_SHIFT_LEFT:
699 o4(0xE1A00011); // lsl r0,r1,r0
700 break;
701 case OP_SHIFT_RIGHT:
702 o4(0xE1A00051); // asr r0,r1,r0
703 break;
704 case OP_BIT_AND:
705 o4(0xE0010000); // and r0,r1,r0
706 break;
707 case OP_BIT_XOR:
708 o4(0xE0210000); // eor r0,r1,r0
709 break;
710 case OP_BIT_OR:
711 o4(0xE1810000); // orr r0,r1,r0
712 break;
713 case OP_BIT_NOT:
714 o4(0xE1E00000); // mvn r0, r0
715 break;
716 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700717 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700718 break;
719 }
Jack Palevich8df46192009-07-07 14:48:51 -0700720 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700721 }
722
Jack Palevich9eed7a22009-07-06 17:24:34 -0700723 virtual void gUnaryCmp(int op) {
724 LOG_API("gcmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700725 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700726 o4(0xE1510000); // cmp r1, r1
727 switch(op) {
728 case OP_NOT_EQUALS:
729 o4(0x03A00000); // moveq r0,#0
730 o4(0x13A00001); // movne r0,#1
731 break;
732 default:
733 error("Unknown unary comparison op %d", op);
734 break;
735 }
736 }
737
738 virtual void genUnaryOp(int op) {
739 LOG_API("genOp(%d);\n", op);
740 switch(op) {
741 case OP_PLUS:
742 // Do nothing
743 break;
744 case OP_MINUS:
745 o4(0xE3A01000); // mov r1, #0
746 o4(0xE0410000); // sub r0,r1,r0
747 break;
748 case OP_BIT_NOT:
749 o4(0xE1E00000); // mvn r0, r0
750 break;
751 default:
752 error("Unknown unary op %d\n", op);
753 break;
754 }
Jack Palevich22305132009-05-13 10:58:45 -0700755 }
756
Jack Palevich1cdef202009-05-22 12:06:27 -0700757 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700758 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700759 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700760 mStackUse += 4;
Jack Palevich8df46192009-07-07 14:48:51 -0700761 pushType();
-b master422972c2009-06-17 19:13:52 -0700762 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700763 }
764
Jack Palevich9eed7a22009-07-06 17:24:34 -0700765 virtual void storeR0ToTOS(Type* pPointerType) {
766 LOG_API("storeR0ToTOS(%d);\n", isInt);
767 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700768 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700769 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700770 switch (pPointerType->pHead->tag) {
771 case TY_INT:
772 o4(0xE5810000); // str r0, [r1]
773 break;
774 case TY_CHAR:
775 o4(0xE5C10000); // strb r0, [r1]
776 break;
777 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700778 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700779 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700780 }
Jack Palevich8df46192009-07-07 14:48:51 -0700781 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700782 }
783
Jack Palevich9eed7a22009-07-06 17:24:34 -0700784 virtual void loadR0FromR0(Type* pPointerType) {
785 LOG_API("loadR0FromR0(%d);\n", pPointerType);
786 assert(pPointerType->tag == TY_POINTER);
787 switch (pPointerType->pHead->tag) {
788 case TY_INT:
789 o4(0xE5900000); // ldr r0, [r0]
790 break;
791 case TY_CHAR:
792 o4(0xE5D00000); // ldrb r0, [r0]
793 break;
794 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700795 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700796 break;
797 }
Jack Palevich8df46192009-07-07 14:48:51 -0700798 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -0700799 }
800
Jack Palevich8df46192009-07-07 14:48:51 -0700801 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700802 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700803 if (ea < LOCAL) {
804 // Local, fp relative
805 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
806 error("Offset out of range: %08x", ea);
807 }
808 if (ea < 0) {
809 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
810 } else {
811 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
812 }
Jack Palevichbd894902009-05-14 19:35:31 -0700813 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700814 // Global, absolute.
815 o4(0xE59F0000); // ldr r0, .L1
816 o4(0xEA000000); // b .L99
817 o4(ea); // .L1: .word 0
818 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700819 }
Jack Palevich8df46192009-07-07 14:48:51 -0700820 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -0700821 }
822
Jack Palevich1cdef202009-05-22 12:06:27 -0700823 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700824 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700825 if (ea < LOCAL) {
826 // Local, fp relative
827 if (ea < -4095 || ea > 4095) {
828 error("Offset out of range: %08x", ea);
829 }
830 if (ea < 0) {
831 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
832 } else {
833 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
834 }
835 } else{
836 // Global, absolute
837 o4(0xE59F1000); // ldr r1, .L1
838 o4(0xEA000000); // b .L99
839 o4(ea); // .L1: .word 0
840 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700841 }
Jack Palevich22305132009-05-13 10:58:45 -0700842 }
843
Jack Palevich8df46192009-07-07 14:48:51 -0700844 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700845 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich4d93f302009-05-15 13:30:00 -0700846 if (ea < LOCAL) {
847 // Local, fp relative
848 if (ea < -4095 || ea > 4095) {
849 error("Offset out of range: %08x", ea);
850 }
851 if (ea < 0) {
852 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
853 } else {
854 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
855 }
Jack Palevich69796b62009-05-14 15:42:26 -0700856 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700857 // Global, absolute
858 o4(0xE59F2000); // ldr r2, .L1
859 o4(0xEA000000); // b .L99
860 o4(ea); // .L1: .word ea
861 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700862 }
Jack Palevich22305132009-05-13 10:58:45 -0700863
Jack Palevich4d93f302009-05-15 13:30:00 -0700864 if (isIncDec) {
865 switch (op) {
866 case OP_INCREMENT:
867 o4(0xE2801001); // add r1, r0, #1
868 break;
869 case OP_DECREMENT:
870 o4(0xE2401001); // sub r1, r0, #1
871 break;
872 default:
873 error("unknown opcode: %d", op);
874 }
875 if (ea < LOCAL) {
876 // Local, fp relative
877 // Don't need range check, was already checked above
878 if (ea < 0) {
879 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
880 } else {
881 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
882 }
883 } else{
884 // Global, absolute
885 // r2 is already set up from before.
886 o4(0xE5821000); // str r1, [r2]
887 }
Jack Palevichbd894902009-05-14 19:35:31 -0700888 }
Jack Palevich8df46192009-07-07 14:48:51 -0700889 setR0Type(pType);
890 }
891
892 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -0700893 Type* pR0Type = getR0Type();
894 if (bitsSame(pType, pR0Type)) {
895 // do nothing special
896 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
897 // do nothing special, both held in same register on x87.
898 } else {
899 error("Incompatible types old: %d new: %d",
900 pR0Type->tag, pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -0700901 }
Jack Palevich1a539db2009-07-08 13:04:41 -0700902 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700903 }
904
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700905 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700906 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700907 return o4(0xE24DDF00); // Placeholder
908 }
909
Jack Palevich1a539db2009-07-08 13:04:41 -0700910 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700911 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700912 if (l < 0 || l > 4096-4) {
913 error("l out of range for stack offset: 0x%08x", l);
914 }
915 o4(0xE58D0000 + l); // str r0, [sp, #4]
Jack Palevich1a539db2009-07-08 13:04:41 -0700916 return 4;
Jack Palevich7810bc92009-05-15 14:31:47 -0700917 }
918
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700919 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700920 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700921 int argCount = l >> 2;
922 int argumentStackUse = l;
923 if (argCount > 0) {
924 int regArgCount = argCount > 4 ? 4 : argCount;
925 argumentStackUse -= regArgCount * 4;
926 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
927 }
928 mStackUse += argumentStackUse;
929
930 // Align stack.
931 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
932 * STACK_ALIGNMENT);
933 mStackAlignmentAdjustment = 0;
934 if (missalignment > 0) {
935 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
936 }
937 l += mStackAlignmentAdjustment;
938
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700939 if (l < 0 || l > 0x3FC) {
940 error("L out of range for stack adjustment: 0x%08x", l);
941 }
942 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700943 mStackUse += mStackAlignmentAdjustment;
944 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
945 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700946 }
947
Jack Palevich8df46192009-07-07 14:48:51 -0700948 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700949 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -0700950 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700951 // Forward calls are always short (local)
952 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700953 }
954
Jack Palevich8df46192009-07-07 14:48:51 -0700955 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700956 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -0700957 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700958 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700959 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700960 if (t >= - (1 << 25) && t < (1 << 25)) {
961 o4(0xEB000000 | encodeAddress(t));
962 } else {
963 // Long call.
964 o4(0xE59FC000); // ldr r12, .L1
965 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700966 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700967 o4(0xE08CC00F); // .L99: add r12,pc
968 o4(0xE12FFF3C); // blx r12
969 }
Jack Palevich22305132009-05-13 10:58:45 -0700970 }
971
Jack Palevich8df46192009-07-07 14:48:51 -0700972 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700973 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -0700974 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -0700975 int argCount = l >> 2;
976 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700977 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700978 if (adjustedL < 0 || adjustedL > 4096-4) {
979 error("l out of range for stack offset: 0x%08x", l);
980 }
981 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
982 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700983 }
984
Jack Palevich7810bc92009-05-15 14:31:47 -0700985 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700986 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700987 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700988 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700989 int stackUse = stackArgs + (isIndirect ? 1 : 0)
990 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700991 if (stackUse) {
992 if (stackUse < 0 || stackUse > 255) {
993 error("L out of range for stack adjustment: 0x%08x", l);
994 }
995 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -0700996 mStackUse -= stackUse * 4;
997 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700998 }
Jack Palevich22305132009-05-13 10:58:45 -0700999 }
1000
Jack Palevicha6535612009-05-13 16:24:17 -07001001 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001002 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001003 }
1004
1005 /* output a symbol and patch all calls to it */
1006 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001007 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001008 int n;
1009 int base = getBase();
1010 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001011 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001012 while (t) {
1013 int data = * (int*) t;
1014 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1015 if (decodedOffset == 0) {
1016 n = 0;
1017 } else {
1018 n = base + decodedOffset; /* next value */
1019 }
1020 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1021 | encodeRelAddress(pc - t - 8);
1022 t = n;
1023 }
1024 }
1025
Jack Palevich1cdef202009-05-22 12:06:27 -07001026 virtual int finishCompile() {
1027#if defined(__arm__)
1028 const long base = long(getBase());
1029 const long curr = long(getPC());
1030 int err = cacheflush(base, curr, 0);
1031 return err;
1032#else
1033 return 0;
1034#endif
1035 }
1036
Jack Palevicha6535612009-05-13 16:24:17 -07001037 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001038#ifdef ENABLE_ARM_DISASSEMBLY
1039 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001040 disasm_interface_t di;
1041 di.di_readword = disassemble_readword;
1042 di.di_printaddr = disassemble_printaddr;
1043 di.di_printf = disassemble_printf;
1044
1045 int base = getBase();
1046 int pc = getPC();
1047 for(int i = base; i < pc; i += 4) {
1048 fprintf(out, "%08x: %08x ", i, *(int*) i);
1049 ::disasm(&di, i, 0);
1050 }
Jack Palevich09555c72009-05-27 12:25:55 -07001051#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001052 return 0;
1053 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001054
Jack Palevich9eed7a22009-07-06 17:24:34 -07001055 /**
1056 * Stack alignment (in bytes) for this type of data
1057 */
1058 virtual size_t stackAlignment(Type* pType){
1059 switch(pType->tag) {
1060 case TY_DOUBLE:
1061 return 8;
1062 default:
1063 return 4;
1064 }
1065 }
1066
1067 /**
1068 * Array element alignment (in bytes) for this type of data.
1069 */
1070 virtual size_t sizeOf(Type* pType){
1071 switch(pType->tag) {
1072 case TY_INT:
1073 return 4;
1074 case TY_CHAR:
1075 return 1;
1076 default:
1077 return 0;
1078 case TY_FLOAT:
1079 return 4;
1080 case TY_DOUBLE:
1081 return 8;
1082 case TY_POINTER:
1083 return 4;
1084 }
1085 }
Jack Palevich22305132009-05-13 10:58:45 -07001086 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001087 static FILE* disasmOut;
1088
1089 static u_int
1090 disassemble_readword(u_int address)
1091 {
1092 return(*((u_int *)address));
1093 }
1094
1095 static void
1096 disassemble_printaddr(u_int address)
1097 {
1098 fprintf(disasmOut, "0x%08x", address);
1099 }
1100
1101 static void
1102 disassemble_printf(const char *fmt, ...) {
1103 va_list ap;
1104 va_start(ap, fmt);
1105 vfprintf(disasmOut, fmt, ap);
1106 va_end(ap);
1107 }
1108
1109 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1110
1111 /** Encode a relative address that might also be
1112 * a label.
1113 */
1114 int encodeAddress(int value) {
1115 int base = getBase();
1116 if (value >= base && value <= getPC() ) {
1117 // This is a label, encode it relative to the base.
1118 value = value - base;
1119 }
1120 return encodeRelAddress(value);
1121 }
1122
1123 int encodeRelAddress(int value) {
1124 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1125 }
Jack Palevich22305132009-05-13 10:58:45 -07001126
Jack Palevich3d474a72009-05-15 15:12:38 -07001127 typedef int (*int2FnPtr)(int a, int b);
1128 void callRuntime(int2FnPtr fn) {
1129 o4(0xE59F2000); // ldr r2, .L1
1130 o4(0xEA000000); // b .L99
1131 o4((int) fn); //.L1: .word fn
1132 o4(0xE12FFF32); //.L99: blx r2
1133 }
1134
1135 static int runtime_DIV(int a, int b) {
1136 return b / a;
1137 }
1138
1139 static int runtime_MOD(int a, int b) {
1140 return b % a;
1141 }
-b master422972c2009-06-17 19:13:52 -07001142
1143 static const int STACK_ALIGNMENT = 8;
1144 int mStackUse;
1145 // This variable holds the amount we adjusted the stack in the most
1146 // recent endFunctionCallArguments call. It's examined by the
1147 // following adjustStackAfterCall call.
1148 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001149 };
1150
Jack Palevich09555c72009-05-27 12:25:55 -07001151#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001152
1153#ifdef PROVIDE_X86_CODEGEN
1154
Jack Palevich21a15a22009-05-11 14:49:29 -07001155 class X86CodeGenerator : public CodeGenerator {
1156 public:
1157 X86CodeGenerator() {}
1158 virtual ~X86CodeGenerator() {}
1159
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001160 /* returns address to patch with local variable size
1161 */
Jack Palevich546b2242009-05-13 15:10:04 -07001162 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001163 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1164 return oad(0xec81, 0); /* sub $xxx, %esp */
1165 }
1166
Jack Palevich546b2242009-05-13 15:10:04 -07001167 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001168 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001169 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001170 }
1171
Jack Palevich21a15a22009-05-11 14:49:29 -07001172 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001173 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001174 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001175 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001176 }
1177
Jack Palevich1a539db2009-07-08 13:04:41 -07001178 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001179 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001180 switch (pType->tag) {
1181 case TY_FLOAT:
1182 oad(0x05D9, address); // flds
1183 break;
1184 case TY_DOUBLE:
1185 oad(0x05DD, address); // fldl
1186 break;
1187 default:
1188 assert(false);
1189 break;
1190 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001191 }
1192
Jack Palevich22305132009-05-13 10:58:45 -07001193 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001194 return psym(0xe9, t);
1195 }
1196
1197 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001198 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001199 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1200 return psym(0x84 + l, t);
1201 }
1202
Jack Palevich22305132009-05-13 10:58:45 -07001203 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001204 int t = decodeOp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001205 o(0x59); /* pop %ecx */
Jack Palevich21a15a22009-05-11 14:49:29 -07001206 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001207 li(0, NULL);
Jack Palevich21a15a22009-05-11 14:49:29 -07001208 o(0x0f); /* setxx %al */
1209 o(t + 0x90);
1210 o(0xc0);
Jack Palevich8df46192009-07-07 14:48:51 -07001211 popType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001212 }
1213
Jack Palevich546b2242009-05-13 15:10:04 -07001214 virtual void genOp(int op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001215 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001216 o(decodeOp(op));
1217 if (op == OP_MOD)
1218 o(0x92); /* xchg %edx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001219 popType();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001220 }
1221
Jack Palevich9eed7a22009-07-06 17:24:34 -07001222 virtual void gUnaryCmp(int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001223 oad(0xb9, 0); /* movl $0, %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001224 int t = decodeOp(op);
1225 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001226 li(0, NULL);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001227 o(0x0f); /* setxx %al */
1228 o(t + 0x90);
1229 o(0xc0);
1230 }
1231
1232 virtual void genUnaryOp(int op) {
1233 oad(0xb9, 0); /* movl $0, %ecx */
1234 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -07001235 }
1236
Jack Palevich1cdef202009-05-22 12:06:27 -07001237 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001238 o(0x50); /* push %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001239 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001240 }
1241
Jack Palevich9eed7a22009-07-06 17:24:34 -07001242 virtual void storeR0ToTOS(Type* pPointerType) {
1243 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001244 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001245 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001246 switch (pPointerType->pHead->tag) {
1247 case TY_INT:
1248 o(0x0189); /* movl %eax/%al, (%ecx) */
1249 break;
1250 case TY_CHAR:
1251 o(0x0188); /* movl %eax/%al, (%ecx) */
1252 break;
1253 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001254 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001255 break;
1256 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001257 }
1258
Jack Palevich9eed7a22009-07-06 17:24:34 -07001259 virtual void loadR0FromR0(Type* pPointerType) {
1260 assert(pPointerType->tag == TY_POINTER);
1261 switch (pPointerType->pHead->tag) {
1262 case TY_INT:
1263 o(0x8b); /* mov (%eax), %eax */
1264 break;
1265 case TY_CHAR:
1266 o(0xbe0f); /* movsbl (%eax), %eax */
1267 break;
1268 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001269 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001270 break;
1271 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001272 ob(0); /* add zero in code */
Jack Palevich8df46192009-07-07 14:48:51 -07001273 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001274 }
1275
Jack Palevich8df46192009-07-07 14:48:51 -07001276 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001277 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001278 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001279 }
1280
Jack Palevich1cdef202009-05-22 12:06:27 -07001281 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001282 gmov(6, ea); /* mov %eax, EA */
1283 }
1284
Jack Palevich8df46192009-07-07 14:48:51 -07001285 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001286 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -07001287 if (isIncDec) {
1288 /* Implement post-increment or post decrement.
1289 */
1290 gmov(0, ea); /* 83 ADD */
1291 o(decodeOp(op));
1292 }
Jack Palevich8df46192009-07-07 14:48:51 -07001293 setR0Type(pType);
1294 }
1295
1296 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001297 Type* pR0Type = getR0Type();
1298 if (pR0Type == NULL) {
1299 error("don't know R0Type");
1300 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07001301 return;
1302 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001303 if (bitsSame(pType, pR0Type)) {
1304 // do nothing special
1305 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
1306 // do nothing special, both held in same register on x87.
1307 } else {
1308 error("Incompatible types old: %d new: %d",
1309 pR0Type->tag, pType->tag);
1310 }
1311 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001312 }
1313
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001314 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001315 return oad(0xec81, 0); /* sub $xxx, %esp */
1316 }
1317
Jack Palevich1a539db2009-07-08 13:04:41 -07001318 virtual size_t storeR0ToArg(int l) {
1319 Type* pR0Type = getR0Type();
1320 TypeTag r0ct = collapseType(pR0Type->tag);
1321 switch(r0ct) {
1322 case TY_INT:
1323 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1324 return 4;
1325 case TY_FLOAT:
1326 oad(0x249CD9, l); /* fstps xxx(%esp) */
1327 return 4;
1328 case TY_DOUBLE:
1329 oad(0x249CDD, l); /* fstpl xxx(%esp) */
1330 return 8;
1331 default:
1332 assert(false);
1333 return 0;
1334 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001335 }
1336
Jack Palevich7810bc92009-05-15 14:31:47 -07001337 virtual void endFunctionCallArguments(int a, int l) {
1338 * (int*) a = l;
1339 }
1340
Jack Palevich8df46192009-07-07 14:48:51 -07001341 virtual int callForward(int symbol, Type* pFunc) {
1342 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001343 return psym(0xe8, symbol); /* call xxx */
1344 }
1345
Jack Palevich8df46192009-07-07 14:48:51 -07001346 virtual void callRelative(int t, Type* pFunc) {
1347 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001348 psym(0xe8, t); /* call xxx */
1349 }
1350
Jack Palevich8df46192009-07-07 14:48:51 -07001351 virtual void callIndirect(int l, Type* pFunc) {
1352 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001353 oad(0x2494ff, l); /* call *xxx(%esp) */
1354 }
1355
Jack Palevich7810bc92009-05-15 14:31:47 -07001356 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1357 if (isIndirect) {
1358 l += 4;
1359 }
-b master422972c2009-06-17 19:13:52 -07001360 if (l > 0) {
1361 oad(0xc481, l); /* add $xxx, %esp */
1362 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001363 }
1364
Jack Palevicha6535612009-05-13 16:24:17 -07001365 virtual int jumpOffset() {
1366 return 5;
1367 }
1368
1369 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001370 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001371 }
1372
Jack Paleviche7b59062009-05-19 17:12:17 -07001373 /* output a symbol and patch all calls to it */
1374 virtual void gsym(int t) {
1375 int n;
1376 int pc = getPC();
1377 while (t) {
1378 n = *(int *) t; /* next value */
1379 *(int *) t = pc - t - 4;
1380 t = n;
1381 }
1382 }
1383
Jack Palevich1cdef202009-05-22 12:06:27 -07001384 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001385 size_t pagesize = 4096;
1386 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1387 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1388 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1389 if (err) {
1390 error("mprotect() failed: %d", errno);
1391 }
1392 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001393 }
1394
Jack Palevich9eed7a22009-07-06 17:24:34 -07001395 /**
1396 * Stack alignment (in bytes) for this type of data
1397 */
1398 virtual size_t stackAlignment(Type* pType){
1399 switch(pType->tag) {
1400 case TY_DOUBLE:
1401 return 8;
1402 default:
1403 return 4;
1404 }
1405 }
1406
1407 /**
1408 * Array element alignment (in bytes) for this type of data.
1409 */
1410 virtual size_t sizeOf(Type* pType){
1411 switch(pType->tag) {
1412 case TY_INT:
1413 return 4;
1414 case TY_CHAR:
1415 return 1;
1416 default:
1417 return 0;
1418 case TY_FLOAT:
1419 return 4;
1420 case TY_DOUBLE:
1421 return 8;
1422 case TY_POINTER:
1423 return 4;
1424 }
1425 }
1426
Jack Palevich21a15a22009-05-11 14:49:29 -07001427 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001428
1429 /** Output 1 to 4 bytes.
1430 *
1431 */
1432 void o(int n) {
1433 /* cannot use unsigned, so we must do a hack */
1434 while (n && n != -1) {
1435 ob(n & 0xff);
1436 n = n >> 8;
1437 }
1438 }
1439
1440 /* psym is used to put an instruction with a data field which is a
1441 reference to a symbol. It is in fact the same as oad ! */
1442 int psym(int n, int t) {
1443 return oad(n, t);
1444 }
1445
1446 /* instruction + address */
1447 int oad(int n, int t) {
1448 o(n);
1449 int result = getPC();
1450 o4(t);
1451 return result;
1452 }
1453
1454
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001455 static const int operatorHelper[];
1456
1457 int decodeOp(int op) {
1458 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001459 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001460 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001461 }
1462 return operatorHelper[op];
1463 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001464
Jack Palevich546b2242009-05-13 15:10:04 -07001465 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001466 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001467 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001468 }
1469 };
1470
Jack Paleviche7b59062009-05-19 17:12:17 -07001471#endif // PROVIDE_X86_CODEGEN
1472
Jack Palevichb67b18f2009-06-11 21:12:23 -07001473#ifdef PROVIDE_TRACE_CODEGEN
1474 class TraceCodeGenerator : public CodeGenerator {
1475 private:
1476 CodeGenerator* mpBase;
1477
1478 public:
1479 TraceCodeGenerator(CodeGenerator* pBase) {
1480 mpBase = pBase;
1481 }
1482
1483 virtual ~TraceCodeGenerator() {
1484 delete mpBase;
1485 }
1486
1487 virtual void init(CodeBuf* pCodeBuf) {
1488 mpBase->init(pCodeBuf);
1489 }
1490
1491 void setErrorSink(ErrorSink* pErrorSink) {
1492 mpBase->setErrorSink(pErrorSink);
1493 }
1494
1495 /* returns address to patch with local variable size
1496 */
1497 virtual int functionEntry(int argCount) {
1498 int result = mpBase->functionEntry(argCount);
1499 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1500 return result;
1501 }
1502
1503 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1504 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1505 argCount, localVariableAddress, localVariableSize);
1506 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1507 }
1508
1509 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001510 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001511 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001512 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001513 }
1514
Jack Palevich1a539db2009-07-08 13:04:41 -07001515 virtual void loadFloat(int address, Type* pType) {
1516 fprintf(stderr, "loadFloat(%d, type)\n", address);
1517 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001518 }
1519
Jack Palevichb67b18f2009-06-11 21:12:23 -07001520 virtual int gjmp(int t) {
1521 int result = mpBase->gjmp(t);
1522 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1523 return result;
1524 }
1525
1526 /* l = 0: je, l == 1: jne */
1527 virtual int gtst(bool l, int t) {
1528 int result = mpBase->gtst(l, t);
1529 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1530 return result;
1531 }
1532
1533 virtual void gcmp(int op) {
1534 fprintf(stderr, "gcmp(%d)\n", op);
1535 mpBase->gcmp(op);
1536 }
1537
1538 virtual void genOp(int op) {
1539 fprintf(stderr, "genOp(%d)\n", op);
1540 mpBase->genOp(op);
1541 }
1542
Jack Palevich9eed7a22009-07-06 17:24:34 -07001543
1544 virtual void gUnaryCmp(int op) {
1545 fprintf(stderr, "gUnaryCmp(%d)\n", op);
1546 mpBase->gUnaryCmp(op);
1547 }
1548
1549 virtual void genUnaryOp(int op) {
1550 fprintf(stderr, "genUnaryOp(%d)\n", op);
1551 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001552 }
1553
1554 virtual void pushR0() {
1555 fprintf(stderr, "pushR0()\n");
1556 mpBase->pushR0();
1557 }
1558
Jack Palevich9eed7a22009-07-06 17:24:34 -07001559 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001560 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001561 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001562 }
1563
Jack Palevich9eed7a22009-07-06 17:24:34 -07001564 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001565 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001566 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001567 }
1568
Jack Palevich8df46192009-07-07 14:48:51 -07001569 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001570 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001571 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001572 }
1573
1574 virtual void storeR0(int ea) {
1575 fprintf(stderr, "storeR0(%d)\n", ea);
1576 mpBase->storeR0(ea);
1577 }
1578
Jack Palevich8df46192009-07-07 14:48:51 -07001579 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001580 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001581 mpBase->loadR0(ea, isIncDec, op, pType);
1582 }
1583
1584 virtual void convertR0(Type* pType){
1585 fprintf(stderr, "convertR0(pType)\n");
1586 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001587 }
1588
1589 virtual int beginFunctionCallArguments() {
1590 int result = mpBase->beginFunctionCallArguments();
1591 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1592 return result;
1593 }
1594
Jack Palevich1a539db2009-07-08 13:04:41 -07001595 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001596 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07001597 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001598 }
1599
1600 virtual void endFunctionCallArguments(int a, int l) {
1601 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1602 mpBase->endFunctionCallArguments(a, l);
1603 }
1604
Jack Palevich8df46192009-07-07 14:48:51 -07001605 virtual int callForward(int symbol, Type* pFunc) {
1606 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001607 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1608 return result;
1609 }
1610
Jack Palevich8df46192009-07-07 14:48:51 -07001611 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001612 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001613 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001614 }
1615
Jack Palevich8df46192009-07-07 14:48:51 -07001616 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001617 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001618 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001619 }
1620
1621 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1622 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1623 mpBase->adjustStackAfterCall(l, isIndirect);
1624 }
1625
1626 virtual int jumpOffset() {
1627 return mpBase->jumpOffset();
1628 }
1629
1630 virtual int disassemble(FILE* out) {
1631 return mpBase->disassemble(out);
1632 }
1633
1634 /* output a symbol and patch all calls to it */
1635 virtual void gsym(int t) {
1636 fprintf(stderr, "gsym(%d)\n", t);
1637 mpBase->gsym(t);
1638 }
1639
1640 virtual int finishCompile() {
1641 int result = mpBase->finishCompile();
1642 fprintf(stderr, "finishCompile() = %d\n", result);
1643 return result;
1644 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001645
1646 /**
1647 * Stack alignment (in bytes) for this type of data
1648 */
1649 virtual size_t stackAlignment(Type* pType){
1650 return mpBase->stackAlignment(pType);
1651 }
1652
1653 /**
1654 * Array element alignment (in bytes) for this type of data.
1655 */
1656 virtual size_t sizeOf(Type* pType){
1657 return mpBase->sizeOf(pType);
1658 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001659
1660 virtual Type* getR0Type() {
1661 return mpBase->getR0Type();
1662 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001663 };
1664
1665#endif // PROVIDE_TRACE_CODEGEN
1666
Jack Palevich569f1352009-06-29 14:29:08 -07001667 class Arena {
1668 public:
1669 // Used to record a given allocation amount.
1670 // Used:
1671 // Mark mark = arena.mark();
1672 // ... lots of arena.allocate()
1673 // arena.free(mark);
1674
1675 struct Mark {
1676 size_t chunk;
1677 size_t offset;
1678 };
1679
1680 Arena() {
1681 mCurrentChunk = 0;
1682 Chunk start(CHUNK_SIZE);
1683 mData.push_back(start);
1684 }
1685
1686 ~Arena() {
1687 for(size_t i = 0; i < mData.size(); i++) {
1688 mData[i].free();
1689 }
1690 }
1691
1692 // Alloc using the standard alignment size safe for any variable
1693 void* alloc(size_t size) {
1694 return alloc(size, 8);
1695 }
1696
1697 Mark mark(){
1698 Mark result;
1699 result.chunk = mCurrentChunk;
1700 result.offset = mData[mCurrentChunk].mOffset;
1701 return result;
1702 }
1703
1704 void freeToMark(const Mark& mark) {
1705 mCurrentChunk = mark.chunk;
1706 mData[mCurrentChunk].mOffset = mark.offset;
1707 }
1708
1709 private:
1710 // Allocate memory aligned to a given size
1711 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1712 // Memory is not zero filled.
1713
1714 void* alloc(size_t size, size_t alignment) {
1715 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1716 if (mCurrentChunk + 1 < mData.size()) {
1717 mCurrentChunk++;
1718 } else {
1719 size_t allocSize = CHUNK_SIZE;
1720 if (allocSize < size + alignment - 1) {
1721 allocSize = size + alignment - 1;
1722 }
1723 Chunk chunk(allocSize);
1724 mData.push_back(chunk);
1725 mCurrentChunk++;
1726 }
1727 }
1728 return mData[mCurrentChunk].allocate(size, alignment);
1729 }
1730
1731 static const size_t CHUNK_SIZE = 128*1024;
1732 // Note: this class does not deallocate its
1733 // memory when it's destroyed. It depends upon
1734 // its parent to deallocate the memory.
1735 struct Chunk {
1736 Chunk() {
1737 mpData = 0;
1738 mSize = 0;
1739 mOffset = 0;
1740 }
1741
1742 Chunk(size_t size) {
1743 mSize = size;
1744 mpData = (char*) malloc(size);
1745 mOffset = 0;
1746 }
1747
1748 ~Chunk() {
1749 // Doesn't deallocate memory.
1750 }
1751
1752 void* allocate(size_t size, size_t alignment) {
1753 size_t alignedOffset = aligned(mOffset, alignment);
1754 void* result = mpData + alignedOffset;
1755 mOffset = alignedOffset + size;
1756 return result;
1757 }
1758
1759 void free() {
1760 if (mpData) {
1761 ::free(mpData);
1762 mpData = 0;
1763 }
1764 }
1765
1766 size_t remainingCapacity(size_t alignment) {
1767 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1768 }
1769
1770 // Assume alignment is a power of two
1771 inline size_t aligned(size_t v, size_t alignment) {
1772 size_t mask = alignment-1;
1773 return (v + mask) & ~mask;
1774 }
1775
1776 char* mpData;
1777 size_t mSize;
1778 size_t mOffset;
1779 };
1780
1781 size_t mCurrentChunk;
1782
1783 Vector<Chunk> mData;
1784 };
1785
Jack Palevich569f1352009-06-29 14:29:08 -07001786 struct VariableInfo;
1787
1788 struct Token {
1789 int hash;
1790 size_t length;
1791 char* pText;
1792 tokenid_t id;
1793
1794 // Current values for the token
1795 char* mpMacroDefinition;
1796 VariableInfo* mpVariableInfo;
1797 };
1798
1799 class TokenTable {
1800 public:
1801 // Don't use 0..0xff, allows characters and operators to be tokens too.
1802
1803 static const int TOKEN_BASE = 0x100;
1804 TokenTable() {
1805 mpMap = hashmapCreate(128, hashFn, equalsFn);
1806 }
1807
1808 ~TokenTable() {
1809 hashmapFree(mpMap);
1810 }
1811
1812 void setArena(Arena* pArena) {
1813 mpArena = pArena;
1814 }
1815
1816 // Returns a token for a given string of characters.
1817 tokenid_t intern(const char* pText, size_t length) {
1818 Token probe;
1819 int hash = hashmapHash((void*) pText, length);
1820 {
1821 Token probe;
1822 probe.hash = hash;
1823 probe.length = length;
1824 probe.pText = (char*) pText;
1825 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1826 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001827 return pValue->id;
1828 }
1829 }
1830
1831 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1832 memset(pToken, 0, sizeof(*pToken));
1833 pToken->hash = hash;
1834 pToken->length = length;
1835 pToken->pText = (char*) mpArena->alloc(length + 1);
1836 memcpy(pToken->pText, pText, length);
1837 pToken->pText[length] = 0;
1838 pToken->id = mTokens.size() + TOKEN_BASE;
1839 mTokens.push_back(pToken);
1840 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001841 return pToken->id;
1842 }
1843
1844 // Return the Token for a given tokenid.
1845 Token& operator[](tokenid_t id) {
1846 return *mTokens[id - TOKEN_BASE];
1847 }
1848
1849 inline size_t size() {
1850 return mTokens.size();
1851 }
1852
1853 private:
1854
1855 static int hashFn(void* pKey) {
1856 Token* pToken = (Token*) pKey;
1857 return pToken->hash;
1858 }
1859
1860 static bool equalsFn(void* keyA, void* keyB) {
1861 Token* pTokenA = (Token*) keyA;
1862 Token* pTokenB = (Token*) keyB;
1863 // Don't need to compare hash values, they should always be equal
1864 return pTokenA->length == pTokenB->length
1865 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1866 }
1867
1868 Hashmap* mpMap;
1869 Vector<Token*> mTokens;
1870 Arena* mpArena;
1871 };
1872
Jack Palevich1cdef202009-05-22 12:06:27 -07001873 class InputStream {
1874 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001875 int getChar() {
1876 if (bumpLine) {
1877 line++;
1878 bumpLine = false;
1879 }
1880 int ch = get();
1881 if (ch == '\n') {
1882 bumpLine = true;
1883 }
1884 return ch;
1885 }
1886 int getLine() {
1887 return line;
1888 }
1889 protected:
1890 InputStream() :
1891 line(1), bumpLine(false) {
1892 }
1893 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001894 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001895 int line;
1896 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001897 };
1898
1899 class FileInputStream : public InputStream {
1900 public:
1901 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001902 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001903 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001904 FILE* f;
1905 };
1906
1907 class TextInputStream : public InputStream {
1908 public:
1909 TextInputStream(const char* text, size_t textLength)
1910 : pText(text), mTextLength(textLength), mPosition(0) {
1911 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001912
1913 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001914 virtual int get() {
1915 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1916 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001917
Jack Palevich1cdef202009-05-22 12:06:27 -07001918 const char* pText;
1919 size_t mTextLength;
1920 size_t mPosition;
1921 };
1922
Jack Palevicheedf9d22009-06-04 16:23:40 -07001923 class String {
1924 public:
1925 String() {
1926 mpBase = 0;
1927 mUsed = 0;
1928 mSize = 0;
1929 }
1930
Jack Palevich303d8ff2009-06-11 19:06:24 -07001931 String(const char* item, int len, bool adopt) {
1932 if (len < 0) {
1933 len = strlen(item);
1934 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001935 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001936 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001937 mUsed = len;
1938 mSize = len + 1;
1939 } else {
1940 mpBase = 0;
1941 mUsed = 0;
1942 mSize = 0;
1943 appendBytes(item, len);
1944 }
1945 }
1946
Jack Palevich303d8ff2009-06-11 19:06:24 -07001947 String(const String& other) {
1948 mpBase = 0;
1949 mUsed = 0;
1950 mSize = 0;
1951 appendBytes(other.getUnwrapped(), other.len());
1952 }
1953
Jack Palevicheedf9d22009-06-04 16:23:40 -07001954 ~String() {
1955 if (mpBase) {
1956 free(mpBase);
1957 }
1958 }
1959
Jack Palevicha6baa232009-06-12 11:25:59 -07001960 String& operator=(const String& other) {
1961 clear();
1962 appendBytes(other.getUnwrapped(), other.len());
1963 return *this;
1964 }
1965
Jack Palevich303d8ff2009-06-11 19:06:24 -07001966 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001967 return mpBase;
1968 }
1969
Jack Palevich303d8ff2009-06-11 19:06:24 -07001970 void clear() {
1971 mUsed = 0;
1972 if (mSize > 0) {
1973 mpBase[0] = 0;
1974 }
1975 }
1976
Jack Palevicheedf9d22009-06-04 16:23:40 -07001977 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001978 appendBytes(s, strlen(s));
1979 }
1980
1981 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001982 memcpy(ensure(n), s, n + 1);
1983 }
1984
1985 void append(char c) {
1986 * ensure(1) = c;
1987 }
1988
Jack Palevich86351982009-06-30 18:09:56 -07001989 void append(String& other) {
1990 appendBytes(other.getUnwrapped(), other.len());
1991 }
1992
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001993 char* orphan() {
1994 char* result = mpBase;
1995 mpBase = 0;
1996 mUsed = 0;
1997 mSize = 0;
1998 return result;
1999 }
2000
Jack Palevicheedf9d22009-06-04 16:23:40 -07002001 void printf(const char* fmt,...) {
2002 va_list ap;
2003 va_start(ap, fmt);
2004 vprintf(fmt, ap);
2005 va_end(ap);
2006 }
2007
2008 void vprintf(const char* fmt, va_list ap) {
2009 char* temp;
2010 int numChars = vasprintf(&temp, fmt, ap);
2011 memcpy(ensure(numChars), temp, numChars+1);
2012 free(temp);
2013 }
2014
Jack Palevich303d8ff2009-06-11 19:06:24 -07002015 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002016 return mUsed;
2017 }
2018
2019 private:
2020 char* ensure(int n) {
2021 size_t newUsed = mUsed + n;
2022 if (newUsed > mSize) {
2023 size_t newSize = mSize * 2 + 10;
2024 if (newSize < newUsed) {
2025 newSize = newUsed;
2026 }
2027 mpBase = (char*) realloc(mpBase, newSize + 1);
2028 mSize = newSize;
2029 }
2030 mpBase[newUsed] = '\0';
2031 char* result = mpBase + mUsed;
2032 mUsed = newUsed;
2033 return result;
2034 }
2035
2036 char* mpBase;
2037 size_t mUsed;
2038 size_t mSize;
2039 };
2040
Jack Palevich569f1352009-06-29 14:29:08 -07002041 void internKeywords() {
2042 // Note: order has to match TOK_ constants
2043 static const char* keywords[] = {
2044 "int",
2045 "char",
2046 "void",
2047 "if",
2048 "else",
2049 "while",
2050 "break",
2051 "return",
2052 "for",
2053 "pragma",
2054 "define",
2055 "auto",
2056 "case",
2057 "const",
2058 "continue",
2059 "default",
2060 "do",
2061 "double",
2062 "enum",
2063 "extern",
2064 "float",
2065 "goto",
2066 "long",
2067 "register",
2068 "short",
2069 "signed",
2070 "sizeof",
2071 "static",
2072 "struct",
2073 "switch",
2074 "typedef",
2075 "union",
2076 "unsigned",
2077 "volatile",
2078 "_Bool",
2079 "_Complex",
2080 "_Imaginary",
2081 "inline",
2082 "restrict",
2083 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002084
Jack Palevich569f1352009-06-29 14:29:08 -07002085 for(int i = 0; keywords[i]; i++) {
2086 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002087 }
Jack Palevich569f1352009-06-29 14:29:08 -07002088 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002089
Jack Palevich36d94142009-06-08 15:55:32 -07002090 struct InputState {
2091 InputStream* pStream;
2092 int oldCh;
2093 };
2094
Jack Palevich2db168f2009-06-11 14:29:47 -07002095 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002096 void* pAddress;
2097 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002098 tokenid_t tok;
2099 size_t level;
2100 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002101 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002102 };
2103
Jack Palevich303d8ff2009-06-11 19:06:24 -07002104 class SymbolStack {
2105 public:
2106 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002107 mpArena = 0;
2108 mpTokenTable = 0;
2109 }
2110
2111 void setArena(Arena* pArena) {
2112 mpArena = pArena;
2113 }
2114
2115 void setTokenTable(TokenTable* pTokenTable) {
2116 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002117 }
2118
2119 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002120 Mark mark;
2121 mark.mArenaMark = mpArena->mark();
2122 mark.mSymbolHead = mStack.size();
2123 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002124 }
2125
2126 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002127 // Undo any shadowing that was done:
2128 Mark mark = mLevelStack.back();
2129 mLevelStack.pop_back();
2130 while (mStack.size() > mark.mSymbolHead) {
2131 VariableInfo* pV = mStack.back();
2132 mStack.pop_back();
2133 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002134 }
Jack Palevich569f1352009-06-29 14:29:08 -07002135 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002136 }
2137
Jack Palevich569f1352009-06-29 14:29:08 -07002138 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2139 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2140 return pV && pV->level == level();
2141 }
2142
2143 VariableInfo* add(tokenid_t tok) {
2144 Token& token = (*mpTokenTable)[tok];
2145 VariableInfo* pOldV = token.mpVariableInfo;
2146 VariableInfo* pNewV =
2147 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2148 memset(pNewV, 0, sizeof(VariableInfo));
2149 pNewV->tok = tok;
2150 pNewV->level = level();
2151 pNewV->pOldDefinition = pOldV;
2152 token.mpVariableInfo = pNewV;
2153 mStack.push_back(pNewV);
2154 return pNewV;
2155 }
2156
Jack Palevich86351982009-06-30 18:09:56 -07002157 VariableInfo* add(Type* pType) {
2158 VariableInfo* pVI = add(pType->id);
2159 pVI->pType = pType;
2160 return pVI;
2161 }
2162
Jack Palevich569f1352009-06-29 14:29:08 -07002163 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2164 for (size_t i = 0; i < mStack.size(); i++) {
2165 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002166 break;
2167 }
2168 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002169 }
2170
Jack Palevich303d8ff2009-06-11 19:06:24 -07002171 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002172 inline size_t level() {
2173 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002174 }
2175
Jack Palevich569f1352009-06-29 14:29:08 -07002176 struct Mark {
2177 Arena::Mark mArenaMark;
2178 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002179 };
2180
Jack Palevich569f1352009-06-29 14:29:08 -07002181 Arena* mpArena;
2182 TokenTable* mpTokenTable;
2183 Vector<VariableInfo*> mStack;
2184 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002185 };
Jack Palevich36d94142009-06-08 15:55:32 -07002186
2187 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002188 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002189 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002190 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002191 int tokl; // token operator level
2192 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002193 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002194 intptr_t loc; // local variable index
2195 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002196 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002197 char* dptr; // Macro state: Points to macro text during macro playback.
2198 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002199 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002200
2201 // Arena for the duration of the compile
2202 Arena mGlobalArena;
2203 // Arena for data that's only needed when compiling a single function
2204 Arena mLocalArena;
2205
2206 TokenTable mTokenTable;
2207 SymbolStack mGlobals;
2208 SymbolStack mLocals;
2209
Jack Palevich40600de2009-07-01 15:32:35 -07002210 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002211 Type* mkpInt; // int
2212 Type* mkpChar; // char
2213 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002214 Type* mkpFloat;
2215 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002216 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002217 Type* mkpIntPtr;
2218 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07002219 Type* mkpFloatPtr;
2220 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07002221 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002222
Jack Palevich36d94142009-06-08 15:55:32 -07002223 InputStream* file;
2224
2225 CodeBuf codeBuf;
2226 CodeGenerator* pGen;
2227
Jack Palevicheedf9d22009-06-04 16:23:40 -07002228 String mErrorBuf;
2229
Jack Palevicheedf9d22009-06-04 16:23:40 -07002230 String mPragmas;
2231 int mPragmaStringCount;
2232
Jack Palevich21a15a22009-05-11 14:49:29 -07002233 static const int ALLOC_SIZE = 99999;
2234
Jack Palevich303d8ff2009-06-11 19:06:24 -07002235 static const int TOK_DUMMY = 1;
2236 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002237 static const int TOK_NUM_FLOAT = 3;
2238 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002239
2240 // 3..255 are character and/or operators
2241
Jack Palevich2db168f2009-06-11 14:29:47 -07002242 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002243 // Order has to match string list in "internKeywords".
2244 enum {
2245 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2246 TOK_INT = TOK_KEYWORD,
2247 TOK_CHAR,
2248 TOK_VOID,
2249 TOK_IF,
2250 TOK_ELSE,
2251 TOK_WHILE,
2252 TOK_BREAK,
2253 TOK_RETURN,
2254 TOK_FOR,
2255 TOK_PRAGMA,
2256 TOK_DEFINE,
2257 TOK_AUTO,
2258 TOK_CASE,
2259 TOK_CONST,
2260 TOK_CONTINUE,
2261 TOK_DEFAULT,
2262 TOK_DO,
2263 TOK_DOUBLE,
2264 TOK_ENUM,
2265 TOK_EXTERN,
2266 TOK_FLOAT,
2267 TOK_GOTO,
2268 TOK_LONG,
2269 TOK_REGISTER,
2270 TOK_SHORT,
2271 TOK_SIGNED,
2272 TOK_SIZEOF,
2273 TOK_STATIC,
2274 TOK_STRUCT,
2275 TOK_SWITCH,
2276 TOK_TYPEDEF,
2277 TOK_UNION,
2278 TOK_UNSIGNED,
2279 TOK_VOLATILE,
2280 TOK__BOOL,
2281 TOK__COMPLEX,
2282 TOK__IMAGINARY,
2283 TOK_INLINE,
2284 TOK_RESTRICT,
2285 // Symbols start after tokens
2286 TOK_SYMBOL
2287 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002288
2289 static const int LOCAL = 0x200;
2290
2291 static const int SYM_FORWARD = 0;
2292 static const int SYM_DEFINE = 1;
2293
2294 /* tokens in string heap */
2295 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002296
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002297 static const int OP_INCREMENT = 0;
2298 static const int OP_DECREMENT = 1;
2299 static const int OP_MUL = 2;
2300 static const int OP_DIV = 3;
2301 static const int OP_MOD = 4;
2302 static const int OP_PLUS = 5;
2303 static const int OP_MINUS = 6;
2304 static const int OP_SHIFT_LEFT = 7;
2305 static const int OP_SHIFT_RIGHT = 8;
2306 static const int OP_LESS_EQUAL = 9;
2307 static const int OP_GREATER_EQUAL = 10;
2308 static const int OP_LESS = 11;
2309 static const int OP_GREATER = 12;
2310 static const int OP_EQUALS = 13;
2311 static const int OP_NOT_EQUALS = 14;
2312 static const int OP_LOGICAL_AND = 15;
2313 static const int OP_LOGICAL_OR = 16;
2314 static const int OP_BIT_AND = 17;
2315 static const int OP_BIT_XOR = 18;
2316 static const int OP_BIT_OR = 19;
2317 static const int OP_BIT_NOT = 20;
2318 static const int OP_LOGICAL_NOT = 21;
2319 static const int OP_COUNT = 22;
2320
2321 /* Operators are searched from front, the two-character operators appear
2322 * before the single-character operators with the same first character.
2323 * @ is used to pad out single-character operators.
2324 */
2325 static const char* operatorChars;
2326 static const char operatorLevel[];
2327
Jack Palevich569f1352009-06-29 14:29:08 -07002328 /* Called when we detect an internal problem. Does nothing in production.
2329 *
2330 */
2331 void internalError() {
2332 * (char*) 0 = 0;
2333 }
2334
Jack Palevich86351982009-06-30 18:09:56 -07002335 void assert(bool isTrue) {
2336 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002337 internalError();
2338 }
Jack Palevich86351982009-06-30 18:09:56 -07002339 }
2340
Jack Palevich40600de2009-07-01 15:32:35 -07002341 bool isSymbol(tokenid_t t) {
2342 return t >= TOK_SYMBOL &&
2343 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2344 }
2345
2346 bool isSymbolOrKeyword(tokenid_t t) {
2347 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002348 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002349 }
2350
Jack Palevich86351982009-06-30 18:09:56 -07002351 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002352 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002353 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2354 if (pV && pV->tok != t) {
2355 internalError();
2356 }
2357 return pV;
2358 }
2359
2360 inline bool isDefined(tokenid_t t) {
2361 return t >= TOK_SYMBOL && VI(t) != 0;
2362 }
2363
Jack Palevich40600de2009-07-01 15:32:35 -07002364 const char* nameof(tokenid_t t) {
2365 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002366 return mTokenTable[t].pText;
2367 }
2368
Jack Palevich21a15a22009-05-11 14:49:29 -07002369 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002370 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002371 }
2372
2373 void inp() {
2374 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002375 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002376 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002377 dptr = 0;
2378 ch = dch;
2379 }
2380 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002381 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002382#if 0
2383 printf("ch='%c' 0x%x\n", ch, ch);
2384#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002385 }
2386
2387 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002388 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002389 }
2390
Jack Palevichb4758ff2009-06-12 12:49:14 -07002391 /* read a character constant, advances ch to after end of constant */
2392 int getq() {
2393 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002394 if (ch == '\\') {
2395 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002396 if (isoctal(ch)) {
2397 // 1 to 3 octal characters.
2398 val = 0;
2399 for(int i = 0; i < 3; i++) {
2400 if (isoctal(ch)) {
2401 val = (val << 3) + ch - '0';
2402 inp();
2403 }
2404 }
2405 return val;
2406 } else if (ch == 'x' || ch == 'X') {
2407 // N hex chars
2408 inp();
2409 if (! isxdigit(ch)) {
2410 error("'x' character escape requires at least one digit.");
2411 } else {
2412 val = 0;
2413 while (isxdigit(ch)) {
2414 int d = ch;
2415 if (isdigit(d)) {
2416 d -= '0';
2417 } else if (d <= 'F') {
2418 d = d - 'A' + 10;
2419 } else {
2420 d = d - 'a' + 10;
2421 }
2422 val = (val << 4) + d;
2423 inp();
2424 }
2425 }
2426 } else {
2427 int val = ch;
2428 switch (ch) {
2429 case 'a':
2430 val = '\a';
2431 break;
2432 case 'b':
2433 val = '\b';
2434 break;
2435 case 'f':
2436 val = '\f';
2437 break;
2438 case 'n':
2439 val = '\n';
2440 break;
2441 case 'r':
2442 val = '\r';
2443 break;
2444 case 't':
2445 val = '\t';
2446 break;
2447 case 'v':
2448 val = '\v';
2449 break;
2450 case '\\':
2451 val = '\\';
2452 break;
2453 case '\'':
2454 val = '\'';
2455 break;
2456 case '"':
2457 val = '"';
2458 break;
2459 case '?':
2460 val = '?';
2461 break;
2462 default:
2463 error("Undefined character escape %c", ch);
2464 break;
2465 }
2466 inp();
2467 return val;
2468 }
2469 } else {
2470 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002471 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002472 return val;
2473 }
2474
2475 static bool isoctal(int ch) {
2476 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002477 }
2478
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002479 bool acceptCh(int c) {
2480 bool result = c == ch;
2481 if (result) {
2482 pdef(ch);
2483 inp();
2484 }
2485 return result;
2486 }
2487
2488 bool acceptDigitsCh() {
2489 bool result = false;
2490 while (isdigit(ch)) {
2491 result = true;
2492 pdef(ch);
2493 inp();
2494 }
2495 return result;
2496 }
2497
2498 void parseFloat() {
2499 tok = TOK_NUM_DOUBLE;
2500 // mTokenString already has the integral part of the number.
2501 acceptCh('.');
2502 acceptDigitsCh();
2503 bool doExp = true;
2504 if (acceptCh('e') || acceptCh('E')) {
2505 // Don't need to do any extra work
2506 } else if (ch == 'f' || ch == 'F') {
2507 pdef('e'); // So it can be parsed by strtof.
2508 inp();
2509 tok = TOK_NUM_FLOAT;
2510 } else {
2511 doExp = false;
2512 }
2513 if (doExp) {
2514 bool digitsRequired = acceptCh('-');
2515 bool digitsFound = acceptDigitsCh();
2516 if (digitsRequired && ! digitsFound) {
2517 error("malformed exponent");
2518 }
2519 }
2520 char* pText = mTokenString.getUnwrapped();
2521 if (tok == TOK_NUM_FLOAT) {
2522 tokd = strtof(pText, 0);
2523 } else {
2524 tokd = strtod(pText, 0);
2525 }
2526 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2527 }
2528
Jack Palevich21a15a22009-05-11 14:49:29 -07002529 void next() {
2530 int l, a;
2531
Jack Palevich546b2242009-05-13 15:10:04 -07002532 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002533 if (ch == '#') {
2534 inp();
2535 next();
2536 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002537 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002538 } else if (tok == TOK_PRAGMA) {
2539 doPragma();
2540 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002541 error("Unsupported preprocessor directive \"%s\"",
2542 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002543 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002544 }
2545 inp();
2546 }
2547 tokl = 0;
2548 tok = ch;
2549 /* encode identifiers & numbers */
2550 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002551 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002552 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002553 pdef(ch);
2554 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002555 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002556 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002557 // Start of a numeric constant. Could be integer, float, or
2558 // double, won't know until we look further.
2559 if (ch == '.' || ch == 'e' || ch == 'e'
2560 || ch == 'f' || ch == 'F') {
2561 parseFloat();
2562 } else {
2563 // It's an integer constant
2564 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2565 tok = TOK_NUM;
2566 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002567 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002568 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2569 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002570 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002571 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2572 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002573 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002574 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002575 dch = ch;
2576 inp();
2577 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002578 }
2579 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002580 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002581 inp();
2582 if (tok == '\'') {
2583 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002584 tokc = getq();
2585 if (ch != '\'') {
2586 error("Expected a ' character, got %c", ch);
2587 } else {
2588 inp();
2589 }
Jack Palevich546b2242009-05-13 15:10:04 -07002590 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002591 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002592 while (ch && ch != EOF) {
2593 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002594 inp();
2595 inp();
2596 if (ch == '/')
2597 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002598 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002599 if (ch == EOF) {
2600 error("End of file inside comment.");
2601 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002602 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002603 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002604 } else if ((tok == '/') & (ch == '/')) {
2605 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002606 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002607 inp();
2608 }
2609 inp();
2610 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002611 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002612 const char* t = operatorChars;
2613 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002614 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002615 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002616 tokl = operatorLevel[opIndex];
2617 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002618 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002619#if 0
2620 printf("%c%c -> tokl=%d tokc=0x%x\n",
2621 l, a, tokl, tokc);
2622#endif
2623 if (a == ch) {
2624 inp();
2625 tok = TOK_DUMMY; /* dummy token for double tokens */
2626 }
2627 break;
2628 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002629 opIndex++;
2630 }
2631 if (l == 0) {
2632 tokl = 0;
2633 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002634 }
2635 }
2636 }
2637#if 0
2638 {
Jack Palevich569f1352009-06-29 14:29:08 -07002639 String buf;
2640 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002641 fprintf(stderr, "%s\n", buf.getUnwrapped());
2642 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002643#endif
2644 }
2645
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002646 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002647 next();
2648 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002649 String* pName = new String();
2650 while (isspace(ch)) {
2651 inp();
2652 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002653 if (ch == '(') {
2654 delete pName;
2655 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002656 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002657 }
2658 while (isspace(ch)) {
2659 inp();
2660 }
Jack Palevich569f1352009-06-29 14:29:08 -07002661 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002662 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002663 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002664 inp();
2665 }
Jack Palevich569f1352009-06-29 14:29:08 -07002666 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2667 memcpy(pDefn, value.getUnwrapped(), value.len());
2668 pDefn[value.len()] = 0;
2669 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002670 }
2671
Jack Palevicheedf9d22009-06-04 16:23:40 -07002672 void doPragma() {
2673 // # pragma name(val)
2674 int state = 0;
2675 while(ch != EOF && ch != '\n' && state < 10) {
2676 switch(state) {
2677 case 0:
2678 if (isspace(ch)) {
2679 inp();
2680 } else {
2681 state++;
2682 }
2683 break;
2684 case 1:
2685 if (isalnum(ch)) {
2686 mPragmas.append(ch);
2687 inp();
2688 } else if (ch == '(') {
2689 mPragmas.append(0);
2690 inp();
2691 state++;
2692 } else {
2693 state = 11;
2694 }
2695 break;
2696 case 2:
2697 if (isalnum(ch)) {
2698 mPragmas.append(ch);
2699 inp();
2700 } else if (ch == ')') {
2701 mPragmas.append(0);
2702 inp();
2703 state = 10;
2704 } else {
2705 state = 11;
2706 }
2707 break;
2708 }
2709 }
2710 if(state != 10) {
2711 error("Unexpected pragma syntax");
2712 }
2713 mPragmaStringCount += 2;
2714 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002715
Jack Palevichac0e95e2009-05-29 13:53:44 -07002716 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002717 mErrorBuf.printf("%ld: ", file->getLine());
2718 mErrorBuf.vprintf(fmt, ap);
2719 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002720 }
2721
Jack Palevich8b0624c2009-05-20 12:12:06 -07002722 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002723 if (tok != c) {
2724 error("'%c' expected", c);
2725 }
2726 next();
2727 }
2728
Jack Palevich86351982009-06-30 18:09:56 -07002729 bool accept(intptr_t c) {
2730 if (tok == c) {
2731 next();
2732 return true;
2733 }
2734 return false;
2735 }
2736
Jack Palevich40600de2009-07-01 15:32:35 -07002737 bool acceptStringLiteral() {
2738 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07002739 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07002740 // This while loop merges multiple adjacent string constants.
2741 while (tok == '"') {
2742 while (ch != '"' && ch != EOF) {
2743 *allocGlobalSpace(1) = getq();
2744 }
2745 if (ch != '"') {
2746 error("Unterminated string constant.");
2747 }
2748 inp();
2749 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002750 }
Jack Palevich40600de2009-07-01 15:32:35 -07002751 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002752 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002753 /* align heap */
2754 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002755
2756 return true;
2757 }
2758 return false;
2759 }
2760 /* Parse and evaluate a unary expression.
2761 * allowAssignment is true if '=' parsing wanted (quick hack)
2762 */
2763 void unary(bool allowAssignment) {
2764 intptr_t n, t, a;
2765 t = 0;
2766 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2767 if (acceptStringLiteral()) {
2768 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002769 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002770 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002771 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002772 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07002773 t = tok;
2774 next();
2775 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07002776 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002777 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002778 // Align to 4-byte boundary
2779 glo = (char*) (((intptr_t) glo + 3) & -4);
2780 * (float*) glo = (float) ad;
2781 pGen->loadFloat((int) glo, mkpFloat);
2782 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002783 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002784 // Align to 8-byte boundary
2785 glo = (char*) (((intptr_t) glo + 7) & -8);
2786 * (double*) glo = ad;
2787 pGen->loadFloat((int) glo, mkpDouble);
2788 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07002789 } else if (c == 2) {
2790 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002791 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002792 if (t == '!')
Jack Palevich9eed7a22009-07-06 17:24:34 -07002793 pGen->gUnaryCmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002794 else
Jack Palevich9eed7a22009-07-06 17:24:34 -07002795 pGen->genUnaryOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002796 } else if (t == '(') {
2797 expr();
2798 skip(')');
2799 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002800 /* This is a pointer dereference, but we currently only
2801 * support a pointer dereference if it's immediately
2802 * in front of a cast. So parse the cast right here.
2803 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002804 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002805 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2806 // We currently only handle 3 types of cast:
2807 // (int*), (char*) , (int (*)())
2808 if(typeEqual(pCast, mkpIntPtr)) {
2809 t = TOK_INT;
2810 } else if (typeEqual(pCast, mkpCharPtr)) {
2811 t = TOK_CHAR;
2812 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002813 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002814 } else {
2815 String buffer;
2816 decodeType(buffer, pCast);
2817 error("Unsupported cast type %s", buffer.getUnwrapped());
2818 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002819 }
2820 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002821 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002822 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002823 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002824 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002825 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002826 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002827 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002828 }
Jack Palevich3f226492009-07-02 14:46:19 -07002829 // Else we fall through to the function call below, with
2830 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002831 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07002832 VariableInfo* pVI = VI(tok);
2833 pGen->leaR0((int) pVI->pAddress,
2834 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07002835 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002836 } else if (t == EOF ) {
2837 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002838 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002839 // Don't have to do anything special here, the error
2840 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002841 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002842 if (!isDefined(t)) {
2843 mGlobals.add(t);
2844 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002845 }
Jack Palevich8df46192009-07-07 14:48:51 -07002846 VariableInfo* pVI = VI(t);
2847 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002848 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002849 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002850 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07002851 if (tok == '(') {
2852 pVI->pType = mkpIntFn;
2853 } else {
2854 pVI->pType = mkpInt;
2855 }
Jack Palevich8df46192009-07-07 14:48:51 -07002856 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002857 }
Jack Palevich40600de2009-07-01 15:32:35 -07002858 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002859 /* assignment */
2860 next();
2861 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002862 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002863 } else if (tok != '(') {
2864 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002865 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002866 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07002867 }
Jack Palevich8df46192009-07-07 14:48:51 -07002868 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002869 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002870 next();
2871 }
2872 }
2873 }
2874 }
2875
2876 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07002877 if (accept('(')) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002878 Type* pArgList = NULL;
2879 VariableInfo* pVI = NULL;
2880 if (n == 1) { // Indirect function call, push address of fn.
2881 pArgList = pGen->getR0Type()->pTail;
Jack Palevich1cdef202009-05-22 12:06:27 -07002882 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07002883 } else {
2884 pVI = VI(t);
2885 pArgList = pVI->pType->pTail;
2886 }
2887 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07002888 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002889 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07002890 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002891 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002892 if (! varArgs && !pArgList) {
2893 error ("Unexpected argument.");
2894 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002895 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07002896 Type* pTargetType;
2897 if (pArgList) {
2898 pTargetType = pArgList->pHead;
2899 pArgList = pArgList->pTail;
2900 } else {
2901 pTargetType = pGen->getR0Type();
2902 if (pTargetType->tag == TY_FLOAT) {
2903 pTargetType = mkpDouble;
2904 }
2905 }
2906 pGen->convertR0(pTargetType);
2907 l += pGen->storeR0ToArg(l);
Jack Palevich95727a02009-07-06 12:07:15 -07002908 if (accept(',')) {
2909 // fine
2910 } else if ( tok != ')') {
2911 error("Expected ',' or ')'");
2912 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002913 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002914 if (! varArgs && pArgList) {
2915 error ("Expected more argument(s).");
2916 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002917 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002918 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002919 if (!n) {
2920 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07002921 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
2922 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002923 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07002924 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002925 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07002926 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
2927 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002928 }
-b master422972c2009-06-17 19:13:52 -07002929 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002930 }
2931 }
2932
Jack Palevich40600de2009-07-01 15:32:35 -07002933 /* Recursive descent parser for binary operations.
2934 */
2935 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002936 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002937 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002938 if (level-- == 1)
2939 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07002940 else {
Jack Palevich40600de2009-07-01 15:32:35 -07002941 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002942 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002943 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002944 n = tok;
2945 t = tokc;
2946 next();
2947
Jack Palevich40600de2009-07-01 15:32:35 -07002948 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002949 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002950 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002951 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002952 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07002953 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002954
Jack Palevich40600de2009-07-01 15:32:35 -07002955 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002956 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002957 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002958 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002959 }
2960 }
2961 }
2962 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002963 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002964 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07002965 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07002966 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002967 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07002968 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002969 }
2970 }
2971 }
2972
2973 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07002974 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07002975 }
2976
2977 int test_expr() {
2978 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002979 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002980 }
2981
Jack Palevicha6baa232009-06-12 11:25:59 -07002982 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002983 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002984
Jack Palevich95727a02009-07-06 12:07:15 -07002985 Type* pBaseType;
2986 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002987 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07002988 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07002989 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002990 next();
2991 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002992 a = test_expr();
2993 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002994 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002995 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002996 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002997 n = pGen->gjmp(0); /* jmp */
2998 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002999 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003000 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003001 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003002 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003003 }
Jack Palevich546b2242009-05-13 15:10:04 -07003004 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003005 t = tok;
3006 next();
3007 skip('(');
3008 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003009 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003010 a = test_expr();
3011 } else {
3012 if (tok != ';')
3013 expr();
3014 skip(';');
3015 n = codeBuf.getPC();
3016 a = 0;
3017 if (tok != ';')
3018 a = test_expr();
3019 skip(';');
3020 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003021 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003022 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003023 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003024 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003025 n = t + 4;
3026 }
3027 }
3028 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003029 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003030 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003031 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003032 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003033 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003034 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003035 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003036 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003037 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003038 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003039 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003040 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003041 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003042 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003043 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003044 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003045 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003046 expr();
Jack Palevich8df46192009-07-07 14:48:51 -07003047 pGen->convertR0(pReturnType);
3048 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003049 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003050 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003051 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003052 } else if (tok != ';')
3053 expr();
3054 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003055 }
3056 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003057
Jack Palevich3f226492009-07-02 14:46:19 -07003058 bool typeEqual(Type* a, Type* b) {
3059 if (a == b) {
3060 return true;
3061 }
3062 if (a == NULL || b == NULL) {
3063 return false;
3064 }
3065 TypeTag at = a->tag;
3066 if (at != b->tag) {
3067 return false;
3068 }
3069 if (at == TY_POINTER) {
3070 return typeEqual(a->pHead, b->pHead);
3071 } else if (at == TY_FUNC || at == TY_PARAM) {
3072 return typeEqual(a->pHead, b->pHead)
3073 && typeEqual(a->pTail, b->pTail);
3074 }
3075 return true;
3076 }
3077
Jack Palevich86351982009-06-30 18:09:56 -07003078 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3079 assert(tag >= TY_INT && tag <= TY_PARAM);
3080 Type* pType = (Type*) arena.alloc(sizeof(Type));
3081 memset(pType, 0, sizeof(*pType));
3082 pType->tag = tag;
3083 pType->pHead = pHead;
3084 pType->pTail = pTail;
3085 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003086 }
3087
Jack Palevich3f226492009-07-02 14:46:19 -07003088 Type* createPtrType(Type* pType, Arena& arena) {
3089 return createType(TY_POINTER, pType, NULL, arena);
3090 }
3091
3092 /**
3093 * Try to print a type in declaration order
3094 */
Jack Palevich86351982009-06-30 18:09:56 -07003095 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003096 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003097 if (pType == NULL) {
3098 buffer.appendCStr("null");
3099 return;
3100 }
Jack Palevich3f226492009-07-02 14:46:19 -07003101 decodeTypeImp(buffer, pType);
3102 }
3103
3104 void decodeTypeImp(String& buffer, Type* pType) {
3105 decodeTypeImpPrefix(buffer, pType);
3106
Jack Palevich86351982009-06-30 18:09:56 -07003107 String temp;
3108 if (pType->id != 0) {
3109 decodeToken(temp, pType->id);
3110 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003111 }
3112
3113 decodeTypeImpPostfix(buffer, pType);
3114 }
3115
3116 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3117 TypeTag tag = pType->tag;
3118
3119 if (tag >= TY_INT && tag <= TY_VOID) {
3120 switch (tag) {
3121 case TY_INT:
3122 buffer.appendCStr("int");
3123 break;
3124 case TY_CHAR:
3125 buffer.appendCStr("char");
3126 break;
3127 case TY_VOID:
3128 buffer.appendCStr("void");
3129 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003130 case TY_FLOAT:
3131 buffer.appendCStr("float");
3132 break;
3133 case TY_DOUBLE:
3134 buffer.appendCStr("double");
3135 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003136 default:
3137 break;
3138 }
Jack Palevich86351982009-06-30 18:09:56 -07003139 buffer.append(' ');
3140 }
Jack Palevich3f226492009-07-02 14:46:19 -07003141
3142 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003143 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003144 break;
3145 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003146 break;
3147 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003148 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003149 case TY_FLOAT:
3150 break;
3151 case TY_DOUBLE:
3152 break;
Jack Palevich86351982009-06-30 18:09:56 -07003153 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003154 decodeTypeImpPrefix(buffer, pType->pHead);
3155 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3156 buffer.append('(');
3157 }
3158 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003159 break;
3160 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003161 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003162 break;
3163 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003164 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003165 break;
3166 default:
3167 String temp;
3168 temp.printf("Unknown tag %d", pType->tag);
3169 buffer.append(temp);
3170 break;
3171 }
Jack Palevich3f226492009-07-02 14:46:19 -07003172 }
3173
3174 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3175 TypeTag tag = pType->tag;
3176
3177 switch(tag) {
3178 case TY_POINTER:
3179 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3180 buffer.append(')');
3181 }
3182 decodeTypeImpPostfix(buffer, pType->pHead);
3183 break;
3184 case TY_FUNC:
3185 buffer.append('(');
3186 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3187 decodeTypeImp(buffer, pArg);
3188 if (pArg->pTail) {
3189 buffer.appendCStr(", ");
3190 }
3191 }
3192 buffer.append(')');
3193 break;
3194 default:
3195 break;
Jack Palevich86351982009-06-30 18:09:56 -07003196 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003197 }
3198
Jack Palevich86351982009-06-30 18:09:56 -07003199 void printType(Type* pType) {
3200 String buffer;
3201 decodeType(buffer, pType);
3202 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003203 }
3204
Jack Palevich86351982009-06-30 18:09:56 -07003205 Type* acceptPrimitiveType(Arena& arena) {
3206 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003207 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003208 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003209 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003210 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003211 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003212 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003213 } else if (tok == TOK_FLOAT) {
3214 pType = mkpFloat;
3215 } else if (tok == TOK_DOUBLE) {
3216 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003217 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003218 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003219 }
3220 next();
Jack Palevich86351982009-06-30 18:09:56 -07003221 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003222 }
3223
Jack Palevich3f226492009-07-02 14:46:19 -07003224 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3225 Arena& arena) {
3226 tokenid_t declName = 0;
3227 pType = acceptDecl2(pType, declName, nameAllowed,
3228 nameRequired, arena);
3229 if (declName) {
3230 // Clone the parent type so we can set a unique ID
3231 pType = createType(pType->tag, pType->pHead,
3232 pType->pTail, arena);
3233
Jack Palevich86351982009-06-30 18:09:56 -07003234 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003235 }
Jack Palevich3f226492009-07-02 14:46:19 -07003236 // fprintf(stderr, "Parsed a declaration: ");
3237 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003238 return pType;
3239 }
3240
Jack Palevich3f226492009-07-02 14:46:19 -07003241 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3242 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003243 if (! pType) {
3244 error("Expected a declaration");
3245 }
3246 return pType;
3247 }
3248
Jack Palevich3f226492009-07-02 14:46:19 -07003249 /* Used for accepting types that appear in casts */
3250 Type* acceptCastTypeDeclaration(Arena& arena) {
3251 Type* pType = acceptPrimitiveType(arena);
3252 if (pType) {
3253 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003254 }
Jack Palevich86351982009-06-30 18:09:56 -07003255 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003256 }
3257
Jack Palevich3f226492009-07-02 14:46:19 -07003258 Type* expectCastTypeDeclaration(Arena& arena) {
3259 Type* pType = acceptCastTypeDeclaration(arena);
3260 if (! pType) {
3261 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003262 }
Jack Palevich3f226492009-07-02 14:46:19 -07003263 return pType;
3264 }
3265
3266 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3267 bool nameAllowed, bool nameRequired, Arena& arena) {
3268 int ptrCounter = 0;
3269 while (accept('*')) {
3270 ptrCounter++;
3271 }
3272 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3273 while (ptrCounter-- > 0) {
3274 pType = createType(TY_POINTER, pType, NULL, arena);
3275 }
3276 return pType;
3277 }
3278
3279 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3280 bool nameAllowed, bool nameRequired, Arena& arena) {
3281 // direct-dcl :
3282 // name
3283 // (dcl)
3284 // direct-dcl()
3285 // direct-dcl[]
3286 Type* pNewHead = NULL;
3287 if (accept('(')) {
3288 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3289 nameRequired, arena);
3290 skip(')');
3291 } else if ((declName = acceptSymbol()) != 0) {
3292 if (nameAllowed == false && declName) {
3293 error("Symbol %s not allowed here", nameof(declName));
3294 } else if (nameRequired && ! declName) {
3295 String temp;
3296 decodeToken(temp, tok);
3297 error("Expected symbol. Got %s", temp.getUnwrapped());
3298 }
3299 }
3300 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003301 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003302 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003303 pType = createType(TY_FUNC, pType, pTail, arena);
3304 skip(')');
3305 }
Jack Palevich3f226492009-07-02 14:46:19 -07003306
3307 if (pNewHead) {
3308 Type* pA = pNewHead;
3309 while (pA->pHead) {
3310 pA = pA->pHead;
3311 }
3312 pA->pHead = pType;
3313 pType = pNewHead;
3314 }
Jack Palevich86351982009-06-30 18:09:56 -07003315 return pType;
3316 }
3317
Jack Palevich3f226492009-07-02 14:46:19 -07003318 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003319 Type* pHead = NULL;
3320 Type* pTail = NULL;
3321 for(;;) {
3322 Type* pBaseArg = acceptPrimitiveType(arena);
3323 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003324 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3325 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003326 if (pArg) {
3327 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3328 if (!pHead) {
3329 pHead = pParam;
3330 pTail = pParam;
3331 } else {
3332 pTail->pTail = pParam;
3333 pTail = pParam;
3334 }
3335 }
3336 }
3337 if (! accept(',')) {
3338 break;
3339 }
3340 }
3341 return pHead;
3342 }
3343
3344 Type* expectPrimitiveType(Arena& arena) {
3345 Type* pType = acceptPrimitiveType(arena);
3346 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003347 String buf;
3348 decodeToken(buf, tok);
3349 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003350 }
Jack Palevich86351982009-06-30 18:09:56 -07003351 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003352 }
3353
Jack Palevich86351982009-06-30 18:09:56 -07003354 void addGlobalSymbol(Type* pDecl) {
3355 tokenid_t t = pDecl->id;
3356 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003357 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003358 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003359 }
Jack Palevich86351982009-06-30 18:09:56 -07003360 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003361 }
3362
Jack Palevich86351982009-06-30 18:09:56 -07003363 void reportDuplicate(tokenid_t t) {
3364 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003365 }
3366
Jack Palevich86351982009-06-30 18:09:56 -07003367 void addLocalSymbol(Type* pDecl) {
3368 tokenid_t t = pDecl->id;
3369 if (mLocals.isDefinedAtCurrentLevel(t)) {
3370 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003371 }
Jack Palevich86351982009-06-30 18:09:56 -07003372 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003373 }
3374
Jack Palevich95727a02009-07-06 12:07:15 -07003375 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003376 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003377
Jack Palevich95727a02009-07-06 12:07:15 -07003378 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003379 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003380 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3381 if (!pDecl) {
3382 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003383 }
Jack Palevich86351982009-06-30 18:09:56 -07003384 int variableAddress = 0;
3385 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003386 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003387 loc = loc + 4;
3388 variableAddress = -loc;
3389 VI(pDecl->id)->pAddress = (void*) variableAddress;
3390 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003391 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003392 expr();
3393 pGen->storeR0(variableAddress);
3394 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003395 if (tok == ',')
3396 next();
3397 }
3398 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003399 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003400 }
3401 }
3402
Jack Palevichf1728be2009-06-12 13:53:51 -07003403 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003404 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003405 }
3406
Jack Palevich569f1352009-06-29 14:29:08 -07003407 void decodeToken(String& buffer, tokenid_t token) {
3408 if (token == EOF ) {
3409 buffer.printf("EOF");
3410 } else if (token == TOK_NUM) {
3411 buffer.printf("numeric constant");
3412 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003413 if (token < 32) {
3414 buffer.printf("'\\x%02x'", token);
3415 } else {
3416 buffer.printf("'%c'", token);
3417 }
Jack Palevich569f1352009-06-29 14:29:08 -07003418 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3419 buffer.printf("keyword \"%s\"", nameof(token));
3420 } else {
3421 buffer.printf("symbol \"%s\"", nameof(token));
3422 }
3423 }
3424
Jack Palevich40600de2009-07-01 15:32:35 -07003425 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003426 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003427 if (!result) {
3428 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003429 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003430 error("Expected symbol. Got %s", temp.getUnwrapped());
3431 }
3432 return result;
3433 }
3434
Jack Palevich86351982009-06-30 18:09:56 -07003435 tokenid_t acceptSymbol() {
3436 tokenid_t result = 0;
3437 if (tok >= TOK_SYMBOL) {
3438 result = tok;
3439 next();
Jack Palevich86351982009-06-30 18:09:56 -07003440 }
3441 return result;
3442 }
3443
Jack Palevichb7c81e92009-06-04 19:56:13 -07003444 void globalDeclarations() {
3445 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003446 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3447 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003448 break;
3449 }
Jack Palevich86351982009-06-30 18:09:56 -07003450 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3451 if (!pDecl) {
3452 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003453 }
Jack Palevich86351982009-06-30 18:09:56 -07003454 if (! isDefined(pDecl->id)) {
3455 addGlobalSymbol(pDecl);
3456 }
3457 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003458 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003459 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003460 }
Jack Palevich86351982009-06-30 18:09:56 -07003461 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003462 // it's a variable declaration
3463 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003464 if (name && !name->pAddress) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003465 name->pAddress = (int*) allocGlobalSpace(4);
3466 }
Jack Palevich86351982009-06-30 18:09:56 -07003467 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003468 if (tok == TOK_NUM) {
3469 if (name) {
3470 * (int*) name->pAddress = tokc;
3471 }
3472 next();
3473 } else {
3474 error("Expected an integer constant");
3475 }
3476 }
Jack Palevich86351982009-06-30 18:09:56 -07003477 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003478 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003479 }
Jack Palevich86351982009-06-30 18:09:56 -07003480 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3481 if (!pDecl) {
3482 break;
3483 }
3484 if (! isDefined(pDecl->id)) {
3485 addGlobalSymbol(pDecl);
3486 }
3487 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003488 }
3489 skip(';');
3490 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003491 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003492 if (accept(';')) {
3493 // forward declaration.
3494 } else {
3495 if (name) {
3496 /* patch forward references (XXX: does not work for function
3497 pointers) */
3498 pGen->gsym((int) name->pForward);
3499 /* put function address */
3500 name->pAddress = (void*) codeBuf.getPC();
3501 }
3502 // Calculate stack offsets for parameters
3503 mLocals.pushLevel();
3504 intptr_t a = 8;
3505 int argCount = 0;
3506 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3507 Type* pArg = pP->pHead;
3508 addLocalSymbol(pArg);
3509 /* read param name and compute offset */
3510 VI(pArg->id)->pAddress = (void*) a;
3511 a = a + 4;
3512 argCount++;
3513 }
3514 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003515 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003516 a = pGen->functionEntry(argCount);
3517 block(0, true);
3518 pGen->gsym(rsym);
3519 pGen->functionExit(argCount, a, loc);
3520 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003521 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003522 }
3523 }
3524 }
3525
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003526 char* allocGlobalSpace(int bytes) {
3527 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
3528 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003529 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003530 }
3531 char* result = glo;
3532 glo += bytes;
3533 return result;
3534 }
3535
Jack Palevich21a15a22009-05-11 14:49:29 -07003536 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003537 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003538 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003539 pGlobalBase = 0;
3540 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003541 if (pGen) {
3542 delete pGen;
3543 pGen = 0;
3544 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003545 if (file) {
3546 delete file;
3547 file = 0;
3548 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003549 }
3550
3551 void clear() {
3552 tok = 0;
3553 tokc = 0;
3554 tokl = 0;
3555 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003556 rsym = 0;
3557 loc = 0;
3558 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003559 dptr = 0;
3560 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003561 file = 0;
3562 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003563 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003564 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003565 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003566
Jack Palevich22305132009-05-13 10:58:45 -07003567 void setArchitecture(const char* architecture) {
3568 delete pGen;
3569 pGen = 0;
3570
3571 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003572#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003573 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003574 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003575 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003576#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003577#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003578 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003579 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003580 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003581#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003582 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003583 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003584 }
3585 }
3586
3587 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003588#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003589 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003590#elif defined(DEFAULT_X86_CODEGEN)
3591 pGen = new X86CodeGenerator();
3592#endif
3593 }
3594 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003595 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003596 } else {
3597 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003598 }
3599 }
3600
Jack Palevich77ae76e2009-05-10 19:59:24 -07003601public:
Jack Palevich22305132009-05-13 10:58:45 -07003602 struct args {
3603 args() {
3604 architecture = 0;
3605 }
3606 const char* architecture;
3607 };
3608
Jack Paleviche7b59062009-05-19 17:12:17 -07003609 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003610 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003611 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003612
Jack Paleviche7b59062009-05-19 17:12:17 -07003613 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003614 cleanup();
3615 }
3616
Jack Palevich1cdef202009-05-22 12:06:27 -07003617 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003618 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003619
3620 cleanup();
3621 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003622 mTokenTable.setArena(&mGlobalArena);
3623 mGlobals.setArena(&mGlobalArena);
3624 mGlobals.setTokenTable(&mTokenTable);
3625 mLocals.setArena(&mLocalArena);
3626 mLocals.setTokenTable(&mTokenTable);
3627
3628 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003629 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003630 codeBuf.init(ALLOC_SIZE);
3631 setArchitecture(NULL);
3632 if (!pGen) {
3633 return -1;
3634 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003635#ifdef PROVIDE_TRACE_CODEGEN
3636 pGen = new TraceCodeGenerator(pGen);
3637#endif
3638 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003639 pGen->init(&codeBuf);
3640 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003641 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3642 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003643 inp();
3644 next();
3645 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003646 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003647 result = pGen->finishCompile();
3648 if (result == 0) {
3649 if (mErrorBuf.len()) {
3650 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003651 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003652 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003653 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003654 }
3655
Jack Palevich86351982009-06-30 18:09:56 -07003656 void createPrimitiveTypes() {
3657 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3658 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3659 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003660 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3661 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003662 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003663 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3664 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07003665 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
3666 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003667 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003668 }
3669
Jack Palevicha6baa232009-06-12 11:25:59 -07003670 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003671 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003672 }
3673
Jack Palevich569f1352009-06-29 14:29:08 -07003674 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003675 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003676 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003677 }
3678
Jack Palevich569f1352009-06-29 14:29:08 -07003679 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003680 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003681 error("Undefined forward reference: %s",
3682 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003683 }
3684 return true;
3685 }
3686
Jack Palevich21a15a22009-05-11 14:49:29 -07003687 int dump(FILE* out) {
3688 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3689 return 0;
3690 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003691
Jack Palevicha6535612009-05-13 16:24:17 -07003692 int disassemble(FILE* out) {
3693 return pGen->disassemble(out);
3694 }
3695
Jack Palevich1cdef202009-05-22 12:06:27 -07003696 /* Look through the symbol table to find a symbol.
3697 * If found, return its value.
3698 */
3699 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003700 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3701 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003702 if (pVariableInfo) {
3703 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003704 }
3705 return NULL;
3706 }
3707
Jack Palevicheedf9d22009-06-04 16:23:40 -07003708 void getPragmas(ACCsizei* actualStringCount,
3709 ACCsizei maxStringCount, ACCchar** strings) {
3710 int stringCount = mPragmaStringCount;
3711 if (actualStringCount) {
3712 *actualStringCount = stringCount;
3713 }
3714 if (stringCount > maxStringCount) {
3715 stringCount = maxStringCount;
3716 }
3717 if (strings) {
3718 char* pPragmas = mPragmas.getUnwrapped();
3719 while (stringCount-- > 0) {
3720 *strings++ = pPragmas;
3721 pPragmas += strlen(pPragmas) + 1;
3722 }
3723 }
3724 }
3725
Jack Palevichac0e95e2009-05-29 13:53:44 -07003726 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003727 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003728 }
3729
Jack Palevich77ae76e2009-05-10 19:59:24 -07003730};
3731
Jack Paleviche7b59062009-05-19 17:12:17 -07003732const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003733 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3734
Jack Paleviche7b59062009-05-19 17:12:17 -07003735const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003736 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3737 5, 5, /* ==, != */
3738 9, 10, /* &&, || */
3739 6, 7, 8, /* & ^ | */
3740 2, 2 /* ~ ! */
3741 };
3742
Jack Palevich8b0624c2009-05-20 12:12:06 -07003743#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003744FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003745#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003746
Jack Palevich8b0624c2009-05-20 12:12:06 -07003747#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003748const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003749 0x1, // ++
3750 0xff, // --
3751 0xc1af0f, // *
3752 0xf9f79991, // /
3753 0xf9f79991, // % (With manual assist to swap results)
3754 0xc801, // +
3755 0xd8f7c829, // -
3756 0xe0d391, // <<
3757 0xf8d391, // >>
3758 0xe, // <=
3759 0xd, // >=
3760 0xc, // <
3761 0xf, // >
3762 0x4, // ==
3763 0x5, // !=
3764 0x0, // &&
3765 0x1, // ||
3766 0xc821, // &
3767 0xc831, // ^
3768 0xc809, // |
3769 0xd0f7, // ~
3770 0x4 // !
3771};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003772#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003773
Jack Palevich1cdef202009-05-22 12:06:27 -07003774struct ACCscript {
3775 ACCscript() {
3776 text = 0;
3777 textLength = 0;
3778 accError = ACC_NO_ERROR;
3779 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003780
Jack Palevich1cdef202009-05-22 12:06:27 -07003781 ~ACCscript() {
3782 delete text;
3783 }
Jack Palevich546b2242009-05-13 15:10:04 -07003784
Jack Palevich1cdef202009-05-22 12:06:27 -07003785 void setError(ACCenum error) {
3786 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3787 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003788 }
3789 }
3790
Jack Palevich1cdef202009-05-22 12:06:27 -07003791 ACCenum getError() {
3792 ACCenum result = accError;
3793 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003794 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003795 }
3796
Jack Palevich1cdef202009-05-22 12:06:27 -07003797 Compiler compiler;
3798 char* text;
3799 int textLength;
3800 ACCenum accError;
3801};
3802
3803
3804extern "C"
3805ACCscript* accCreateScript() {
3806 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003807}
Jack Palevich1cdef202009-05-22 12:06:27 -07003808
3809extern "C"
3810ACCenum accGetError( ACCscript* script ) {
3811 return script->getError();
3812}
3813
3814extern "C"
3815void accDeleteScript(ACCscript* script) {
3816 delete script;
3817}
3818
3819extern "C"
3820void accScriptSource(ACCscript* script,
3821 ACCsizei count,
3822 const ACCchar ** string,
3823 const ACCint * length) {
3824 int totalLength = 0;
3825 for(int i = 0; i < count; i++) {
3826 int len = -1;
3827 const ACCchar* s = string[i];
3828 if (length) {
3829 len = length[i];
3830 }
3831 if (len < 0) {
3832 len = strlen(s);
3833 }
3834 totalLength += len;
3835 }
3836 delete script->text;
3837 char* text = new char[totalLength + 1];
3838 script->text = text;
3839 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003840 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003841 for(int i = 0; i < count; i++) {
3842 int len = -1;
3843 const ACCchar* s = string[i];
3844 if (length) {
3845 len = length[i];
3846 }
3847 if (len < 0) {
3848 len = strlen(s);
3849 }
Jack Palevich09555c72009-05-27 12:25:55 -07003850 memcpy(dest, s, len);
3851 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003852 }
3853 text[totalLength] = '\0';
3854}
3855
3856extern "C"
3857void accCompileScript(ACCscript* script) {
3858 int result = script->compiler.compile(script->text, script->textLength);
3859 if (result) {
3860 script->setError(ACC_INVALID_OPERATION);
3861 }
3862}
3863
3864extern "C"
3865void accGetScriptiv(ACCscript* script,
3866 ACCenum pname,
3867 ACCint * params) {
3868 switch (pname) {
3869 case ACC_INFO_LOG_LENGTH:
3870 *params = 0;
3871 break;
3872 }
3873}
3874
3875extern "C"
3876void accGetScriptInfoLog(ACCscript* script,
3877 ACCsizei maxLength,
3878 ACCsizei * length,
3879 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003880 char* message = script->compiler.getErrorMessage();
3881 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003882 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003883 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003884 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003885 if (infoLog && maxLength > 0) {
3886 int trimmedLength = maxLength < messageLength ?
3887 maxLength : messageLength;
3888 memcpy(infoLog, message, trimmedLength);
3889 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003890 }
3891}
3892
3893extern "C"
3894void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3895 ACCvoid ** address) {
3896 void* value = script->compiler.lookup(name);
3897 if (value) {
3898 *address = value;
3899 } else {
3900 script->setError(ACC_INVALID_VALUE);
3901 }
3902}
3903
Jack Palevicheedf9d22009-06-04 16:23:40 -07003904extern "C"
3905void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3906 ACCsizei maxStringCount, ACCchar** strings){
3907 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3908}
3909
-b master422972c2009-06-17 19:13:52 -07003910extern "C"
3911void accDisassemble(ACCscript* script) {
3912 script->compiler.disassemble(stderr);
3913}
3914
Jack Palevicheedf9d22009-06-04 16:23:40 -07003915
Jack Palevich1cdef202009-05-22 12:06:27 -07003916} // namespace acc
3917