blob: e4e5baa84a3f78d5b363b9903255c13430dd30d6 [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 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700363 virtual void storeR0(int ea, Type* pType) = 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 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700452 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700453 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700454 virtual size_t alignment(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700455
456 /**
457 * Array element alignment (in bytes) for this type of data.
458 */
459 virtual size_t sizeOf(Type* type) = 0;
460
Jack Palevich9cbd2262009-07-08 16:48:41 -0700461 /**
462 * Stack argument size of this data type.
463 */
464 virtual size_t stackSizeOf(Type* pType) = 0;
465
Jack Palevich1a539db2009-07-08 13:04:41 -0700466 virtual Type* getR0Type() {
467 return mExpressionStack.back();
468 }
469
Jack Palevich21a15a22009-05-11 14:49:29 -0700470 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700471 /*
472 * Output a byte. Handles all values, 0..ff.
473 */
474 void ob(int n) {
475 pCodeBuf->ob(n);
476 }
477
Jack Palevich8b0624c2009-05-20 12:12:06 -0700478 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700479 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700480 }
481
Jack Palevich8b0624c2009-05-20 12:12:06 -0700482 intptr_t getBase() {
483 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700484 }
485
Jack Palevich8b0624c2009-05-20 12:12:06 -0700486 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700487 return pCodeBuf->getPC();
488 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700489
490 intptr_t getSize() {
491 return pCodeBuf->getSize();
492 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700493
494 void error(const char* fmt,...) {
495 va_list ap;
496 va_start(ap, fmt);
497 mErrorSink->verror(fmt, ap);
498 va_end(ap);
499 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700500
501 void assert(bool test) {
502 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700503 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700504 error("code generator assertion failed.");
505 }
506 }
Jack Palevich8df46192009-07-07 14:48:51 -0700507
508 void setR0Type(Type* pType) {
509 mExpressionStack.back() = pType;
510 }
511
Jack Palevich8df46192009-07-07 14:48:51 -0700512 Type* getTOSType() {
513 return mExpressionStack[mExpressionStack.size()-2];
514 }
515
516 void pushType() {
517 mExpressionStack.push_back(NULL);
518 }
519
520 void popType() {
521 mExpressionStack.pop_back();
522 }
523
524 bool bitsSame(Type* pA, Type* pB) {
525 return collapseType(pA->tag) == collapseType(pB->tag);
526 }
527
528 TypeTag collapseType(TypeTag tag) {
529 static const TypeTag collapsedTag[] = {
530 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
531 TY_VOID, TY_VOID};
532 return collapsedTag[tag];
533 }
534
Jack Palevich1a539db2009-07-08 13:04:41 -0700535 TypeTag collapseTypeR0() {
536 return collapseType(getR0Type()->tag);
537 }
538
539 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700540 return isFloatTag(pType->tag);
541 }
542
543 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700544 return tag == TY_FLOAT || tag == TY_DOUBLE;
545 }
546
Jack Palevich21a15a22009-05-11 14:49:29 -0700547 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700548 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700549 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700550 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700551 };
552
Jack Paleviche7b59062009-05-19 17:12:17 -0700553#ifdef PROVIDE_ARM_CODEGEN
554
Jack Palevich22305132009-05-13 10:58:45 -0700555 class ARMCodeGenerator : public CodeGenerator {
556 public:
557 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700558
Jack Palevich22305132009-05-13 10:58:45 -0700559 virtual ~ARMCodeGenerator() {}
560
561 /* returns address to patch with local variable size
562 */
Jack Palevich546b2242009-05-13 15:10:04 -0700563 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700564 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700565 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700566 // sp -> arg4 arg5 ...
567 // Push our register-based arguments back on the stack
568 if (argCount > 0) {
569 int regArgCount = argCount <= 4 ? argCount : 4;
570 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700571 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700572 }
573 // sp -> arg0 arg1 ...
574 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700575 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700576 // sp, fp -> oldfp, retadr, arg0 arg1 ....
577 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700578 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700579 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700580 // We don't know how many local variables we are going to use,
581 // but we will round the allocation up to a multiple of
582 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700583 }
584
Jack Palevich546b2242009-05-13 15:10:04 -0700585 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700586 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700587 // Round local variable size up to a multiple of stack alignment
588 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
589 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700590 // Patch local variable allocation code:
591 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700592 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700593 }
Jack Palevich69796b62009-05-14 15:42:26 -0700594 *(char*) (localVariableAddress) = localVariableSize;
595
596 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
597 o4(0xE1A0E00B); // mov lr, fp
598 o4(0xE59BB000); // ldr fp, [fp]
599 o4(0xE28ED004); // add sp, lr, #4
600 // sp -> retadr, arg0, ...
601 o4(0xE8BD4000); // ldmfd sp!, {lr}
602 // sp -> arg0 ....
603 if (argCount > 0) {
604 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700605 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700606 // earlier. We don't need to actually store them anywhere,
607 // just adjust the stack.
608 int regArgCount = argCount <= 4 ? argCount : 4;
609 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
610 }
611 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700612 }
613
614 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700615 virtual void li(int t, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700616 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700617 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700618 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700619 } else if (t >= -256 && t < 0) {
620 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700621 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700622 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700623 o4(0xE51F0000); // ldr r0, .L3
624 o4(0xEA000000); // b .L99
625 o4(t); // .L3: .word 0
626 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700627 }
Jack Palevich8df46192009-07-07 14:48:51 -0700628 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700629 }
630
Jack Palevich1a539db2009-07-08 13:04:41 -0700631 virtual void loadFloat(int address, Type* pType) {
632 error("Unimplemented.\n");
Jack Palevich8df46192009-07-07 14:48:51 -0700633 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700634 }
635
Jack Palevich22305132009-05-13 10:58:45 -0700636 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700637 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700638 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700639 }
640
641 /* l = 0: je, l == 1: jne */
642 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700643 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700644 o4(0xE3500000); // cmp r0,#0
645 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
646 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700647 }
648
649 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700650 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700651 o4(0xE8BD0002); // ldmfd sp!,{r1}
652 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700653 o4(0xE1510000); // cmp r1, r1
654 switch(op) {
655 case OP_EQUALS:
656 o4(0x03A00001); // moveq r0,#1
657 o4(0x13A00000); // movne r0,#0
658 break;
659 case OP_NOT_EQUALS:
660 o4(0x03A00000); // moveq r0,#0
661 o4(0x13A00001); // movne r0,#1
662 break;
663 case OP_LESS_EQUAL:
664 o4(0xD3A00001); // movle r0,#1
665 o4(0xC3A00000); // movgt r0,#0
666 break;
667 case OP_GREATER:
668 o4(0xD3A00000); // movle r0,#0
669 o4(0xC3A00001); // movgt r0,#1
670 break;
671 case OP_GREATER_EQUAL:
672 o4(0xA3A00001); // movge r0,#1
673 o4(0xB3A00000); // movlt r0,#0
674 break;
675 case OP_LESS:
676 o4(0xA3A00000); // movge r0,#0
677 o4(0xB3A00001); // movlt r0,#1
678 break;
679 default:
680 error("Unknown comparison op %d", op);
681 break;
682 }
Jack Palevich8df46192009-07-07 14:48:51 -0700683 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700684 }
685
Jack Palevich546b2242009-05-13 15:10:04 -0700686 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700687 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700688 o4(0xE8BD0002); // ldmfd sp!,{r1}
689 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700690 switch(op) {
691 case OP_MUL:
692 o4(0x0E0000091); // mul r0,r1,r0
693 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700694 case OP_DIV:
695 callRuntime(runtime_DIV);
696 break;
697 case OP_MOD:
698 callRuntime(runtime_MOD);
699 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700700 case OP_PLUS:
701 o4(0xE0810000); // add r0,r1,r0
702 break;
703 case OP_MINUS:
704 o4(0xE0410000); // sub r0,r1,r0
705 break;
706 case OP_SHIFT_LEFT:
707 o4(0xE1A00011); // lsl r0,r1,r0
708 break;
709 case OP_SHIFT_RIGHT:
710 o4(0xE1A00051); // asr r0,r1,r0
711 break;
712 case OP_BIT_AND:
713 o4(0xE0010000); // and r0,r1,r0
714 break;
715 case OP_BIT_XOR:
716 o4(0xE0210000); // eor r0,r1,r0
717 break;
718 case OP_BIT_OR:
719 o4(0xE1810000); // orr r0,r1,r0
720 break;
721 case OP_BIT_NOT:
722 o4(0xE1E00000); // mvn r0, r0
723 break;
724 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700725 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700726 break;
727 }
Jack Palevich8df46192009-07-07 14:48:51 -0700728 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700729 }
730
Jack Palevich9eed7a22009-07-06 17:24:34 -0700731 virtual void gUnaryCmp(int op) {
732 LOG_API("gcmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700733 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700734 o4(0xE1510000); // cmp r1, r1
735 switch(op) {
736 case OP_NOT_EQUALS:
737 o4(0x03A00000); // moveq r0,#0
738 o4(0x13A00001); // movne r0,#1
739 break;
740 default:
741 error("Unknown unary comparison op %d", op);
742 break;
743 }
744 }
745
746 virtual void genUnaryOp(int op) {
747 LOG_API("genOp(%d);\n", op);
748 switch(op) {
749 case OP_PLUS:
750 // Do nothing
751 break;
752 case OP_MINUS:
753 o4(0xE3A01000); // mov r1, #0
754 o4(0xE0410000); // sub r0,r1,r0
755 break;
756 case OP_BIT_NOT:
757 o4(0xE1E00000); // mvn r0, r0
758 break;
759 default:
760 error("Unknown unary op %d\n", op);
761 break;
762 }
Jack Palevich22305132009-05-13 10:58:45 -0700763 }
764
Jack Palevich1cdef202009-05-22 12:06:27 -0700765 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700766 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700767 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700768 mStackUse += 4;
Jack Palevich8df46192009-07-07 14:48:51 -0700769 pushType();
-b master422972c2009-06-17 19:13:52 -0700770 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700771 }
772
Jack Palevich9eed7a22009-07-06 17:24:34 -0700773 virtual void storeR0ToTOS(Type* pPointerType) {
774 LOG_API("storeR0ToTOS(%d);\n", isInt);
775 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700776 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700777 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700778 switch (pPointerType->pHead->tag) {
779 case TY_INT:
780 o4(0xE5810000); // str r0, [r1]
781 break;
782 case TY_CHAR:
783 o4(0xE5C10000); // strb r0, [r1]
784 break;
785 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700786 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700787 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700788 }
Jack Palevich8df46192009-07-07 14:48:51 -0700789 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700790 }
791
Jack Palevich9eed7a22009-07-06 17:24:34 -0700792 virtual void loadR0FromR0(Type* pPointerType) {
793 LOG_API("loadR0FromR0(%d);\n", pPointerType);
794 assert(pPointerType->tag == TY_POINTER);
795 switch (pPointerType->pHead->tag) {
796 case TY_INT:
797 o4(0xE5900000); // ldr r0, [r0]
798 break;
799 case TY_CHAR:
800 o4(0xE5D00000); // ldrb r0, [r0]
801 break;
802 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700803 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700804 break;
805 }
Jack Palevich8df46192009-07-07 14:48:51 -0700806 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -0700807 }
808
Jack Palevich8df46192009-07-07 14:48:51 -0700809 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700810 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700811 if (ea < LOCAL) {
812 // Local, fp relative
813 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
814 error("Offset out of range: %08x", ea);
815 }
816 if (ea < 0) {
817 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
818 } else {
819 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
820 }
Jack Palevichbd894902009-05-14 19:35:31 -0700821 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700822 // Global, absolute.
823 o4(0xE59F0000); // ldr r0, .L1
824 o4(0xEA000000); // b .L99
825 o4(ea); // .L1: .word 0
826 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700827 }
Jack Palevich8df46192009-07-07 14:48:51 -0700828 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -0700829 }
830
Jack Palevich9cbd2262009-07-08 16:48:41 -0700831 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700832 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700833 if (ea < LOCAL) {
834 // Local, fp relative
835 if (ea < -4095 || ea > 4095) {
836 error("Offset out of range: %08x", ea);
837 }
838 if (ea < 0) {
839 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
840 } else {
841 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
842 }
843 } else{
844 // Global, absolute
845 o4(0xE59F1000); // ldr r1, .L1
846 o4(0xEA000000); // b .L99
847 o4(ea); // .L1: .word 0
848 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700849 }
Jack Palevich22305132009-05-13 10:58:45 -0700850 }
851
Jack Palevich8df46192009-07-07 14:48:51 -0700852 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700853 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich4d93f302009-05-15 13:30:00 -0700854 if (ea < LOCAL) {
855 // Local, fp relative
856 if (ea < -4095 || ea > 4095) {
857 error("Offset out of range: %08x", ea);
858 }
859 if (ea < 0) {
860 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
861 } else {
862 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
863 }
Jack Palevich69796b62009-05-14 15:42:26 -0700864 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700865 // Global, absolute
866 o4(0xE59F2000); // ldr r2, .L1
867 o4(0xEA000000); // b .L99
868 o4(ea); // .L1: .word ea
869 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700870 }
Jack Palevich22305132009-05-13 10:58:45 -0700871
Jack Palevich4d93f302009-05-15 13:30:00 -0700872 if (isIncDec) {
873 switch (op) {
874 case OP_INCREMENT:
875 o4(0xE2801001); // add r1, r0, #1
876 break;
877 case OP_DECREMENT:
878 o4(0xE2401001); // sub r1, r0, #1
879 break;
880 default:
881 error("unknown opcode: %d", op);
882 }
883 if (ea < LOCAL) {
884 // Local, fp relative
885 // Don't need range check, was already checked above
886 if (ea < 0) {
887 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
888 } else {
889 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
890 }
891 } else{
892 // Global, absolute
893 // r2 is already set up from before.
894 o4(0xE5821000); // str r1, [r2]
895 }
Jack Palevichbd894902009-05-14 19:35:31 -0700896 }
Jack Palevich8df46192009-07-07 14:48:51 -0700897 setR0Type(pType);
898 }
899
900 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -0700901 Type* pR0Type = getR0Type();
902 if (bitsSame(pType, pR0Type)) {
903 // do nothing special
904 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
905 // do nothing special, both held in same register on x87.
906 } else {
907 error("Incompatible types old: %d new: %d",
908 pR0Type->tag, pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -0700909 }
Jack Palevich1a539db2009-07-08 13:04:41 -0700910 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700911 }
912
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700913 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700914 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700915 return o4(0xE24DDF00); // Placeholder
916 }
917
Jack Palevich1a539db2009-07-08 13:04:41 -0700918 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700919 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700920 if (l < 0 || l > 4096-4) {
921 error("l out of range for stack offset: 0x%08x", l);
922 }
923 o4(0xE58D0000 + l); // str r0, [sp, #4]
Jack Palevich1a539db2009-07-08 13:04:41 -0700924 return 4;
Jack Palevich7810bc92009-05-15 14:31:47 -0700925 }
926
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700927 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700928 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700929 int argCount = l >> 2;
930 int argumentStackUse = l;
931 if (argCount > 0) {
932 int regArgCount = argCount > 4 ? 4 : argCount;
933 argumentStackUse -= regArgCount * 4;
934 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
935 }
936 mStackUse += argumentStackUse;
937
938 // Align stack.
939 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
940 * STACK_ALIGNMENT);
941 mStackAlignmentAdjustment = 0;
942 if (missalignment > 0) {
943 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
944 }
945 l += mStackAlignmentAdjustment;
946
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700947 if (l < 0 || l > 0x3FC) {
948 error("L out of range for stack adjustment: 0x%08x", l);
949 }
950 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700951 mStackUse += mStackAlignmentAdjustment;
952 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
953 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700954 }
955
Jack Palevich8df46192009-07-07 14:48:51 -0700956 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700957 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -0700958 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700959 // Forward calls are always short (local)
960 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700961 }
962
Jack Palevich8df46192009-07-07 14:48:51 -0700963 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700964 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -0700965 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700966 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700967 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700968 if (t >= - (1 << 25) && t < (1 << 25)) {
969 o4(0xEB000000 | encodeAddress(t));
970 } else {
971 // Long call.
972 o4(0xE59FC000); // ldr r12, .L1
973 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700974 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700975 o4(0xE08CC00F); // .L99: add r12,pc
976 o4(0xE12FFF3C); // blx r12
977 }
Jack Palevich22305132009-05-13 10:58:45 -0700978 }
979
Jack Palevich8df46192009-07-07 14:48:51 -0700980 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700981 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -0700982 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -0700983 int argCount = l >> 2;
984 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700985 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700986 if (adjustedL < 0 || adjustedL > 4096-4) {
987 error("l out of range for stack offset: 0x%08x", l);
988 }
989 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
990 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700991 }
992
Jack Palevich7810bc92009-05-15 14:31:47 -0700993 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700994 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700995 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700996 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700997 int stackUse = stackArgs + (isIndirect ? 1 : 0)
998 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700999 if (stackUse) {
1000 if (stackUse < 0 || stackUse > 255) {
1001 error("L out of range for stack adjustment: 0x%08x", l);
1002 }
1003 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001004 mStackUse -= stackUse * 4;
1005 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001006 }
Jack Palevich22305132009-05-13 10:58:45 -07001007 }
1008
Jack Palevicha6535612009-05-13 16:24:17 -07001009 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001010 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001011 }
1012
1013 /* output a symbol and patch all calls to it */
1014 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001015 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001016 int n;
1017 int base = getBase();
1018 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001019 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001020 while (t) {
1021 int data = * (int*) t;
1022 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1023 if (decodedOffset == 0) {
1024 n = 0;
1025 } else {
1026 n = base + decodedOffset; /* next value */
1027 }
1028 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1029 | encodeRelAddress(pc - t - 8);
1030 t = n;
1031 }
1032 }
1033
Jack Palevich1cdef202009-05-22 12:06:27 -07001034 virtual int finishCompile() {
1035#if defined(__arm__)
1036 const long base = long(getBase());
1037 const long curr = long(getPC());
1038 int err = cacheflush(base, curr, 0);
1039 return err;
1040#else
1041 return 0;
1042#endif
1043 }
1044
Jack Palevicha6535612009-05-13 16:24:17 -07001045 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001046#ifdef ENABLE_ARM_DISASSEMBLY
1047 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001048 disasm_interface_t di;
1049 di.di_readword = disassemble_readword;
1050 di.di_printaddr = disassemble_printaddr;
1051 di.di_printf = disassemble_printf;
1052
1053 int base = getBase();
1054 int pc = getPC();
1055 for(int i = base; i < pc; i += 4) {
1056 fprintf(out, "%08x: %08x ", i, *(int*) i);
1057 ::disasm(&di, i, 0);
1058 }
Jack Palevich09555c72009-05-27 12:25:55 -07001059#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001060 return 0;
1061 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001062
Jack Palevich9eed7a22009-07-06 17:24:34 -07001063 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001064 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001065 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001066 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001067 switch(pType->tag) {
1068 case TY_DOUBLE:
1069 return 8;
1070 default:
1071 return 4;
1072 }
1073 }
1074
1075 /**
1076 * Array element alignment (in bytes) for this type of data.
1077 */
1078 virtual size_t sizeOf(Type* pType){
1079 switch(pType->tag) {
1080 case TY_INT:
1081 return 4;
1082 case TY_CHAR:
1083 return 1;
1084 default:
1085 return 0;
1086 case TY_FLOAT:
1087 return 4;
1088 case TY_DOUBLE:
1089 return 8;
1090 case TY_POINTER:
1091 return 4;
1092 }
1093 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001094
1095 virtual size_t stackSizeOf(Type* pType) {
1096 switch(pType->tag) {
1097 case TY_DOUBLE:
1098 return 8;
1099 default:
1100 return 4;
1101 }
1102 }
1103
Jack Palevich22305132009-05-13 10:58:45 -07001104 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001105 static FILE* disasmOut;
1106
1107 static u_int
1108 disassemble_readword(u_int address)
1109 {
1110 return(*((u_int *)address));
1111 }
1112
1113 static void
1114 disassemble_printaddr(u_int address)
1115 {
1116 fprintf(disasmOut, "0x%08x", address);
1117 }
1118
1119 static void
1120 disassemble_printf(const char *fmt, ...) {
1121 va_list ap;
1122 va_start(ap, fmt);
1123 vfprintf(disasmOut, fmt, ap);
1124 va_end(ap);
1125 }
1126
1127 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1128
1129 /** Encode a relative address that might also be
1130 * a label.
1131 */
1132 int encodeAddress(int value) {
1133 int base = getBase();
1134 if (value >= base && value <= getPC() ) {
1135 // This is a label, encode it relative to the base.
1136 value = value - base;
1137 }
1138 return encodeRelAddress(value);
1139 }
1140
1141 int encodeRelAddress(int value) {
1142 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1143 }
Jack Palevich22305132009-05-13 10:58:45 -07001144
Jack Palevich3d474a72009-05-15 15:12:38 -07001145 typedef int (*int2FnPtr)(int a, int b);
1146 void callRuntime(int2FnPtr fn) {
1147 o4(0xE59F2000); // ldr r2, .L1
1148 o4(0xEA000000); // b .L99
1149 o4((int) fn); //.L1: .word fn
1150 o4(0xE12FFF32); //.L99: blx r2
1151 }
1152
1153 static int runtime_DIV(int a, int b) {
1154 return b / a;
1155 }
1156
1157 static int runtime_MOD(int a, int b) {
1158 return b % a;
1159 }
-b master422972c2009-06-17 19:13:52 -07001160
1161 static const int STACK_ALIGNMENT = 8;
1162 int mStackUse;
1163 // This variable holds the amount we adjusted the stack in the most
1164 // recent endFunctionCallArguments call. It's examined by the
1165 // following adjustStackAfterCall call.
1166 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001167 };
1168
Jack Palevich09555c72009-05-27 12:25:55 -07001169#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001170
1171#ifdef PROVIDE_X86_CODEGEN
1172
Jack Palevich21a15a22009-05-11 14:49:29 -07001173 class X86CodeGenerator : public CodeGenerator {
1174 public:
1175 X86CodeGenerator() {}
1176 virtual ~X86CodeGenerator() {}
1177
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001178 /* returns address to patch with local variable size
1179 */
Jack Palevich546b2242009-05-13 15:10:04 -07001180 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001181 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1182 return oad(0xec81, 0); /* sub $xxx, %esp */
1183 }
1184
Jack Palevich546b2242009-05-13 15:10:04 -07001185 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001186 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001187 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001188 }
1189
Jack Palevich21a15a22009-05-11 14:49:29 -07001190 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001191 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001192 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001193 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001194 }
1195
Jack Palevich1a539db2009-07-08 13:04:41 -07001196 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001197 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001198 switch (pType->tag) {
1199 case TY_FLOAT:
1200 oad(0x05D9, address); // flds
1201 break;
1202 case TY_DOUBLE:
1203 oad(0x05DD, address); // fldl
1204 break;
1205 default:
1206 assert(false);
1207 break;
1208 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001209 }
1210
Jack Palevich22305132009-05-13 10:58:45 -07001211 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001212 return psym(0xe9, t);
1213 }
1214
1215 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001216 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001217 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1218 return psym(0x84 + l, t);
1219 }
1220
Jack Palevich22305132009-05-13 10:58:45 -07001221 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001222 int t = decodeOp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001223 o(0x59); /* pop %ecx */
Jack Palevich21a15a22009-05-11 14:49:29 -07001224 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001225 li(0, NULL);
Jack Palevich21a15a22009-05-11 14:49:29 -07001226 o(0x0f); /* setxx %al */
1227 o(t + 0x90);
1228 o(0xc0);
Jack Palevich8df46192009-07-07 14:48:51 -07001229 popType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001230 }
1231
Jack Palevich546b2242009-05-13 15:10:04 -07001232 virtual void genOp(int op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001233 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001234 o(decodeOp(op));
1235 if (op == OP_MOD)
1236 o(0x92); /* xchg %edx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001237 popType();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001238 }
1239
Jack Palevich9eed7a22009-07-06 17:24:34 -07001240 virtual void gUnaryCmp(int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001241 oad(0xb9, 0); /* movl $0, %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001242 int t = decodeOp(op);
1243 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001244 li(0, NULL);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001245 o(0x0f); /* setxx %al */
1246 o(t + 0x90);
1247 o(0xc0);
1248 }
1249
1250 virtual void genUnaryOp(int op) {
1251 oad(0xb9, 0); /* movl $0, %ecx */
1252 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -07001253 }
1254
Jack Palevich1cdef202009-05-22 12:06:27 -07001255 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001256 Type* pR0Type = getR0Type();
1257 TypeTag r0ct = collapseType(pR0Type->tag);
1258 switch(r0ct) {
1259 case TY_INT:
1260 o(0x50); /* push %eax */
1261 break;
1262 case TY_FLOAT:
1263 o(0x50); /* push %eax */
1264 o(0x241cd9); // fstps 0(%esp)
1265 break;
1266 case TY_DOUBLE:
1267 o(0x50); /* push %eax */
1268 o(0x50); /* push %eax */
1269 o(0x241cdd); // fstpl 0(%esp)
1270 break;
1271 default:
1272 error("pushR0 %d", r0ct);
1273 break;
1274 }
Jack Palevich8df46192009-07-07 14:48:51 -07001275 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001276 }
1277
Jack Palevich9eed7a22009-07-06 17:24:34 -07001278 virtual void storeR0ToTOS(Type* pPointerType) {
1279 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001280 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001281 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001282 switch (pPointerType->pHead->tag) {
1283 case TY_INT:
1284 o(0x0189); /* movl %eax/%al, (%ecx) */
1285 break;
1286 case TY_CHAR:
1287 o(0x0188); /* movl %eax/%al, (%ecx) */
1288 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001289 case TY_FLOAT:
1290 o(0x19d9); /* fstps (%ecx) */
1291 break;
1292 case TY_DOUBLE:
1293 o(0x19dd); /* fstpl (%ecx) */
1294 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001295 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001296 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001297 break;
1298 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001299 }
1300
Jack Palevich9eed7a22009-07-06 17:24:34 -07001301 virtual void loadR0FromR0(Type* pPointerType) {
1302 assert(pPointerType->tag == TY_POINTER);
1303 switch (pPointerType->pHead->tag) {
1304 case TY_INT:
1305 o(0x8b); /* mov (%eax), %eax */
1306 break;
1307 case TY_CHAR:
1308 o(0xbe0f); /* movsbl (%eax), %eax */
1309 break;
1310 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001311 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001312 break;
1313 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001314 ob(0); /* add zero in code */
Jack Palevich8df46192009-07-07 14:48:51 -07001315 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001316 }
1317
Jack Palevich8df46192009-07-07 14:48:51 -07001318 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001319 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001320 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001321 }
1322
Jack Palevich9cbd2262009-07-08 16:48:41 -07001323 virtual void storeR0(int ea, Type* pType) {
1324 TypeTag tag = pType->tag;
1325 switch (tag) {
1326 case TY_INT:
1327 gmov(6, ea); /* mov %eax, EA */
1328 break;
1329 case TY_FLOAT:
1330 if (ea < -LOCAL || ea > LOCAL) {
1331 oad(0x1dd9, ea); // fstps ea
1332 } else {
1333 oad(0x9dd9, ea); // fstps ea(%ebp)
1334 }
1335 break;
1336 case TY_DOUBLE:
1337 if (ea < -LOCAL || ea > LOCAL) {
1338 oad(0x1ddd, ea); // fstpl ea
1339 } else {
1340 oad(0x9ddd, ea); // fstpl ea(%ebp)
1341 }
1342 break;
1343 default:
1344 error("Unable to store to type %d", tag);
1345 break;
1346 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001347 }
1348
Jack Palevich8df46192009-07-07 14:48:51 -07001349 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001350 TypeTag tag = collapseType(pType->tag);
1351 switch (tag) {
1352 case TY_INT:
1353 gmov(8, ea); /* mov EA, %eax */
1354 if (isIncDec) {
1355 /* Implement post-increment or post decrement.
1356 */
1357 gmov(0, ea); /* 83 ADD */
1358 o(decodeOp(op));
1359 }
1360 break;
1361 case TY_FLOAT:
1362 if (ea < -LOCAL || ea > LOCAL) {
1363 oad(0x05d9, ea); // flds ea
1364 } else {
1365 oad(0x85d9, ea); // flds ea(%ebp)
1366 }
1367 if (isIncDec) {
1368 error("inc/dec not implemented for float.");
1369 }
1370 break;
1371 case TY_DOUBLE:
1372 if (ea < -LOCAL || ea > LOCAL) {
1373 oad(0x05dd, ea); // fldl ea
1374 } else {
1375 oad(0x85dd, ea); // fldl ea(%ebp)
1376 }
1377 if (isIncDec) {
1378 error("inc/dec not implemented for double.");
1379 }
1380 break;
1381 default:
1382 error("Unable to load type %d", tag);
1383 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07001384 }
Jack Palevich8df46192009-07-07 14:48:51 -07001385 setR0Type(pType);
1386 }
1387
1388 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001389 Type* pR0Type = getR0Type();
1390 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001391 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07001392 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07001393 return;
1394 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001395 if (bitsSame(pType, pR0Type)) {
1396 // do nothing special
1397 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
1398 // do nothing special, both held in same register on x87.
1399 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001400 TypeTag r0Tag = collapseType(pR0Type->tag);
1401 TypeTag destTag = collapseType(pType->tag);
1402 if (r0Tag == TY_INT && isFloatTag(destTag)) {
1403 // Convert R0 from int to float
1404 o(0x50); // push %eax
1405 o(0x2404DB); // fildl 0(%esp)
1406 o(0x58); // pop %eax
1407 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
1408 // Convert R0 from float to int. Complicated because
1409 // need to save and restore the rounding mode.
1410 o(0x50); // push %eax
1411 o(0x50); // push %eax
1412 o(0x02247cD9); // fnstcw 2(%esp)
1413 o(0x2444b70f); // movzwl 2(%esp), %eax
1414 o(0x02);
1415 o(0x0cb4); // movb $12, %ah
1416 o(0x24048966); // movw %ax, 0(%esp)
1417 o(0x242cd9); // fldcw 0(%esp)
1418 o(0x04245cdb); // fistpl 4(%esp)
1419 o(0x02246cd9); // fldcw 2(%esp)
1420 o(0x58); // pop %eax
1421 o(0x58); // pop %eax
1422 } else {
1423 error("Incompatible types old: %d new: %d",
1424 pR0Type->tag, pType->tag);
1425 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001426 }
1427 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001428 }
1429
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001430 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001431 return oad(0xec81, 0); /* sub $xxx, %esp */
1432 }
1433
Jack Palevich1a539db2009-07-08 13:04:41 -07001434 virtual size_t storeR0ToArg(int l) {
1435 Type* pR0Type = getR0Type();
1436 TypeTag r0ct = collapseType(pR0Type->tag);
1437 switch(r0ct) {
1438 case TY_INT:
1439 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1440 return 4;
1441 case TY_FLOAT:
1442 oad(0x249CD9, l); /* fstps xxx(%esp) */
1443 return 4;
1444 case TY_DOUBLE:
1445 oad(0x249CDD, l); /* fstpl xxx(%esp) */
1446 return 8;
1447 default:
1448 assert(false);
1449 return 0;
1450 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001451 }
1452
Jack Palevich7810bc92009-05-15 14:31:47 -07001453 virtual void endFunctionCallArguments(int a, int l) {
1454 * (int*) a = l;
1455 }
1456
Jack Palevich8df46192009-07-07 14:48:51 -07001457 virtual int callForward(int symbol, Type* pFunc) {
1458 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001459 return psym(0xe8, symbol); /* call xxx */
1460 }
1461
Jack Palevich8df46192009-07-07 14:48:51 -07001462 virtual void callRelative(int t, Type* pFunc) {
1463 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001464 psym(0xe8, t); /* call xxx */
1465 }
1466
Jack Palevich8df46192009-07-07 14:48:51 -07001467 virtual void callIndirect(int l, Type* pFunc) {
1468 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001469 oad(0x2494ff, l); /* call *xxx(%esp) */
1470 }
1471
Jack Palevich7810bc92009-05-15 14:31:47 -07001472 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1473 if (isIndirect) {
1474 l += 4;
1475 }
-b master422972c2009-06-17 19:13:52 -07001476 if (l > 0) {
1477 oad(0xc481, l); /* add $xxx, %esp */
1478 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001479 }
1480
Jack Palevicha6535612009-05-13 16:24:17 -07001481 virtual int jumpOffset() {
1482 return 5;
1483 }
1484
1485 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001486 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001487 }
1488
Jack Paleviche7b59062009-05-19 17:12:17 -07001489 /* output a symbol and patch all calls to it */
1490 virtual void gsym(int t) {
1491 int n;
1492 int pc = getPC();
1493 while (t) {
1494 n = *(int *) t; /* next value */
1495 *(int *) t = pc - t - 4;
1496 t = n;
1497 }
1498 }
1499
Jack Palevich1cdef202009-05-22 12:06:27 -07001500 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001501 size_t pagesize = 4096;
1502 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1503 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1504 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1505 if (err) {
1506 error("mprotect() failed: %d", errno);
1507 }
1508 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001509 }
1510
Jack Palevich9eed7a22009-07-06 17:24:34 -07001511 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001512 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001513 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001514 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001515 switch(pType->tag) {
1516 case TY_DOUBLE:
1517 return 8;
1518 default:
1519 return 4;
1520 }
1521 }
1522
1523 /**
1524 * Array element alignment (in bytes) for this type of data.
1525 */
1526 virtual size_t sizeOf(Type* pType){
1527 switch(pType->tag) {
1528 case TY_INT:
1529 return 4;
1530 case TY_CHAR:
1531 return 1;
1532 default:
1533 return 0;
1534 case TY_FLOAT:
1535 return 4;
1536 case TY_DOUBLE:
1537 return 8;
1538 case TY_POINTER:
1539 return 4;
1540 }
1541 }
1542
Jack Palevich9cbd2262009-07-08 16:48:41 -07001543 virtual size_t stackSizeOf(Type* pType) {
1544 switch(pType->tag) {
1545 case TY_DOUBLE:
1546 return 8;
1547 default:
1548 return 4;
1549 }
1550 }
1551
Jack Palevich21a15a22009-05-11 14:49:29 -07001552 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001553
1554 /** Output 1 to 4 bytes.
1555 *
1556 */
1557 void o(int n) {
1558 /* cannot use unsigned, so we must do a hack */
1559 while (n && n != -1) {
1560 ob(n & 0xff);
1561 n = n >> 8;
1562 }
1563 }
1564
1565 /* psym is used to put an instruction with a data field which is a
1566 reference to a symbol. It is in fact the same as oad ! */
1567 int psym(int n, int t) {
1568 return oad(n, t);
1569 }
1570
1571 /* instruction + address */
1572 int oad(int n, int t) {
1573 o(n);
1574 int result = getPC();
1575 o4(t);
1576 return result;
1577 }
1578
1579
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001580 static const int operatorHelper[];
1581
1582 int decodeOp(int op) {
1583 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001584 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001585 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001586 }
1587 return operatorHelper[op];
1588 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001589
Jack Palevich546b2242009-05-13 15:10:04 -07001590 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001591 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001592 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001593 }
1594 };
1595
Jack Paleviche7b59062009-05-19 17:12:17 -07001596#endif // PROVIDE_X86_CODEGEN
1597
Jack Palevichb67b18f2009-06-11 21:12:23 -07001598#ifdef PROVIDE_TRACE_CODEGEN
1599 class TraceCodeGenerator : public CodeGenerator {
1600 private:
1601 CodeGenerator* mpBase;
1602
1603 public:
1604 TraceCodeGenerator(CodeGenerator* pBase) {
1605 mpBase = pBase;
1606 }
1607
1608 virtual ~TraceCodeGenerator() {
1609 delete mpBase;
1610 }
1611
1612 virtual void init(CodeBuf* pCodeBuf) {
1613 mpBase->init(pCodeBuf);
1614 }
1615
1616 void setErrorSink(ErrorSink* pErrorSink) {
1617 mpBase->setErrorSink(pErrorSink);
1618 }
1619
1620 /* returns address to patch with local variable size
1621 */
1622 virtual int functionEntry(int argCount) {
1623 int result = mpBase->functionEntry(argCount);
1624 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1625 return result;
1626 }
1627
1628 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1629 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1630 argCount, localVariableAddress, localVariableSize);
1631 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1632 }
1633
1634 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001635 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001636 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001637 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001638 }
1639
Jack Palevich1a539db2009-07-08 13:04:41 -07001640 virtual void loadFloat(int address, Type* pType) {
1641 fprintf(stderr, "loadFloat(%d, type)\n", address);
1642 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001643 }
1644
Jack Palevichb67b18f2009-06-11 21:12:23 -07001645 virtual int gjmp(int t) {
1646 int result = mpBase->gjmp(t);
1647 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1648 return result;
1649 }
1650
1651 /* l = 0: je, l == 1: jne */
1652 virtual int gtst(bool l, int t) {
1653 int result = mpBase->gtst(l, t);
1654 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1655 return result;
1656 }
1657
1658 virtual void gcmp(int op) {
1659 fprintf(stderr, "gcmp(%d)\n", op);
1660 mpBase->gcmp(op);
1661 }
1662
1663 virtual void genOp(int op) {
1664 fprintf(stderr, "genOp(%d)\n", op);
1665 mpBase->genOp(op);
1666 }
1667
Jack Palevich9eed7a22009-07-06 17:24:34 -07001668
1669 virtual void gUnaryCmp(int op) {
1670 fprintf(stderr, "gUnaryCmp(%d)\n", op);
1671 mpBase->gUnaryCmp(op);
1672 }
1673
1674 virtual void genUnaryOp(int op) {
1675 fprintf(stderr, "genUnaryOp(%d)\n", op);
1676 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001677 }
1678
1679 virtual void pushR0() {
1680 fprintf(stderr, "pushR0()\n");
1681 mpBase->pushR0();
1682 }
1683
Jack Palevich9eed7a22009-07-06 17:24:34 -07001684 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001685 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001686 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001687 }
1688
Jack Palevich9eed7a22009-07-06 17:24:34 -07001689 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001690 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001691 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001692 }
1693
Jack Palevich8df46192009-07-07 14:48:51 -07001694 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001695 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001696 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001697 }
1698
Jack Palevich9cbd2262009-07-08 16:48:41 -07001699 virtual void storeR0(int ea, Type* pType) {
1700 fprintf(stderr, "storeR0(%d, pType)\n", ea);
1701 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001702 }
1703
Jack Palevich8df46192009-07-07 14:48:51 -07001704 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001705 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001706 mpBase->loadR0(ea, isIncDec, op, pType);
1707 }
1708
1709 virtual void convertR0(Type* pType){
1710 fprintf(stderr, "convertR0(pType)\n");
1711 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001712 }
1713
1714 virtual int beginFunctionCallArguments() {
1715 int result = mpBase->beginFunctionCallArguments();
1716 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1717 return result;
1718 }
1719
Jack Palevich1a539db2009-07-08 13:04:41 -07001720 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001721 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07001722 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001723 }
1724
1725 virtual void endFunctionCallArguments(int a, int l) {
1726 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1727 mpBase->endFunctionCallArguments(a, l);
1728 }
1729
Jack Palevich8df46192009-07-07 14:48:51 -07001730 virtual int callForward(int symbol, Type* pFunc) {
1731 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001732 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1733 return result;
1734 }
1735
Jack Palevich8df46192009-07-07 14:48:51 -07001736 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001737 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001738 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001739 }
1740
Jack Palevich8df46192009-07-07 14:48:51 -07001741 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001742 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001743 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001744 }
1745
1746 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1747 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1748 mpBase->adjustStackAfterCall(l, isIndirect);
1749 }
1750
1751 virtual int jumpOffset() {
1752 return mpBase->jumpOffset();
1753 }
1754
1755 virtual int disassemble(FILE* out) {
1756 return mpBase->disassemble(out);
1757 }
1758
1759 /* output a symbol and patch all calls to it */
1760 virtual void gsym(int t) {
1761 fprintf(stderr, "gsym(%d)\n", t);
1762 mpBase->gsym(t);
1763 }
1764
1765 virtual int finishCompile() {
1766 int result = mpBase->finishCompile();
1767 fprintf(stderr, "finishCompile() = %d\n", result);
1768 return result;
1769 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001770
1771 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001772 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001773 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001774 virtual size_t alignment(Type* pType){
1775 return mpBase->alignment(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001776 }
1777
1778 /**
1779 * Array element alignment (in bytes) for this type of data.
1780 */
1781 virtual size_t sizeOf(Type* pType){
1782 return mpBase->sizeOf(pType);
1783 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001784
Jack Palevich9cbd2262009-07-08 16:48:41 -07001785
1786 virtual size_t stackSizeOf(Type* pType) {
1787 return mpBase->stackSizeOf(pType);
1788 }
1789
1790
Jack Palevich1a539db2009-07-08 13:04:41 -07001791 virtual Type* getR0Type() {
1792 return mpBase->getR0Type();
1793 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001794 };
1795
1796#endif // PROVIDE_TRACE_CODEGEN
1797
Jack Palevich569f1352009-06-29 14:29:08 -07001798 class Arena {
1799 public:
1800 // Used to record a given allocation amount.
1801 // Used:
1802 // Mark mark = arena.mark();
1803 // ... lots of arena.allocate()
1804 // arena.free(mark);
1805
1806 struct Mark {
1807 size_t chunk;
1808 size_t offset;
1809 };
1810
1811 Arena() {
1812 mCurrentChunk = 0;
1813 Chunk start(CHUNK_SIZE);
1814 mData.push_back(start);
1815 }
1816
1817 ~Arena() {
1818 for(size_t i = 0; i < mData.size(); i++) {
1819 mData[i].free();
1820 }
1821 }
1822
1823 // Alloc using the standard alignment size safe for any variable
1824 void* alloc(size_t size) {
1825 return alloc(size, 8);
1826 }
1827
1828 Mark mark(){
1829 Mark result;
1830 result.chunk = mCurrentChunk;
1831 result.offset = mData[mCurrentChunk].mOffset;
1832 return result;
1833 }
1834
1835 void freeToMark(const Mark& mark) {
1836 mCurrentChunk = mark.chunk;
1837 mData[mCurrentChunk].mOffset = mark.offset;
1838 }
1839
1840 private:
1841 // Allocate memory aligned to a given size
1842 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1843 // Memory is not zero filled.
1844
1845 void* alloc(size_t size, size_t alignment) {
1846 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1847 if (mCurrentChunk + 1 < mData.size()) {
1848 mCurrentChunk++;
1849 } else {
1850 size_t allocSize = CHUNK_SIZE;
1851 if (allocSize < size + alignment - 1) {
1852 allocSize = size + alignment - 1;
1853 }
1854 Chunk chunk(allocSize);
1855 mData.push_back(chunk);
1856 mCurrentChunk++;
1857 }
1858 }
1859 return mData[mCurrentChunk].allocate(size, alignment);
1860 }
1861
1862 static const size_t CHUNK_SIZE = 128*1024;
1863 // Note: this class does not deallocate its
1864 // memory when it's destroyed. It depends upon
1865 // its parent to deallocate the memory.
1866 struct Chunk {
1867 Chunk() {
1868 mpData = 0;
1869 mSize = 0;
1870 mOffset = 0;
1871 }
1872
1873 Chunk(size_t size) {
1874 mSize = size;
1875 mpData = (char*) malloc(size);
1876 mOffset = 0;
1877 }
1878
1879 ~Chunk() {
1880 // Doesn't deallocate memory.
1881 }
1882
1883 void* allocate(size_t size, size_t alignment) {
1884 size_t alignedOffset = aligned(mOffset, alignment);
1885 void* result = mpData + alignedOffset;
1886 mOffset = alignedOffset + size;
1887 return result;
1888 }
1889
1890 void free() {
1891 if (mpData) {
1892 ::free(mpData);
1893 mpData = 0;
1894 }
1895 }
1896
1897 size_t remainingCapacity(size_t alignment) {
1898 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1899 }
1900
1901 // Assume alignment is a power of two
1902 inline size_t aligned(size_t v, size_t alignment) {
1903 size_t mask = alignment-1;
1904 return (v + mask) & ~mask;
1905 }
1906
1907 char* mpData;
1908 size_t mSize;
1909 size_t mOffset;
1910 };
1911
1912 size_t mCurrentChunk;
1913
1914 Vector<Chunk> mData;
1915 };
1916
Jack Palevich569f1352009-06-29 14:29:08 -07001917 struct VariableInfo;
1918
1919 struct Token {
1920 int hash;
1921 size_t length;
1922 char* pText;
1923 tokenid_t id;
1924
1925 // Current values for the token
1926 char* mpMacroDefinition;
1927 VariableInfo* mpVariableInfo;
1928 };
1929
1930 class TokenTable {
1931 public:
1932 // Don't use 0..0xff, allows characters and operators to be tokens too.
1933
1934 static const int TOKEN_BASE = 0x100;
1935 TokenTable() {
1936 mpMap = hashmapCreate(128, hashFn, equalsFn);
1937 }
1938
1939 ~TokenTable() {
1940 hashmapFree(mpMap);
1941 }
1942
1943 void setArena(Arena* pArena) {
1944 mpArena = pArena;
1945 }
1946
1947 // Returns a token for a given string of characters.
1948 tokenid_t intern(const char* pText, size_t length) {
1949 Token probe;
1950 int hash = hashmapHash((void*) pText, length);
1951 {
1952 Token probe;
1953 probe.hash = hash;
1954 probe.length = length;
1955 probe.pText = (char*) pText;
1956 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1957 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001958 return pValue->id;
1959 }
1960 }
1961
1962 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1963 memset(pToken, 0, sizeof(*pToken));
1964 pToken->hash = hash;
1965 pToken->length = length;
1966 pToken->pText = (char*) mpArena->alloc(length + 1);
1967 memcpy(pToken->pText, pText, length);
1968 pToken->pText[length] = 0;
1969 pToken->id = mTokens.size() + TOKEN_BASE;
1970 mTokens.push_back(pToken);
1971 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001972 return pToken->id;
1973 }
1974
1975 // Return the Token for a given tokenid.
1976 Token& operator[](tokenid_t id) {
1977 return *mTokens[id - TOKEN_BASE];
1978 }
1979
1980 inline size_t size() {
1981 return mTokens.size();
1982 }
1983
1984 private:
1985
1986 static int hashFn(void* pKey) {
1987 Token* pToken = (Token*) pKey;
1988 return pToken->hash;
1989 }
1990
1991 static bool equalsFn(void* keyA, void* keyB) {
1992 Token* pTokenA = (Token*) keyA;
1993 Token* pTokenB = (Token*) keyB;
1994 // Don't need to compare hash values, they should always be equal
1995 return pTokenA->length == pTokenB->length
1996 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1997 }
1998
1999 Hashmap* mpMap;
2000 Vector<Token*> mTokens;
2001 Arena* mpArena;
2002 };
2003
Jack Palevich1cdef202009-05-22 12:06:27 -07002004 class InputStream {
2005 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002006 int getChar() {
2007 if (bumpLine) {
2008 line++;
2009 bumpLine = false;
2010 }
2011 int ch = get();
2012 if (ch == '\n') {
2013 bumpLine = true;
2014 }
2015 return ch;
2016 }
2017 int getLine() {
2018 return line;
2019 }
2020 protected:
2021 InputStream() :
2022 line(1), bumpLine(false) {
2023 }
2024 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002025 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002026 int line;
2027 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002028 };
2029
2030 class FileInputStream : public InputStream {
2031 public:
2032 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002033 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002034 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002035 FILE* f;
2036 };
2037
2038 class TextInputStream : public InputStream {
2039 public:
2040 TextInputStream(const char* text, size_t textLength)
2041 : pText(text), mTextLength(textLength), mPosition(0) {
2042 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002043
2044 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002045 virtual int get() {
2046 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2047 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002048
Jack Palevich1cdef202009-05-22 12:06:27 -07002049 const char* pText;
2050 size_t mTextLength;
2051 size_t mPosition;
2052 };
2053
Jack Palevicheedf9d22009-06-04 16:23:40 -07002054 class String {
2055 public:
2056 String() {
2057 mpBase = 0;
2058 mUsed = 0;
2059 mSize = 0;
2060 }
2061
Jack Palevich303d8ff2009-06-11 19:06:24 -07002062 String(const char* item, int len, bool adopt) {
2063 if (len < 0) {
2064 len = strlen(item);
2065 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002066 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002067 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002068 mUsed = len;
2069 mSize = len + 1;
2070 } else {
2071 mpBase = 0;
2072 mUsed = 0;
2073 mSize = 0;
2074 appendBytes(item, len);
2075 }
2076 }
2077
Jack Palevich303d8ff2009-06-11 19:06:24 -07002078 String(const String& other) {
2079 mpBase = 0;
2080 mUsed = 0;
2081 mSize = 0;
2082 appendBytes(other.getUnwrapped(), other.len());
2083 }
2084
Jack Palevicheedf9d22009-06-04 16:23:40 -07002085 ~String() {
2086 if (mpBase) {
2087 free(mpBase);
2088 }
2089 }
2090
Jack Palevicha6baa232009-06-12 11:25:59 -07002091 String& operator=(const String& other) {
2092 clear();
2093 appendBytes(other.getUnwrapped(), other.len());
2094 return *this;
2095 }
2096
Jack Palevich303d8ff2009-06-11 19:06:24 -07002097 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002098 return mpBase;
2099 }
2100
Jack Palevich303d8ff2009-06-11 19:06:24 -07002101 void clear() {
2102 mUsed = 0;
2103 if (mSize > 0) {
2104 mpBase[0] = 0;
2105 }
2106 }
2107
Jack Palevicheedf9d22009-06-04 16:23:40 -07002108 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002109 appendBytes(s, strlen(s));
2110 }
2111
2112 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002113 memcpy(ensure(n), s, n + 1);
2114 }
2115
2116 void append(char c) {
2117 * ensure(1) = c;
2118 }
2119
Jack Palevich86351982009-06-30 18:09:56 -07002120 void append(String& other) {
2121 appendBytes(other.getUnwrapped(), other.len());
2122 }
2123
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002124 char* orphan() {
2125 char* result = mpBase;
2126 mpBase = 0;
2127 mUsed = 0;
2128 mSize = 0;
2129 return result;
2130 }
2131
Jack Palevicheedf9d22009-06-04 16:23:40 -07002132 void printf(const char* fmt,...) {
2133 va_list ap;
2134 va_start(ap, fmt);
2135 vprintf(fmt, ap);
2136 va_end(ap);
2137 }
2138
2139 void vprintf(const char* fmt, va_list ap) {
2140 char* temp;
2141 int numChars = vasprintf(&temp, fmt, ap);
2142 memcpy(ensure(numChars), temp, numChars+1);
2143 free(temp);
2144 }
2145
Jack Palevich303d8ff2009-06-11 19:06:24 -07002146 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002147 return mUsed;
2148 }
2149
2150 private:
2151 char* ensure(int n) {
2152 size_t newUsed = mUsed + n;
2153 if (newUsed > mSize) {
2154 size_t newSize = mSize * 2 + 10;
2155 if (newSize < newUsed) {
2156 newSize = newUsed;
2157 }
2158 mpBase = (char*) realloc(mpBase, newSize + 1);
2159 mSize = newSize;
2160 }
2161 mpBase[newUsed] = '\0';
2162 char* result = mpBase + mUsed;
2163 mUsed = newUsed;
2164 return result;
2165 }
2166
2167 char* mpBase;
2168 size_t mUsed;
2169 size_t mSize;
2170 };
2171
Jack Palevich569f1352009-06-29 14:29:08 -07002172 void internKeywords() {
2173 // Note: order has to match TOK_ constants
2174 static const char* keywords[] = {
2175 "int",
2176 "char",
2177 "void",
2178 "if",
2179 "else",
2180 "while",
2181 "break",
2182 "return",
2183 "for",
2184 "pragma",
2185 "define",
2186 "auto",
2187 "case",
2188 "const",
2189 "continue",
2190 "default",
2191 "do",
2192 "double",
2193 "enum",
2194 "extern",
2195 "float",
2196 "goto",
2197 "long",
2198 "register",
2199 "short",
2200 "signed",
2201 "sizeof",
2202 "static",
2203 "struct",
2204 "switch",
2205 "typedef",
2206 "union",
2207 "unsigned",
2208 "volatile",
2209 "_Bool",
2210 "_Complex",
2211 "_Imaginary",
2212 "inline",
2213 "restrict",
2214 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002215
Jack Palevich569f1352009-06-29 14:29:08 -07002216 for(int i = 0; keywords[i]; i++) {
2217 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002218 }
Jack Palevich569f1352009-06-29 14:29:08 -07002219 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002220
Jack Palevich36d94142009-06-08 15:55:32 -07002221 struct InputState {
2222 InputStream* pStream;
2223 int oldCh;
2224 };
2225
Jack Palevich2db168f2009-06-11 14:29:47 -07002226 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002227 void* pAddress;
2228 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002229 tokenid_t tok;
2230 size_t level;
2231 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002232 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002233 };
2234
Jack Palevich303d8ff2009-06-11 19:06:24 -07002235 class SymbolStack {
2236 public:
2237 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002238 mpArena = 0;
2239 mpTokenTable = 0;
2240 }
2241
2242 void setArena(Arena* pArena) {
2243 mpArena = pArena;
2244 }
2245
2246 void setTokenTable(TokenTable* pTokenTable) {
2247 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002248 }
2249
2250 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002251 Mark mark;
2252 mark.mArenaMark = mpArena->mark();
2253 mark.mSymbolHead = mStack.size();
2254 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002255 }
2256
2257 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002258 // Undo any shadowing that was done:
2259 Mark mark = mLevelStack.back();
2260 mLevelStack.pop_back();
2261 while (mStack.size() > mark.mSymbolHead) {
2262 VariableInfo* pV = mStack.back();
2263 mStack.pop_back();
2264 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002265 }
Jack Palevich569f1352009-06-29 14:29:08 -07002266 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002267 }
2268
Jack Palevich569f1352009-06-29 14:29:08 -07002269 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2270 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2271 return pV && pV->level == level();
2272 }
2273
2274 VariableInfo* add(tokenid_t tok) {
2275 Token& token = (*mpTokenTable)[tok];
2276 VariableInfo* pOldV = token.mpVariableInfo;
2277 VariableInfo* pNewV =
2278 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2279 memset(pNewV, 0, sizeof(VariableInfo));
2280 pNewV->tok = tok;
2281 pNewV->level = level();
2282 pNewV->pOldDefinition = pOldV;
2283 token.mpVariableInfo = pNewV;
2284 mStack.push_back(pNewV);
2285 return pNewV;
2286 }
2287
Jack Palevich86351982009-06-30 18:09:56 -07002288 VariableInfo* add(Type* pType) {
2289 VariableInfo* pVI = add(pType->id);
2290 pVI->pType = pType;
2291 return pVI;
2292 }
2293
Jack Palevich569f1352009-06-29 14:29:08 -07002294 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2295 for (size_t i = 0; i < mStack.size(); i++) {
2296 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002297 break;
2298 }
2299 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002300 }
2301
Jack Palevich303d8ff2009-06-11 19:06:24 -07002302 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002303 inline size_t level() {
2304 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002305 }
2306
Jack Palevich569f1352009-06-29 14:29:08 -07002307 struct Mark {
2308 Arena::Mark mArenaMark;
2309 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002310 };
2311
Jack Palevich569f1352009-06-29 14:29:08 -07002312 Arena* mpArena;
2313 TokenTable* mpTokenTable;
2314 Vector<VariableInfo*> mStack;
2315 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002316 };
Jack Palevich36d94142009-06-08 15:55:32 -07002317
2318 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002319 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002320 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002321 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002322 int tokl; // token operator level
2323 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002324 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002325 intptr_t loc; // local variable index
2326 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002327 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002328 char* dptr; // Macro state: Points to macro text during macro playback.
2329 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002330 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002331
2332 // Arena for the duration of the compile
2333 Arena mGlobalArena;
2334 // Arena for data that's only needed when compiling a single function
2335 Arena mLocalArena;
2336
2337 TokenTable mTokenTable;
2338 SymbolStack mGlobals;
2339 SymbolStack mLocals;
2340
Jack Palevich40600de2009-07-01 15:32:35 -07002341 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002342 Type* mkpInt; // int
2343 Type* mkpChar; // char
2344 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002345 Type* mkpFloat;
2346 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002347 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002348 Type* mkpIntPtr;
2349 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07002350 Type* mkpFloatPtr;
2351 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07002352 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002353
Jack Palevich36d94142009-06-08 15:55:32 -07002354 InputStream* file;
2355
2356 CodeBuf codeBuf;
2357 CodeGenerator* pGen;
2358
Jack Palevicheedf9d22009-06-04 16:23:40 -07002359 String mErrorBuf;
2360
Jack Palevicheedf9d22009-06-04 16:23:40 -07002361 String mPragmas;
2362 int mPragmaStringCount;
2363
Jack Palevich21a15a22009-05-11 14:49:29 -07002364 static const int ALLOC_SIZE = 99999;
2365
Jack Palevich303d8ff2009-06-11 19:06:24 -07002366 static const int TOK_DUMMY = 1;
2367 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002368 static const int TOK_NUM_FLOAT = 3;
2369 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002370
2371 // 3..255 are character and/or operators
2372
Jack Palevich2db168f2009-06-11 14:29:47 -07002373 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002374 // Order has to match string list in "internKeywords".
2375 enum {
2376 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2377 TOK_INT = TOK_KEYWORD,
2378 TOK_CHAR,
2379 TOK_VOID,
2380 TOK_IF,
2381 TOK_ELSE,
2382 TOK_WHILE,
2383 TOK_BREAK,
2384 TOK_RETURN,
2385 TOK_FOR,
2386 TOK_PRAGMA,
2387 TOK_DEFINE,
2388 TOK_AUTO,
2389 TOK_CASE,
2390 TOK_CONST,
2391 TOK_CONTINUE,
2392 TOK_DEFAULT,
2393 TOK_DO,
2394 TOK_DOUBLE,
2395 TOK_ENUM,
2396 TOK_EXTERN,
2397 TOK_FLOAT,
2398 TOK_GOTO,
2399 TOK_LONG,
2400 TOK_REGISTER,
2401 TOK_SHORT,
2402 TOK_SIGNED,
2403 TOK_SIZEOF,
2404 TOK_STATIC,
2405 TOK_STRUCT,
2406 TOK_SWITCH,
2407 TOK_TYPEDEF,
2408 TOK_UNION,
2409 TOK_UNSIGNED,
2410 TOK_VOLATILE,
2411 TOK__BOOL,
2412 TOK__COMPLEX,
2413 TOK__IMAGINARY,
2414 TOK_INLINE,
2415 TOK_RESTRICT,
2416 // Symbols start after tokens
2417 TOK_SYMBOL
2418 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002419
2420 static const int LOCAL = 0x200;
2421
2422 static const int SYM_FORWARD = 0;
2423 static const int SYM_DEFINE = 1;
2424
2425 /* tokens in string heap */
2426 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002427
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002428 static const int OP_INCREMENT = 0;
2429 static const int OP_DECREMENT = 1;
2430 static const int OP_MUL = 2;
2431 static const int OP_DIV = 3;
2432 static const int OP_MOD = 4;
2433 static const int OP_PLUS = 5;
2434 static const int OP_MINUS = 6;
2435 static const int OP_SHIFT_LEFT = 7;
2436 static const int OP_SHIFT_RIGHT = 8;
2437 static const int OP_LESS_EQUAL = 9;
2438 static const int OP_GREATER_EQUAL = 10;
2439 static const int OP_LESS = 11;
2440 static const int OP_GREATER = 12;
2441 static const int OP_EQUALS = 13;
2442 static const int OP_NOT_EQUALS = 14;
2443 static const int OP_LOGICAL_AND = 15;
2444 static const int OP_LOGICAL_OR = 16;
2445 static const int OP_BIT_AND = 17;
2446 static const int OP_BIT_XOR = 18;
2447 static const int OP_BIT_OR = 19;
2448 static const int OP_BIT_NOT = 20;
2449 static const int OP_LOGICAL_NOT = 21;
2450 static const int OP_COUNT = 22;
2451
2452 /* Operators are searched from front, the two-character operators appear
2453 * before the single-character operators with the same first character.
2454 * @ is used to pad out single-character operators.
2455 */
2456 static const char* operatorChars;
2457 static const char operatorLevel[];
2458
Jack Palevich569f1352009-06-29 14:29:08 -07002459 /* Called when we detect an internal problem. Does nothing in production.
2460 *
2461 */
2462 void internalError() {
2463 * (char*) 0 = 0;
2464 }
2465
Jack Palevich86351982009-06-30 18:09:56 -07002466 void assert(bool isTrue) {
2467 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002468 internalError();
2469 }
Jack Palevich86351982009-06-30 18:09:56 -07002470 }
2471
Jack Palevich40600de2009-07-01 15:32:35 -07002472 bool isSymbol(tokenid_t t) {
2473 return t >= TOK_SYMBOL &&
2474 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2475 }
2476
2477 bool isSymbolOrKeyword(tokenid_t t) {
2478 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002479 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002480 }
2481
Jack Palevich86351982009-06-30 18:09:56 -07002482 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002483 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002484 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2485 if (pV && pV->tok != t) {
2486 internalError();
2487 }
2488 return pV;
2489 }
2490
2491 inline bool isDefined(tokenid_t t) {
2492 return t >= TOK_SYMBOL && VI(t) != 0;
2493 }
2494
Jack Palevich40600de2009-07-01 15:32:35 -07002495 const char* nameof(tokenid_t t) {
2496 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002497 return mTokenTable[t].pText;
2498 }
2499
Jack Palevich21a15a22009-05-11 14:49:29 -07002500 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002501 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002502 }
2503
2504 void inp() {
2505 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002506 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002507 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002508 dptr = 0;
2509 ch = dch;
2510 }
2511 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002512 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002513#if 0
2514 printf("ch='%c' 0x%x\n", ch, ch);
2515#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002516 }
2517
2518 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002519 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002520 }
2521
Jack Palevichb4758ff2009-06-12 12:49:14 -07002522 /* read a character constant, advances ch to after end of constant */
2523 int getq() {
2524 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002525 if (ch == '\\') {
2526 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002527 if (isoctal(ch)) {
2528 // 1 to 3 octal characters.
2529 val = 0;
2530 for(int i = 0; i < 3; i++) {
2531 if (isoctal(ch)) {
2532 val = (val << 3) + ch - '0';
2533 inp();
2534 }
2535 }
2536 return val;
2537 } else if (ch == 'x' || ch == 'X') {
2538 // N hex chars
2539 inp();
2540 if (! isxdigit(ch)) {
2541 error("'x' character escape requires at least one digit.");
2542 } else {
2543 val = 0;
2544 while (isxdigit(ch)) {
2545 int d = ch;
2546 if (isdigit(d)) {
2547 d -= '0';
2548 } else if (d <= 'F') {
2549 d = d - 'A' + 10;
2550 } else {
2551 d = d - 'a' + 10;
2552 }
2553 val = (val << 4) + d;
2554 inp();
2555 }
2556 }
2557 } else {
2558 int val = ch;
2559 switch (ch) {
2560 case 'a':
2561 val = '\a';
2562 break;
2563 case 'b':
2564 val = '\b';
2565 break;
2566 case 'f':
2567 val = '\f';
2568 break;
2569 case 'n':
2570 val = '\n';
2571 break;
2572 case 'r':
2573 val = '\r';
2574 break;
2575 case 't':
2576 val = '\t';
2577 break;
2578 case 'v':
2579 val = '\v';
2580 break;
2581 case '\\':
2582 val = '\\';
2583 break;
2584 case '\'':
2585 val = '\'';
2586 break;
2587 case '"':
2588 val = '"';
2589 break;
2590 case '?':
2591 val = '?';
2592 break;
2593 default:
2594 error("Undefined character escape %c", ch);
2595 break;
2596 }
2597 inp();
2598 return val;
2599 }
2600 } else {
2601 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002602 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002603 return val;
2604 }
2605
2606 static bool isoctal(int ch) {
2607 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002608 }
2609
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002610 bool acceptCh(int c) {
2611 bool result = c == ch;
2612 if (result) {
2613 pdef(ch);
2614 inp();
2615 }
2616 return result;
2617 }
2618
2619 bool acceptDigitsCh() {
2620 bool result = false;
2621 while (isdigit(ch)) {
2622 result = true;
2623 pdef(ch);
2624 inp();
2625 }
2626 return result;
2627 }
2628
2629 void parseFloat() {
2630 tok = TOK_NUM_DOUBLE;
2631 // mTokenString already has the integral part of the number.
2632 acceptCh('.');
2633 acceptDigitsCh();
2634 bool doExp = true;
2635 if (acceptCh('e') || acceptCh('E')) {
2636 // Don't need to do any extra work
2637 } else if (ch == 'f' || ch == 'F') {
2638 pdef('e'); // So it can be parsed by strtof.
2639 inp();
2640 tok = TOK_NUM_FLOAT;
2641 } else {
2642 doExp = false;
2643 }
2644 if (doExp) {
2645 bool digitsRequired = acceptCh('-');
2646 bool digitsFound = acceptDigitsCh();
2647 if (digitsRequired && ! digitsFound) {
2648 error("malformed exponent");
2649 }
2650 }
2651 char* pText = mTokenString.getUnwrapped();
2652 if (tok == TOK_NUM_FLOAT) {
2653 tokd = strtof(pText, 0);
2654 } else {
2655 tokd = strtod(pText, 0);
2656 }
2657 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2658 }
2659
Jack Palevich21a15a22009-05-11 14:49:29 -07002660 void next() {
2661 int l, a;
2662
Jack Palevich546b2242009-05-13 15:10:04 -07002663 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002664 if (ch == '#') {
2665 inp();
2666 next();
2667 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002668 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002669 } else if (tok == TOK_PRAGMA) {
2670 doPragma();
2671 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002672 error("Unsupported preprocessor directive \"%s\"",
2673 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002674 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002675 }
2676 inp();
2677 }
2678 tokl = 0;
2679 tok = ch;
2680 /* encode identifiers & numbers */
2681 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002682 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002683 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002684 pdef(ch);
2685 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002686 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002687 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002688 // Start of a numeric constant. Could be integer, float, or
2689 // double, won't know until we look further.
2690 if (ch == '.' || ch == 'e' || ch == 'e'
2691 || ch == 'f' || ch == 'F') {
2692 parseFloat();
2693 } else {
2694 // It's an integer constant
2695 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2696 tok = TOK_NUM;
2697 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002698 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002699 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2700 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002701 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002702 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2703 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002704 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002705 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002706 dch = ch;
2707 inp();
2708 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002709 }
2710 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002711 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002712 inp();
2713 if (tok == '\'') {
2714 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002715 tokc = getq();
2716 if (ch != '\'') {
2717 error("Expected a ' character, got %c", ch);
2718 } else {
2719 inp();
2720 }
Jack Palevich546b2242009-05-13 15:10:04 -07002721 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002722 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002723 while (ch && ch != EOF) {
2724 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002725 inp();
2726 inp();
2727 if (ch == '/')
2728 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002729 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002730 if (ch == EOF) {
2731 error("End of file inside comment.");
2732 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002733 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002734 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002735 } else if ((tok == '/') & (ch == '/')) {
2736 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002737 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002738 inp();
2739 }
2740 inp();
2741 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002742 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002743 const char* t = operatorChars;
2744 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002745 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002746 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002747 tokl = operatorLevel[opIndex];
2748 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002749 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002750#if 0
2751 printf("%c%c -> tokl=%d tokc=0x%x\n",
2752 l, a, tokl, tokc);
2753#endif
2754 if (a == ch) {
2755 inp();
2756 tok = TOK_DUMMY; /* dummy token for double tokens */
2757 }
2758 break;
2759 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002760 opIndex++;
2761 }
2762 if (l == 0) {
2763 tokl = 0;
2764 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002765 }
2766 }
2767 }
2768#if 0
2769 {
Jack Palevich569f1352009-06-29 14:29:08 -07002770 String buf;
2771 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002772 fprintf(stderr, "%s\n", buf.getUnwrapped());
2773 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002774#endif
2775 }
2776
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002777 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002778 next();
2779 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002780 String* pName = new String();
2781 while (isspace(ch)) {
2782 inp();
2783 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002784 if (ch == '(') {
2785 delete pName;
2786 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002787 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002788 }
2789 while (isspace(ch)) {
2790 inp();
2791 }
Jack Palevich569f1352009-06-29 14:29:08 -07002792 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002793 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002794 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002795 inp();
2796 }
Jack Palevich569f1352009-06-29 14:29:08 -07002797 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2798 memcpy(pDefn, value.getUnwrapped(), value.len());
2799 pDefn[value.len()] = 0;
2800 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002801 }
2802
Jack Palevicheedf9d22009-06-04 16:23:40 -07002803 void doPragma() {
2804 // # pragma name(val)
2805 int state = 0;
2806 while(ch != EOF && ch != '\n' && state < 10) {
2807 switch(state) {
2808 case 0:
2809 if (isspace(ch)) {
2810 inp();
2811 } else {
2812 state++;
2813 }
2814 break;
2815 case 1:
2816 if (isalnum(ch)) {
2817 mPragmas.append(ch);
2818 inp();
2819 } else if (ch == '(') {
2820 mPragmas.append(0);
2821 inp();
2822 state++;
2823 } else {
2824 state = 11;
2825 }
2826 break;
2827 case 2:
2828 if (isalnum(ch)) {
2829 mPragmas.append(ch);
2830 inp();
2831 } else if (ch == ')') {
2832 mPragmas.append(0);
2833 inp();
2834 state = 10;
2835 } else {
2836 state = 11;
2837 }
2838 break;
2839 }
2840 }
2841 if(state != 10) {
2842 error("Unexpected pragma syntax");
2843 }
2844 mPragmaStringCount += 2;
2845 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002846
Jack Palevichac0e95e2009-05-29 13:53:44 -07002847 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002848 mErrorBuf.printf("%ld: ", file->getLine());
2849 mErrorBuf.vprintf(fmt, ap);
2850 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002851 }
2852
Jack Palevich8b0624c2009-05-20 12:12:06 -07002853 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002854 if (tok != c) {
2855 error("'%c' expected", c);
2856 }
2857 next();
2858 }
2859
Jack Palevich86351982009-06-30 18:09:56 -07002860 bool accept(intptr_t c) {
2861 if (tok == c) {
2862 next();
2863 return true;
2864 }
2865 return false;
2866 }
2867
Jack Palevich40600de2009-07-01 15:32:35 -07002868 bool acceptStringLiteral() {
2869 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07002870 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07002871 // This while loop merges multiple adjacent string constants.
2872 while (tok == '"') {
2873 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002874 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07002875 }
2876 if (ch != '"') {
2877 error("Unterminated string constant.");
2878 }
2879 inp();
2880 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002881 }
Jack Palevich40600de2009-07-01 15:32:35 -07002882 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002883 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002884 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07002885 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002886
2887 return true;
2888 }
2889 return false;
2890 }
2891 /* Parse and evaluate a unary expression.
2892 * allowAssignment is true if '=' parsing wanted (quick hack)
2893 */
2894 void unary(bool allowAssignment) {
2895 intptr_t n, t, a;
2896 t = 0;
2897 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2898 if (acceptStringLiteral()) {
2899 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002900 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002901 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002902 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002903 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07002904 t = tok;
2905 next();
2906 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07002907 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002908 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002909 // Align to 4-byte boundary
2910 glo = (char*) (((intptr_t) glo + 3) & -4);
2911 * (float*) glo = (float) ad;
2912 pGen->loadFloat((int) glo, mkpFloat);
2913 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002914 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002915 // Align to 8-byte boundary
2916 glo = (char*) (((intptr_t) glo + 7) & -8);
2917 * (double*) glo = ad;
2918 pGen->loadFloat((int) glo, mkpDouble);
2919 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07002920 } else if (c == 2) {
2921 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002922 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002923 if (t == '!')
Jack Palevich9eed7a22009-07-06 17:24:34 -07002924 pGen->gUnaryCmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002925 else
Jack Palevich9eed7a22009-07-06 17:24:34 -07002926 pGen->genUnaryOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002927 } else if (t == '(') {
2928 expr();
2929 skip(')');
2930 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002931 /* This is a pointer dereference, but we currently only
2932 * support a pointer dereference if it's immediately
2933 * in front of a cast. So parse the cast right here.
2934 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002935 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002936 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2937 // We currently only handle 3 types of cast:
2938 // (int*), (char*) , (int (*)())
2939 if(typeEqual(pCast, mkpIntPtr)) {
2940 t = TOK_INT;
2941 } else if (typeEqual(pCast, mkpCharPtr)) {
2942 t = TOK_CHAR;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002943 } else if (typeEqual(pCast, mkpFloatPtr)) {
2944 t = TOK_FLOAT;
2945 } else if (typeEqual(pCast, mkpDoublePtr)) {
2946 t = TOK_DOUBLE;
Jack Palevich3f226492009-07-02 14:46:19 -07002947 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002948 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002949 } else {
2950 String buffer;
2951 decodeType(buffer, pCast);
2952 error("Unsupported cast type %s", buffer.getUnwrapped());
2953 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002954 }
2955 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002956 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002957 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002958 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002959 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002960 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002961 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002962 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002963 }
Jack Palevich3f226492009-07-02 14:46:19 -07002964 // Else we fall through to the function call below, with
2965 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002966 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07002967 VariableInfo* pVI = VI(tok);
2968 pGen->leaR0((int) pVI->pAddress,
2969 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07002970 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002971 } else if (t == EOF ) {
2972 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002973 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002974 // Don't have to do anything special here, the error
2975 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002976 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002977 if (!isDefined(t)) {
2978 mGlobals.add(t);
2979 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002980 }
Jack Palevich8df46192009-07-07 14:48:51 -07002981 VariableInfo* pVI = VI(t);
2982 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002983 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002984 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002985 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07002986 if (tok == '(') {
2987 pVI->pType = mkpIntFn;
2988 } else {
2989 pVI->pType = mkpInt;
2990 }
Jack Palevich8df46192009-07-07 14:48:51 -07002991 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002992 }
Jack Palevich40600de2009-07-01 15:32:35 -07002993 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002994 /* assignment */
2995 next();
2996 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07002997 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002998 } else if (tok != '(') {
2999 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003000 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003001 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003002 }
Jack Palevich8df46192009-07-07 14:48:51 -07003003 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003004 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003005 next();
3006 }
3007 }
3008 }
3009 }
3010
3011 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003012 if (accept('(')) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003013 Type* pArgList = NULL;
3014 VariableInfo* pVI = NULL;
3015 if (n == 1) { // Indirect function call, push address of fn.
3016 pArgList = pGen->getR0Type()->pTail;
Jack Palevich1cdef202009-05-22 12:06:27 -07003017 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003018 } else {
3019 pVI = VI(t);
3020 pArgList = pVI->pType->pTail;
3021 }
3022 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003023 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003024 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003025 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003026 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003027 if (! varArgs && !pArgList) {
3028 error ("Unexpected argument.");
3029 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003030 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003031 Type* pTargetType;
3032 if (pArgList) {
3033 pTargetType = pArgList->pHead;
3034 pArgList = pArgList->pTail;
3035 } else {
3036 pTargetType = pGen->getR0Type();
3037 if (pTargetType->tag == TY_FLOAT) {
3038 pTargetType = mkpDouble;
3039 }
3040 }
3041 pGen->convertR0(pTargetType);
3042 l += pGen->storeR0ToArg(l);
Jack Palevich95727a02009-07-06 12:07:15 -07003043 if (accept(',')) {
3044 // fine
3045 } else if ( tok != ')') {
3046 error("Expected ',' or ')'");
3047 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003048 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003049 if (! varArgs && pArgList) {
3050 error ("Expected more argument(s).");
3051 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003052 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003053 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003054 if (!n) {
3055 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003056 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3057 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003058 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003059 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003060 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003061 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3062 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003063 }
-b master422972c2009-06-17 19:13:52 -07003064 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003065 }
3066 }
3067
Jack Palevich40600de2009-07-01 15:32:35 -07003068 /* Recursive descent parser for binary operations.
3069 */
3070 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003071 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003072 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003073 if (level-- == 1)
3074 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003075 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003076 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003077 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003078 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003079 n = tok;
3080 t = tokc;
3081 next();
3082
Jack Palevich40600de2009-07-01 15:32:35 -07003083 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003084 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003085 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003086 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003087 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003088 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003089
Jack Palevich40600de2009-07-01 15:32:35 -07003090 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003091 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003092 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003093 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003094 }
3095 }
3096 }
3097 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003098 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003099 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003100 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003101 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003102 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003103 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003104 }
3105 }
3106 }
3107
3108 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003109 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003110 }
3111
3112 int test_expr() {
3113 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003114 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003115 }
3116
Jack Palevicha6baa232009-06-12 11:25:59 -07003117 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003118 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003119
Jack Palevich95727a02009-07-06 12:07:15 -07003120 Type* pBaseType;
3121 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003122 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003123 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003124 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003125 next();
3126 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003127 a = test_expr();
3128 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003129 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003130 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003131 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003132 n = pGen->gjmp(0); /* jmp */
3133 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003134 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003135 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003136 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003137 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003138 }
Jack Palevich546b2242009-05-13 15:10:04 -07003139 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003140 t = tok;
3141 next();
3142 skip('(');
3143 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003144 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003145 a = test_expr();
3146 } else {
3147 if (tok != ';')
3148 expr();
3149 skip(';');
3150 n = codeBuf.getPC();
3151 a = 0;
3152 if (tok != ';')
3153 a = test_expr();
3154 skip(';');
3155 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003156 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003157 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003158 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003159 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003160 n = t + 4;
3161 }
3162 }
3163 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003164 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003165 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003166 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003167 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003168 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003169 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003170 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003171 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003172 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003173 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003174 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003175 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003176 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003177 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003178 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003179 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003180 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003181 expr();
Jack Palevich8df46192009-07-07 14:48:51 -07003182 pGen->convertR0(pReturnType);
3183 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003184 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003185 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003186 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003187 } else if (tok != ';')
3188 expr();
3189 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003190 }
3191 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003192
Jack Palevich3f226492009-07-02 14:46:19 -07003193 bool typeEqual(Type* a, Type* b) {
3194 if (a == b) {
3195 return true;
3196 }
3197 if (a == NULL || b == NULL) {
3198 return false;
3199 }
3200 TypeTag at = a->tag;
3201 if (at != b->tag) {
3202 return false;
3203 }
3204 if (at == TY_POINTER) {
3205 return typeEqual(a->pHead, b->pHead);
3206 } else if (at == TY_FUNC || at == TY_PARAM) {
3207 return typeEqual(a->pHead, b->pHead)
3208 && typeEqual(a->pTail, b->pTail);
3209 }
3210 return true;
3211 }
3212
Jack Palevich86351982009-06-30 18:09:56 -07003213 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3214 assert(tag >= TY_INT && tag <= TY_PARAM);
3215 Type* pType = (Type*) arena.alloc(sizeof(Type));
3216 memset(pType, 0, sizeof(*pType));
3217 pType->tag = tag;
3218 pType->pHead = pHead;
3219 pType->pTail = pTail;
3220 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003221 }
3222
Jack Palevich3f226492009-07-02 14:46:19 -07003223 Type* createPtrType(Type* pType, Arena& arena) {
3224 return createType(TY_POINTER, pType, NULL, arena);
3225 }
3226
3227 /**
3228 * Try to print a type in declaration order
3229 */
Jack Palevich86351982009-06-30 18:09:56 -07003230 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003231 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003232 if (pType == NULL) {
3233 buffer.appendCStr("null");
3234 return;
3235 }
Jack Palevich3f226492009-07-02 14:46:19 -07003236 decodeTypeImp(buffer, pType);
3237 }
3238
3239 void decodeTypeImp(String& buffer, Type* pType) {
3240 decodeTypeImpPrefix(buffer, pType);
3241
Jack Palevich86351982009-06-30 18:09:56 -07003242 String temp;
3243 if (pType->id != 0) {
3244 decodeToken(temp, pType->id);
3245 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003246 }
3247
3248 decodeTypeImpPostfix(buffer, pType);
3249 }
3250
3251 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3252 TypeTag tag = pType->tag;
3253
3254 if (tag >= TY_INT && tag <= TY_VOID) {
3255 switch (tag) {
3256 case TY_INT:
3257 buffer.appendCStr("int");
3258 break;
3259 case TY_CHAR:
3260 buffer.appendCStr("char");
3261 break;
3262 case TY_VOID:
3263 buffer.appendCStr("void");
3264 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003265 case TY_FLOAT:
3266 buffer.appendCStr("float");
3267 break;
3268 case TY_DOUBLE:
3269 buffer.appendCStr("double");
3270 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003271 default:
3272 break;
3273 }
Jack Palevich86351982009-06-30 18:09:56 -07003274 buffer.append(' ');
3275 }
Jack Palevich3f226492009-07-02 14:46:19 -07003276
3277 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003278 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003279 break;
3280 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003281 break;
3282 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003283 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003284 case TY_FLOAT:
3285 break;
3286 case TY_DOUBLE:
3287 break;
Jack Palevich86351982009-06-30 18:09:56 -07003288 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003289 decodeTypeImpPrefix(buffer, pType->pHead);
3290 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3291 buffer.append('(');
3292 }
3293 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003294 break;
3295 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003296 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003297 break;
3298 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003299 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003300 break;
3301 default:
3302 String temp;
3303 temp.printf("Unknown tag %d", pType->tag);
3304 buffer.append(temp);
3305 break;
3306 }
Jack Palevich3f226492009-07-02 14:46:19 -07003307 }
3308
3309 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3310 TypeTag tag = pType->tag;
3311
3312 switch(tag) {
3313 case TY_POINTER:
3314 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3315 buffer.append(')');
3316 }
3317 decodeTypeImpPostfix(buffer, pType->pHead);
3318 break;
3319 case TY_FUNC:
3320 buffer.append('(');
3321 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3322 decodeTypeImp(buffer, pArg);
3323 if (pArg->pTail) {
3324 buffer.appendCStr(", ");
3325 }
3326 }
3327 buffer.append(')');
3328 break;
3329 default:
3330 break;
Jack Palevich86351982009-06-30 18:09:56 -07003331 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003332 }
3333
Jack Palevich86351982009-06-30 18:09:56 -07003334 void printType(Type* pType) {
3335 String buffer;
3336 decodeType(buffer, pType);
3337 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003338 }
3339
Jack Palevich86351982009-06-30 18:09:56 -07003340 Type* acceptPrimitiveType(Arena& arena) {
3341 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003342 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003343 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003344 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003345 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003346 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003347 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003348 } else if (tok == TOK_FLOAT) {
3349 pType = mkpFloat;
3350 } else if (tok == TOK_DOUBLE) {
3351 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003352 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003353 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003354 }
3355 next();
Jack Palevich86351982009-06-30 18:09:56 -07003356 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003357 }
3358
Jack Palevich3f226492009-07-02 14:46:19 -07003359 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3360 Arena& arena) {
3361 tokenid_t declName = 0;
3362 pType = acceptDecl2(pType, declName, nameAllowed,
3363 nameRequired, arena);
3364 if (declName) {
3365 // Clone the parent type so we can set a unique ID
3366 pType = createType(pType->tag, pType->pHead,
3367 pType->pTail, arena);
3368
Jack Palevich86351982009-06-30 18:09:56 -07003369 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003370 }
Jack Palevich3f226492009-07-02 14:46:19 -07003371 // fprintf(stderr, "Parsed a declaration: ");
3372 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003373 return pType;
3374 }
3375
Jack Palevich3f226492009-07-02 14:46:19 -07003376 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3377 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003378 if (! pType) {
3379 error("Expected a declaration");
3380 }
3381 return pType;
3382 }
3383
Jack Palevich3f226492009-07-02 14:46:19 -07003384 /* Used for accepting types that appear in casts */
3385 Type* acceptCastTypeDeclaration(Arena& arena) {
3386 Type* pType = acceptPrimitiveType(arena);
3387 if (pType) {
3388 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003389 }
Jack Palevich86351982009-06-30 18:09:56 -07003390 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003391 }
3392
Jack Palevich3f226492009-07-02 14:46:19 -07003393 Type* expectCastTypeDeclaration(Arena& arena) {
3394 Type* pType = acceptCastTypeDeclaration(arena);
3395 if (! pType) {
3396 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003397 }
Jack Palevich3f226492009-07-02 14:46:19 -07003398 return pType;
3399 }
3400
3401 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3402 bool nameAllowed, bool nameRequired, Arena& arena) {
3403 int ptrCounter = 0;
3404 while (accept('*')) {
3405 ptrCounter++;
3406 }
3407 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3408 while (ptrCounter-- > 0) {
3409 pType = createType(TY_POINTER, pType, NULL, arena);
3410 }
3411 return pType;
3412 }
3413
3414 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3415 bool nameAllowed, bool nameRequired, Arena& arena) {
3416 // direct-dcl :
3417 // name
3418 // (dcl)
3419 // direct-dcl()
3420 // direct-dcl[]
3421 Type* pNewHead = NULL;
3422 if (accept('(')) {
3423 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3424 nameRequired, arena);
3425 skip(')');
3426 } else if ((declName = acceptSymbol()) != 0) {
3427 if (nameAllowed == false && declName) {
3428 error("Symbol %s not allowed here", nameof(declName));
3429 } else if (nameRequired && ! declName) {
3430 String temp;
3431 decodeToken(temp, tok);
3432 error("Expected symbol. Got %s", temp.getUnwrapped());
3433 }
3434 }
3435 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003436 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003437 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003438 pType = createType(TY_FUNC, pType, pTail, arena);
3439 skip(')');
3440 }
Jack Palevich3f226492009-07-02 14:46:19 -07003441
3442 if (pNewHead) {
3443 Type* pA = pNewHead;
3444 while (pA->pHead) {
3445 pA = pA->pHead;
3446 }
3447 pA->pHead = pType;
3448 pType = pNewHead;
3449 }
Jack Palevich86351982009-06-30 18:09:56 -07003450 return pType;
3451 }
3452
Jack Palevich3f226492009-07-02 14:46:19 -07003453 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003454 Type* pHead = NULL;
3455 Type* pTail = NULL;
3456 for(;;) {
3457 Type* pBaseArg = acceptPrimitiveType(arena);
3458 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003459 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3460 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003461 if (pArg) {
3462 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3463 if (!pHead) {
3464 pHead = pParam;
3465 pTail = pParam;
3466 } else {
3467 pTail->pTail = pParam;
3468 pTail = pParam;
3469 }
3470 }
3471 }
3472 if (! accept(',')) {
3473 break;
3474 }
3475 }
3476 return pHead;
3477 }
3478
3479 Type* expectPrimitiveType(Arena& arena) {
3480 Type* pType = acceptPrimitiveType(arena);
3481 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003482 String buf;
3483 decodeToken(buf, tok);
3484 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003485 }
Jack Palevich86351982009-06-30 18:09:56 -07003486 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003487 }
3488
Jack Palevich86351982009-06-30 18:09:56 -07003489 void addGlobalSymbol(Type* pDecl) {
3490 tokenid_t t = pDecl->id;
3491 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003492 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003493 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003494 }
Jack Palevich86351982009-06-30 18:09:56 -07003495 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003496 }
3497
Jack Palevich86351982009-06-30 18:09:56 -07003498 void reportDuplicate(tokenid_t t) {
3499 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003500 }
3501
Jack Palevich86351982009-06-30 18:09:56 -07003502 void addLocalSymbol(Type* pDecl) {
3503 tokenid_t t = pDecl->id;
3504 if (mLocals.isDefinedAtCurrentLevel(t)) {
3505 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003506 }
Jack Palevich86351982009-06-30 18:09:56 -07003507 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003508 }
3509
Jack Palevich95727a02009-07-06 12:07:15 -07003510 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003511 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003512
Jack Palevich95727a02009-07-06 12:07:15 -07003513 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003514 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003515 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3516 if (!pDecl) {
3517 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003518 }
Jack Palevich86351982009-06-30 18:09:56 -07003519 int variableAddress = 0;
3520 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003521 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003522 loc = loc + 4;
3523 variableAddress = -loc;
3524 VI(pDecl->id)->pAddress = (void*) variableAddress;
3525 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003526 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003527 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003528 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07003529 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003530 if (tok == ',')
3531 next();
3532 }
3533 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003534 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003535 }
3536 }
3537
Jack Palevichf1728be2009-06-12 13:53:51 -07003538 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003539 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003540 }
3541
Jack Palevich569f1352009-06-29 14:29:08 -07003542 void decodeToken(String& buffer, tokenid_t token) {
3543 if (token == EOF ) {
3544 buffer.printf("EOF");
3545 } else if (token == TOK_NUM) {
3546 buffer.printf("numeric constant");
3547 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003548 if (token < 32) {
3549 buffer.printf("'\\x%02x'", token);
3550 } else {
3551 buffer.printf("'%c'", token);
3552 }
Jack Palevich569f1352009-06-29 14:29:08 -07003553 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3554 buffer.printf("keyword \"%s\"", nameof(token));
3555 } else {
3556 buffer.printf("symbol \"%s\"", nameof(token));
3557 }
3558 }
3559
Jack Palevich40600de2009-07-01 15:32:35 -07003560 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003561 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003562 if (!result) {
3563 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003564 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003565 error("Expected symbol. Got %s", temp.getUnwrapped());
3566 }
3567 return result;
3568 }
3569
Jack Palevich86351982009-06-30 18:09:56 -07003570 tokenid_t acceptSymbol() {
3571 tokenid_t result = 0;
3572 if (tok >= TOK_SYMBOL) {
3573 result = tok;
3574 next();
Jack Palevich86351982009-06-30 18:09:56 -07003575 }
3576 return result;
3577 }
3578
Jack Palevichb7c81e92009-06-04 19:56:13 -07003579 void globalDeclarations() {
3580 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003581 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3582 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003583 break;
3584 }
Jack Palevich86351982009-06-30 18:09:56 -07003585 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3586 if (!pDecl) {
3587 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003588 }
Jack Palevich86351982009-06-30 18:09:56 -07003589 if (! isDefined(pDecl->id)) {
3590 addGlobalSymbol(pDecl);
3591 }
3592 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003593 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003594 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003595 }
Jack Palevich86351982009-06-30 18:09:56 -07003596 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003597 // it's a variable declaration
3598 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003599 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003600 name->pAddress = (int*) allocGlobalSpace(
3601 pGen->alignment(name->pType),
3602 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07003603 }
Jack Palevich86351982009-06-30 18:09:56 -07003604 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003605 if (tok == TOK_NUM) {
3606 if (name) {
3607 * (int*) name->pAddress = tokc;
3608 }
3609 next();
3610 } else {
3611 error("Expected an integer constant");
3612 }
3613 }
Jack Palevich86351982009-06-30 18:09:56 -07003614 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003615 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003616 }
Jack Palevich86351982009-06-30 18:09:56 -07003617 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3618 if (!pDecl) {
3619 break;
3620 }
3621 if (! isDefined(pDecl->id)) {
3622 addGlobalSymbol(pDecl);
3623 }
3624 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003625 }
3626 skip(';');
3627 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003628 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003629 if (accept(';')) {
3630 // forward declaration.
3631 } else {
3632 if (name) {
3633 /* patch forward references (XXX: does not work for function
3634 pointers) */
3635 pGen->gsym((int) name->pForward);
3636 /* put function address */
3637 name->pAddress = (void*) codeBuf.getPC();
3638 }
3639 // Calculate stack offsets for parameters
3640 mLocals.pushLevel();
3641 intptr_t a = 8;
3642 int argCount = 0;
3643 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3644 Type* pArg = pP->pHead;
3645 addLocalSymbol(pArg);
3646 /* read param name and compute offset */
3647 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003648 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07003649 argCount++;
3650 }
3651 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003652 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003653 a = pGen->functionEntry(argCount);
3654 block(0, true);
3655 pGen->gsym(rsym);
3656 pGen->functionExit(argCount, a, loc);
3657 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003658 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003659 }
3660 }
3661 }
3662
Jack Palevich9cbd2262009-07-08 16:48:41 -07003663 char* allocGlobalSpace(size_t alignment, size_t bytes) {
3664 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
3665 size_t end = base + bytes;
3666 if ((end - (size_t) pGlobalBase) > ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003667 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003668 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003669 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07003670 char* result = (char*) base;
3671 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003672 return result;
3673 }
3674
Jack Palevich21a15a22009-05-11 14:49:29 -07003675 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003676 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003677 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003678 pGlobalBase = 0;
3679 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003680 if (pGen) {
3681 delete pGen;
3682 pGen = 0;
3683 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003684 if (file) {
3685 delete file;
3686 file = 0;
3687 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003688 }
3689
3690 void clear() {
3691 tok = 0;
3692 tokc = 0;
3693 tokl = 0;
3694 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003695 rsym = 0;
3696 loc = 0;
3697 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003698 dptr = 0;
3699 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003700 file = 0;
3701 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003702 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003703 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003704 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003705
Jack Palevich22305132009-05-13 10:58:45 -07003706 void setArchitecture(const char* architecture) {
3707 delete pGen;
3708 pGen = 0;
3709
3710 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003711#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003712 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003713 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003714 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003715#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003716#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003717 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003718 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003719 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003720#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003721 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003722 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003723 }
3724 }
3725
3726 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003727#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003728 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003729#elif defined(DEFAULT_X86_CODEGEN)
3730 pGen = new X86CodeGenerator();
3731#endif
3732 }
3733 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003734 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003735 } else {
3736 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003737 }
3738 }
3739
Jack Palevich77ae76e2009-05-10 19:59:24 -07003740public:
Jack Palevich22305132009-05-13 10:58:45 -07003741 struct args {
3742 args() {
3743 architecture = 0;
3744 }
3745 const char* architecture;
3746 };
3747
Jack Paleviche7b59062009-05-19 17:12:17 -07003748 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003749 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003750 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003751
Jack Paleviche7b59062009-05-19 17:12:17 -07003752 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003753 cleanup();
3754 }
3755
Jack Palevich1cdef202009-05-22 12:06:27 -07003756 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003757 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003758
3759 cleanup();
3760 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003761 mTokenTable.setArena(&mGlobalArena);
3762 mGlobals.setArena(&mGlobalArena);
3763 mGlobals.setTokenTable(&mTokenTable);
3764 mLocals.setArena(&mLocalArena);
3765 mLocals.setTokenTable(&mTokenTable);
3766
3767 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003768 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003769 codeBuf.init(ALLOC_SIZE);
3770 setArchitecture(NULL);
3771 if (!pGen) {
3772 return -1;
3773 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003774#ifdef PROVIDE_TRACE_CODEGEN
3775 pGen = new TraceCodeGenerator(pGen);
3776#endif
3777 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003778 pGen->init(&codeBuf);
3779 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003780 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3781 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003782 inp();
3783 next();
3784 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003785 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003786 result = pGen->finishCompile();
3787 if (result == 0) {
3788 if (mErrorBuf.len()) {
3789 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003790 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003791 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003792 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003793 }
3794
Jack Palevich86351982009-06-30 18:09:56 -07003795 void createPrimitiveTypes() {
3796 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3797 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3798 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003799 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3800 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003801 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003802 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3803 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07003804 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
3805 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003806 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003807 }
3808
Jack Palevicha6baa232009-06-12 11:25:59 -07003809 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003810 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003811 }
3812
Jack Palevich569f1352009-06-29 14:29:08 -07003813 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003814 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003815 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003816 }
3817
Jack Palevich569f1352009-06-29 14:29:08 -07003818 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003819 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003820 error("Undefined forward reference: %s",
3821 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003822 }
3823 return true;
3824 }
3825
Jack Palevich21a15a22009-05-11 14:49:29 -07003826 int dump(FILE* out) {
3827 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3828 return 0;
3829 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003830
Jack Palevicha6535612009-05-13 16:24:17 -07003831 int disassemble(FILE* out) {
3832 return pGen->disassemble(out);
3833 }
3834
Jack Palevich1cdef202009-05-22 12:06:27 -07003835 /* Look through the symbol table to find a symbol.
3836 * If found, return its value.
3837 */
3838 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003839 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3840 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003841 if (pVariableInfo) {
3842 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003843 }
3844 return NULL;
3845 }
3846
Jack Palevicheedf9d22009-06-04 16:23:40 -07003847 void getPragmas(ACCsizei* actualStringCount,
3848 ACCsizei maxStringCount, ACCchar** strings) {
3849 int stringCount = mPragmaStringCount;
3850 if (actualStringCount) {
3851 *actualStringCount = stringCount;
3852 }
3853 if (stringCount > maxStringCount) {
3854 stringCount = maxStringCount;
3855 }
3856 if (strings) {
3857 char* pPragmas = mPragmas.getUnwrapped();
3858 while (stringCount-- > 0) {
3859 *strings++ = pPragmas;
3860 pPragmas += strlen(pPragmas) + 1;
3861 }
3862 }
3863 }
3864
Jack Palevichac0e95e2009-05-29 13:53:44 -07003865 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003866 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003867 }
3868
Jack Palevich77ae76e2009-05-10 19:59:24 -07003869};
3870
Jack Paleviche7b59062009-05-19 17:12:17 -07003871const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003872 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3873
Jack Paleviche7b59062009-05-19 17:12:17 -07003874const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003875 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3876 5, 5, /* ==, != */
3877 9, 10, /* &&, || */
3878 6, 7, 8, /* & ^ | */
3879 2, 2 /* ~ ! */
3880 };
3881
Jack Palevich8b0624c2009-05-20 12:12:06 -07003882#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003883FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003884#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003885
Jack Palevich8b0624c2009-05-20 12:12:06 -07003886#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003887const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003888 0x1, // ++
3889 0xff, // --
3890 0xc1af0f, // *
3891 0xf9f79991, // /
3892 0xf9f79991, // % (With manual assist to swap results)
3893 0xc801, // +
3894 0xd8f7c829, // -
3895 0xe0d391, // <<
3896 0xf8d391, // >>
3897 0xe, // <=
3898 0xd, // >=
3899 0xc, // <
3900 0xf, // >
3901 0x4, // ==
3902 0x5, // !=
3903 0x0, // &&
3904 0x1, // ||
3905 0xc821, // &
3906 0xc831, // ^
3907 0xc809, // |
3908 0xd0f7, // ~
3909 0x4 // !
3910};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003911#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003912
Jack Palevich1cdef202009-05-22 12:06:27 -07003913struct ACCscript {
3914 ACCscript() {
3915 text = 0;
3916 textLength = 0;
3917 accError = ACC_NO_ERROR;
3918 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003919
Jack Palevich1cdef202009-05-22 12:06:27 -07003920 ~ACCscript() {
3921 delete text;
3922 }
Jack Palevich546b2242009-05-13 15:10:04 -07003923
Jack Palevich1cdef202009-05-22 12:06:27 -07003924 void setError(ACCenum error) {
3925 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3926 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003927 }
3928 }
3929
Jack Palevich1cdef202009-05-22 12:06:27 -07003930 ACCenum getError() {
3931 ACCenum result = accError;
3932 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003933 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003934 }
3935
Jack Palevich1cdef202009-05-22 12:06:27 -07003936 Compiler compiler;
3937 char* text;
3938 int textLength;
3939 ACCenum accError;
3940};
3941
3942
3943extern "C"
3944ACCscript* accCreateScript() {
3945 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003946}
Jack Palevich1cdef202009-05-22 12:06:27 -07003947
3948extern "C"
3949ACCenum accGetError( ACCscript* script ) {
3950 return script->getError();
3951}
3952
3953extern "C"
3954void accDeleteScript(ACCscript* script) {
3955 delete script;
3956}
3957
3958extern "C"
3959void accScriptSource(ACCscript* script,
3960 ACCsizei count,
3961 const ACCchar ** string,
3962 const ACCint * length) {
3963 int totalLength = 0;
3964 for(int i = 0; i < count; i++) {
3965 int len = -1;
3966 const ACCchar* s = string[i];
3967 if (length) {
3968 len = length[i];
3969 }
3970 if (len < 0) {
3971 len = strlen(s);
3972 }
3973 totalLength += len;
3974 }
3975 delete script->text;
3976 char* text = new char[totalLength + 1];
3977 script->text = text;
3978 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003979 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003980 for(int i = 0; i < count; i++) {
3981 int len = -1;
3982 const ACCchar* s = string[i];
3983 if (length) {
3984 len = length[i];
3985 }
3986 if (len < 0) {
3987 len = strlen(s);
3988 }
Jack Palevich09555c72009-05-27 12:25:55 -07003989 memcpy(dest, s, len);
3990 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003991 }
3992 text[totalLength] = '\0';
3993}
3994
3995extern "C"
3996void accCompileScript(ACCscript* script) {
3997 int result = script->compiler.compile(script->text, script->textLength);
3998 if (result) {
3999 script->setError(ACC_INVALID_OPERATION);
4000 }
4001}
4002
4003extern "C"
4004void accGetScriptiv(ACCscript* script,
4005 ACCenum pname,
4006 ACCint * params) {
4007 switch (pname) {
4008 case ACC_INFO_LOG_LENGTH:
4009 *params = 0;
4010 break;
4011 }
4012}
4013
4014extern "C"
4015void accGetScriptInfoLog(ACCscript* script,
4016 ACCsizei maxLength,
4017 ACCsizei * length,
4018 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004019 char* message = script->compiler.getErrorMessage();
4020 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004021 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004022 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004023 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004024 if (infoLog && maxLength > 0) {
4025 int trimmedLength = maxLength < messageLength ?
4026 maxLength : messageLength;
4027 memcpy(infoLog, message, trimmedLength);
4028 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004029 }
4030}
4031
4032extern "C"
4033void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4034 ACCvoid ** address) {
4035 void* value = script->compiler.lookup(name);
4036 if (value) {
4037 *address = value;
4038 } else {
4039 script->setError(ACC_INVALID_VALUE);
4040 }
4041}
4042
Jack Palevicheedf9d22009-06-04 16:23:40 -07004043extern "C"
4044void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4045 ACCsizei maxStringCount, ACCchar** strings){
4046 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4047}
4048
-b master422972c2009-06-17 19:13:52 -07004049extern "C"
4050void accDisassemble(ACCscript* script) {
4051 script->compiler.disassemble(stderr);
4052}
4053
Jack Palevicheedf9d22009-06-04 16:23:40 -07004054
Jack Palevich1cdef202009-05-22 12:06:27 -07004055} // namespace acc
4056