blob: 0935be890a518df889b34bb524b81c4bb2ce6cc2 [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
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700130 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700131 virtual void verror(const char* fmt, va_list ap) = 0;
132};
133
134class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700135 typedef int tokenid_t;
136 enum TypeTag {
137 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
138 TY_POINTER, TY_FUNC, TY_PARAM
139 };
140
141 struct Type {
142 TypeTag tag;
143 tokenid_t id; // For function arguments
144 Type* pHead;
145 Type* pTail;
146 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700147
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700149 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700150 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700151 ErrorSink* mErrorSink;
152 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700153 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700154
Jack Palevich21a15a22009-05-11 14:49:29 -0700155 void release() {
156 if (pProgramBase != 0) {
157 free(pProgramBase);
158 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700159 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700160 }
161
Jack Palevich0a280a02009-06-11 10:53:51 -0700162 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700163 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700164 bool overflow = newSize > mSize;
165 if (overflow && !mOverflowed) {
166 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700167 if (mErrorSink) {
168 mErrorSink->error("Code too large: %d bytes", newSize);
169 }
170 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700171 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700172 }
173
Jack Palevich21a15a22009-05-11 14:49:29 -0700174 public:
175 CodeBuf() {
176 pProgramBase = 0;
177 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700178 mErrorSink = 0;
179 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700180 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 }
182
183 ~CodeBuf() {
184 release();
185 }
186
187 void init(int size) {
188 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700190 pProgramBase = (char*) calloc(1, size);
191 ind = pProgramBase;
192 }
193
Jack Palevichac0e95e2009-05-29 13:53:44 -0700194 void setErrorSink(ErrorSink* pErrorSink) {
195 mErrorSink = pErrorSink;
196 }
197
Jack Palevich546b2242009-05-13 15:10:04 -0700198 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700199 if(check(4)) {
200 return 0;
201 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700202 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700203 * (int*) ind = n;
204 ind += 4;
205 return result;
206 }
207
Jack Palevich21a15a22009-05-11 14:49:29 -0700208 /*
209 * Output a byte. Handles all values, 0..ff.
210 */
211 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(1)) {
213 return;
214 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 *ind++ = n;
216 }
217
Jack Palevich21a15a22009-05-11 14:49:29 -0700218 inline void* getBase() {
219 return (void*) pProgramBase;
220 }
221
Jack Palevich8b0624c2009-05-20 12:12:06 -0700222 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700223 return ind - pProgramBase;
224 }
225
Jack Palevich8b0624c2009-05-20 12:12:06 -0700226 intptr_t getPC() {
227 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 }
229 };
230
Jack Palevich1cdef202009-05-22 12:06:27 -0700231 /**
232 * A code generator creates an in-memory program, generating the code on
233 * the fly. There is one code generator implementation for each supported
234 * architecture.
235 *
236 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700237 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700238 * FP - a frame pointer for accessing function arguments and local
239 * variables.
240 * SP - a stack pointer for storing intermediate results while evaluating
241 * expressions. The stack pointer grows downwards.
242 *
243 * The function calling convention is that all arguments are placed on the
244 * stack such that the first argument has the lowest address.
245 * After the call, the result is in R0. The caller is responsible for
246 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700247 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700248 * FP and SP registers are saved.
249 */
250
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 class CodeGenerator {
252 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700253 CodeGenerator() {
254 mErrorSink = 0;
255 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700256 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700257 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 virtual ~CodeGenerator() {}
259
Jack Palevich22305132009-05-13 10:58:45 -0700260 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700262 pCodeBuf->setErrorSink(mErrorSink);
263 }
264
Jack Palevichb67b18f2009-06-11 21:12:23 -0700265 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 mErrorSink = pErrorSink;
267 if (pCodeBuf) {
268 pCodeBuf->setErrorSink(mErrorSink);
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 }
271
Jack Palevich1cdef202009-05-22 12:06:27 -0700272 /* Emit a function prolog.
273 * argCount is the number of arguments.
274 * Save the old value of the FP.
275 * Set the new value of the FP.
276 * Convert from the native platform calling convention to
277 * our stack-based calling convention. This may require
278 * pushing arguments from registers to the stack.
279 * Allocate "N" bytes of stack space. N isn't known yet, so
280 * just emit the instructions for adjusting the stack, and return
281 * the address to patch up. The patching will be done in
282 * functionExit().
283 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700284 */
Jack Palevich546b2242009-05-13 15:10:04 -0700285 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700286
Jack Palevich1cdef202009-05-22 12:06:27 -0700287 /* Emit a function epilog.
288 * Restore the old SP and FP register values.
289 * Return to the calling function.
290 * argCount - the number of arguments to the function.
291 * localVariableAddress - returned from functionEntry()
292 * localVariableSize - the size in bytes of the local variables.
293 */
294 virtual void functionExit(int argCount, int localVariableAddress,
295 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700296
Jack Palevich1cdef202009-05-22 12:06:27 -0700297 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700298 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700299
Jack Palevich1a539db2009-07-08 13:04:41 -0700300 /* Load floating point value from global address. */
301 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700302
Jack Palevich1cdef202009-05-22 12:06:27 -0700303 /* Jump to a target, and return the address of the word that
304 * holds the target data, in case it needs to be fixed up later.
305 */
Jack Palevich22305132009-05-13 10:58:45 -0700306 virtual int gjmp(int t) = 0;
307
Jack Palevich1cdef202009-05-22 12:06:27 -0700308 /* Test R0 and jump to a target if the test succeeds.
309 * l = 0: je, l == 1: jne
310 * Return the address of the word that holds the targed data, in
311 * case it needs to be fixed up later.
312 */
Jack Palevich22305132009-05-13 10:58:45 -0700313 virtual int gtst(bool l, int t) = 0;
314
Jack Palevich9eed7a22009-07-06 17:24:34 -0700315 /* Compare TOS against R0, and store the boolean result in R0.
316 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 * op specifies the comparison.
318 */
Jack Palevich22305132009-05-13 10:58:45 -0700319 virtual void gcmp(int op) = 0;
320
Jack Palevich9eed7a22009-07-06 17:24:34 -0700321 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700322 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700323 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 */
Jack Palevich546b2242009-05-13 15:10:04 -0700325 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700326
Jack Palevich9eed7a22009-07-06 17:24:34 -0700327 /* Compare 0 against R0, and store the boolean result in R0.
328 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700330 virtual void gUnaryCmp(int op) = 0;
331
332 /* Perform the arithmetic op specified by op. 0 is the
333 * left argument, R0 is the right argument.
334 */
335 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700336
Jack Palevich1cdef202009-05-22 12:06:27 -0700337 /* Push R0 onto the stack.
338 */
339 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700340
Jack Palevich9eed7a22009-07-06 17:24:34 -0700341 /* Store R0 to the address stored in TOS.
342 * The TOS is popped.
343 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700346
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700348 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700350 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700351
Jack Palevich1cdef202009-05-22 12:06:27 -0700352 /* Load the absolute address of a variable to R0.
353 * If ea <= LOCAL, then this is a local variable, or an
354 * argument, addressed relative to FP.
355 * else it is an absolute global address.
356 */
Jack Palevich8df46192009-07-07 14:48:51 -0700357 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevich1cdef202009-05-22 12:06:27 -0700359 /* Store R0 to a variable.
360 * If ea <= LOCAL, then this is a local variable, or an
361 * argument, addressed relative to FP.
362 * else it is an absolute global address.
363 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700364 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700365
Jack Palevich1cdef202009-05-22 12:06:27 -0700366 /* load R0 from a variable.
367 * If ea <= LOCAL, then this is a local variable, or an
368 * argument, addressed relative to FP.
369 * else it is an absolute global address.
370 * If isIncDec is true, then the stored variable's value
371 * should be post-incremented or post-decremented, based
372 * on the value of op.
373 */
Jack Palevich8df46192009-07-07 14:48:51 -0700374 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
375
376 /**
377 * Convert R0 to the given type.
378 */
379 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700380
Jack Palevich1cdef202009-05-22 12:06:27 -0700381 /* Emit code to adjust the stack for a function call. Return the
382 * label for the address of the instruction that adjusts the
383 * stack size. This will be passed as argument "a" to
384 * endFunctionCallArguments.
385 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700386 virtual int beginFunctionCallArguments() = 0;
387
Jack Palevich1cdef202009-05-22 12:06:27 -0700388 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700389 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700391 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700392
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 /* Patch the function call preamble.
394 * a is the address returned from beginFunctionCallArguments
395 * l is the number of bytes the arguments took on the stack.
396 * Typically you would also emit code to convert the argument
397 * list into whatever the native function calling convention is.
398 * On ARM for example you would pop the first 5 arguments into
399 * R0..R4
400 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700401 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700402
Jack Palevich1cdef202009-05-22 12:06:27 -0700403 /* Emit a call to an unknown function. The argument "symbol" needs to
404 * be stored in the location where the address should go. It forms
405 * a chain. The address will be patched later.
406 * Return the address of the word that has to be patched.
407 */
Jack Palevich8df46192009-07-07 14:48:51 -0700408 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 /* Call a function using PC-relative addressing. t is the PC-relative
411 * address of the function. It has already been adjusted for the
412 * architectural jump offset, so just store it as-is.
413 */
Jack Palevich8df46192009-07-07 14:48:51 -0700414 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700415
Jack Palevich1cdef202009-05-22 12:06:27 -0700416 /* Call a function pointer. L is the number of bytes the arguments
417 * take on the stack. The address of the function is stored at
418 * location SP + l.
419 */
Jack Palevich8df46192009-07-07 14:48:51 -0700420 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700421
Jack Palevich1cdef202009-05-22 12:06:27 -0700422 /* Adjust SP after returning from a function call. l is the
423 * number of bytes of arguments stored on the stack. isIndirect
424 * is true if this was an indirect call. (In which case the
425 * address of the function is stored at location SP + l.)
426 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700427 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700428
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 /* Print a disassembly of the assembled code to out. Return
430 * non-zero if there is an error.
431 */
Jack Palevicha6535612009-05-13 16:24:17 -0700432 virtual int disassemble(FILE* out) = 0;
433
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 /* Generate a symbol at the current PC. t is the head of a
435 * linked list of addresses to patch.
436 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700437 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700438
Jack Palevich1cdef202009-05-22 12:06:27 -0700439 /*
440 * Do any cleanup work required at the end of a compile.
441 * For example, an instruction cache might need to be
442 * invalidated.
443 * Return non-zero if there is an error.
444 */
445 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700446
Jack Palevicha6535612009-05-13 16:24:17 -0700447 /**
448 * Adjust relative branches by this amount.
449 */
450 virtual int jumpOffset() = 0;
451
Jack Palevich9eed7a22009-07-06 17:24:34 -0700452 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700453 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700454 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700455 virtual size_t alignment(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700456
457 /**
458 * Array element alignment (in bytes) for this type of data.
459 */
460 virtual size_t sizeOf(Type* type) = 0;
461
Jack Palevich9cbd2262009-07-08 16:48:41 -0700462 /**
463 * Stack argument size of this data type.
464 */
465 virtual size_t stackSizeOf(Type* pType) = 0;
466
Jack Palevich1a539db2009-07-08 13:04:41 -0700467 virtual Type* getR0Type() {
468 return mExpressionStack.back();
469 }
470
Jack Palevich21a15a22009-05-11 14:49:29 -0700471 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700472 /*
473 * Output a byte. Handles all values, 0..ff.
474 */
475 void ob(int n) {
476 pCodeBuf->ob(n);
477 }
478
Jack Palevich8b0624c2009-05-20 12:12:06 -0700479 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700480 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700481 }
482
Jack Palevich8b0624c2009-05-20 12:12:06 -0700483 intptr_t getBase() {
484 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700485 }
486
Jack Palevich8b0624c2009-05-20 12:12:06 -0700487 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700488 return pCodeBuf->getPC();
489 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700490
491 intptr_t getSize() {
492 return pCodeBuf->getSize();
493 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700494
495 void error(const char* fmt,...) {
496 va_list ap;
497 va_start(ap, fmt);
498 mErrorSink->verror(fmt, ap);
499 va_end(ap);
500 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700501
502 void assert(bool test) {
503 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700504 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700505 error("code generator assertion failed.");
506 }
507 }
Jack Palevich8df46192009-07-07 14:48:51 -0700508
509 void setR0Type(Type* pType) {
510 mExpressionStack.back() = pType;
511 }
512
Jack Palevich8df46192009-07-07 14:48:51 -0700513 Type* getTOSType() {
514 return mExpressionStack[mExpressionStack.size()-2];
515 }
516
517 void pushType() {
518 mExpressionStack.push_back(NULL);
519 }
520
521 void popType() {
522 mExpressionStack.pop_back();
523 }
524
525 bool bitsSame(Type* pA, Type* pB) {
526 return collapseType(pA->tag) == collapseType(pB->tag);
527 }
528
529 TypeTag collapseType(TypeTag tag) {
530 static const TypeTag collapsedTag[] = {
531 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
532 TY_VOID, TY_VOID};
533 return collapsedTag[tag];
534 }
535
Jack Palevich1a539db2009-07-08 13:04:41 -0700536 TypeTag collapseTypeR0() {
537 return collapseType(getR0Type()->tag);
538 }
539
540 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700541 return isFloatTag(pType->tag);
542 }
543
544 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700545 return tag == TY_FLOAT || tag == TY_DOUBLE;
546 }
547
Jack Palevich21a15a22009-05-11 14:49:29 -0700548 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700549 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700550 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700551 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700552 };
553
Jack Paleviche7b59062009-05-19 17:12:17 -0700554#ifdef PROVIDE_ARM_CODEGEN
555
Jack Palevich22305132009-05-13 10:58:45 -0700556 class ARMCodeGenerator : public CodeGenerator {
557 public:
558 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700559
Jack Palevich22305132009-05-13 10:58:45 -0700560 virtual ~ARMCodeGenerator() {}
561
562 /* returns address to patch with local variable size
563 */
Jack Palevich546b2242009-05-13 15:10:04 -0700564 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700565 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700566 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700567 // sp -> arg4 arg5 ...
568 // Push our register-based arguments back on the stack
569 if (argCount > 0) {
570 int regArgCount = argCount <= 4 ? argCount : 4;
571 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700572 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700573 }
574 // sp -> arg0 arg1 ...
575 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700576 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700577 // sp, fp -> oldfp, retadr, arg0 arg1 ....
578 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700579 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700580 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700581 // We don't know how many local variables we are going to use,
582 // but we will round the allocation up to a multiple of
583 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700584 }
585
Jack Palevich546b2242009-05-13 15:10:04 -0700586 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700587 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700588 // Round local variable size up to a multiple of stack alignment
589 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
590 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700591 // Patch local variable allocation code:
592 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700593 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700594 }
Jack Palevich69796b62009-05-14 15:42:26 -0700595 *(char*) (localVariableAddress) = localVariableSize;
596
597 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
598 o4(0xE1A0E00B); // mov lr, fp
599 o4(0xE59BB000); // ldr fp, [fp]
600 o4(0xE28ED004); // add sp, lr, #4
601 // sp -> retadr, arg0, ...
602 o4(0xE8BD4000); // ldmfd sp!, {lr}
603 // sp -> arg0 ....
604 if (argCount > 0) {
605 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700606 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700607 // earlier. We don't need to actually store them anywhere,
608 // just adjust the stack.
609 int regArgCount = argCount <= 4 ? argCount : 4;
610 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
611 }
612 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700613 }
614
615 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700616 virtual void li(int t, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700617 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700618 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700619 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700620 } else if (t >= -256 && t < 0) {
621 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700622 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700623 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700624 o4(0xE51F0000); // ldr r0, .L3
625 o4(0xEA000000); // b .L99
626 o4(t); // .L3: .word 0
627 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700628 }
Jack Palevich8df46192009-07-07 14:48:51 -0700629 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700630 }
631
Jack Palevich1a539db2009-07-08 13:04:41 -0700632 virtual void loadFloat(int address, Type* pType) {
633 error("Unimplemented.\n");
Jack Palevich8df46192009-07-07 14:48:51 -0700634 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700635 }
636
Jack Palevich22305132009-05-13 10:58:45 -0700637 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700638 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700639 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700640 }
641
642 /* l = 0: je, l == 1: jne */
643 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700644 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700645 o4(0xE3500000); // cmp r0,#0
646 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
647 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700648 }
649
650 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700651 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700652 o4(0xE8BD0002); // ldmfd sp!,{r1}
653 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700654 o4(0xE1510000); // cmp r1, r1
655 switch(op) {
656 case OP_EQUALS:
657 o4(0x03A00001); // moveq r0,#1
658 o4(0x13A00000); // movne r0,#0
659 break;
660 case OP_NOT_EQUALS:
661 o4(0x03A00000); // moveq r0,#0
662 o4(0x13A00001); // movne r0,#1
663 break;
664 case OP_LESS_EQUAL:
665 o4(0xD3A00001); // movle r0,#1
666 o4(0xC3A00000); // movgt r0,#0
667 break;
668 case OP_GREATER:
669 o4(0xD3A00000); // movle r0,#0
670 o4(0xC3A00001); // movgt r0,#1
671 break;
672 case OP_GREATER_EQUAL:
673 o4(0xA3A00001); // movge r0,#1
674 o4(0xB3A00000); // movlt r0,#0
675 break;
676 case OP_LESS:
677 o4(0xA3A00000); // movge r0,#0
678 o4(0xB3A00001); // movlt r0,#1
679 break;
680 default:
681 error("Unknown comparison op %d", op);
682 break;
683 }
Jack Palevich8df46192009-07-07 14:48:51 -0700684 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700685 }
686
Jack Palevich546b2242009-05-13 15:10:04 -0700687 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700688 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700689 o4(0xE8BD0002); // ldmfd sp!,{r1}
690 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700691 switch(op) {
692 case OP_MUL:
693 o4(0x0E0000091); // mul r0,r1,r0
694 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700695 case OP_DIV:
696 callRuntime(runtime_DIV);
697 break;
698 case OP_MOD:
699 callRuntime(runtime_MOD);
700 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700701 case OP_PLUS:
702 o4(0xE0810000); // add r0,r1,r0
703 break;
704 case OP_MINUS:
705 o4(0xE0410000); // sub r0,r1,r0
706 break;
707 case OP_SHIFT_LEFT:
708 o4(0xE1A00011); // lsl r0,r1,r0
709 break;
710 case OP_SHIFT_RIGHT:
711 o4(0xE1A00051); // asr r0,r1,r0
712 break;
713 case OP_BIT_AND:
714 o4(0xE0010000); // and r0,r1,r0
715 break;
716 case OP_BIT_XOR:
717 o4(0xE0210000); // eor r0,r1,r0
718 break;
719 case OP_BIT_OR:
720 o4(0xE1810000); // orr r0,r1,r0
721 break;
722 case OP_BIT_NOT:
723 o4(0xE1E00000); // mvn r0, r0
724 break;
725 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700726 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700727 break;
728 }
Jack Palevich8df46192009-07-07 14:48:51 -0700729 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700730 }
731
Jack Palevich9eed7a22009-07-06 17:24:34 -0700732 virtual void gUnaryCmp(int op) {
733 LOG_API("gcmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700734 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700735 o4(0xE1510000); // cmp r1, r1
736 switch(op) {
737 case OP_NOT_EQUALS:
738 o4(0x03A00000); // moveq r0,#0
739 o4(0x13A00001); // movne r0,#1
740 break;
741 default:
742 error("Unknown unary comparison op %d", op);
743 break;
744 }
745 }
746
747 virtual void genUnaryOp(int op) {
748 LOG_API("genOp(%d);\n", op);
749 switch(op) {
750 case OP_PLUS:
751 // Do nothing
752 break;
753 case OP_MINUS:
754 o4(0xE3A01000); // mov r1, #0
755 o4(0xE0410000); // sub r0,r1,r0
756 break;
757 case OP_BIT_NOT:
758 o4(0xE1E00000); // mvn r0, r0
759 break;
760 default:
761 error("Unknown unary op %d\n", op);
762 break;
763 }
Jack Palevich22305132009-05-13 10:58:45 -0700764 }
765
Jack Palevich1cdef202009-05-22 12:06:27 -0700766 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700767 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700768 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700769 mStackUse += 4;
Jack Palevich8df46192009-07-07 14:48:51 -0700770 pushType();
-b master422972c2009-06-17 19:13:52 -0700771 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700772 }
773
Jack Palevich9eed7a22009-07-06 17:24:34 -0700774 virtual void storeR0ToTOS(Type* pPointerType) {
775 LOG_API("storeR0ToTOS(%d);\n", isInt);
776 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700777 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700778 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700779 switch (pPointerType->pHead->tag) {
780 case TY_INT:
781 o4(0xE5810000); // str r0, [r1]
782 break;
783 case TY_CHAR:
784 o4(0xE5C10000); // strb r0, [r1]
785 break;
786 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700787 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700788 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700789 }
Jack Palevich8df46192009-07-07 14:48:51 -0700790 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700791 }
792
Jack Palevich9eed7a22009-07-06 17:24:34 -0700793 virtual void loadR0FromR0(Type* pPointerType) {
794 LOG_API("loadR0FromR0(%d);\n", pPointerType);
795 assert(pPointerType->tag == TY_POINTER);
796 switch (pPointerType->pHead->tag) {
797 case TY_INT:
798 o4(0xE5900000); // ldr r0, [r0]
799 break;
800 case TY_CHAR:
801 o4(0xE5D00000); // ldrb r0, [r0]
802 break;
803 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700804 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700805 break;
806 }
Jack Palevich8df46192009-07-07 14:48:51 -0700807 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -0700808 }
809
Jack Palevich8df46192009-07-07 14:48:51 -0700810 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700811 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700812 if (ea < LOCAL) {
813 // Local, fp relative
814 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
815 error("Offset out of range: %08x", ea);
816 }
817 if (ea < 0) {
818 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
819 } else {
820 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
821 }
Jack Palevichbd894902009-05-14 19:35:31 -0700822 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700823 // Global, absolute.
824 o4(0xE59F0000); // ldr r0, .L1
825 o4(0xEA000000); // b .L99
826 o4(ea); // .L1: .word 0
827 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700828 }
Jack Palevich8df46192009-07-07 14:48:51 -0700829 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -0700830 }
831
Jack Palevich9cbd2262009-07-08 16:48:41 -0700832 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700833 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700834 if (ea < LOCAL) {
835 // Local, fp relative
836 if (ea < -4095 || ea > 4095) {
837 error("Offset out of range: %08x", ea);
838 }
839 if (ea < 0) {
840 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
841 } else {
842 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
843 }
844 } else{
845 // Global, absolute
846 o4(0xE59F1000); // ldr r1, .L1
847 o4(0xEA000000); // b .L99
848 o4(ea); // .L1: .word 0
849 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700850 }
Jack Palevich22305132009-05-13 10:58:45 -0700851 }
852
Jack Palevich8df46192009-07-07 14:48:51 -0700853 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700854 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich4d93f302009-05-15 13:30:00 -0700855 if (ea < LOCAL) {
856 // Local, fp relative
857 if (ea < -4095 || ea > 4095) {
858 error("Offset out of range: %08x", ea);
859 }
860 if (ea < 0) {
861 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
862 } else {
863 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
864 }
Jack Palevich69796b62009-05-14 15:42:26 -0700865 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700866 // Global, absolute
867 o4(0xE59F2000); // ldr r2, .L1
868 o4(0xEA000000); // b .L99
869 o4(ea); // .L1: .word ea
870 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700871 }
Jack Palevich22305132009-05-13 10:58:45 -0700872
Jack Palevich4d93f302009-05-15 13:30:00 -0700873 if (isIncDec) {
874 switch (op) {
875 case OP_INCREMENT:
876 o4(0xE2801001); // add r1, r0, #1
877 break;
878 case OP_DECREMENT:
879 o4(0xE2401001); // sub r1, r0, #1
880 break;
881 default:
882 error("unknown opcode: %d", op);
883 }
884 if (ea < LOCAL) {
885 // Local, fp relative
886 // Don't need range check, was already checked above
887 if (ea < 0) {
888 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
889 } else {
890 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
891 }
892 } else{
893 // Global, absolute
894 // r2 is already set up from before.
895 o4(0xE5821000); // str r1, [r2]
896 }
Jack Palevichbd894902009-05-14 19:35:31 -0700897 }
Jack Palevich8df46192009-07-07 14:48:51 -0700898 setR0Type(pType);
899 }
900
901 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -0700902 Type* pR0Type = getR0Type();
903 if (bitsSame(pType, pR0Type)) {
904 // do nothing special
905 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
906 // do nothing special, both held in same register on x87.
907 } else {
908 error("Incompatible types old: %d new: %d",
909 pR0Type->tag, pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -0700910 }
Jack Palevich1a539db2009-07-08 13:04:41 -0700911 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700912 }
913
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700914 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700915 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700916 return o4(0xE24DDF00); // Placeholder
917 }
918
Jack Palevich1a539db2009-07-08 13:04:41 -0700919 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700920 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700921 if (l < 0 || l > 4096-4) {
922 error("l out of range for stack offset: 0x%08x", l);
923 }
924 o4(0xE58D0000 + l); // str r0, [sp, #4]
Jack Palevich1a539db2009-07-08 13:04:41 -0700925 return 4;
Jack Palevich7810bc92009-05-15 14:31:47 -0700926 }
927
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700928 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700929 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700930 int argCount = l >> 2;
931 int argumentStackUse = l;
932 if (argCount > 0) {
933 int regArgCount = argCount > 4 ? 4 : argCount;
934 argumentStackUse -= regArgCount * 4;
935 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
936 }
937 mStackUse += argumentStackUse;
938
939 // Align stack.
940 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
941 * STACK_ALIGNMENT);
942 mStackAlignmentAdjustment = 0;
943 if (missalignment > 0) {
944 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
945 }
946 l += mStackAlignmentAdjustment;
947
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700948 if (l < 0 || l > 0x3FC) {
949 error("L out of range for stack adjustment: 0x%08x", l);
950 }
951 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700952 mStackUse += mStackAlignmentAdjustment;
953 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
954 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700955 }
956
Jack Palevich8df46192009-07-07 14:48:51 -0700957 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700958 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -0700959 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700960 // Forward calls are always short (local)
961 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700962 }
963
Jack Palevich8df46192009-07-07 14:48:51 -0700964 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700965 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -0700966 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700967 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700968 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700969 if (t >= - (1 << 25) && t < (1 << 25)) {
970 o4(0xEB000000 | encodeAddress(t));
971 } else {
972 // Long call.
973 o4(0xE59FC000); // ldr r12, .L1
974 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700975 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700976 o4(0xE08CC00F); // .L99: add r12,pc
977 o4(0xE12FFF3C); // blx r12
978 }
Jack Palevich22305132009-05-13 10:58:45 -0700979 }
980
Jack Palevich8df46192009-07-07 14:48:51 -0700981 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700982 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -0700983 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -0700984 int argCount = l >> 2;
985 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700986 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700987 if (adjustedL < 0 || adjustedL > 4096-4) {
988 error("l out of range for stack offset: 0x%08x", l);
989 }
990 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
991 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700992 }
993
Jack Palevich7810bc92009-05-15 14:31:47 -0700994 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700995 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700996 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700997 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700998 int stackUse = stackArgs + (isIndirect ? 1 : 0)
999 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001000 if (stackUse) {
1001 if (stackUse < 0 || stackUse > 255) {
1002 error("L out of range for stack adjustment: 0x%08x", l);
1003 }
1004 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001005 mStackUse -= stackUse * 4;
1006 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001007 }
Jack Palevich22305132009-05-13 10:58:45 -07001008 }
1009
Jack Palevicha6535612009-05-13 16:24:17 -07001010 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001011 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001012 }
1013
1014 /* output a symbol and patch all calls to it */
1015 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001016 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001017 int n;
1018 int base = getBase();
1019 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001020 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001021 while (t) {
1022 int data = * (int*) t;
1023 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1024 if (decodedOffset == 0) {
1025 n = 0;
1026 } else {
1027 n = base + decodedOffset; /* next value */
1028 }
1029 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1030 | encodeRelAddress(pc - t - 8);
1031 t = n;
1032 }
1033 }
1034
Jack Palevich1cdef202009-05-22 12:06:27 -07001035 virtual int finishCompile() {
1036#if defined(__arm__)
1037 const long base = long(getBase());
1038 const long curr = long(getPC());
1039 int err = cacheflush(base, curr, 0);
1040 return err;
1041#else
1042 return 0;
1043#endif
1044 }
1045
Jack Palevicha6535612009-05-13 16:24:17 -07001046 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001047#ifdef ENABLE_ARM_DISASSEMBLY
1048 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001049 disasm_interface_t di;
1050 di.di_readword = disassemble_readword;
1051 di.di_printaddr = disassemble_printaddr;
1052 di.di_printf = disassemble_printf;
1053
1054 int base = getBase();
1055 int pc = getPC();
1056 for(int i = base; i < pc; i += 4) {
1057 fprintf(out, "%08x: %08x ", i, *(int*) i);
1058 ::disasm(&di, i, 0);
1059 }
Jack Palevich09555c72009-05-27 12:25:55 -07001060#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001061 return 0;
1062 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001063
Jack Palevich9eed7a22009-07-06 17:24:34 -07001064 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001065 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001066 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001067 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001068 switch(pType->tag) {
1069 case TY_DOUBLE:
1070 return 8;
1071 default:
1072 return 4;
1073 }
1074 }
1075
1076 /**
1077 * Array element alignment (in bytes) for this type of data.
1078 */
1079 virtual size_t sizeOf(Type* pType){
1080 switch(pType->tag) {
1081 case TY_INT:
1082 return 4;
1083 case TY_CHAR:
1084 return 1;
1085 default:
1086 return 0;
1087 case TY_FLOAT:
1088 return 4;
1089 case TY_DOUBLE:
1090 return 8;
1091 case TY_POINTER:
1092 return 4;
1093 }
1094 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001095
1096 virtual size_t stackSizeOf(Type* pType) {
1097 switch(pType->tag) {
1098 case TY_DOUBLE:
1099 return 8;
1100 default:
1101 return 4;
1102 }
1103 }
1104
Jack Palevich22305132009-05-13 10:58:45 -07001105 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001106 static FILE* disasmOut;
1107
1108 static u_int
1109 disassemble_readword(u_int address)
1110 {
1111 return(*((u_int *)address));
1112 }
1113
1114 static void
1115 disassemble_printaddr(u_int address)
1116 {
1117 fprintf(disasmOut, "0x%08x", address);
1118 }
1119
1120 static void
1121 disassemble_printf(const char *fmt, ...) {
1122 va_list ap;
1123 va_start(ap, fmt);
1124 vfprintf(disasmOut, fmt, ap);
1125 va_end(ap);
1126 }
1127
1128 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1129
1130 /** Encode a relative address that might also be
1131 * a label.
1132 */
1133 int encodeAddress(int value) {
1134 int base = getBase();
1135 if (value >= base && value <= getPC() ) {
1136 // This is a label, encode it relative to the base.
1137 value = value - base;
1138 }
1139 return encodeRelAddress(value);
1140 }
1141
1142 int encodeRelAddress(int value) {
1143 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1144 }
Jack Palevich22305132009-05-13 10:58:45 -07001145
Jack Palevich3d474a72009-05-15 15:12:38 -07001146 typedef int (*int2FnPtr)(int a, int b);
1147 void callRuntime(int2FnPtr fn) {
1148 o4(0xE59F2000); // ldr r2, .L1
1149 o4(0xEA000000); // b .L99
1150 o4((int) fn); //.L1: .word fn
1151 o4(0xE12FFF32); //.L99: blx r2
1152 }
1153
1154 static int runtime_DIV(int a, int b) {
1155 return b / a;
1156 }
1157
1158 static int runtime_MOD(int a, int b) {
1159 return b % a;
1160 }
-b master422972c2009-06-17 19:13:52 -07001161
1162 static const int STACK_ALIGNMENT = 8;
1163 int mStackUse;
1164 // This variable holds the amount we adjusted the stack in the most
1165 // recent endFunctionCallArguments call. It's examined by the
1166 // following adjustStackAfterCall call.
1167 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001168 };
1169
Jack Palevich09555c72009-05-27 12:25:55 -07001170#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001171
1172#ifdef PROVIDE_X86_CODEGEN
1173
Jack Palevich21a15a22009-05-11 14:49:29 -07001174 class X86CodeGenerator : public CodeGenerator {
1175 public:
1176 X86CodeGenerator() {}
1177 virtual ~X86CodeGenerator() {}
1178
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001179 /* returns address to patch with local variable size
1180 */
Jack Palevich546b2242009-05-13 15:10:04 -07001181 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001182 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1183 return oad(0xec81, 0); /* sub $xxx, %esp */
1184 }
1185
Jack Palevich546b2242009-05-13 15:10:04 -07001186 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001187 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001188 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001189 }
1190
Jack Palevich21a15a22009-05-11 14:49:29 -07001191 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001192 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001193 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001194 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001195 }
1196
Jack Palevich1a539db2009-07-08 13:04:41 -07001197 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001198 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001199 switch (pType->tag) {
1200 case TY_FLOAT:
1201 oad(0x05D9, address); // flds
1202 break;
1203 case TY_DOUBLE:
1204 oad(0x05DD, address); // fldl
1205 break;
1206 default:
1207 assert(false);
1208 break;
1209 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001210 }
1211
Jack Palevich22305132009-05-13 10:58:45 -07001212 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001213 return psym(0xe9, t);
1214 }
1215
1216 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001217 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001218 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1219 return psym(0x84 + l, t);
1220 }
1221
Jack Palevich22305132009-05-13 10:58:45 -07001222 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001223 int t = decodeOp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001224 o(0x59); /* pop %ecx */
Jack Palevich21a15a22009-05-11 14:49:29 -07001225 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001226 li(0, NULL);
Jack Palevich21a15a22009-05-11 14:49:29 -07001227 o(0x0f); /* setxx %al */
1228 o(t + 0x90);
1229 o(0xc0);
Jack Palevich8df46192009-07-07 14:48:51 -07001230 popType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001231 }
1232
Jack Palevich546b2242009-05-13 15:10:04 -07001233 virtual void genOp(int op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001234 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001235 o(decodeOp(op));
1236 if (op == OP_MOD)
1237 o(0x92); /* xchg %edx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001238 popType();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001239 }
1240
Jack Palevich9eed7a22009-07-06 17:24:34 -07001241 virtual void gUnaryCmp(int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001242 oad(0xb9, 0); /* movl $0, %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001243 int t = decodeOp(op);
1244 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001245 li(0, NULL);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001246 o(0x0f); /* setxx %al */
1247 o(t + 0x90);
1248 o(0xc0);
1249 }
1250
1251 virtual void genUnaryOp(int op) {
1252 oad(0xb9, 0); /* movl $0, %ecx */
1253 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -07001254 }
1255
Jack Palevich1cdef202009-05-22 12:06:27 -07001256 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001257 Type* pR0Type = getR0Type();
1258 TypeTag r0ct = collapseType(pR0Type->tag);
1259 switch(r0ct) {
1260 case TY_INT:
1261 o(0x50); /* push %eax */
1262 break;
1263 case TY_FLOAT:
1264 o(0x50); /* push %eax */
1265 o(0x241cd9); // fstps 0(%esp)
1266 break;
1267 case TY_DOUBLE:
1268 o(0x50); /* push %eax */
1269 o(0x50); /* push %eax */
1270 o(0x241cdd); // fstpl 0(%esp)
1271 break;
1272 default:
1273 error("pushR0 %d", r0ct);
1274 break;
1275 }
Jack Palevich8df46192009-07-07 14:48:51 -07001276 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001277 }
1278
Jack Palevich9eed7a22009-07-06 17:24:34 -07001279 virtual void storeR0ToTOS(Type* pPointerType) {
1280 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001281 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001282 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001283 switch (pPointerType->pHead->tag) {
1284 case TY_INT:
1285 o(0x0189); /* movl %eax/%al, (%ecx) */
1286 break;
1287 case TY_CHAR:
1288 o(0x0188); /* movl %eax/%al, (%ecx) */
1289 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001290 case TY_FLOAT:
1291 o(0x19d9); /* fstps (%ecx) */
1292 break;
1293 case TY_DOUBLE:
1294 o(0x19dd); /* fstpl (%ecx) */
1295 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001296 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001297 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001298 break;
1299 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001300 }
1301
Jack Palevich9eed7a22009-07-06 17:24:34 -07001302 virtual void loadR0FromR0(Type* pPointerType) {
1303 assert(pPointerType->tag == TY_POINTER);
1304 switch (pPointerType->pHead->tag) {
1305 case TY_INT:
1306 o(0x8b); /* mov (%eax), %eax */
1307 break;
1308 case TY_CHAR:
1309 o(0xbe0f); /* movsbl (%eax), %eax */
1310 break;
1311 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001312 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001313 break;
1314 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001315 ob(0); /* add zero in code */
Jack Palevich8df46192009-07-07 14:48:51 -07001316 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001317 }
1318
Jack Palevich8df46192009-07-07 14:48:51 -07001319 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001320 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001321 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001322 }
1323
Jack Palevich9cbd2262009-07-08 16:48:41 -07001324 virtual void storeR0(int ea, Type* pType) {
1325 TypeTag tag = pType->tag;
1326 switch (tag) {
1327 case TY_INT:
1328 gmov(6, ea); /* mov %eax, EA */
1329 break;
1330 case TY_FLOAT:
1331 if (ea < -LOCAL || ea > LOCAL) {
1332 oad(0x1dd9, ea); // fstps ea
1333 } else {
1334 oad(0x9dd9, ea); // fstps ea(%ebp)
1335 }
1336 break;
1337 case TY_DOUBLE:
1338 if (ea < -LOCAL || ea > LOCAL) {
1339 oad(0x1ddd, ea); // fstpl ea
1340 } else {
1341 oad(0x9ddd, ea); // fstpl ea(%ebp)
1342 }
1343 break;
1344 default:
1345 error("Unable to store to type %d", tag);
1346 break;
1347 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001348 }
1349
Jack Palevich8df46192009-07-07 14:48:51 -07001350 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001351 TypeTag tag = collapseType(pType->tag);
1352 switch (tag) {
1353 case TY_INT:
1354 gmov(8, ea); /* mov EA, %eax */
1355 if (isIncDec) {
1356 /* Implement post-increment or post decrement.
1357 */
1358 gmov(0, ea); /* 83 ADD */
1359 o(decodeOp(op));
1360 }
1361 break;
1362 case TY_FLOAT:
1363 if (ea < -LOCAL || ea > LOCAL) {
1364 oad(0x05d9, ea); // flds ea
1365 } else {
1366 oad(0x85d9, ea); // flds ea(%ebp)
1367 }
1368 if (isIncDec) {
1369 error("inc/dec not implemented for float.");
1370 }
1371 break;
1372 case TY_DOUBLE:
1373 if (ea < -LOCAL || ea > LOCAL) {
1374 oad(0x05dd, ea); // fldl ea
1375 } else {
1376 oad(0x85dd, ea); // fldl ea(%ebp)
1377 }
1378 if (isIncDec) {
1379 error("inc/dec not implemented for double.");
1380 }
1381 break;
1382 default:
1383 error("Unable to load type %d", tag);
1384 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07001385 }
Jack Palevich8df46192009-07-07 14:48:51 -07001386 setR0Type(pType);
1387 }
1388
1389 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001390 Type* pR0Type = getR0Type();
1391 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001392 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07001393 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07001394 return;
1395 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001396 if (bitsSame(pType, pR0Type)) {
1397 // do nothing special
1398 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
1399 // do nothing special, both held in same register on x87.
1400 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001401 TypeTag r0Tag = collapseType(pR0Type->tag);
1402 TypeTag destTag = collapseType(pType->tag);
1403 if (r0Tag == TY_INT && isFloatTag(destTag)) {
1404 // Convert R0 from int to float
1405 o(0x50); // push %eax
1406 o(0x2404DB); // fildl 0(%esp)
1407 o(0x58); // pop %eax
1408 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
1409 // Convert R0 from float to int. Complicated because
1410 // need to save and restore the rounding mode.
1411 o(0x50); // push %eax
1412 o(0x50); // push %eax
1413 o(0x02247cD9); // fnstcw 2(%esp)
1414 o(0x2444b70f); // movzwl 2(%esp), %eax
1415 o(0x02);
1416 o(0x0cb4); // movb $12, %ah
1417 o(0x24048966); // movw %ax, 0(%esp)
1418 o(0x242cd9); // fldcw 0(%esp)
1419 o(0x04245cdb); // fistpl 4(%esp)
1420 o(0x02246cd9); // fldcw 2(%esp)
1421 o(0x58); // pop %eax
1422 o(0x58); // pop %eax
1423 } else {
1424 error("Incompatible types old: %d new: %d",
1425 pR0Type->tag, pType->tag);
1426 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001427 }
1428 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001429 }
1430
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001431 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001432 return oad(0xec81, 0); /* sub $xxx, %esp */
1433 }
1434
Jack Palevich1a539db2009-07-08 13:04:41 -07001435 virtual size_t storeR0ToArg(int l) {
1436 Type* pR0Type = getR0Type();
1437 TypeTag r0ct = collapseType(pR0Type->tag);
1438 switch(r0ct) {
1439 case TY_INT:
1440 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1441 return 4;
1442 case TY_FLOAT:
1443 oad(0x249CD9, l); /* fstps xxx(%esp) */
1444 return 4;
1445 case TY_DOUBLE:
1446 oad(0x249CDD, l); /* fstpl xxx(%esp) */
1447 return 8;
1448 default:
1449 assert(false);
1450 return 0;
1451 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001452 }
1453
Jack Palevich7810bc92009-05-15 14:31:47 -07001454 virtual void endFunctionCallArguments(int a, int l) {
1455 * (int*) a = l;
1456 }
1457
Jack Palevich8df46192009-07-07 14:48:51 -07001458 virtual int callForward(int symbol, Type* pFunc) {
1459 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001460 return psym(0xe8, symbol); /* call xxx */
1461 }
1462
Jack Palevich8df46192009-07-07 14:48:51 -07001463 virtual void callRelative(int t, Type* pFunc) {
1464 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001465 psym(0xe8, t); /* call xxx */
1466 }
1467
Jack Palevich8df46192009-07-07 14:48:51 -07001468 virtual void callIndirect(int l, Type* pFunc) {
1469 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001470 oad(0x2494ff, l); /* call *xxx(%esp) */
1471 }
1472
Jack Palevich7810bc92009-05-15 14:31:47 -07001473 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1474 if (isIndirect) {
1475 l += 4;
1476 }
-b master422972c2009-06-17 19:13:52 -07001477 if (l > 0) {
1478 oad(0xc481, l); /* add $xxx, %esp */
1479 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001480 }
1481
Jack Palevicha6535612009-05-13 16:24:17 -07001482 virtual int jumpOffset() {
1483 return 5;
1484 }
1485
1486 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001487 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001488 }
1489
Jack Paleviche7b59062009-05-19 17:12:17 -07001490 /* output a symbol and patch all calls to it */
1491 virtual void gsym(int t) {
1492 int n;
1493 int pc = getPC();
1494 while (t) {
1495 n = *(int *) t; /* next value */
1496 *(int *) t = pc - t - 4;
1497 t = n;
1498 }
1499 }
1500
Jack Palevich1cdef202009-05-22 12:06:27 -07001501 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001502 size_t pagesize = 4096;
1503 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1504 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1505 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1506 if (err) {
1507 error("mprotect() failed: %d", errno);
1508 }
1509 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001510 }
1511
Jack Palevich9eed7a22009-07-06 17:24:34 -07001512 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001513 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001514 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001515 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001516 switch(pType->tag) {
1517 case TY_DOUBLE:
1518 return 8;
1519 default:
1520 return 4;
1521 }
1522 }
1523
1524 /**
1525 * Array element alignment (in bytes) for this type of data.
1526 */
1527 virtual size_t sizeOf(Type* pType){
1528 switch(pType->tag) {
1529 case TY_INT:
1530 return 4;
1531 case TY_CHAR:
1532 return 1;
1533 default:
1534 return 0;
1535 case TY_FLOAT:
1536 return 4;
1537 case TY_DOUBLE:
1538 return 8;
1539 case TY_POINTER:
1540 return 4;
1541 }
1542 }
1543
Jack Palevich9cbd2262009-07-08 16:48:41 -07001544 virtual size_t stackSizeOf(Type* pType) {
1545 switch(pType->tag) {
1546 case TY_DOUBLE:
1547 return 8;
1548 default:
1549 return 4;
1550 }
1551 }
1552
Jack Palevich21a15a22009-05-11 14:49:29 -07001553 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001554
1555 /** Output 1 to 4 bytes.
1556 *
1557 */
1558 void o(int n) {
1559 /* cannot use unsigned, so we must do a hack */
1560 while (n && n != -1) {
1561 ob(n & 0xff);
1562 n = n >> 8;
1563 }
1564 }
1565
1566 /* psym is used to put an instruction with a data field which is a
1567 reference to a symbol. It is in fact the same as oad ! */
1568 int psym(int n, int t) {
1569 return oad(n, t);
1570 }
1571
1572 /* instruction + address */
1573 int oad(int n, int t) {
1574 o(n);
1575 int result = getPC();
1576 o4(t);
1577 return result;
1578 }
1579
1580
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001581 static const int operatorHelper[];
1582
1583 int decodeOp(int op) {
1584 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001585 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001586 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001587 }
1588 return operatorHelper[op];
1589 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001590
Jack Palevich546b2242009-05-13 15:10:04 -07001591 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001592 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001593 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001594 }
1595 };
1596
Jack Paleviche7b59062009-05-19 17:12:17 -07001597#endif // PROVIDE_X86_CODEGEN
1598
Jack Palevichb67b18f2009-06-11 21:12:23 -07001599#ifdef PROVIDE_TRACE_CODEGEN
1600 class TraceCodeGenerator : public CodeGenerator {
1601 private:
1602 CodeGenerator* mpBase;
1603
1604 public:
1605 TraceCodeGenerator(CodeGenerator* pBase) {
1606 mpBase = pBase;
1607 }
1608
1609 virtual ~TraceCodeGenerator() {
1610 delete mpBase;
1611 }
1612
1613 virtual void init(CodeBuf* pCodeBuf) {
1614 mpBase->init(pCodeBuf);
1615 }
1616
1617 void setErrorSink(ErrorSink* pErrorSink) {
1618 mpBase->setErrorSink(pErrorSink);
1619 }
1620
1621 /* returns address to patch with local variable size
1622 */
1623 virtual int functionEntry(int argCount) {
1624 int result = mpBase->functionEntry(argCount);
1625 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1626 return result;
1627 }
1628
1629 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1630 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1631 argCount, localVariableAddress, localVariableSize);
1632 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1633 }
1634
1635 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001636 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001637 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001638 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001639 }
1640
Jack Palevich1a539db2009-07-08 13:04:41 -07001641 virtual void loadFloat(int address, Type* pType) {
1642 fprintf(stderr, "loadFloat(%d, type)\n", address);
1643 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001644 }
1645
Jack Palevichb67b18f2009-06-11 21:12:23 -07001646 virtual int gjmp(int t) {
1647 int result = mpBase->gjmp(t);
1648 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1649 return result;
1650 }
1651
1652 /* l = 0: je, l == 1: jne */
1653 virtual int gtst(bool l, int t) {
1654 int result = mpBase->gtst(l, t);
1655 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1656 return result;
1657 }
1658
1659 virtual void gcmp(int op) {
1660 fprintf(stderr, "gcmp(%d)\n", op);
1661 mpBase->gcmp(op);
1662 }
1663
1664 virtual void genOp(int op) {
1665 fprintf(stderr, "genOp(%d)\n", op);
1666 mpBase->genOp(op);
1667 }
1668
Jack Palevich9eed7a22009-07-06 17:24:34 -07001669
1670 virtual void gUnaryCmp(int op) {
1671 fprintf(stderr, "gUnaryCmp(%d)\n", op);
1672 mpBase->gUnaryCmp(op);
1673 }
1674
1675 virtual void genUnaryOp(int op) {
1676 fprintf(stderr, "genUnaryOp(%d)\n", op);
1677 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001678 }
1679
1680 virtual void pushR0() {
1681 fprintf(stderr, "pushR0()\n");
1682 mpBase->pushR0();
1683 }
1684
Jack Palevich9eed7a22009-07-06 17:24:34 -07001685 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001686 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001687 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001688 }
1689
Jack Palevich9eed7a22009-07-06 17:24:34 -07001690 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001691 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001692 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001693 }
1694
Jack Palevich8df46192009-07-07 14:48:51 -07001695 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001696 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001697 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001698 }
1699
Jack Palevich9cbd2262009-07-08 16:48:41 -07001700 virtual void storeR0(int ea, Type* pType) {
1701 fprintf(stderr, "storeR0(%d, pType)\n", ea);
1702 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001703 }
1704
Jack Palevich8df46192009-07-07 14:48:51 -07001705 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001706 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001707 mpBase->loadR0(ea, isIncDec, op, pType);
1708 }
1709
1710 virtual void convertR0(Type* pType){
1711 fprintf(stderr, "convertR0(pType)\n");
1712 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001713 }
1714
1715 virtual int beginFunctionCallArguments() {
1716 int result = mpBase->beginFunctionCallArguments();
1717 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1718 return result;
1719 }
1720
Jack Palevich1a539db2009-07-08 13:04:41 -07001721 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001722 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07001723 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001724 }
1725
1726 virtual void endFunctionCallArguments(int a, int l) {
1727 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1728 mpBase->endFunctionCallArguments(a, l);
1729 }
1730
Jack Palevich8df46192009-07-07 14:48:51 -07001731 virtual int callForward(int symbol, Type* pFunc) {
1732 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001733 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1734 return result;
1735 }
1736
Jack Palevich8df46192009-07-07 14:48:51 -07001737 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001738 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001739 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001740 }
1741
Jack Palevich8df46192009-07-07 14:48:51 -07001742 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001743 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001744 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001745 }
1746
1747 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1748 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1749 mpBase->adjustStackAfterCall(l, isIndirect);
1750 }
1751
1752 virtual int jumpOffset() {
1753 return mpBase->jumpOffset();
1754 }
1755
1756 virtual int disassemble(FILE* out) {
1757 return mpBase->disassemble(out);
1758 }
1759
1760 /* output a symbol and patch all calls to it */
1761 virtual void gsym(int t) {
1762 fprintf(stderr, "gsym(%d)\n", t);
1763 mpBase->gsym(t);
1764 }
1765
1766 virtual int finishCompile() {
1767 int result = mpBase->finishCompile();
1768 fprintf(stderr, "finishCompile() = %d\n", result);
1769 return result;
1770 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001771
1772 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001773 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001774 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001775 virtual size_t alignment(Type* pType){
1776 return mpBase->alignment(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001777 }
1778
1779 /**
1780 * Array element alignment (in bytes) for this type of data.
1781 */
1782 virtual size_t sizeOf(Type* pType){
1783 return mpBase->sizeOf(pType);
1784 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001785
Jack Palevich9cbd2262009-07-08 16:48:41 -07001786
1787 virtual size_t stackSizeOf(Type* pType) {
1788 return mpBase->stackSizeOf(pType);
1789 }
1790
1791
Jack Palevich1a539db2009-07-08 13:04:41 -07001792 virtual Type* getR0Type() {
1793 return mpBase->getR0Type();
1794 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001795 };
1796
1797#endif // PROVIDE_TRACE_CODEGEN
1798
Jack Palevich569f1352009-06-29 14:29:08 -07001799 class Arena {
1800 public:
1801 // Used to record a given allocation amount.
1802 // Used:
1803 // Mark mark = arena.mark();
1804 // ... lots of arena.allocate()
1805 // arena.free(mark);
1806
1807 struct Mark {
1808 size_t chunk;
1809 size_t offset;
1810 };
1811
1812 Arena() {
1813 mCurrentChunk = 0;
1814 Chunk start(CHUNK_SIZE);
1815 mData.push_back(start);
1816 }
1817
1818 ~Arena() {
1819 for(size_t i = 0; i < mData.size(); i++) {
1820 mData[i].free();
1821 }
1822 }
1823
1824 // Alloc using the standard alignment size safe for any variable
1825 void* alloc(size_t size) {
1826 return alloc(size, 8);
1827 }
1828
1829 Mark mark(){
1830 Mark result;
1831 result.chunk = mCurrentChunk;
1832 result.offset = mData[mCurrentChunk].mOffset;
1833 return result;
1834 }
1835
1836 void freeToMark(const Mark& mark) {
1837 mCurrentChunk = mark.chunk;
1838 mData[mCurrentChunk].mOffset = mark.offset;
1839 }
1840
1841 private:
1842 // Allocate memory aligned to a given size
1843 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1844 // Memory is not zero filled.
1845
1846 void* alloc(size_t size, size_t alignment) {
1847 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1848 if (mCurrentChunk + 1 < mData.size()) {
1849 mCurrentChunk++;
1850 } else {
1851 size_t allocSize = CHUNK_SIZE;
1852 if (allocSize < size + alignment - 1) {
1853 allocSize = size + alignment - 1;
1854 }
1855 Chunk chunk(allocSize);
1856 mData.push_back(chunk);
1857 mCurrentChunk++;
1858 }
1859 }
1860 return mData[mCurrentChunk].allocate(size, alignment);
1861 }
1862
1863 static const size_t CHUNK_SIZE = 128*1024;
1864 // Note: this class does not deallocate its
1865 // memory when it's destroyed. It depends upon
1866 // its parent to deallocate the memory.
1867 struct Chunk {
1868 Chunk() {
1869 mpData = 0;
1870 mSize = 0;
1871 mOffset = 0;
1872 }
1873
1874 Chunk(size_t size) {
1875 mSize = size;
1876 mpData = (char*) malloc(size);
1877 mOffset = 0;
1878 }
1879
1880 ~Chunk() {
1881 // Doesn't deallocate memory.
1882 }
1883
1884 void* allocate(size_t size, size_t alignment) {
1885 size_t alignedOffset = aligned(mOffset, alignment);
1886 void* result = mpData + alignedOffset;
1887 mOffset = alignedOffset + size;
1888 return result;
1889 }
1890
1891 void free() {
1892 if (mpData) {
1893 ::free(mpData);
1894 mpData = 0;
1895 }
1896 }
1897
1898 size_t remainingCapacity(size_t alignment) {
1899 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1900 }
1901
1902 // Assume alignment is a power of two
1903 inline size_t aligned(size_t v, size_t alignment) {
1904 size_t mask = alignment-1;
1905 return (v + mask) & ~mask;
1906 }
1907
1908 char* mpData;
1909 size_t mSize;
1910 size_t mOffset;
1911 };
1912
1913 size_t mCurrentChunk;
1914
1915 Vector<Chunk> mData;
1916 };
1917
Jack Palevich569f1352009-06-29 14:29:08 -07001918 struct VariableInfo;
1919
1920 struct Token {
1921 int hash;
1922 size_t length;
1923 char* pText;
1924 tokenid_t id;
1925
1926 // Current values for the token
1927 char* mpMacroDefinition;
1928 VariableInfo* mpVariableInfo;
1929 };
1930
1931 class TokenTable {
1932 public:
1933 // Don't use 0..0xff, allows characters and operators to be tokens too.
1934
1935 static const int TOKEN_BASE = 0x100;
1936 TokenTable() {
1937 mpMap = hashmapCreate(128, hashFn, equalsFn);
1938 }
1939
1940 ~TokenTable() {
1941 hashmapFree(mpMap);
1942 }
1943
1944 void setArena(Arena* pArena) {
1945 mpArena = pArena;
1946 }
1947
1948 // Returns a token for a given string of characters.
1949 tokenid_t intern(const char* pText, size_t length) {
1950 Token probe;
1951 int hash = hashmapHash((void*) pText, length);
1952 {
1953 Token probe;
1954 probe.hash = hash;
1955 probe.length = length;
1956 probe.pText = (char*) pText;
1957 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1958 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001959 return pValue->id;
1960 }
1961 }
1962
1963 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1964 memset(pToken, 0, sizeof(*pToken));
1965 pToken->hash = hash;
1966 pToken->length = length;
1967 pToken->pText = (char*) mpArena->alloc(length + 1);
1968 memcpy(pToken->pText, pText, length);
1969 pToken->pText[length] = 0;
1970 pToken->id = mTokens.size() + TOKEN_BASE;
1971 mTokens.push_back(pToken);
1972 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001973 return pToken->id;
1974 }
1975
1976 // Return the Token for a given tokenid.
1977 Token& operator[](tokenid_t id) {
1978 return *mTokens[id - TOKEN_BASE];
1979 }
1980
1981 inline size_t size() {
1982 return mTokens.size();
1983 }
1984
1985 private:
1986
1987 static int hashFn(void* pKey) {
1988 Token* pToken = (Token*) pKey;
1989 return pToken->hash;
1990 }
1991
1992 static bool equalsFn(void* keyA, void* keyB) {
1993 Token* pTokenA = (Token*) keyA;
1994 Token* pTokenB = (Token*) keyB;
1995 // Don't need to compare hash values, they should always be equal
1996 return pTokenA->length == pTokenB->length
1997 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1998 }
1999
2000 Hashmap* mpMap;
2001 Vector<Token*> mTokens;
2002 Arena* mpArena;
2003 };
2004
Jack Palevich1cdef202009-05-22 12:06:27 -07002005 class InputStream {
2006 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002007 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002008 int getChar() {
2009 if (bumpLine) {
2010 line++;
2011 bumpLine = false;
2012 }
2013 int ch = get();
2014 if (ch == '\n') {
2015 bumpLine = true;
2016 }
2017 return ch;
2018 }
2019 int getLine() {
2020 return line;
2021 }
2022 protected:
2023 InputStream() :
2024 line(1), bumpLine(false) {
2025 }
2026 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002027 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002028 int line;
2029 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002030 };
2031
2032 class FileInputStream : public InputStream {
2033 public:
2034 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002035 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002036 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002037 FILE* f;
2038 };
2039
2040 class TextInputStream : public InputStream {
2041 public:
2042 TextInputStream(const char* text, size_t textLength)
2043 : pText(text), mTextLength(textLength), mPosition(0) {
2044 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002045
2046 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002047 virtual int get() {
2048 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2049 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002050
Jack Palevich1cdef202009-05-22 12:06:27 -07002051 const char* pText;
2052 size_t mTextLength;
2053 size_t mPosition;
2054 };
2055
Jack Palevicheedf9d22009-06-04 16:23:40 -07002056 class String {
2057 public:
2058 String() {
2059 mpBase = 0;
2060 mUsed = 0;
2061 mSize = 0;
2062 }
2063
Jack Palevich303d8ff2009-06-11 19:06:24 -07002064 String(const char* item, int len, bool adopt) {
2065 if (len < 0) {
2066 len = strlen(item);
2067 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002068 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002069 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002070 mUsed = len;
2071 mSize = len + 1;
2072 } else {
2073 mpBase = 0;
2074 mUsed = 0;
2075 mSize = 0;
2076 appendBytes(item, len);
2077 }
2078 }
2079
Jack Palevich303d8ff2009-06-11 19:06:24 -07002080 String(const String& other) {
2081 mpBase = 0;
2082 mUsed = 0;
2083 mSize = 0;
2084 appendBytes(other.getUnwrapped(), other.len());
2085 }
2086
Jack Palevicheedf9d22009-06-04 16:23:40 -07002087 ~String() {
2088 if (mpBase) {
2089 free(mpBase);
2090 }
2091 }
2092
Jack Palevicha6baa232009-06-12 11:25:59 -07002093 String& operator=(const String& other) {
2094 clear();
2095 appendBytes(other.getUnwrapped(), other.len());
2096 return *this;
2097 }
2098
Jack Palevich303d8ff2009-06-11 19:06:24 -07002099 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002100 return mpBase;
2101 }
2102
Jack Palevich303d8ff2009-06-11 19:06:24 -07002103 void clear() {
2104 mUsed = 0;
2105 if (mSize > 0) {
2106 mpBase[0] = 0;
2107 }
2108 }
2109
Jack Palevicheedf9d22009-06-04 16:23:40 -07002110 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002111 appendBytes(s, strlen(s));
2112 }
2113
2114 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002115 memcpy(ensure(n), s, n + 1);
2116 }
2117
2118 void append(char c) {
2119 * ensure(1) = c;
2120 }
2121
Jack Palevich86351982009-06-30 18:09:56 -07002122 void append(String& other) {
2123 appendBytes(other.getUnwrapped(), other.len());
2124 }
2125
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002126 char* orphan() {
2127 char* result = mpBase;
2128 mpBase = 0;
2129 mUsed = 0;
2130 mSize = 0;
2131 return result;
2132 }
2133
Jack Palevicheedf9d22009-06-04 16:23:40 -07002134 void printf(const char* fmt,...) {
2135 va_list ap;
2136 va_start(ap, fmt);
2137 vprintf(fmt, ap);
2138 va_end(ap);
2139 }
2140
2141 void vprintf(const char* fmt, va_list ap) {
2142 char* temp;
2143 int numChars = vasprintf(&temp, fmt, ap);
2144 memcpy(ensure(numChars), temp, numChars+1);
2145 free(temp);
2146 }
2147
Jack Palevich303d8ff2009-06-11 19:06:24 -07002148 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002149 return mUsed;
2150 }
2151
2152 private:
2153 char* ensure(int n) {
2154 size_t newUsed = mUsed + n;
2155 if (newUsed > mSize) {
2156 size_t newSize = mSize * 2 + 10;
2157 if (newSize < newUsed) {
2158 newSize = newUsed;
2159 }
2160 mpBase = (char*) realloc(mpBase, newSize + 1);
2161 mSize = newSize;
2162 }
2163 mpBase[newUsed] = '\0';
2164 char* result = mpBase + mUsed;
2165 mUsed = newUsed;
2166 return result;
2167 }
2168
2169 char* mpBase;
2170 size_t mUsed;
2171 size_t mSize;
2172 };
2173
Jack Palevich569f1352009-06-29 14:29:08 -07002174 void internKeywords() {
2175 // Note: order has to match TOK_ constants
2176 static const char* keywords[] = {
2177 "int",
2178 "char",
2179 "void",
2180 "if",
2181 "else",
2182 "while",
2183 "break",
2184 "return",
2185 "for",
2186 "pragma",
2187 "define",
2188 "auto",
2189 "case",
2190 "const",
2191 "continue",
2192 "default",
2193 "do",
2194 "double",
2195 "enum",
2196 "extern",
2197 "float",
2198 "goto",
2199 "long",
2200 "register",
2201 "short",
2202 "signed",
2203 "sizeof",
2204 "static",
2205 "struct",
2206 "switch",
2207 "typedef",
2208 "union",
2209 "unsigned",
2210 "volatile",
2211 "_Bool",
2212 "_Complex",
2213 "_Imaginary",
2214 "inline",
2215 "restrict",
2216 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002217
Jack Palevich569f1352009-06-29 14:29:08 -07002218 for(int i = 0; keywords[i]; i++) {
2219 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002220 }
Jack Palevich569f1352009-06-29 14:29:08 -07002221 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002222
Jack Palevich36d94142009-06-08 15:55:32 -07002223 struct InputState {
2224 InputStream* pStream;
2225 int oldCh;
2226 };
2227
Jack Palevich2db168f2009-06-11 14:29:47 -07002228 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002229 void* pAddress;
2230 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002231 tokenid_t tok;
2232 size_t level;
2233 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002234 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002235 };
2236
Jack Palevich303d8ff2009-06-11 19:06:24 -07002237 class SymbolStack {
2238 public:
2239 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002240 mpArena = 0;
2241 mpTokenTable = 0;
2242 }
2243
2244 void setArena(Arena* pArena) {
2245 mpArena = pArena;
2246 }
2247
2248 void setTokenTable(TokenTable* pTokenTable) {
2249 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002250 }
2251
2252 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002253 Mark mark;
2254 mark.mArenaMark = mpArena->mark();
2255 mark.mSymbolHead = mStack.size();
2256 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002257 }
2258
2259 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002260 // Undo any shadowing that was done:
2261 Mark mark = mLevelStack.back();
2262 mLevelStack.pop_back();
2263 while (mStack.size() > mark.mSymbolHead) {
2264 VariableInfo* pV = mStack.back();
2265 mStack.pop_back();
2266 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002267 }
Jack Palevich569f1352009-06-29 14:29:08 -07002268 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002269 }
2270
Jack Palevich569f1352009-06-29 14:29:08 -07002271 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2272 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2273 return pV && pV->level == level();
2274 }
2275
2276 VariableInfo* add(tokenid_t tok) {
2277 Token& token = (*mpTokenTable)[tok];
2278 VariableInfo* pOldV = token.mpVariableInfo;
2279 VariableInfo* pNewV =
2280 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2281 memset(pNewV, 0, sizeof(VariableInfo));
2282 pNewV->tok = tok;
2283 pNewV->level = level();
2284 pNewV->pOldDefinition = pOldV;
2285 token.mpVariableInfo = pNewV;
2286 mStack.push_back(pNewV);
2287 return pNewV;
2288 }
2289
Jack Palevich86351982009-06-30 18:09:56 -07002290 VariableInfo* add(Type* pType) {
2291 VariableInfo* pVI = add(pType->id);
2292 pVI->pType = pType;
2293 return pVI;
2294 }
2295
Jack Palevich569f1352009-06-29 14:29:08 -07002296 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2297 for (size_t i = 0; i < mStack.size(); i++) {
2298 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002299 break;
2300 }
2301 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002302 }
2303
Jack Palevich303d8ff2009-06-11 19:06:24 -07002304 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002305 inline size_t level() {
2306 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002307 }
2308
Jack Palevich569f1352009-06-29 14:29:08 -07002309 struct Mark {
2310 Arena::Mark mArenaMark;
2311 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002312 };
2313
Jack Palevich569f1352009-06-29 14:29:08 -07002314 Arena* mpArena;
2315 TokenTable* mpTokenTable;
2316 Vector<VariableInfo*> mStack;
2317 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002318 };
Jack Palevich36d94142009-06-08 15:55:32 -07002319
2320 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002321 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002322 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002323 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002324 int tokl; // token operator level
2325 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002326 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002327 intptr_t loc; // local variable index
2328 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002329 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002330 char* dptr; // Macro state: Points to macro text during macro playback.
2331 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002332 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002333
2334 // Arena for the duration of the compile
2335 Arena mGlobalArena;
2336 // Arena for data that's only needed when compiling a single function
2337 Arena mLocalArena;
2338
2339 TokenTable mTokenTable;
2340 SymbolStack mGlobals;
2341 SymbolStack mLocals;
2342
Jack Palevich40600de2009-07-01 15:32:35 -07002343 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002344 Type* mkpInt; // int
2345 Type* mkpChar; // char
2346 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002347 Type* mkpFloat;
2348 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002349 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002350 Type* mkpIntPtr;
2351 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07002352 Type* mkpFloatPtr;
2353 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07002354 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002355
Jack Palevich36d94142009-06-08 15:55:32 -07002356 InputStream* file;
2357
2358 CodeBuf codeBuf;
2359 CodeGenerator* pGen;
2360
Jack Palevicheedf9d22009-06-04 16:23:40 -07002361 String mErrorBuf;
2362
Jack Palevicheedf9d22009-06-04 16:23:40 -07002363 String mPragmas;
2364 int mPragmaStringCount;
2365
Jack Palevich21a15a22009-05-11 14:49:29 -07002366 static const int ALLOC_SIZE = 99999;
2367
Jack Palevich303d8ff2009-06-11 19:06:24 -07002368 static const int TOK_DUMMY = 1;
2369 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002370 static const int TOK_NUM_FLOAT = 3;
2371 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002372
2373 // 3..255 are character and/or operators
2374
Jack Palevich2db168f2009-06-11 14:29:47 -07002375 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002376 // Order has to match string list in "internKeywords".
2377 enum {
2378 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2379 TOK_INT = TOK_KEYWORD,
2380 TOK_CHAR,
2381 TOK_VOID,
2382 TOK_IF,
2383 TOK_ELSE,
2384 TOK_WHILE,
2385 TOK_BREAK,
2386 TOK_RETURN,
2387 TOK_FOR,
2388 TOK_PRAGMA,
2389 TOK_DEFINE,
2390 TOK_AUTO,
2391 TOK_CASE,
2392 TOK_CONST,
2393 TOK_CONTINUE,
2394 TOK_DEFAULT,
2395 TOK_DO,
2396 TOK_DOUBLE,
2397 TOK_ENUM,
2398 TOK_EXTERN,
2399 TOK_FLOAT,
2400 TOK_GOTO,
2401 TOK_LONG,
2402 TOK_REGISTER,
2403 TOK_SHORT,
2404 TOK_SIGNED,
2405 TOK_SIZEOF,
2406 TOK_STATIC,
2407 TOK_STRUCT,
2408 TOK_SWITCH,
2409 TOK_TYPEDEF,
2410 TOK_UNION,
2411 TOK_UNSIGNED,
2412 TOK_VOLATILE,
2413 TOK__BOOL,
2414 TOK__COMPLEX,
2415 TOK__IMAGINARY,
2416 TOK_INLINE,
2417 TOK_RESTRICT,
2418 // Symbols start after tokens
2419 TOK_SYMBOL
2420 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002421
2422 static const int LOCAL = 0x200;
2423
2424 static const int SYM_FORWARD = 0;
2425 static const int SYM_DEFINE = 1;
2426
2427 /* tokens in string heap */
2428 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002429
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002430 static const int OP_INCREMENT = 0;
2431 static const int OP_DECREMENT = 1;
2432 static const int OP_MUL = 2;
2433 static const int OP_DIV = 3;
2434 static const int OP_MOD = 4;
2435 static const int OP_PLUS = 5;
2436 static const int OP_MINUS = 6;
2437 static const int OP_SHIFT_LEFT = 7;
2438 static const int OP_SHIFT_RIGHT = 8;
2439 static const int OP_LESS_EQUAL = 9;
2440 static const int OP_GREATER_EQUAL = 10;
2441 static const int OP_LESS = 11;
2442 static const int OP_GREATER = 12;
2443 static const int OP_EQUALS = 13;
2444 static const int OP_NOT_EQUALS = 14;
2445 static const int OP_LOGICAL_AND = 15;
2446 static const int OP_LOGICAL_OR = 16;
2447 static const int OP_BIT_AND = 17;
2448 static const int OP_BIT_XOR = 18;
2449 static const int OP_BIT_OR = 19;
2450 static const int OP_BIT_NOT = 20;
2451 static const int OP_LOGICAL_NOT = 21;
2452 static const int OP_COUNT = 22;
2453
2454 /* Operators are searched from front, the two-character operators appear
2455 * before the single-character operators with the same first character.
2456 * @ is used to pad out single-character operators.
2457 */
2458 static const char* operatorChars;
2459 static const char operatorLevel[];
2460
Jack Palevich569f1352009-06-29 14:29:08 -07002461 /* Called when we detect an internal problem. Does nothing in production.
2462 *
2463 */
2464 void internalError() {
2465 * (char*) 0 = 0;
2466 }
2467
Jack Palevich86351982009-06-30 18:09:56 -07002468 void assert(bool isTrue) {
2469 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002470 internalError();
2471 }
Jack Palevich86351982009-06-30 18:09:56 -07002472 }
2473
Jack Palevich40600de2009-07-01 15:32:35 -07002474 bool isSymbol(tokenid_t t) {
2475 return t >= TOK_SYMBOL &&
2476 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2477 }
2478
2479 bool isSymbolOrKeyword(tokenid_t t) {
2480 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002481 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002482 }
2483
Jack Palevich86351982009-06-30 18:09:56 -07002484 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002485 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002486 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2487 if (pV && pV->tok != t) {
2488 internalError();
2489 }
2490 return pV;
2491 }
2492
2493 inline bool isDefined(tokenid_t t) {
2494 return t >= TOK_SYMBOL && VI(t) != 0;
2495 }
2496
Jack Palevich40600de2009-07-01 15:32:35 -07002497 const char* nameof(tokenid_t t) {
2498 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002499 return mTokenTable[t].pText;
2500 }
2501
Jack Palevich21a15a22009-05-11 14:49:29 -07002502 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002503 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002504 }
2505
2506 void inp() {
2507 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002508 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002509 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002510 dptr = 0;
2511 ch = dch;
2512 }
2513 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002514 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002515#if 0
2516 printf("ch='%c' 0x%x\n", ch, ch);
2517#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002518 }
2519
2520 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002521 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002522 }
2523
Jack Palevichb4758ff2009-06-12 12:49:14 -07002524 /* read a character constant, advances ch to after end of constant */
2525 int getq() {
2526 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002527 if (ch == '\\') {
2528 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002529 if (isoctal(ch)) {
2530 // 1 to 3 octal characters.
2531 val = 0;
2532 for(int i = 0; i < 3; i++) {
2533 if (isoctal(ch)) {
2534 val = (val << 3) + ch - '0';
2535 inp();
2536 }
2537 }
2538 return val;
2539 } else if (ch == 'x' || ch == 'X') {
2540 // N hex chars
2541 inp();
2542 if (! isxdigit(ch)) {
2543 error("'x' character escape requires at least one digit.");
2544 } else {
2545 val = 0;
2546 while (isxdigit(ch)) {
2547 int d = ch;
2548 if (isdigit(d)) {
2549 d -= '0';
2550 } else if (d <= 'F') {
2551 d = d - 'A' + 10;
2552 } else {
2553 d = d - 'a' + 10;
2554 }
2555 val = (val << 4) + d;
2556 inp();
2557 }
2558 }
2559 } else {
2560 int val = ch;
2561 switch (ch) {
2562 case 'a':
2563 val = '\a';
2564 break;
2565 case 'b':
2566 val = '\b';
2567 break;
2568 case 'f':
2569 val = '\f';
2570 break;
2571 case 'n':
2572 val = '\n';
2573 break;
2574 case 'r':
2575 val = '\r';
2576 break;
2577 case 't':
2578 val = '\t';
2579 break;
2580 case 'v':
2581 val = '\v';
2582 break;
2583 case '\\':
2584 val = '\\';
2585 break;
2586 case '\'':
2587 val = '\'';
2588 break;
2589 case '"':
2590 val = '"';
2591 break;
2592 case '?':
2593 val = '?';
2594 break;
2595 default:
2596 error("Undefined character escape %c", ch);
2597 break;
2598 }
2599 inp();
2600 return val;
2601 }
2602 } else {
2603 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002604 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002605 return val;
2606 }
2607
2608 static bool isoctal(int ch) {
2609 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002610 }
2611
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002612 bool acceptCh(int c) {
2613 bool result = c == ch;
2614 if (result) {
2615 pdef(ch);
2616 inp();
2617 }
2618 return result;
2619 }
2620
2621 bool acceptDigitsCh() {
2622 bool result = false;
2623 while (isdigit(ch)) {
2624 result = true;
2625 pdef(ch);
2626 inp();
2627 }
2628 return result;
2629 }
2630
2631 void parseFloat() {
2632 tok = TOK_NUM_DOUBLE;
2633 // mTokenString already has the integral part of the number.
2634 acceptCh('.');
2635 acceptDigitsCh();
2636 bool doExp = true;
2637 if (acceptCh('e') || acceptCh('E')) {
2638 // Don't need to do any extra work
2639 } else if (ch == 'f' || ch == 'F') {
2640 pdef('e'); // So it can be parsed by strtof.
2641 inp();
2642 tok = TOK_NUM_FLOAT;
2643 } else {
2644 doExp = false;
2645 }
2646 if (doExp) {
2647 bool digitsRequired = acceptCh('-');
2648 bool digitsFound = acceptDigitsCh();
2649 if (digitsRequired && ! digitsFound) {
2650 error("malformed exponent");
2651 }
2652 }
2653 char* pText = mTokenString.getUnwrapped();
2654 if (tok == TOK_NUM_FLOAT) {
2655 tokd = strtof(pText, 0);
2656 } else {
2657 tokd = strtod(pText, 0);
2658 }
2659 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2660 }
2661
Jack Palevich21a15a22009-05-11 14:49:29 -07002662 void next() {
2663 int l, a;
2664
Jack Palevich546b2242009-05-13 15:10:04 -07002665 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002666 if (ch == '#') {
2667 inp();
2668 next();
2669 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002670 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002671 } else if (tok == TOK_PRAGMA) {
2672 doPragma();
2673 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002674 error("Unsupported preprocessor directive \"%s\"",
2675 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002676 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002677 }
2678 inp();
2679 }
2680 tokl = 0;
2681 tok = ch;
2682 /* encode identifiers & numbers */
2683 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002684 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002685 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002686 pdef(ch);
2687 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002688 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002689 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002690 // Start of a numeric constant. Could be integer, float, or
2691 // double, won't know until we look further.
2692 if (ch == '.' || ch == 'e' || ch == 'e'
2693 || ch == 'f' || ch == 'F') {
2694 parseFloat();
2695 } else {
2696 // It's an integer constant
2697 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2698 tok = TOK_NUM;
2699 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002700 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002701 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2702 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002703 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002704 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2705 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002706 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002707 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002708 dch = ch;
2709 inp();
2710 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002711 }
2712 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002713 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002714 inp();
2715 if (tok == '\'') {
2716 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002717 tokc = getq();
2718 if (ch != '\'') {
2719 error("Expected a ' character, got %c", ch);
2720 } else {
2721 inp();
2722 }
Jack Palevich546b2242009-05-13 15:10:04 -07002723 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002724 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002725 while (ch && ch != EOF) {
2726 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002727 inp();
2728 inp();
2729 if (ch == '/')
2730 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002731 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002732 if (ch == EOF) {
2733 error("End of file inside comment.");
2734 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002735 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002736 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002737 } else if ((tok == '/') & (ch == '/')) {
2738 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002739 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002740 inp();
2741 }
2742 inp();
2743 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002744 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002745 const char* t = operatorChars;
2746 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002747 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002748 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002749 tokl = operatorLevel[opIndex];
2750 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002751 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002752#if 0
2753 printf("%c%c -> tokl=%d tokc=0x%x\n",
2754 l, a, tokl, tokc);
2755#endif
2756 if (a == ch) {
2757 inp();
2758 tok = TOK_DUMMY; /* dummy token for double tokens */
2759 }
2760 break;
2761 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002762 opIndex++;
2763 }
2764 if (l == 0) {
2765 tokl = 0;
2766 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002767 }
2768 }
2769 }
2770#if 0
2771 {
Jack Palevich569f1352009-06-29 14:29:08 -07002772 String buf;
2773 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002774 fprintf(stderr, "%s\n", buf.getUnwrapped());
2775 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002776#endif
2777 }
2778
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002779 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002780 next();
2781 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002782 String* pName = new String();
2783 while (isspace(ch)) {
2784 inp();
2785 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002786 if (ch == '(') {
2787 delete pName;
2788 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002789 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002790 }
2791 while (isspace(ch)) {
2792 inp();
2793 }
Jack Palevich569f1352009-06-29 14:29:08 -07002794 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002795 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002796 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002797 inp();
2798 }
Jack Palevich569f1352009-06-29 14:29:08 -07002799 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2800 memcpy(pDefn, value.getUnwrapped(), value.len());
2801 pDefn[value.len()] = 0;
2802 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002803 }
2804
Jack Palevicheedf9d22009-06-04 16:23:40 -07002805 void doPragma() {
2806 // # pragma name(val)
2807 int state = 0;
2808 while(ch != EOF && ch != '\n' && state < 10) {
2809 switch(state) {
2810 case 0:
2811 if (isspace(ch)) {
2812 inp();
2813 } else {
2814 state++;
2815 }
2816 break;
2817 case 1:
2818 if (isalnum(ch)) {
2819 mPragmas.append(ch);
2820 inp();
2821 } else if (ch == '(') {
2822 mPragmas.append(0);
2823 inp();
2824 state++;
2825 } else {
2826 state = 11;
2827 }
2828 break;
2829 case 2:
2830 if (isalnum(ch)) {
2831 mPragmas.append(ch);
2832 inp();
2833 } else if (ch == ')') {
2834 mPragmas.append(0);
2835 inp();
2836 state = 10;
2837 } else {
2838 state = 11;
2839 }
2840 break;
2841 }
2842 }
2843 if(state != 10) {
2844 error("Unexpected pragma syntax");
2845 }
2846 mPragmaStringCount += 2;
2847 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002848
Jack Palevichac0e95e2009-05-29 13:53:44 -07002849 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002850 mErrorBuf.printf("%ld: ", file->getLine());
2851 mErrorBuf.vprintf(fmt, ap);
2852 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002853 }
2854
Jack Palevich8b0624c2009-05-20 12:12:06 -07002855 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002856 if (tok != c) {
2857 error("'%c' expected", c);
2858 }
2859 next();
2860 }
2861
Jack Palevich86351982009-06-30 18:09:56 -07002862 bool accept(intptr_t c) {
2863 if (tok == c) {
2864 next();
2865 return true;
2866 }
2867 return false;
2868 }
2869
Jack Palevich40600de2009-07-01 15:32:35 -07002870 bool acceptStringLiteral() {
2871 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07002872 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07002873 // This while loop merges multiple adjacent string constants.
2874 while (tok == '"') {
2875 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002876 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07002877 }
2878 if (ch != '"') {
2879 error("Unterminated string constant.");
2880 }
2881 inp();
2882 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002883 }
Jack Palevich40600de2009-07-01 15:32:35 -07002884 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002885 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002886 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07002887 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002888
2889 return true;
2890 }
2891 return false;
2892 }
2893 /* Parse and evaluate a unary expression.
2894 * allowAssignment is true if '=' parsing wanted (quick hack)
2895 */
2896 void unary(bool allowAssignment) {
2897 intptr_t n, t, a;
2898 t = 0;
2899 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2900 if (acceptStringLiteral()) {
2901 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002902 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002903 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002904 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002905 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07002906 t = tok;
2907 next();
2908 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07002909 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002910 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002911 // Align to 4-byte boundary
2912 glo = (char*) (((intptr_t) glo + 3) & -4);
2913 * (float*) glo = (float) ad;
2914 pGen->loadFloat((int) glo, mkpFloat);
2915 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002916 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002917 // Align to 8-byte boundary
2918 glo = (char*) (((intptr_t) glo + 7) & -8);
2919 * (double*) glo = ad;
2920 pGen->loadFloat((int) glo, mkpDouble);
2921 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07002922 } else if (c == 2) {
2923 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002924 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002925 if (t == '!')
Jack Palevich9eed7a22009-07-06 17:24:34 -07002926 pGen->gUnaryCmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002927 else
Jack Palevich9eed7a22009-07-06 17:24:34 -07002928 pGen->genUnaryOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002929 } else if (t == '(') {
2930 expr();
2931 skip(')');
2932 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002933 /* This is a pointer dereference, but we currently only
2934 * support a pointer dereference if it's immediately
2935 * in front of a cast. So parse the cast right here.
2936 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002937 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002938 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2939 // We currently only handle 3 types of cast:
2940 // (int*), (char*) , (int (*)())
2941 if(typeEqual(pCast, mkpIntPtr)) {
2942 t = TOK_INT;
2943 } else if (typeEqual(pCast, mkpCharPtr)) {
2944 t = TOK_CHAR;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002945 } else if (typeEqual(pCast, mkpFloatPtr)) {
2946 t = TOK_FLOAT;
2947 } else if (typeEqual(pCast, mkpDoublePtr)) {
2948 t = TOK_DOUBLE;
Jack Palevich3f226492009-07-02 14:46:19 -07002949 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002950 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002951 } else {
2952 String buffer;
2953 decodeType(buffer, pCast);
2954 error("Unsupported cast type %s", buffer.getUnwrapped());
2955 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002956 }
2957 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002958 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002959 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002960 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002961 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002962 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002963 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002964 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002965 }
Jack Palevich3f226492009-07-02 14:46:19 -07002966 // Else we fall through to the function call below, with
2967 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002968 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07002969 VariableInfo* pVI = VI(tok);
2970 pGen->leaR0((int) pVI->pAddress,
2971 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07002972 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002973 } else if (t == EOF ) {
2974 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002975 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002976 // Don't have to do anything special here, the error
2977 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002978 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002979 if (!isDefined(t)) {
2980 mGlobals.add(t);
2981 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002982 }
Jack Palevich8df46192009-07-07 14:48:51 -07002983 VariableInfo* pVI = VI(t);
2984 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002985 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002986 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002987 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07002988 if (tok == '(') {
2989 pVI->pType = mkpIntFn;
2990 } else {
2991 pVI->pType = mkpInt;
2992 }
Jack Palevich8df46192009-07-07 14:48:51 -07002993 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002994 }
Jack Palevich40600de2009-07-01 15:32:35 -07002995 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002996 /* assignment */
2997 next();
2998 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07002999 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003000 } else if (tok != '(') {
3001 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003002 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003003 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003004 }
Jack Palevich8df46192009-07-07 14:48:51 -07003005 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003006 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003007 next();
3008 }
3009 }
3010 }
3011 }
3012
3013 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003014 if (accept('(')) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003015 Type* pArgList = NULL;
3016 VariableInfo* pVI = NULL;
3017 if (n == 1) { // Indirect function call, push address of fn.
3018 pArgList = pGen->getR0Type()->pTail;
Jack Palevich1cdef202009-05-22 12:06:27 -07003019 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003020 } else {
3021 pVI = VI(t);
3022 pArgList = pVI->pType->pTail;
3023 }
3024 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003025 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003026 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003027 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003028 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003029 if (! varArgs && !pArgList) {
3030 error ("Unexpected argument.");
3031 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003032 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003033 Type* pTargetType;
3034 if (pArgList) {
3035 pTargetType = pArgList->pHead;
3036 pArgList = pArgList->pTail;
3037 } else {
3038 pTargetType = pGen->getR0Type();
3039 if (pTargetType->tag == TY_FLOAT) {
3040 pTargetType = mkpDouble;
3041 }
3042 }
3043 pGen->convertR0(pTargetType);
3044 l += pGen->storeR0ToArg(l);
Jack Palevich95727a02009-07-06 12:07:15 -07003045 if (accept(',')) {
3046 // fine
3047 } else if ( tok != ')') {
3048 error("Expected ',' or ')'");
3049 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003050 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003051 if (! varArgs && pArgList) {
3052 error ("Expected more argument(s).");
3053 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003054 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003055 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003056 if (!n) {
3057 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003058 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3059 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003060 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003061 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003062 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003063 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3064 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003065 }
-b master422972c2009-06-17 19:13:52 -07003066 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003067 }
3068 }
3069
Jack Palevich40600de2009-07-01 15:32:35 -07003070 /* Recursive descent parser for binary operations.
3071 */
3072 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003073 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003074 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003075 if (level-- == 1)
3076 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003077 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003078 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003079 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003080 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003081 n = tok;
3082 t = tokc;
3083 next();
3084
Jack Palevich40600de2009-07-01 15:32:35 -07003085 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003086 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003087 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003088 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003089 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003090 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003091
Jack Palevich40600de2009-07-01 15:32:35 -07003092 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003093 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003094 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003095 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003096 }
3097 }
3098 }
3099 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003100 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003101 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003102 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003103 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003104 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003105 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003106 }
3107 }
3108 }
3109
3110 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003111 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003112 }
3113
3114 int test_expr() {
3115 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003116 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003117 }
3118
Jack Palevicha6baa232009-06-12 11:25:59 -07003119 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003120 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003121
Jack Palevich95727a02009-07-06 12:07:15 -07003122 Type* pBaseType;
3123 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003124 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003125 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003126 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003127 next();
3128 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003129 a = test_expr();
3130 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003131 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003132 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003133 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003134 n = pGen->gjmp(0); /* jmp */
3135 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003136 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003137 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003138 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003139 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003140 }
Jack Palevich546b2242009-05-13 15:10:04 -07003141 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003142 t = tok;
3143 next();
3144 skip('(');
3145 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003146 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003147 a = test_expr();
3148 } else {
3149 if (tok != ';')
3150 expr();
3151 skip(';');
3152 n = codeBuf.getPC();
3153 a = 0;
3154 if (tok != ';')
3155 a = test_expr();
3156 skip(';');
3157 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003158 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003159 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003160 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003161 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003162 n = t + 4;
3163 }
3164 }
3165 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003166 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003167 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003168 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003169 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003170 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003171 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003172 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003173 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003174 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003175 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003176 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003177 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003178 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003179 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003180 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003181 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003182 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003183 expr();
Jack Palevich8df46192009-07-07 14:48:51 -07003184 pGen->convertR0(pReturnType);
3185 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003186 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003187 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003188 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003189 } else if (tok != ';')
3190 expr();
3191 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003192 }
3193 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003194
Jack Palevich3f226492009-07-02 14:46:19 -07003195 bool typeEqual(Type* a, Type* b) {
3196 if (a == b) {
3197 return true;
3198 }
3199 if (a == NULL || b == NULL) {
3200 return false;
3201 }
3202 TypeTag at = a->tag;
3203 if (at != b->tag) {
3204 return false;
3205 }
3206 if (at == TY_POINTER) {
3207 return typeEqual(a->pHead, b->pHead);
3208 } else if (at == TY_FUNC || at == TY_PARAM) {
3209 return typeEqual(a->pHead, b->pHead)
3210 && typeEqual(a->pTail, b->pTail);
3211 }
3212 return true;
3213 }
3214
Jack Palevich86351982009-06-30 18:09:56 -07003215 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3216 assert(tag >= TY_INT && tag <= TY_PARAM);
3217 Type* pType = (Type*) arena.alloc(sizeof(Type));
3218 memset(pType, 0, sizeof(*pType));
3219 pType->tag = tag;
3220 pType->pHead = pHead;
3221 pType->pTail = pTail;
3222 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003223 }
3224
Jack Palevich3f226492009-07-02 14:46:19 -07003225 Type* createPtrType(Type* pType, Arena& arena) {
3226 return createType(TY_POINTER, pType, NULL, arena);
3227 }
3228
3229 /**
3230 * Try to print a type in declaration order
3231 */
Jack Palevich86351982009-06-30 18:09:56 -07003232 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003233 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003234 if (pType == NULL) {
3235 buffer.appendCStr("null");
3236 return;
3237 }
Jack Palevich3f226492009-07-02 14:46:19 -07003238 decodeTypeImp(buffer, pType);
3239 }
3240
3241 void decodeTypeImp(String& buffer, Type* pType) {
3242 decodeTypeImpPrefix(buffer, pType);
3243
Jack Palevich86351982009-06-30 18:09:56 -07003244 String temp;
3245 if (pType->id != 0) {
3246 decodeToken(temp, pType->id);
3247 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003248 }
3249
3250 decodeTypeImpPostfix(buffer, pType);
3251 }
3252
3253 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3254 TypeTag tag = pType->tag;
3255
3256 if (tag >= TY_INT && tag <= TY_VOID) {
3257 switch (tag) {
3258 case TY_INT:
3259 buffer.appendCStr("int");
3260 break;
3261 case TY_CHAR:
3262 buffer.appendCStr("char");
3263 break;
3264 case TY_VOID:
3265 buffer.appendCStr("void");
3266 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003267 case TY_FLOAT:
3268 buffer.appendCStr("float");
3269 break;
3270 case TY_DOUBLE:
3271 buffer.appendCStr("double");
3272 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003273 default:
3274 break;
3275 }
Jack Palevich86351982009-06-30 18:09:56 -07003276 buffer.append(' ');
3277 }
Jack Palevich3f226492009-07-02 14:46:19 -07003278
3279 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003280 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003281 break;
3282 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003283 break;
3284 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003285 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003286 case TY_FLOAT:
3287 break;
3288 case TY_DOUBLE:
3289 break;
Jack Palevich86351982009-06-30 18:09:56 -07003290 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003291 decodeTypeImpPrefix(buffer, pType->pHead);
3292 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3293 buffer.append('(');
3294 }
3295 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003296 break;
3297 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003298 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003299 break;
3300 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003301 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003302 break;
3303 default:
3304 String temp;
3305 temp.printf("Unknown tag %d", pType->tag);
3306 buffer.append(temp);
3307 break;
3308 }
Jack Palevich3f226492009-07-02 14:46:19 -07003309 }
3310
3311 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3312 TypeTag tag = pType->tag;
3313
3314 switch(tag) {
3315 case TY_POINTER:
3316 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3317 buffer.append(')');
3318 }
3319 decodeTypeImpPostfix(buffer, pType->pHead);
3320 break;
3321 case TY_FUNC:
3322 buffer.append('(');
3323 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3324 decodeTypeImp(buffer, pArg);
3325 if (pArg->pTail) {
3326 buffer.appendCStr(", ");
3327 }
3328 }
3329 buffer.append(')');
3330 break;
3331 default:
3332 break;
Jack Palevich86351982009-06-30 18:09:56 -07003333 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003334 }
3335
Jack Palevich86351982009-06-30 18:09:56 -07003336 void printType(Type* pType) {
3337 String buffer;
3338 decodeType(buffer, pType);
3339 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003340 }
3341
Jack Palevich86351982009-06-30 18:09:56 -07003342 Type* acceptPrimitiveType(Arena& arena) {
3343 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003344 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003345 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003346 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003347 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003348 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003349 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003350 } else if (tok == TOK_FLOAT) {
3351 pType = mkpFloat;
3352 } else if (tok == TOK_DOUBLE) {
3353 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003354 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003355 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003356 }
3357 next();
Jack Palevich86351982009-06-30 18:09:56 -07003358 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003359 }
3360
Jack Palevich3f226492009-07-02 14:46:19 -07003361 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3362 Arena& arena) {
3363 tokenid_t declName = 0;
3364 pType = acceptDecl2(pType, declName, nameAllowed,
3365 nameRequired, arena);
3366 if (declName) {
3367 // Clone the parent type so we can set a unique ID
3368 pType = createType(pType->tag, pType->pHead,
3369 pType->pTail, arena);
3370
Jack Palevich86351982009-06-30 18:09:56 -07003371 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003372 }
Jack Palevich3f226492009-07-02 14:46:19 -07003373 // fprintf(stderr, "Parsed a declaration: ");
3374 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003375 return pType;
3376 }
3377
Jack Palevich3f226492009-07-02 14:46:19 -07003378 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3379 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003380 if (! pType) {
3381 error("Expected a declaration");
3382 }
3383 return pType;
3384 }
3385
Jack Palevich3f226492009-07-02 14:46:19 -07003386 /* Used for accepting types that appear in casts */
3387 Type* acceptCastTypeDeclaration(Arena& arena) {
3388 Type* pType = acceptPrimitiveType(arena);
3389 if (pType) {
3390 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003391 }
Jack Palevich86351982009-06-30 18:09:56 -07003392 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003393 }
3394
Jack Palevich3f226492009-07-02 14:46:19 -07003395 Type* expectCastTypeDeclaration(Arena& arena) {
3396 Type* pType = acceptCastTypeDeclaration(arena);
3397 if (! pType) {
3398 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003399 }
Jack Palevich3f226492009-07-02 14:46:19 -07003400 return pType;
3401 }
3402
3403 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3404 bool nameAllowed, bool nameRequired, Arena& arena) {
3405 int ptrCounter = 0;
3406 while (accept('*')) {
3407 ptrCounter++;
3408 }
3409 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3410 while (ptrCounter-- > 0) {
3411 pType = createType(TY_POINTER, pType, NULL, arena);
3412 }
3413 return pType;
3414 }
3415
3416 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3417 bool nameAllowed, bool nameRequired, Arena& arena) {
3418 // direct-dcl :
3419 // name
3420 // (dcl)
3421 // direct-dcl()
3422 // direct-dcl[]
3423 Type* pNewHead = NULL;
3424 if (accept('(')) {
3425 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3426 nameRequired, arena);
3427 skip(')');
3428 } else if ((declName = acceptSymbol()) != 0) {
3429 if (nameAllowed == false && declName) {
3430 error("Symbol %s not allowed here", nameof(declName));
3431 } else if (nameRequired && ! declName) {
3432 String temp;
3433 decodeToken(temp, tok);
3434 error("Expected symbol. Got %s", temp.getUnwrapped());
3435 }
3436 }
3437 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003438 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003439 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003440 pType = createType(TY_FUNC, pType, pTail, arena);
3441 skip(')');
3442 }
Jack Palevich3f226492009-07-02 14:46:19 -07003443
3444 if (pNewHead) {
3445 Type* pA = pNewHead;
3446 while (pA->pHead) {
3447 pA = pA->pHead;
3448 }
3449 pA->pHead = pType;
3450 pType = pNewHead;
3451 }
Jack Palevich86351982009-06-30 18:09:56 -07003452 return pType;
3453 }
3454
Jack Palevich3f226492009-07-02 14:46:19 -07003455 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003456 Type* pHead = NULL;
3457 Type* pTail = NULL;
3458 for(;;) {
3459 Type* pBaseArg = acceptPrimitiveType(arena);
3460 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003461 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3462 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003463 if (pArg) {
3464 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3465 if (!pHead) {
3466 pHead = pParam;
3467 pTail = pParam;
3468 } else {
3469 pTail->pTail = pParam;
3470 pTail = pParam;
3471 }
3472 }
3473 }
3474 if (! accept(',')) {
3475 break;
3476 }
3477 }
3478 return pHead;
3479 }
3480
3481 Type* expectPrimitiveType(Arena& arena) {
3482 Type* pType = acceptPrimitiveType(arena);
3483 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003484 String buf;
3485 decodeToken(buf, tok);
3486 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003487 }
Jack Palevich86351982009-06-30 18:09:56 -07003488 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003489 }
3490
Jack Palevich86351982009-06-30 18:09:56 -07003491 void addGlobalSymbol(Type* pDecl) {
3492 tokenid_t t = pDecl->id;
3493 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003494 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003495 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003496 }
Jack Palevich86351982009-06-30 18:09:56 -07003497 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003498 }
3499
Jack Palevich86351982009-06-30 18:09:56 -07003500 void reportDuplicate(tokenid_t t) {
3501 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003502 }
3503
Jack Palevich86351982009-06-30 18:09:56 -07003504 void addLocalSymbol(Type* pDecl) {
3505 tokenid_t t = pDecl->id;
3506 if (mLocals.isDefinedAtCurrentLevel(t)) {
3507 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003508 }
Jack Palevich86351982009-06-30 18:09:56 -07003509 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003510 }
3511
Jack Palevich95727a02009-07-06 12:07:15 -07003512 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003513 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003514
Jack Palevich95727a02009-07-06 12:07:15 -07003515 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003516 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003517 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3518 if (!pDecl) {
3519 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003520 }
Jack Palevich86351982009-06-30 18:09:56 -07003521 int variableAddress = 0;
3522 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003523 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003524 loc = loc + 4;
3525 variableAddress = -loc;
3526 VI(pDecl->id)->pAddress = (void*) variableAddress;
3527 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003528 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003529 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003530 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07003531 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003532 if (tok == ',')
3533 next();
3534 }
3535 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003536 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003537 }
3538 }
3539
Jack Palevichf1728be2009-06-12 13:53:51 -07003540 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003541 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003542 }
3543
Jack Palevich569f1352009-06-29 14:29:08 -07003544 void decodeToken(String& buffer, tokenid_t token) {
3545 if (token == EOF ) {
3546 buffer.printf("EOF");
3547 } else if (token == TOK_NUM) {
3548 buffer.printf("numeric constant");
3549 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003550 if (token < 32) {
3551 buffer.printf("'\\x%02x'", token);
3552 } else {
3553 buffer.printf("'%c'", token);
3554 }
Jack Palevich569f1352009-06-29 14:29:08 -07003555 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3556 buffer.printf("keyword \"%s\"", nameof(token));
3557 } else {
3558 buffer.printf("symbol \"%s\"", nameof(token));
3559 }
3560 }
3561
Jack Palevich40600de2009-07-01 15:32:35 -07003562 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003563 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003564 if (!result) {
3565 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003566 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003567 error("Expected symbol. Got %s", temp.getUnwrapped());
3568 }
3569 return result;
3570 }
3571
Jack Palevich86351982009-06-30 18:09:56 -07003572 tokenid_t acceptSymbol() {
3573 tokenid_t result = 0;
3574 if (tok >= TOK_SYMBOL) {
3575 result = tok;
3576 next();
Jack Palevich86351982009-06-30 18:09:56 -07003577 }
3578 return result;
3579 }
3580
Jack Palevichb7c81e92009-06-04 19:56:13 -07003581 void globalDeclarations() {
3582 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003583 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3584 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003585 break;
3586 }
Jack Palevich86351982009-06-30 18:09:56 -07003587 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3588 if (!pDecl) {
3589 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003590 }
Jack Palevich86351982009-06-30 18:09:56 -07003591 if (! isDefined(pDecl->id)) {
3592 addGlobalSymbol(pDecl);
3593 }
3594 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003595 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003596 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003597 }
Jack Palevich86351982009-06-30 18:09:56 -07003598 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003599 // it's a variable declaration
3600 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003601 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003602 name->pAddress = (int*) allocGlobalSpace(
3603 pGen->alignment(name->pType),
3604 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07003605 }
Jack Palevich86351982009-06-30 18:09:56 -07003606 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003607 if (tok == TOK_NUM) {
3608 if (name) {
3609 * (int*) name->pAddress = tokc;
3610 }
3611 next();
3612 } else {
3613 error("Expected an integer constant");
3614 }
3615 }
Jack Palevich86351982009-06-30 18:09:56 -07003616 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003617 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003618 }
Jack Palevich86351982009-06-30 18:09:56 -07003619 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3620 if (!pDecl) {
3621 break;
3622 }
3623 if (! isDefined(pDecl->id)) {
3624 addGlobalSymbol(pDecl);
3625 }
3626 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003627 }
3628 skip(';');
3629 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003630 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003631 if (accept(';')) {
3632 // forward declaration.
3633 } else {
3634 if (name) {
3635 /* patch forward references (XXX: does not work for function
3636 pointers) */
3637 pGen->gsym((int) name->pForward);
3638 /* put function address */
3639 name->pAddress = (void*) codeBuf.getPC();
3640 }
3641 // Calculate stack offsets for parameters
3642 mLocals.pushLevel();
3643 intptr_t a = 8;
3644 int argCount = 0;
3645 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3646 Type* pArg = pP->pHead;
3647 addLocalSymbol(pArg);
3648 /* read param name and compute offset */
3649 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003650 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07003651 argCount++;
3652 }
3653 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003654 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003655 a = pGen->functionEntry(argCount);
3656 block(0, true);
3657 pGen->gsym(rsym);
3658 pGen->functionExit(argCount, a, loc);
3659 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003660 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003661 }
3662 }
3663 }
3664
Jack Palevich9cbd2262009-07-08 16:48:41 -07003665 char* allocGlobalSpace(size_t alignment, size_t bytes) {
3666 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
3667 size_t end = base + bytes;
3668 if ((end - (size_t) pGlobalBase) > ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003669 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003670 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003671 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07003672 char* result = (char*) base;
3673 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003674 return result;
3675 }
3676
Jack Palevich21a15a22009-05-11 14:49:29 -07003677 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003678 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003679 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003680 pGlobalBase = 0;
3681 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003682 if (pGen) {
3683 delete pGen;
3684 pGen = 0;
3685 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003686 if (file) {
3687 delete file;
3688 file = 0;
3689 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003690 }
3691
3692 void clear() {
3693 tok = 0;
3694 tokc = 0;
3695 tokl = 0;
3696 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003697 rsym = 0;
3698 loc = 0;
3699 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003700 dptr = 0;
3701 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003702 file = 0;
3703 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003704 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003705 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003706 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003707
Jack Palevich22305132009-05-13 10:58:45 -07003708 void setArchitecture(const char* architecture) {
3709 delete pGen;
3710 pGen = 0;
3711
3712 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003713#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003714 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003715 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003716 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003717#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003718#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003719 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003720 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003721 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003722#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003723 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003724 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003725 }
3726 }
3727
3728 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003729#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003730 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003731#elif defined(DEFAULT_X86_CODEGEN)
3732 pGen = new X86CodeGenerator();
3733#endif
3734 }
3735 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003736 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003737 } else {
3738 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003739 }
3740 }
3741
Jack Palevich77ae76e2009-05-10 19:59:24 -07003742public:
Jack Palevich22305132009-05-13 10:58:45 -07003743 struct args {
3744 args() {
3745 architecture = 0;
3746 }
3747 const char* architecture;
3748 };
3749
Jack Paleviche7b59062009-05-19 17:12:17 -07003750 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003751 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003752 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003753
Jack Paleviche7b59062009-05-19 17:12:17 -07003754 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003755 cleanup();
3756 }
3757
Jack Palevich1cdef202009-05-22 12:06:27 -07003758 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003759 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003760
3761 cleanup();
3762 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003763 mTokenTable.setArena(&mGlobalArena);
3764 mGlobals.setArena(&mGlobalArena);
3765 mGlobals.setTokenTable(&mTokenTable);
3766 mLocals.setArena(&mLocalArena);
3767 mLocals.setTokenTable(&mTokenTable);
3768
3769 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003770 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003771 codeBuf.init(ALLOC_SIZE);
3772 setArchitecture(NULL);
3773 if (!pGen) {
3774 return -1;
3775 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003776#ifdef PROVIDE_TRACE_CODEGEN
3777 pGen = new TraceCodeGenerator(pGen);
3778#endif
3779 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003780 pGen->init(&codeBuf);
3781 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003782 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3783 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003784 inp();
3785 next();
3786 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003787 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003788 result = pGen->finishCompile();
3789 if (result == 0) {
3790 if (mErrorBuf.len()) {
3791 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003792 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003793 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003794 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003795 }
3796
Jack Palevich86351982009-06-30 18:09:56 -07003797 void createPrimitiveTypes() {
3798 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3799 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3800 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003801 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3802 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003803 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003804 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3805 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07003806 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
3807 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003808 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003809 }
3810
Jack Palevicha6baa232009-06-12 11:25:59 -07003811 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003812 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003813 }
3814
Jack Palevich569f1352009-06-29 14:29:08 -07003815 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003816 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003817 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003818 }
3819
Jack Palevich569f1352009-06-29 14:29:08 -07003820 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003821 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003822 error("Undefined forward reference: %s",
3823 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003824 }
3825 return true;
3826 }
3827
Jack Palevich21a15a22009-05-11 14:49:29 -07003828 int dump(FILE* out) {
3829 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3830 return 0;
3831 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003832
Jack Palevicha6535612009-05-13 16:24:17 -07003833 int disassemble(FILE* out) {
3834 return pGen->disassemble(out);
3835 }
3836
Jack Palevich1cdef202009-05-22 12:06:27 -07003837 /* Look through the symbol table to find a symbol.
3838 * If found, return its value.
3839 */
3840 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003841 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3842 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003843 if (pVariableInfo) {
3844 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003845 }
3846 return NULL;
3847 }
3848
Jack Palevicheedf9d22009-06-04 16:23:40 -07003849 void getPragmas(ACCsizei* actualStringCount,
3850 ACCsizei maxStringCount, ACCchar** strings) {
3851 int stringCount = mPragmaStringCount;
3852 if (actualStringCount) {
3853 *actualStringCount = stringCount;
3854 }
3855 if (stringCount > maxStringCount) {
3856 stringCount = maxStringCount;
3857 }
3858 if (strings) {
3859 char* pPragmas = mPragmas.getUnwrapped();
3860 while (stringCount-- > 0) {
3861 *strings++ = pPragmas;
3862 pPragmas += strlen(pPragmas) + 1;
3863 }
3864 }
3865 }
3866
Jack Palevichac0e95e2009-05-29 13:53:44 -07003867 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003868 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003869 }
3870
Jack Palevich77ae76e2009-05-10 19:59:24 -07003871};
3872
Jack Paleviche7b59062009-05-19 17:12:17 -07003873const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003874 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3875
Jack Paleviche7b59062009-05-19 17:12:17 -07003876const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003877 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3878 5, 5, /* ==, != */
3879 9, 10, /* &&, || */
3880 6, 7, 8, /* & ^ | */
3881 2, 2 /* ~ ! */
3882 };
3883
Jack Palevich8b0624c2009-05-20 12:12:06 -07003884#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003885FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003886#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003887
Jack Palevich8b0624c2009-05-20 12:12:06 -07003888#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003889const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003890 0x1, // ++
3891 0xff, // --
3892 0xc1af0f, // *
3893 0xf9f79991, // /
3894 0xf9f79991, // % (With manual assist to swap results)
3895 0xc801, // +
3896 0xd8f7c829, // -
3897 0xe0d391, // <<
3898 0xf8d391, // >>
3899 0xe, // <=
3900 0xd, // >=
3901 0xc, // <
3902 0xf, // >
3903 0x4, // ==
3904 0x5, // !=
3905 0x0, // &&
3906 0x1, // ||
3907 0xc821, // &
3908 0xc831, // ^
3909 0xc809, // |
3910 0xd0f7, // ~
3911 0x4 // !
3912};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003913#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003914
Jack Palevich1cdef202009-05-22 12:06:27 -07003915struct ACCscript {
3916 ACCscript() {
3917 text = 0;
3918 textLength = 0;
3919 accError = ACC_NO_ERROR;
3920 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003921
Jack Palevich1cdef202009-05-22 12:06:27 -07003922 ~ACCscript() {
3923 delete text;
3924 }
Jack Palevich546b2242009-05-13 15:10:04 -07003925
Jack Palevich1cdef202009-05-22 12:06:27 -07003926 void setError(ACCenum error) {
3927 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3928 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003929 }
3930 }
3931
Jack Palevich1cdef202009-05-22 12:06:27 -07003932 ACCenum getError() {
3933 ACCenum result = accError;
3934 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003935 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003936 }
3937
Jack Palevich1cdef202009-05-22 12:06:27 -07003938 Compiler compiler;
3939 char* text;
3940 int textLength;
3941 ACCenum accError;
3942};
3943
3944
3945extern "C"
3946ACCscript* accCreateScript() {
3947 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003948}
Jack Palevich1cdef202009-05-22 12:06:27 -07003949
3950extern "C"
3951ACCenum accGetError( ACCscript* script ) {
3952 return script->getError();
3953}
3954
3955extern "C"
3956void accDeleteScript(ACCscript* script) {
3957 delete script;
3958}
3959
3960extern "C"
3961void accScriptSource(ACCscript* script,
3962 ACCsizei count,
3963 const ACCchar ** string,
3964 const ACCint * length) {
3965 int totalLength = 0;
3966 for(int i = 0; i < count; i++) {
3967 int len = -1;
3968 const ACCchar* s = string[i];
3969 if (length) {
3970 len = length[i];
3971 }
3972 if (len < 0) {
3973 len = strlen(s);
3974 }
3975 totalLength += len;
3976 }
3977 delete script->text;
3978 char* text = new char[totalLength + 1];
3979 script->text = text;
3980 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003981 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003982 for(int i = 0; i < count; i++) {
3983 int len = -1;
3984 const ACCchar* s = string[i];
3985 if (length) {
3986 len = length[i];
3987 }
3988 if (len < 0) {
3989 len = strlen(s);
3990 }
Jack Palevich09555c72009-05-27 12:25:55 -07003991 memcpy(dest, s, len);
3992 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003993 }
3994 text[totalLength] = '\0';
3995}
3996
3997extern "C"
3998void accCompileScript(ACCscript* script) {
3999 int result = script->compiler.compile(script->text, script->textLength);
4000 if (result) {
4001 script->setError(ACC_INVALID_OPERATION);
4002 }
4003}
4004
4005extern "C"
4006void accGetScriptiv(ACCscript* script,
4007 ACCenum pname,
4008 ACCint * params) {
4009 switch (pname) {
4010 case ACC_INFO_LOG_LENGTH:
4011 *params = 0;
4012 break;
4013 }
4014}
4015
4016extern "C"
4017void accGetScriptInfoLog(ACCscript* script,
4018 ACCsizei maxLength,
4019 ACCsizei * length,
4020 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004021 char* message = script->compiler.getErrorMessage();
4022 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004023 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004024 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004025 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004026 if (infoLog && maxLength > 0) {
4027 int trimmedLength = maxLength < messageLength ?
4028 maxLength : messageLength;
4029 memcpy(infoLog, message, trimmedLength);
4030 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004031 }
4032}
4033
4034extern "C"
4035void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4036 ACCvoid ** address) {
4037 void* value = script->compiler.lookup(name);
4038 if (value) {
4039 *address = value;
4040 } else {
4041 script->setError(ACC_INVALID_VALUE);
4042 }
4043}
4044
Jack Palevicheedf9d22009-06-04 16:23:40 -07004045extern "C"
4046void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4047 ACCsizei maxStringCount, ACCchar** strings){
4048 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4049}
4050
-b master422972c2009-06-17 19:13:52 -07004051extern "C"
4052void accDisassemble(ACCscript* script) {
4053 script->compiler.disassemble(stderr);
4054}
4055
Jack Palevicheedf9d22009-06-04 16:23:40 -07004056
Jack Palevich1cdef202009-05-22 12:06:27 -07004057} // namespace acc
4058