blob: 38c23d01bd3ac788d2f20b291e3852d76c68ae4b [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070041#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070042#endif
Jack Palevicha6535612009-05-13 16:24:17 -070043
Jack Palevich1cdef202009-05-22 12:06:27 -070044#include <acc/acc.h>
45
Jack Palevich09555c72009-05-27 12:25:55 -070046#define LOG_API(...) do {} while(0)
47// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070048
-b master422972c2009-06-17 19:13:52 -070049#define LOG_STACK(...) do {} while(0)
50// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
51
52// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070053// #define PROVIDE_TRACE_CODEGEN
54
Jack Palevichbbf8ab52009-05-11 11:54:30 -070055namespace acc {
56
Jack Palevich8df46192009-07-07 14:48:51 -070057// Subset of STL vector.
58template<class E> class Vector {
59 public:
60 Vector() {
61 mpBase = 0;
62 mUsed = 0;
63 mSize = 0;
64 }
65
66 ~Vector() {
67 if (mpBase) {
68 for(size_t i = 0; i < mUsed; i++) {
69 mpBase[mUsed].~E();
70 }
71 free(mpBase);
72 }
73 }
74
75 inline E& operator[](size_t i) {
76 return mpBase[i];
77 }
78
79 inline E& front() {
80 return mpBase[0];
81 }
82
83 inline E& back() {
84 return mpBase[mUsed - 1];
85 }
86
87 void pop_back() {
88 mUsed -= 1;
89 mpBase[mUsed].~E();
90 }
91
92 void push_back(const E& item) {
93 * ensure(1) = item;
94 }
95
96 size_t size() {
97 return mUsed;
98 }
99
100private:
101 E* ensure(int n) {
102 size_t newUsed = mUsed + n;
103 if (newUsed > mSize) {
104 size_t newSize = mSize * 2 + 10;
105 if (newSize < newUsed) {
106 newSize = newUsed;
107 }
108 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
109 mSize = newSize;
110 }
111 E* result = mpBase + mUsed;
112 mUsed = newUsed;
113 return result;
114 }
115
116 E* mpBase;
117 size_t mUsed;
118 size_t mSize;
119};
120
Jack Palevichac0e95e2009-05-29 13:53:44 -0700121class ErrorSink {
122public:
123 void error(const char *fmt, ...) {
124 va_list ap;
125 va_start(ap, fmt);
126 verror(fmt, ap);
127 va_end(ap);
128 }
129
130 virtual void verror(const char* fmt, va_list ap) = 0;
131};
132
133class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700134 typedef int tokenid_t;
135 enum TypeTag {
136 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
137 TY_POINTER, TY_FUNC, TY_PARAM
138 };
139
140 struct Type {
141 TypeTag tag;
142 tokenid_t id; // For function arguments
143 Type* pHead;
144 Type* pTail;
145 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700146
Jack Palevich21a15a22009-05-11 14:49:29 -0700147 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700148 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700149 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700150 ErrorSink* mErrorSink;
151 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700152 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700153
Jack Palevich21a15a22009-05-11 14:49:29 -0700154 void release() {
155 if (pProgramBase != 0) {
156 free(pProgramBase);
157 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700158 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700159 }
160
Jack Palevich0a280a02009-06-11 10:53:51 -0700161 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700162 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700163 bool overflow = newSize > mSize;
164 if (overflow && !mOverflowed) {
165 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700166 if (mErrorSink) {
167 mErrorSink->error("Code too large: %d bytes", newSize);
168 }
169 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700170 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700171 }
172
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 public:
174 CodeBuf() {
175 pProgramBase = 0;
176 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700177 mErrorSink = 0;
178 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700179 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700180 }
181
182 ~CodeBuf() {
183 release();
184 }
185
186 void init(int size) {
187 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700188 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700189 pProgramBase = (char*) calloc(1, size);
190 ind = pProgramBase;
191 }
192
Jack Palevichac0e95e2009-05-29 13:53:44 -0700193 void setErrorSink(ErrorSink* pErrorSink) {
194 mErrorSink = pErrorSink;
195 }
196
Jack Palevich546b2242009-05-13 15:10:04 -0700197 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700198 if(check(4)) {
199 return 0;
200 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700201 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700202 * (int*) ind = n;
203 ind += 4;
204 return result;
205 }
206
Jack Palevich21a15a22009-05-11 14:49:29 -0700207 /*
208 * Output a byte. Handles all values, 0..ff.
209 */
210 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700211 if(check(1)) {
212 return;
213 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700214 *ind++ = n;
215 }
216
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 inline void* getBase() {
218 return (void*) pProgramBase;
219 }
220
Jack Palevich8b0624c2009-05-20 12:12:06 -0700221 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700222 return ind - pProgramBase;
223 }
224
Jack Palevich8b0624c2009-05-20 12:12:06 -0700225 intptr_t getPC() {
226 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700227 }
228 };
229
Jack Palevich1cdef202009-05-22 12:06:27 -0700230 /**
231 * A code generator creates an in-memory program, generating the code on
232 * the fly. There is one code generator implementation for each supported
233 * architecture.
234 *
235 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700236 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700237 * FP - a frame pointer for accessing function arguments and local
238 * variables.
239 * SP - a stack pointer for storing intermediate results while evaluating
240 * expressions. The stack pointer grows downwards.
241 *
242 * The function calling convention is that all arguments are placed on the
243 * stack such that the first argument has the lowest address.
244 * After the call, the result is in R0. The caller is responsible for
245 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700246 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700247 * FP and SP registers are saved.
248 */
249
Jack Palevich21a15a22009-05-11 14:49:29 -0700250 class CodeGenerator {
251 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700252 CodeGenerator() {
253 mErrorSink = 0;
254 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700255 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700256 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700257 virtual ~CodeGenerator() {}
258
Jack Palevich22305132009-05-13 10:58:45 -0700259 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700260 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700261 pCodeBuf->setErrorSink(mErrorSink);
262 }
263
Jack Palevichb67b18f2009-06-11 21:12:23 -0700264 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700265 mErrorSink = pErrorSink;
266 if (pCodeBuf) {
267 pCodeBuf->setErrorSink(mErrorSink);
268 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700269 }
270
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 /* Emit a function prolog.
272 * argCount is the number of arguments.
273 * Save the old value of the FP.
274 * Set the new value of the FP.
275 * Convert from the native platform calling convention to
276 * our stack-based calling convention. This may require
277 * pushing arguments from registers to the stack.
278 * Allocate "N" bytes of stack space. N isn't known yet, so
279 * just emit the instructions for adjusting the stack, and return
280 * the address to patch up. The patching will be done in
281 * functionExit().
282 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700283 */
Jack Palevich546b2242009-05-13 15:10:04 -0700284 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700285
Jack Palevich1cdef202009-05-22 12:06:27 -0700286 /* Emit a function epilog.
287 * Restore the old SP and FP register values.
288 * Return to the calling function.
289 * argCount - the number of arguments to the function.
290 * localVariableAddress - returned from functionEntry()
291 * localVariableSize - the size in bytes of the local variables.
292 */
293 virtual void functionExit(int argCount, int localVariableAddress,
294 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700295
Jack Palevich1cdef202009-05-22 12:06:27 -0700296 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700297 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700298
Jack Palevich1a539db2009-07-08 13:04:41 -0700299 /* Load floating point value from global address. */
300 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700301
Jack Palevich1cdef202009-05-22 12:06:27 -0700302 /* Jump to a target, and return the address of the word that
303 * holds the target data, in case it needs to be fixed up later.
304 */
Jack Palevich22305132009-05-13 10:58:45 -0700305 virtual int gjmp(int t) = 0;
306
Jack Palevich1cdef202009-05-22 12:06:27 -0700307 /* Test R0 and jump to a target if the test succeeds.
308 * l = 0: je, l == 1: jne
309 * Return the address of the word that holds the targed data, in
310 * case it needs to be fixed up later.
311 */
Jack Palevich22305132009-05-13 10:58:45 -0700312 virtual int gtst(bool l, int t) = 0;
313
Jack Palevich9eed7a22009-07-06 17:24:34 -0700314 /* Compare TOS against R0, and store the boolean result in R0.
315 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700316 * op specifies the comparison.
317 */
Jack Palevich22305132009-05-13 10:58:45 -0700318 virtual void gcmp(int op) = 0;
319
Jack Palevich9eed7a22009-07-06 17:24:34 -0700320 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700321 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700322 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700323 */
Jack Palevich546b2242009-05-13 15:10:04 -0700324 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700325
Jack Palevich9eed7a22009-07-06 17:24:34 -0700326 /* Compare 0 against R0, and store the boolean result in R0.
327 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700329 virtual void gUnaryCmp(int op) = 0;
330
331 /* Perform the arithmetic op specified by op. 0 is the
332 * left argument, R0 is the right argument.
333 */
334 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700335
Jack Palevich1cdef202009-05-22 12:06:27 -0700336 /* Push R0 onto the stack.
337 */
338 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700339
Jack Palevich9eed7a22009-07-06 17:24:34 -0700340 /* Store R0 to the address stored in TOS.
341 * The TOS is popped.
342 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700343 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700344 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700345
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700347 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700348 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700350
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 /* Load the absolute address of a variable to R0.
352 * If ea <= LOCAL, then this is a local variable, or an
353 * argument, addressed relative to FP.
354 * else it is an absolute global address.
355 */
Jack Palevich8df46192009-07-07 14:48:51 -0700356 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700357
Jack Palevich1cdef202009-05-22 12:06:27 -0700358 /* Store R0 to a variable.
359 * If ea <= LOCAL, then this is a local variable, or an
360 * argument, addressed relative to FP.
361 * else it is an absolute global address.
362 */
363 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700364
Jack Palevich1cdef202009-05-22 12:06:27 -0700365 /* load R0 from a variable.
366 * If ea <= LOCAL, then this is a local variable, or an
367 * argument, addressed relative to FP.
368 * else it is an absolute global address.
369 * If isIncDec is true, then the stored variable's value
370 * should be post-incremented or post-decremented, based
371 * on the value of op.
372 */
Jack Palevich8df46192009-07-07 14:48:51 -0700373 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
374
375 /**
376 * Convert R0 to the given type.
377 */
378 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700379
Jack Palevich1cdef202009-05-22 12:06:27 -0700380 /* Emit code to adjust the stack for a function call. Return the
381 * label for the address of the instruction that adjusts the
382 * stack size. This will be passed as argument "a" to
383 * endFunctionCallArguments.
384 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700385 virtual int beginFunctionCallArguments() = 0;
386
Jack Palevich1cdef202009-05-22 12:06:27 -0700387 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700388 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700389 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700390 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700391
Jack Palevich1cdef202009-05-22 12:06:27 -0700392 /* Patch the function call preamble.
393 * a is the address returned from beginFunctionCallArguments
394 * l is the number of bytes the arguments took on the stack.
395 * Typically you would also emit code to convert the argument
396 * list into whatever the native function calling convention is.
397 * On ARM for example you would pop the first 5 arguments into
398 * R0..R4
399 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700400 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700401
Jack Palevich1cdef202009-05-22 12:06:27 -0700402 /* Emit a call to an unknown function. The argument "symbol" needs to
403 * be stored in the location where the address should go. It forms
404 * a chain. The address will be patched later.
405 * Return the address of the word that has to be patched.
406 */
Jack Palevich8df46192009-07-07 14:48:51 -0700407 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700408
Jack Palevich1cdef202009-05-22 12:06:27 -0700409 /* Call a function using PC-relative addressing. t is the PC-relative
410 * address of the function. It has already been adjusted for the
411 * architectural jump offset, so just store it as-is.
412 */
Jack Palevich8df46192009-07-07 14:48:51 -0700413 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700414
Jack Palevich1cdef202009-05-22 12:06:27 -0700415 /* Call a function pointer. L is the number of bytes the arguments
416 * take on the stack. The address of the function is stored at
417 * location SP + l.
418 */
Jack Palevich8df46192009-07-07 14:48:51 -0700419 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700420
Jack Palevich1cdef202009-05-22 12:06:27 -0700421 /* Adjust SP after returning from a function call. l is the
422 * number of bytes of arguments stored on the stack. isIndirect
423 * is true if this was an indirect call. (In which case the
424 * address of the function is stored at location SP + l.)
425 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700426 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevich1cdef202009-05-22 12:06:27 -0700428 /* Print a disassembly of the assembled code to out. Return
429 * non-zero if there is an error.
430 */
Jack Palevicha6535612009-05-13 16:24:17 -0700431 virtual int disassemble(FILE* out) = 0;
432
Jack Palevich1cdef202009-05-22 12:06:27 -0700433 /* Generate a symbol at the current PC. t is the head of a
434 * linked list of addresses to patch.
435 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700436 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700437
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 /*
439 * Do any cleanup work required at the end of a compile.
440 * For example, an instruction cache might need to be
441 * invalidated.
442 * Return non-zero if there is an error.
443 */
444 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700445
Jack Palevicha6535612009-05-13 16:24:17 -0700446 /**
447 * Adjust relative branches by this amount.
448 */
449 virtual int jumpOffset() = 0;
450
Jack Palevich9eed7a22009-07-06 17:24:34 -0700451 /**
452 * Stack alignment (in bytes) for this type of data
453 */
454 virtual size_t stackAlignment(Type* type) = 0;
455
456 /**
457 * Array element alignment (in bytes) for this type of data.
458 */
459 virtual size_t sizeOf(Type* type) = 0;
460
Jack Palevich1a539db2009-07-08 13:04:41 -0700461 virtual Type* getR0Type() {
462 return mExpressionStack.back();
463 }
464
Jack Palevich21a15a22009-05-11 14:49:29 -0700465 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700466 /*
467 * Output a byte. Handles all values, 0..ff.
468 */
469 void ob(int n) {
470 pCodeBuf->ob(n);
471 }
472
Jack Palevich8b0624c2009-05-20 12:12:06 -0700473 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700474 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700475 }
476
Jack Palevich8b0624c2009-05-20 12:12:06 -0700477 intptr_t getBase() {
478 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700479 }
480
Jack Palevich8b0624c2009-05-20 12:12:06 -0700481 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700482 return pCodeBuf->getPC();
483 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700484
485 intptr_t getSize() {
486 return pCodeBuf->getSize();
487 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700488
489 void error(const char* fmt,...) {
490 va_list ap;
491 va_start(ap, fmt);
492 mErrorSink->verror(fmt, ap);
493 va_end(ap);
494 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700495
496 void assert(bool test) {
497 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700498 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700499 error("code generator assertion failed.");
500 }
501 }
Jack Palevich8df46192009-07-07 14:48:51 -0700502
503 void setR0Type(Type* pType) {
504 mExpressionStack.back() = pType;
505 }
506
Jack Palevich8df46192009-07-07 14:48:51 -0700507 Type* getTOSType() {
508 return mExpressionStack[mExpressionStack.size()-2];
509 }
510
511 void pushType() {
512 mExpressionStack.push_back(NULL);
513 }
514
515 void popType() {
516 mExpressionStack.pop_back();
517 }
518
519 bool bitsSame(Type* pA, Type* pB) {
520 return collapseType(pA->tag) == collapseType(pB->tag);
521 }
522
523 TypeTag collapseType(TypeTag tag) {
524 static const TypeTag collapsedTag[] = {
525 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
526 TY_VOID, TY_VOID};
527 return collapsedTag[tag];
528 }
529
Jack Palevich1a539db2009-07-08 13:04:41 -0700530 TypeTag collapseTypeR0() {
531 return collapseType(getR0Type()->tag);
532 }
533
534 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700535 return isFloatTag(pType->tag);
536 }
537
538 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700539 return tag == TY_FLOAT || tag == TY_DOUBLE;
540 }
541
Jack Palevich21a15a22009-05-11 14:49:29 -0700542 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700543 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700544 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700545 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700546 };
547
Jack Paleviche7b59062009-05-19 17:12:17 -0700548#ifdef PROVIDE_ARM_CODEGEN
549
Jack Palevich22305132009-05-13 10:58:45 -0700550 class ARMCodeGenerator : public CodeGenerator {
551 public:
552 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700553
Jack Palevich22305132009-05-13 10:58:45 -0700554 virtual ~ARMCodeGenerator() {}
555
556 /* returns address to patch with local variable size
557 */
Jack Palevich546b2242009-05-13 15:10:04 -0700558 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700559 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700560 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700561 // sp -> arg4 arg5 ...
562 // Push our register-based arguments back on the stack
563 if (argCount > 0) {
564 int regArgCount = argCount <= 4 ? argCount : 4;
565 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700566 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700567 }
568 // sp -> arg0 arg1 ...
569 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700570 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700571 // sp, fp -> oldfp, retadr, arg0 arg1 ....
572 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700573 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700574 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700575 // We don't know how many local variables we are going to use,
576 // but we will round the allocation up to a multiple of
577 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700578 }
579
Jack Palevich546b2242009-05-13 15:10:04 -0700580 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700581 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700582 // Round local variable size up to a multiple of stack alignment
583 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
584 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700585 // Patch local variable allocation code:
586 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700587 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700588 }
Jack Palevich69796b62009-05-14 15:42:26 -0700589 *(char*) (localVariableAddress) = localVariableSize;
590
591 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
592 o4(0xE1A0E00B); // mov lr, fp
593 o4(0xE59BB000); // ldr fp, [fp]
594 o4(0xE28ED004); // add sp, lr, #4
595 // sp -> retadr, arg0, ...
596 o4(0xE8BD4000); // ldmfd sp!, {lr}
597 // sp -> arg0 ....
598 if (argCount > 0) {
599 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700600 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700601 // earlier. We don't need to actually store them anywhere,
602 // just adjust the stack.
603 int regArgCount = argCount <= 4 ? argCount : 4;
604 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
605 }
606 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700607 }
608
609 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700610 virtual void li(int t, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700611 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700612 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700613 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700614 } else if (t >= -256 && t < 0) {
615 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700616 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700617 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700618 o4(0xE51F0000); // ldr r0, .L3
619 o4(0xEA000000); // b .L99
620 o4(t); // .L3: .word 0
621 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700622 }
Jack Palevich8df46192009-07-07 14:48:51 -0700623 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700624 }
625
Jack Palevich1a539db2009-07-08 13:04:41 -0700626 virtual void loadFloat(int address, Type* pType) {
627 error("Unimplemented.\n");
Jack Palevich8df46192009-07-07 14:48:51 -0700628 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700629 }
630
Jack Palevich22305132009-05-13 10:58:45 -0700631 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700632 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700633 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700634 }
635
636 /* l = 0: je, l == 1: jne */
637 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700638 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700639 o4(0xE3500000); // cmp r0,#0
640 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
641 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700642 }
643
644 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700645 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700646 o4(0xE8BD0002); // ldmfd sp!,{r1}
647 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700648 o4(0xE1510000); // cmp r1, r1
649 switch(op) {
650 case OP_EQUALS:
651 o4(0x03A00001); // moveq r0,#1
652 o4(0x13A00000); // movne r0,#0
653 break;
654 case OP_NOT_EQUALS:
655 o4(0x03A00000); // moveq r0,#0
656 o4(0x13A00001); // movne r0,#1
657 break;
658 case OP_LESS_EQUAL:
659 o4(0xD3A00001); // movle r0,#1
660 o4(0xC3A00000); // movgt r0,#0
661 break;
662 case OP_GREATER:
663 o4(0xD3A00000); // movle r0,#0
664 o4(0xC3A00001); // movgt r0,#1
665 break;
666 case OP_GREATER_EQUAL:
667 o4(0xA3A00001); // movge r0,#1
668 o4(0xB3A00000); // movlt r0,#0
669 break;
670 case OP_LESS:
671 o4(0xA3A00000); // movge r0,#0
672 o4(0xB3A00001); // movlt r0,#1
673 break;
674 default:
675 error("Unknown comparison op %d", op);
676 break;
677 }
Jack Palevich8df46192009-07-07 14:48:51 -0700678 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700679 }
680
Jack Palevich546b2242009-05-13 15:10:04 -0700681 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700682 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700683 o4(0xE8BD0002); // ldmfd sp!,{r1}
684 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700685 switch(op) {
686 case OP_MUL:
687 o4(0x0E0000091); // mul r0,r1,r0
688 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700689 case OP_DIV:
690 callRuntime(runtime_DIV);
691 break;
692 case OP_MOD:
693 callRuntime(runtime_MOD);
694 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700695 case OP_PLUS:
696 o4(0xE0810000); // add r0,r1,r0
697 break;
698 case OP_MINUS:
699 o4(0xE0410000); // sub r0,r1,r0
700 break;
701 case OP_SHIFT_LEFT:
702 o4(0xE1A00011); // lsl r0,r1,r0
703 break;
704 case OP_SHIFT_RIGHT:
705 o4(0xE1A00051); // asr r0,r1,r0
706 break;
707 case OP_BIT_AND:
708 o4(0xE0010000); // and r0,r1,r0
709 break;
710 case OP_BIT_XOR:
711 o4(0xE0210000); // eor r0,r1,r0
712 break;
713 case OP_BIT_OR:
714 o4(0xE1810000); // orr r0,r1,r0
715 break;
716 case OP_BIT_NOT:
717 o4(0xE1E00000); // mvn r0, r0
718 break;
719 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700720 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700721 break;
722 }
Jack Palevich8df46192009-07-07 14:48:51 -0700723 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700724 }
725
Jack Palevich9eed7a22009-07-06 17:24:34 -0700726 virtual void gUnaryCmp(int op) {
727 LOG_API("gcmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700728 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700729 o4(0xE1510000); // cmp r1, r1
730 switch(op) {
731 case OP_NOT_EQUALS:
732 o4(0x03A00000); // moveq r0,#0
733 o4(0x13A00001); // movne r0,#1
734 break;
735 default:
736 error("Unknown unary comparison op %d", op);
737 break;
738 }
739 }
740
741 virtual void genUnaryOp(int op) {
742 LOG_API("genOp(%d);\n", op);
743 switch(op) {
744 case OP_PLUS:
745 // Do nothing
746 break;
747 case OP_MINUS:
748 o4(0xE3A01000); // mov r1, #0
749 o4(0xE0410000); // sub r0,r1,r0
750 break;
751 case OP_BIT_NOT:
752 o4(0xE1E00000); // mvn r0, r0
753 break;
754 default:
755 error("Unknown unary op %d\n", op);
756 break;
757 }
Jack Palevich22305132009-05-13 10:58:45 -0700758 }
759
Jack Palevich1cdef202009-05-22 12:06:27 -0700760 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700761 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700762 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700763 mStackUse += 4;
Jack Palevich8df46192009-07-07 14:48:51 -0700764 pushType();
-b master422972c2009-06-17 19:13:52 -0700765 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700766 }
767
Jack Palevich9eed7a22009-07-06 17:24:34 -0700768 virtual void storeR0ToTOS(Type* pPointerType) {
769 LOG_API("storeR0ToTOS(%d);\n", isInt);
770 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700771 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700772 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700773 switch (pPointerType->pHead->tag) {
774 case TY_INT:
775 o4(0xE5810000); // str r0, [r1]
776 break;
777 case TY_CHAR:
778 o4(0xE5C10000); // strb r0, [r1]
779 break;
780 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700781 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700782 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700783 }
Jack Palevich8df46192009-07-07 14:48:51 -0700784 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700785 }
786
Jack Palevich9eed7a22009-07-06 17:24:34 -0700787 virtual void loadR0FromR0(Type* pPointerType) {
788 LOG_API("loadR0FromR0(%d);\n", pPointerType);
789 assert(pPointerType->tag == TY_POINTER);
790 switch (pPointerType->pHead->tag) {
791 case TY_INT:
792 o4(0xE5900000); // ldr r0, [r0]
793 break;
794 case TY_CHAR:
795 o4(0xE5D00000); // ldrb r0, [r0]
796 break;
797 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700798 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700799 break;
800 }
Jack Palevich8df46192009-07-07 14:48:51 -0700801 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -0700802 }
803
Jack Palevich8df46192009-07-07 14:48:51 -0700804 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700805 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700806 if (ea < LOCAL) {
807 // Local, fp relative
808 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
809 error("Offset out of range: %08x", ea);
810 }
811 if (ea < 0) {
812 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
813 } else {
814 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
815 }
Jack Palevichbd894902009-05-14 19:35:31 -0700816 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700817 // Global, absolute.
818 o4(0xE59F0000); // ldr r0, .L1
819 o4(0xEA000000); // b .L99
820 o4(ea); // .L1: .word 0
821 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700822 }
Jack Palevich8df46192009-07-07 14:48:51 -0700823 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -0700824 }
825
Jack Palevich1cdef202009-05-22 12:06:27 -0700826 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700827 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700828 if (ea < LOCAL) {
829 // Local, fp relative
830 if (ea < -4095 || ea > 4095) {
831 error("Offset out of range: %08x", ea);
832 }
833 if (ea < 0) {
834 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
835 } else {
836 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
837 }
838 } else{
839 // Global, absolute
840 o4(0xE59F1000); // ldr r1, .L1
841 o4(0xEA000000); // b .L99
842 o4(ea); // .L1: .word 0
843 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700844 }
Jack Palevich22305132009-05-13 10:58:45 -0700845 }
846
Jack Palevich8df46192009-07-07 14:48:51 -0700847 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700848 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich4d93f302009-05-15 13:30:00 -0700849 if (ea < LOCAL) {
850 // Local, fp relative
851 if (ea < -4095 || ea > 4095) {
852 error("Offset out of range: %08x", ea);
853 }
854 if (ea < 0) {
855 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
856 } else {
857 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
858 }
Jack Palevich69796b62009-05-14 15:42:26 -0700859 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700860 // Global, absolute
861 o4(0xE59F2000); // ldr r2, .L1
862 o4(0xEA000000); // b .L99
863 o4(ea); // .L1: .word ea
864 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700865 }
Jack Palevich22305132009-05-13 10:58:45 -0700866
Jack Palevich4d93f302009-05-15 13:30:00 -0700867 if (isIncDec) {
868 switch (op) {
869 case OP_INCREMENT:
870 o4(0xE2801001); // add r1, r0, #1
871 break;
872 case OP_DECREMENT:
873 o4(0xE2401001); // sub r1, r0, #1
874 break;
875 default:
876 error("unknown opcode: %d", op);
877 }
878 if (ea < LOCAL) {
879 // Local, fp relative
880 // Don't need range check, was already checked above
881 if (ea < 0) {
882 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
883 } else {
884 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
885 }
886 } else{
887 // Global, absolute
888 // r2 is already set up from before.
889 o4(0xE5821000); // str r1, [r2]
890 }
Jack Palevichbd894902009-05-14 19:35:31 -0700891 }
Jack Palevich8df46192009-07-07 14:48:51 -0700892 setR0Type(pType);
893 }
894
895 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -0700896 Type* pR0Type = getR0Type();
897 if (bitsSame(pType, pR0Type)) {
898 // do nothing special
899 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
900 // do nothing special, both held in same register on x87.
901 } else {
902 error("Incompatible types old: %d new: %d",
903 pR0Type->tag, pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -0700904 }
Jack Palevich1a539db2009-07-08 13:04:41 -0700905 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700906 }
907
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700908 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700909 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700910 return o4(0xE24DDF00); // Placeholder
911 }
912
Jack Palevich1a539db2009-07-08 13:04:41 -0700913 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700914 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700915 if (l < 0 || l > 4096-4) {
916 error("l out of range for stack offset: 0x%08x", l);
917 }
918 o4(0xE58D0000 + l); // str r0, [sp, #4]
Jack Palevich1a539db2009-07-08 13:04:41 -0700919 return 4;
Jack Palevich7810bc92009-05-15 14:31:47 -0700920 }
921
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700922 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700923 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700924 int argCount = l >> 2;
925 int argumentStackUse = l;
926 if (argCount > 0) {
927 int regArgCount = argCount > 4 ? 4 : argCount;
928 argumentStackUse -= regArgCount * 4;
929 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
930 }
931 mStackUse += argumentStackUse;
932
933 // Align stack.
934 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
935 * STACK_ALIGNMENT);
936 mStackAlignmentAdjustment = 0;
937 if (missalignment > 0) {
938 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
939 }
940 l += mStackAlignmentAdjustment;
941
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700942 if (l < 0 || l > 0x3FC) {
943 error("L out of range for stack adjustment: 0x%08x", l);
944 }
945 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700946 mStackUse += mStackAlignmentAdjustment;
947 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
948 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700949 }
950
Jack Palevich8df46192009-07-07 14:48:51 -0700951 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700952 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -0700953 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700954 // Forward calls are always short (local)
955 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700956 }
957
Jack Palevich8df46192009-07-07 14:48:51 -0700958 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700959 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -0700960 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700961 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700962 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700963 if (t >= - (1 << 25) && t < (1 << 25)) {
964 o4(0xEB000000 | encodeAddress(t));
965 } else {
966 // Long call.
967 o4(0xE59FC000); // ldr r12, .L1
968 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700969 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700970 o4(0xE08CC00F); // .L99: add r12,pc
971 o4(0xE12FFF3C); // blx r12
972 }
Jack Palevich22305132009-05-13 10:58:45 -0700973 }
974
Jack Palevich8df46192009-07-07 14:48:51 -0700975 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700976 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -0700977 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -0700978 int argCount = l >> 2;
979 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700980 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700981 if (adjustedL < 0 || adjustedL > 4096-4) {
982 error("l out of range for stack offset: 0x%08x", l);
983 }
984 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
985 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700986 }
987
Jack Palevich7810bc92009-05-15 14:31:47 -0700988 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700989 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700990 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700991 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700992 int stackUse = stackArgs + (isIndirect ? 1 : 0)
993 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700994 if (stackUse) {
995 if (stackUse < 0 || stackUse > 255) {
996 error("L out of range for stack adjustment: 0x%08x", l);
997 }
998 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -0700999 mStackUse -= stackUse * 4;
1000 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001001 }
Jack Palevich22305132009-05-13 10:58:45 -07001002 }
1003
Jack Palevicha6535612009-05-13 16:24:17 -07001004 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001005 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001006 }
1007
1008 /* output a symbol and patch all calls to it */
1009 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001010 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001011 int n;
1012 int base = getBase();
1013 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001014 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001015 while (t) {
1016 int data = * (int*) t;
1017 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1018 if (decodedOffset == 0) {
1019 n = 0;
1020 } else {
1021 n = base + decodedOffset; /* next value */
1022 }
1023 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1024 | encodeRelAddress(pc - t - 8);
1025 t = n;
1026 }
1027 }
1028
Jack Palevich1cdef202009-05-22 12:06:27 -07001029 virtual int finishCompile() {
1030#if defined(__arm__)
1031 const long base = long(getBase());
1032 const long curr = long(getPC());
1033 int err = cacheflush(base, curr, 0);
1034 return err;
1035#else
1036 return 0;
1037#endif
1038 }
1039
Jack Palevicha6535612009-05-13 16:24:17 -07001040 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001041#ifdef ENABLE_ARM_DISASSEMBLY
1042 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001043 disasm_interface_t di;
1044 di.di_readword = disassemble_readword;
1045 di.di_printaddr = disassemble_printaddr;
1046 di.di_printf = disassemble_printf;
1047
1048 int base = getBase();
1049 int pc = getPC();
1050 for(int i = base; i < pc; i += 4) {
1051 fprintf(out, "%08x: %08x ", i, *(int*) i);
1052 ::disasm(&di, i, 0);
1053 }
Jack Palevich09555c72009-05-27 12:25:55 -07001054#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001055 return 0;
1056 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001057
Jack Palevich9eed7a22009-07-06 17:24:34 -07001058 /**
1059 * Stack alignment (in bytes) for this type of data
1060 */
1061 virtual size_t stackAlignment(Type* pType){
1062 switch(pType->tag) {
1063 case TY_DOUBLE:
1064 return 8;
1065 default:
1066 return 4;
1067 }
1068 }
1069
1070 /**
1071 * Array element alignment (in bytes) for this type of data.
1072 */
1073 virtual size_t sizeOf(Type* pType){
1074 switch(pType->tag) {
1075 case TY_INT:
1076 return 4;
1077 case TY_CHAR:
1078 return 1;
1079 default:
1080 return 0;
1081 case TY_FLOAT:
1082 return 4;
1083 case TY_DOUBLE:
1084 return 8;
1085 case TY_POINTER:
1086 return 4;
1087 }
1088 }
Jack Palevich22305132009-05-13 10:58:45 -07001089 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001090 static FILE* disasmOut;
1091
1092 static u_int
1093 disassemble_readword(u_int address)
1094 {
1095 return(*((u_int *)address));
1096 }
1097
1098 static void
1099 disassemble_printaddr(u_int address)
1100 {
1101 fprintf(disasmOut, "0x%08x", address);
1102 }
1103
1104 static void
1105 disassemble_printf(const char *fmt, ...) {
1106 va_list ap;
1107 va_start(ap, fmt);
1108 vfprintf(disasmOut, fmt, ap);
1109 va_end(ap);
1110 }
1111
1112 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1113
1114 /** Encode a relative address that might also be
1115 * a label.
1116 */
1117 int encodeAddress(int value) {
1118 int base = getBase();
1119 if (value >= base && value <= getPC() ) {
1120 // This is a label, encode it relative to the base.
1121 value = value - base;
1122 }
1123 return encodeRelAddress(value);
1124 }
1125
1126 int encodeRelAddress(int value) {
1127 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1128 }
Jack Palevich22305132009-05-13 10:58:45 -07001129
Jack Palevich3d474a72009-05-15 15:12:38 -07001130 typedef int (*int2FnPtr)(int a, int b);
1131 void callRuntime(int2FnPtr fn) {
1132 o4(0xE59F2000); // ldr r2, .L1
1133 o4(0xEA000000); // b .L99
1134 o4((int) fn); //.L1: .word fn
1135 o4(0xE12FFF32); //.L99: blx r2
1136 }
1137
1138 static int runtime_DIV(int a, int b) {
1139 return b / a;
1140 }
1141
1142 static int runtime_MOD(int a, int b) {
1143 return b % a;
1144 }
-b master422972c2009-06-17 19:13:52 -07001145
1146 static const int STACK_ALIGNMENT = 8;
1147 int mStackUse;
1148 // This variable holds the amount we adjusted the stack in the most
1149 // recent endFunctionCallArguments call. It's examined by the
1150 // following adjustStackAfterCall call.
1151 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001152 };
1153
Jack Palevich09555c72009-05-27 12:25:55 -07001154#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001155
1156#ifdef PROVIDE_X86_CODEGEN
1157
Jack Palevich21a15a22009-05-11 14:49:29 -07001158 class X86CodeGenerator : public CodeGenerator {
1159 public:
1160 X86CodeGenerator() {}
1161 virtual ~X86CodeGenerator() {}
1162
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001163 /* returns address to patch with local variable size
1164 */
Jack Palevich546b2242009-05-13 15:10:04 -07001165 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001166 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1167 return oad(0xec81, 0); /* sub $xxx, %esp */
1168 }
1169
Jack Palevich546b2242009-05-13 15:10:04 -07001170 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001171 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001172 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001173 }
1174
Jack Palevich21a15a22009-05-11 14:49:29 -07001175 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001176 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001177 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001178 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001179 }
1180
Jack Palevich1a539db2009-07-08 13:04:41 -07001181 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001182 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001183 switch (pType->tag) {
1184 case TY_FLOAT:
1185 oad(0x05D9, address); // flds
1186 break;
1187 case TY_DOUBLE:
1188 oad(0x05DD, address); // fldl
1189 break;
1190 default:
1191 assert(false);
1192 break;
1193 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001194 }
1195
Jack Palevich22305132009-05-13 10:58:45 -07001196 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001197 return psym(0xe9, t);
1198 }
1199
1200 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001201 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001202 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1203 return psym(0x84 + l, t);
1204 }
1205
Jack Palevich22305132009-05-13 10:58:45 -07001206 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001207 int t = decodeOp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001208 o(0x59); /* pop %ecx */
Jack Palevich21a15a22009-05-11 14:49:29 -07001209 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001210 li(0, NULL);
Jack Palevich21a15a22009-05-11 14:49:29 -07001211 o(0x0f); /* setxx %al */
1212 o(t + 0x90);
1213 o(0xc0);
Jack Palevich8df46192009-07-07 14:48:51 -07001214 popType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001215 }
1216
Jack Palevich546b2242009-05-13 15:10:04 -07001217 virtual void genOp(int op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001218 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001219 o(decodeOp(op));
1220 if (op == OP_MOD)
1221 o(0x92); /* xchg %edx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001222 popType();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001223 }
1224
Jack Palevich9eed7a22009-07-06 17:24:34 -07001225 virtual void gUnaryCmp(int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001226 oad(0xb9, 0); /* movl $0, %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001227 int t = decodeOp(op);
1228 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001229 li(0, NULL);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001230 o(0x0f); /* setxx %al */
1231 o(t + 0x90);
1232 o(0xc0);
1233 }
1234
1235 virtual void genUnaryOp(int op) {
1236 oad(0xb9, 0); /* movl $0, %ecx */
1237 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -07001238 }
1239
Jack Palevich1cdef202009-05-22 12:06:27 -07001240 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001241 o(0x50); /* push %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001242 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001243 }
1244
Jack Palevich9eed7a22009-07-06 17:24:34 -07001245 virtual void storeR0ToTOS(Type* pPointerType) {
1246 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001247 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001248 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001249 switch (pPointerType->pHead->tag) {
1250 case TY_INT:
1251 o(0x0189); /* movl %eax/%al, (%ecx) */
1252 break;
1253 case TY_CHAR:
1254 o(0x0188); /* movl %eax/%al, (%ecx) */
1255 break;
1256 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001257 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001258 break;
1259 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001260 }
1261
Jack Palevich9eed7a22009-07-06 17:24:34 -07001262 virtual void loadR0FromR0(Type* pPointerType) {
1263 assert(pPointerType->tag == TY_POINTER);
1264 switch (pPointerType->pHead->tag) {
1265 case TY_INT:
1266 o(0x8b); /* mov (%eax), %eax */
1267 break;
1268 case TY_CHAR:
1269 o(0xbe0f); /* movsbl (%eax), %eax */
1270 break;
1271 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001272 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001273 break;
1274 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001275 ob(0); /* add zero in code */
Jack Palevich8df46192009-07-07 14:48:51 -07001276 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001277 }
1278
Jack Palevich8df46192009-07-07 14:48:51 -07001279 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001280 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001281 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001282 }
1283
Jack Palevich1cdef202009-05-22 12:06:27 -07001284 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001285 gmov(6, ea); /* mov %eax, EA */
1286 }
1287
Jack Palevich8df46192009-07-07 14:48:51 -07001288 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001289 TypeTag tag = collapseType(pType->tag);
1290 switch (tag) {
1291 case TY_INT:
1292 gmov(8, ea); /* mov EA, %eax */
1293 if (isIncDec) {
1294 /* Implement post-increment or post decrement.
1295 */
1296 gmov(0, ea); /* 83 ADD */
1297 o(decodeOp(op));
1298 }
1299 break;
1300 case TY_FLOAT:
1301 if (ea < -LOCAL || ea > LOCAL) {
1302 oad(0x05d9, ea); // flds ea
1303 } else {
1304 oad(0x85d9, ea); // flds ea(%ebp)
1305 }
1306 if (isIncDec) {
1307 error("inc/dec not implemented for float.");
1308 }
1309 break;
1310 case TY_DOUBLE:
1311 if (ea < -LOCAL || ea > LOCAL) {
1312 oad(0x05dd, ea); // fldl ea
1313 } else {
1314 oad(0x85dd, ea); // fldl ea(%ebp)
1315 }
1316 if (isIncDec) {
1317 error("inc/dec not implemented for double.");
1318 }
1319 break;
1320 default:
1321 error("Unable to load type %d", tag);
1322 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07001323 }
Jack Palevich8df46192009-07-07 14:48:51 -07001324 setR0Type(pType);
1325 }
1326
1327 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001328 Type* pR0Type = getR0Type();
1329 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001330 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07001331 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07001332 return;
1333 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001334 if (bitsSame(pType, pR0Type)) {
1335 // do nothing special
1336 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
1337 // do nothing special, both held in same register on x87.
1338 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001339 TypeTag r0Tag = collapseType(pR0Type->tag);
1340 TypeTag destTag = collapseType(pType->tag);
1341 if (r0Tag == TY_INT && isFloatTag(destTag)) {
1342 // Convert R0 from int to float
1343 o(0x50); // push %eax
1344 o(0x2404DB); // fildl 0(%esp)
1345 o(0x58); // pop %eax
1346 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
1347 // Convert R0 from float to int. Complicated because
1348 // need to save and restore the rounding mode.
1349 o(0x50); // push %eax
1350 o(0x50); // push %eax
1351 o(0x02247cD9); // fnstcw 2(%esp)
1352 o(0x2444b70f); // movzwl 2(%esp), %eax
1353 o(0x02);
1354 o(0x0cb4); // movb $12, %ah
1355 o(0x24048966); // movw %ax, 0(%esp)
1356 o(0x242cd9); // fldcw 0(%esp)
1357 o(0x04245cdb); // fistpl 4(%esp)
1358 o(0x02246cd9); // fldcw 2(%esp)
1359 o(0x58); // pop %eax
1360 o(0x58); // pop %eax
1361 } else {
1362 error("Incompatible types old: %d new: %d",
1363 pR0Type->tag, pType->tag);
1364 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001365 }
1366 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001367 }
1368
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001369 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001370 return oad(0xec81, 0); /* sub $xxx, %esp */
1371 }
1372
Jack Palevich1a539db2009-07-08 13:04:41 -07001373 virtual size_t storeR0ToArg(int l) {
1374 Type* pR0Type = getR0Type();
1375 TypeTag r0ct = collapseType(pR0Type->tag);
1376 switch(r0ct) {
1377 case TY_INT:
1378 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1379 return 4;
1380 case TY_FLOAT:
1381 oad(0x249CD9, l); /* fstps xxx(%esp) */
1382 return 4;
1383 case TY_DOUBLE:
1384 oad(0x249CDD, l); /* fstpl xxx(%esp) */
1385 return 8;
1386 default:
1387 assert(false);
1388 return 0;
1389 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001390 }
1391
Jack Palevich7810bc92009-05-15 14:31:47 -07001392 virtual void endFunctionCallArguments(int a, int l) {
1393 * (int*) a = l;
1394 }
1395
Jack Palevich8df46192009-07-07 14:48:51 -07001396 virtual int callForward(int symbol, Type* pFunc) {
1397 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001398 return psym(0xe8, symbol); /* call xxx */
1399 }
1400
Jack Palevich8df46192009-07-07 14:48:51 -07001401 virtual void callRelative(int t, Type* pFunc) {
1402 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001403 psym(0xe8, t); /* call xxx */
1404 }
1405
Jack Palevich8df46192009-07-07 14:48:51 -07001406 virtual void callIndirect(int l, Type* pFunc) {
1407 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001408 oad(0x2494ff, l); /* call *xxx(%esp) */
1409 }
1410
Jack Palevich7810bc92009-05-15 14:31:47 -07001411 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1412 if (isIndirect) {
1413 l += 4;
1414 }
-b master422972c2009-06-17 19:13:52 -07001415 if (l > 0) {
1416 oad(0xc481, l); /* add $xxx, %esp */
1417 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001418 }
1419
Jack Palevicha6535612009-05-13 16:24:17 -07001420 virtual int jumpOffset() {
1421 return 5;
1422 }
1423
1424 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001425 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001426 }
1427
Jack Paleviche7b59062009-05-19 17:12:17 -07001428 /* output a symbol and patch all calls to it */
1429 virtual void gsym(int t) {
1430 int n;
1431 int pc = getPC();
1432 while (t) {
1433 n = *(int *) t; /* next value */
1434 *(int *) t = pc - t - 4;
1435 t = n;
1436 }
1437 }
1438
Jack Palevich1cdef202009-05-22 12:06:27 -07001439 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001440 size_t pagesize = 4096;
1441 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1442 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1443 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1444 if (err) {
1445 error("mprotect() failed: %d", errno);
1446 }
1447 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001448 }
1449
Jack Palevich9eed7a22009-07-06 17:24:34 -07001450 /**
1451 * Stack alignment (in bytes) for this type of data
1452 */
1453 virtual size_t stackAlignment(Type* pType){
1454 switch(pType->tag) {
1455 case TY_DOUBLE:
1456 return 8;
1457 default:
1458 return 4;
1459 }
1460 }
1461
1462 /**
1463 * Array element alignment (in bytes) for this type of data.
1464 */
1465 virtual size_t sizeOf(Type* pType){
1466 switch(pType->tag) {
1467 case TY_INT:
1468 return 4;
1469 case TY_CHAR:
1470 return 1;
1471 default:
1472 return 0;
1473 case TY_FLOAT:
1474 return 4;
1475 case TY_DOUBLE:
1476 return 8;
1477 case TY_POINTER:
1478 return 4;
1479 }
1480 }
1481
Jack Palevich21a15a22009-05-11 14:49:29 -07001482 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001483
1484 /** Output 1 to 4 bytes.
1485 *
1486 */
1487 void o(int n) {
1488 /* cannot use unsigned, so we must do a hack */
1489 while (n && n != -1) {
1490 ob(n & 0xff);
1491 n = n >> 8;
1492 }
1493 }
1494
1495 /* psym is used to put an instruction with a data field which is a
1496 reference to a symbol. It is in fact the same as oad ! */
1497 int psym(int n, int t) {
1498 return oad(n, t);
1499 }
1500
1501 /* instruction + address */
1502 int oad(int n, int t) {
1503 o(n);
1504 int result = getPC();
1505 o4(t);
1506 return result;
1507 }
1508
1509
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001510 static const int operatorHelper[];
1511
1512 int decodeOp(int op) {
1513 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001514 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001515 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001516 }
1517 return operatorHelper[op];
1518 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001519
Jack Palevich546b2242009-05-13 15:10:04 -07001520 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001521 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001522 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001523 }
1524 };
1525
Jack Paleviche7b59062009-05-19 17:12:17 -07001526#endif // PROVIDE_X86_CODEGEN
1527
Jack Palevichb67b18f2009-06-11 21:12:23 -07001528#ifdef PROVIDE_TRACE_CODEGEN
1529 class TraceCodeGenerator : public CodeGenerator {
1530 private:
1531 CodeGenerator* mpBase;
1532
1533 public:
1534 TraceCodeGenerator(CodeGenerator* pBase) {
1535 mpBase = pBase;
1536 }
1537
1538 virtual ~TraceCodeGenerator() {
1539 delete mpBase;
1540 }
1541
1542 virtual void init(CodeBuf* pCodeBuf) {
1543 mpBase->init(pCodeBuf);
1544 }
1545
1546 void setErrorSink(ErrorSink* pErrorSink) {
1547 mpBase->setErrorSink(pErrorSink);
1548 }
1549
1550 /* returns address to patch with local variable size
1551 */
1552 virtual int functionEntry(int argCount) {
1553 int result = mpBase->functionEntry(argCount);
1554 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1555 return result;
1556 }
1557
1558 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1559 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1560 argCount, localVariableAddress, localVariableSize);
1561 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1562 }
1563
1564 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001565 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001566 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001567 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001568 }
1569
Jack Palevich1a539db2009-07-08 13:04:41 -07001570 virtual void loadFloat(int address, Type* pType) {
1571 fprintf(stderr, "loadFloat(%d, type)\n", address);
1572 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001573 }
1574
Jack Palevichb67b18f2009-06-11 21:12:23 -07001575 virtual int gjmp(int t) {
1576 int result = mpBase->gjmp(t);
1577 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1578 return result;
1579 }
1580
1581 /* l = 0: je, l == 1: jne */
1582 virtual int gtst(bool l, int t) {
1583 int result = mpBase->gtst(l, t);
1584 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1585 return result;
1586 }
1587
1588 virtual void gcmp(int op) {
1589 fprintf(stderr, "gcmp(%d)\n", op);
1590 mpBase->gcmp(op);
1591 }
1592
1593 virtual void genOp(int op) {
1594 fprintf(stderr, "genOp(%d)\n", op);
1595 mpBase->genOp(op);
1596 }
1597
Jack Palevich9eed7a22009-07-06 17:24:34 -07001598
1599 virtual void gUnaryCmp(int op) {
1600 fprintf(stderr, "gUnaryCmp(%d)\n", op);
1601 mpBase->gUnaryCmp(op);
1602 }
1603
1604 virtual void genUnaryOp(int op) {
1605 fprintf(stderr, "genUnaryOp(%d)\n", op);
1606 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001607 }
1608
1609 virtual void pushR0() {
1610 fprintf(stderr, "pushR0()\n");
1611 mpBase->pushR0();
1612 }
1613
Jack Palevich9eed7a22009-07-06 17:24:34 -07001614 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001615 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001616 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001617 }
1618
Jack Palevich9eed7a22009-07-06 17:24:34 -07001619 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001620 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001621 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001622 }
1623
Jack Palevich8df46192009-07-07 14:48:51 -07001624 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001625 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001626 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001627 }
1628
1629 virtual void storeR0(int ea) {
1630 fprintf(stderr, "storeR0(%d)\n", ea);
1631 mpBase->storeR0(ea);
1632 }
1633
Jack Palevich8df46192009-07-07 14:48:51 -07001634 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001635 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001636 mpBase->loadR0(ea, isIncDec, op, pType);
1637 }
1638
1639 virtual void convertR0(Type* pType){
1640 fprintf(stderr, "convertR0(pType)\n");
1641 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001642 }
1643
1644 virtual int beginFunctionCallArguments() {
1645 int result = mpBase->beginFunctionCallArguments();
1646 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1647 return result;
1648 }
1649
Jack Palevich1a539db2009-07-08 13:04:41 -07001650 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001651 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07001652 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001653 }
1654
1655 virtual void endFunctionCallArguments(int a, int l) {
1656 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1657 mpBase->endFunctionCallArguments(a, l);
1658 }
1659
Jack Palevich8df46192009-07-07 14:48:51 -07001660 virtual int callForward(int symbol, Type* pFunc) {
1661 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001662 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1663 return result;
1664 }
1665
Jack Palevich8df46192009-07-07 14:48:51 -07001666 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001667 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001668 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001669 }
1670
Jack Palevich8df46192009-07-07 14:48:51 -07001671 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001672 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001673 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001674 }
1675
1676 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1677 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1678 mpBase->adjustStackAfterCall(l, isIndirect);
1679 }
1680
1681 virtual int jumpOffset() {
1682 return mpBase->jumpOffset();
1683 }
1684
1685 virtual int disassemble(FILE* out) {
1686 return mpBase->disassemble(out);
1687 }
1688
1689 /* output a symbol and patch all calls to it */
1690 virtual void gsym(int t) {
1691 fprintf(stderr, "gsym(%d)\n", t);
1692 mpBase->gsym(t);
1693 }
1694
1695 virtual int finishCompile() {
1696 int result = mpBase->finishCompile();
1697 fprintf(stderr, "finishCompile() = %d\n", result);
1698 return result;
1699 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001700
1701 /**
1702 * Stack alignment (in bytes) for this type of data
1703 */
1704 virtual size_t stackAlignment(Type* pType){
1705 return mpBase->stackAlignment(pType);
1706 }
1707
1708 /**
1709 * Array element alignment (in bytes) for this type of data.
1710 */
1711 virtual size_t sizeOf(Type* pType){
1712 return mpBase->sizeOf(pType);
1713 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001714
1715 virtual Type* getR0Type() {
1716 return mpBase->getR0Type();
1717 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001718 };
1719
1720#endif // PROVIDE_TRACE_CODEGEN
1721
Jack Palevich569f1352009-06-29 14:29:08 -07001722 class Arena {
1723 public:
1724 // Used to record a given allocation amount.
1725 // Used:
1726 // Mark mark = arena.mark();
1727 // ... lots of arena.allocate()
1728 // arena.free(mark);
1729
1730 struct Mark {
1731 size_t chunk;
1732 size_t offset;
1733 };
1734
1735 Arena() {
1736 mCurrentChunk = 0;
1737 Chunk start(CHUNK_SIZE);
1738 mData.push_back(start);
1739 }
1740
1741 ~Arena() {
1742 for(size_t i = 0; i < mData.size(); i++) {
1743 mData[i].free();
1744 }
1745 }
1746
1747 // Alloc using the standard alignment size safe for any variable
1748 void* alloc(size_t size) {
1749 return alloc(size, 8);
1750 }
1751
1752 Mark mark(){
1753 Mark result;
1754 result.chunk = mCurrentChunk;
1755 result.offset = mData[mCurrentChunk].mOffset;
1756 return result;
1757 }
1758
1759 void freeToMark(const Mark& mark) {
1760 mCurrentChunk = mark.chunk;
1761 mData[mCurrentChunk].mOffset = mark.offset;
1762 }
1763
1764 private:
1765 // Allocate memory aligned to a given size
1766 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1767 // Memory is not zero filled.
1768
1769 void* alloc(size_t size, size_t alignment) {
1770 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1771 if (mCurrentChunk + 1 < mData.size()) {
1772 mCurrentChunk++;
1773 } else {
1774 size_t allocSize = CHUNK_SIZE;
1775 if (allocSize < size + alignment - 1) {
1776 allocSize = size + alignment - 1;
1777 }
1778 Chunk chunk(allocSize);
1779 mData.push_back(chunk);
1780 mCurrentChunk++;
1781 }
1782 }
1783 return mData[mCurrentChunk].allocate(size, alignment);
1784 }
1785
1786 static const size_t CHUNK_SIZE = 128*1024;
1787 // Note: this class does not deallocate its
1788 // memory when it's destroyed. It depends upon
1789 // its parent to deallocate the memory.
1790 struct Chunk {
1791 Chunk() {
1792 mpData = 0;
1793 mSize = 0;
1794 mOffset = 0;
1795 }
1796
1797 Chunk(size_t size) {
1798 mSize = size;
1799 mpData = (char*) malloc(size);
1800 mOffset = 0;
1801 }
1802
1803 ~Chunk() {
1804 // Doesn't deallocate memory.
1805 }
1806
1807 void* allocate(size_t size, size_t alignment) {
1808 size_t alignedOffset = aligned(mOffset, alignment);
1809 void* result = mpData + alignedOffset;
1810 mOffset = alignedOffset + size;
1811 return result;
1812 }
1813
1814 void free() {
1815 if (mpData) {
1816 ::free(mpData);
1817 mpData = 0;
1818 }
1819 }
1820
1821 size_t remainingCapacity(size_t alignment) {
1822 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1823 }
1824
1825 // Assume alignment is a power of two
1826 inline size_t aligned(size_t v, size_t alignment) {
1827 size_t mask = alignment-1;
1828 return (v + mask) & ~mask;
1829 }
1830
1831 char* mpData;
1832 size_t mSize;
1833 size_t mOffset;
1834 };
1835
1836 size_t mCurrentChunk;
1837
1838 Vector<Chunk> mData;
1839 };
1840
Jack Palevich569f1352009-06-29 14:29:08 -07001841 struct VariableInfo;
1842
1843 struct Token {
1844 int hash;
1845 size_t length;
1846 char* pText;
1847 tokenid_t id;
1848
1849 // Current values for the token
1850 char* mpMacroDefinition;
1851 VariableInfo* mpVariableInfo;
1852 };
1853
1854 class TokenTable {
1855 public:
1856 // Don't use 0..0xff, allows characters and operators to be tokens too.
1857
1858 static const int TOKEN_BASE = 0x100;
1859 TokenTable() {
1860 mpMap = hashmapCreate(128, hashFn, equalsFn);
1861 }
1862
1863 ~TokenTable() {
1864 hashmapFree(mpMap);
1865 }
1866
1867 void setArena(Arena* pArena) {
1868 mpArena = pArena;
1869 }
1870
1871 // Returns a token for a given string of characters.
1872 tokenid_t intern(const char* pText, size_t length) {
1873 Token probe;
1874 int hash = hashmapHash((void*) pText, length);
1875 {
1876 Token probe;
1877 probe.hash = hash;
1878 probe.length = length;
1879 probe.pText = (char*) pText;
1880 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1881 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001882 return pValue->id;
1883 }
1884 }
1885
1886 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1887 memset(pToken, 0, sizeof(*pToken));
1888 pToken->hash = hash;
1889 pToken->length = length;
1890 pToken->pText = (char*) mpArena->alloc(length + 1);
1891 memcpy(pToken->pText, pText, length);
1892 pToken->pText[length] = 0;
1893 pToken->id = mTokens.size() + TOKEN_BASE;
1894 mTokens.push_back(pToken);
1895 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001896 return pToken->id;
1897 }
1898
1899 // Return the Token for a given tokenid.
1900 Token& operator[](tokenid_t id) {
1901 return *mTokens[id - TOKEN_BASE];
1902 }
1903
1904 inline size_t size() {
1905 return mTokens.size();
1906 }
1907
1908 private:
1909
1910 static int hashFn(void* pKey) {
1911 Token* pToken = (Token*) pKey;
1912 return pToken->hash;
1913 }
1914
1915 static bool equalsFn(void* keyA, void* keyB) {
1916 Token* pTokenA = (Token*) keyA;
1917 Token* pTokenB = (Token*) keyB;
1918 // Don't need to compare hash values, they should always be equal
1919 return pTokenA->length == pTokenB->length
1920 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1921 }
1922
1923 Hashmap* mpMap;
1924 Vector<Token*> mTokens;
1925 Arena* mpArena;
1926 };
1927
Jack Palevich1cdef202009-05-22 12:06:27 -07001928 class InputStream {
1929 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001930 int getChar() {
1931 if (bumpLine) {
1932 line++;
1933 bumpLine = false;
1934 }
1935 int ch = get();
1936 if (ch == '\n') {
1937 bumpLine = true;
1938 }
1939 return ch;
1940 }
1941 int getLine() {
1942 return line;
1943 }
1944 protected:
1945 InputStream() :
1946 line(1), bumpLine(false) {
1947 }
1948 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001949 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001950 int line;
1951 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001952 };
1953
1954 class FileInputStream : public InputStream {
1955 public:
1956 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001957 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001958 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001959 FILE* f;
1960 };
1961
1962 class TextInputStream : public InputStream {
1963 public:
1964 TextInputStream(const char* text, size_t textLength)
1965 : pText(text), mTextLength(textLength), mPosition(0) {
1966 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001967
1968 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001969 virtual int get() {
1970 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1971 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001972
Jack Palevich1cdef202009-05-22 12:06:27 -07001973 const char* pText;
1974 size_t mTextLength;
1975 size_t mPosition;
1976 };
1977
Jack Palevicheedf9d22009-06-04 16:23:40 -07001978 class String {
1979 public:
1980 String() {
1981 mpBase = 0;
1982 mUsed = 0;
1983 mSize = 0;
1984 }
1985
Jack Palevich303d8ff2009-06-11 19:06:24 -07001986 String(const char* item, int len, bool adopt) {
1987 if (len < 0) {
1988 len = strlen(item);
1989 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001990 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001991 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001992 mUsed = len;
1993 mSize = len + 1;
1994 } else {
1995 mpBase = 0;
1996 mUsed = 0;
1997 mSize = 0;
1998 appendBytes(item, len);
1999 }
2000 }
2001
Jack Palevich303d8ff2009-06-11 19:06:24 -07002002 String(const String& other) {
2003 mpBase = 0;
2004 mUsed = 0;
2005 mSize = 0;
2006 appendBytes(other.getUnwrapped(), other.len());
2007 }
2008
Jack Palevicheedf9d22009-06-04 16:23:40 -07002009 ~String() {
2010 if (mpBase) {
2011 free(mpBase);
2012 }
2013 }
2014
Jack Palevicha6baa232009-06-12 11:25:59 -07002015 String& operator=(const String& other) {
2016 clear();
2017 appendBytes(other.getUnwrapped(), other.len());
2018 return *this;
2019 }
2020
Jack Palevich303d8ff2009-06-11 19:06:24 -07002021 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002022 return mpBase;
2023 }
2024
Jack Palevich303d8ff2009-06-11 19:06:24 -07002025 void clear() {
2026 mUsed = 0;
2027 if (mSize > 0) {
2028 mpBase[0] = 0;
2029 }
2030 }
2031
Jack Palevicheedf9d22009-06-04 16:23:40 -07002032 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002033 appendBytes(s, strlen(s));
2034 }
2035
2036 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002037 memcpy(ensure(n), s, n + 1);
2038 }
2039
2040 void append(char c) {
2041 * ensure(1) = c;
2042 }
2043
Jack Palevich86351982009-06-30 18:09:56 -07002044 void append(String& other) {
2045 appendBytes(other.getUnwrapped(), other.len());
2046 }
2047
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002048 char* orphan() {
2049 char* result = mpBase;
2050 mpBase = 0;
2051 mUsed = 0;
2052 mSize = 0;
2053 return result;
2054 }
2055
Jack Palevicheedf9d22009-06-04 16:23:40 -07002056 void printf(const char* fmt,...) {
2057 va_list ap;
2058 va_start(ap, fmt);
2059 vprintf(fmt, ap);
2060 va_end(ap);
2061 }
2062
2063 void vprintf(const char* fmt, va_list ap) {
2064 char* temp;
2065 int numChars = vasprintf(&temp, fmt, ap);
2066 memcpy(ensure(numChars), temp, numChars+1);
2067 free(temp);
2068 }
2069
Jack Palevich303d8ff2009-06-11 19:06:24 -07002070 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002071 return mUsed;
2072 }
2073
2074 private:
2075 char* ensure(int n) {
2076 size_t newUsed = mUsed + n;
2077 if (newUsed > mSize) {
2078 size_t newSize = mSize * 2 + 10;
2079 if (newSize < newUsed) {
2080 newSize = newUsed;
2081 }
2082 mpBase = (char*) realloc(mpBase, newSize + 1);
2083 mSize = newSize;
2084 }
2085 mpBase[newUsed] = '\0';
2086 char* result = mpBase + mUsed;
2087 mUsed = newUsed;
2088 return result;
2089 }
2090
2091 char* mpBase;
2092 size_t mUsed;
2093 size_t mSize;
2094 };
2095
Jack Palevich569f1352009-06-29 14:29:08 -07002096 void internKeywords() {
2097 // Note: order has to match TOK_ constants
2098 static const char* keywords[] = {
2099 "int",
2100 "char",
2101 "void",
2102 "if",
2103 "else",
2104 "while",
2105 "break",
2106 "return",
2107 "for",
2108 "pragma",
2109 "define",
2110 "auto",
2111 "case",
2112 "const",
2113 "continue",
2114 "default",
2115 "do",
2116 "double",
2117 "enum",
2118 "extern",
2119 "float",
2120 "goto",
2121 "long",
2122 "register",
2123 "short",
2124 "signed",
2125 "sizeof",
2126 "static",
2127 "struct",
2128 "switch",
2129 "typedef",
2130 "union",
2131 "unsigned",
2132 "volatile",
2133 "_Bool",
2134 "_Complex",
2135 "_Imaginary",
2136 "inline",
2137 "restrict",
2138 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002139
Jack Palevich569f1352009-06-29 14:29:08 -07002140 for(int i = 0; keywords[i]; i++) {
2141 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002142 }
Jack Palevich569f1352009-06-29 14:29:08 -07002143 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002144
Jack Palevich36d94142009-06-08 15:55:32 -07002145 struct InputState {
2146 InputStream* pStream;
2147 int oldCh;
2148 };
2149
Jack Palevich2db168f2009-06-11 14:29:47 -07002150 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002151 void* pAddress;
2152 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002153 tokenid_t tok;
2154 size_t level;
2155 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002156 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002157 };
2158
Jack Palevich303d8ff2009-06-11 19:06:24 -07002159 class SymbolStack {
2160 public:
2161 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002162 mpArena = 0;
2163 mpTokenTable = 0;
2164 }
2165
2166 void setArena(Arena* pArena) {
2167 mpArena = pArena;
2168 }
2169
2170 void setTokenTable(TokenTable* pTokenTable) {
2171 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002172 }
2173
2174 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002175 Mark mark;
2176 mark.mArenaMark = mpArena->mark();
2177 mark.mSymbolHead = mStack.size();
2178 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002179 }
2180
2181 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002182 // Undo any shadowing that was done:
2183 Mark mark = mLevelStack.back();
2184 mLevelStack.pop_back();
2185 while (mStack.size() > mark.mSymbolHead) {
2186 VariableInfo* pV = mStack.back();
2187 mStack.pop_back();
2188 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002189 }
Jack Palevich569f1352009-06-29 14:29:08 -07002190 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002191 }
2192
Jack Palevich569f1352009-06-29 14:29:08 -07002193 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2194 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2195 return pV && pV->level == level();
2196 }
2197
2198 VariableInfo* add(tokenid_t tok) {
2199 Token& token = (*mpTokenTable)[tok];
2200 VariableInfo* pOldV = token.mpVariableInfo;
2201 VariableInfo* pNewV =
2202 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2203 memset(pNewV, 0, sizeof(VariableInfo));
2204 pNewV->tok = tok;
2205 pNewV->level = level();
2206 pNewV->pOldDefinition = pOldV;
2207 token.mpVariableInfo = pNewV;
2208 mStack.push_back(pNewV);
2209 return pNewV;
2210 }
2211
Jack Palevich86351982009-06-30 18:09:56 -07002212 VariableInfo* add(Type* pType) {
2213 VariableInfo* pVI = add(pType->id);
2214 pVI->pType = pType;
2215 return pVI;
2216 }
2217
Jack Palevich569f1352009-06-29 14:29:08 -07002218 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2219 for (size_t i = 0; i < mStack.size(); i++) {
2220 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002221 break;
2222 }
2223 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002224 }
2225
Jack Palevich303d8ff2009-06-11 19:06:24 -07002226 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002227 inline size_t level() {
2228 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002229 }
2230
Jack Palevich569f1352009-06-29 14:29:08 -07002231 struct Mark {
2232 Arena::Mark mArenaMark;
2233 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002234 };
2235
Jack Palevich569f1352009-06-29 14:29:08 -07002236 Arena* mpArena;
2237 TokenTable* mpTokenTable;
2238 Vector<VariableInfo*> mStack;
2239 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002240 };
Jack Palevich36d94142009-06-08 15:55:32 -07002241
2242 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002243 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002244 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002245 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002246 int tokl; // token operator level
2247 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002248 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002249 intptr_t loc; // local variable index
2250 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002251 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002252 char* dptr; // Macro state: Points to macro text during macro playback.
2253 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002254 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002255
2256 // Arena for the duration of the compile
2257 Arena mGlobalArena;
2258 // Arena for data that's only needed when compiling a single function
2259 Arena mLocalArena;
2260
2261 TokenTable mTokenTable;
2262 SymbolStack mGlobals;
2263 SymbolStack mLocals;
2264
Jack Palevich40600de2009-07-01 15:32:35 -07002265 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002266 Type* mkpInt; // int
2267 Type* mkpChar; // char
2268 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002269 Type* mkpFloat;
2270 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002271 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002272 Type* mkpIntPtr;
2273 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07002274 Type* mkpFloatPtr;
2275 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07002276 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002277
Jack Palevich36d94142009-06-08 15:55:32 -07002278 InputStream* file;
2279
2280 CodeBuf codeBuf;
2281 CodeGenerator* pGen;
2282
Jack Palevicheedf9d22009-06-04 16:23:40 -07002283 String mErrorBuf;
2284
Jack Palevicheedf9d22009-06-04 16:23:40 -07002285 String mPragmas;
2286 int mPragmaStringCount;
2287
Jack Palevich21a15a22009-05-11 14:49:29 -07002288 static const int ALLOC_SIZE = 99999;
2289
Jack Palevich303d8ff2009-06-11 19:06:24 -07002290 static const int TOK_DUMMY = 1;
2291 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002292 static const int TOK_NUM_FLOAT = 3;
2293 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002294
2295 // 3..255 are character and/or operators
2296
Jack Palevich2db168f2009-06-11 14:29:47 -07002297 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002298 // Order has to match string list in "internKeywords".
2299 enum {
2300 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2301 TOK_INT = TOK_KEYWORD,
2302 TOK_CHAR,
2303 TOK_VOID,
2304 TOK_IF,
2305 TOK_ELSE,
2306 TOK_WHILE,
2307 TOK_BREAK,
2308 TOK_RETURN,
2309 TOK_FOR,
2310 TOK_PRAGMA,
2311 TOK_DEFINE,
2312 TOK_AUTO,
2313 TOK_CASE,
2314 TOK_CONST,
2315 TOK_CONTINUE,
2316 TOK_DEFAULT,
2317 TOK_DO,
2318 TOK_DOUBLE,
2319 TOK_ENUM,
2320 TOK_EXTERN,
2321 TOK_FLOAT,
2322 TOK_GOTO,
2323 TOK_LONG,
2324 TOK_REGISTER,
2325 TOK_SHORT,
2326 TOK_SIGNED,
2327 TOK_SIZEOF,
2328 TOK_STATIC,
2329 TOK_STRUCT,
2330 TOK_SWITCH,
2331 TOK_TYPEDEF,
2332 TOK_UNION,
2333 TOK_UNSIGNED,
2334 TOK_VOLATILE,
2335 TOK__BOOL,
2336 TOK__COMPLEX,
2337 TOK__IMAGINARY,
2338 TOK_INLINE,
2339 TOK_RESTRICT,
2340 // Symbols start after tokens
2341 TOK_SYMBOL
2342 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002343
2344 static const int LOCAL = 0x200;
2345
2346 static const int SYM_FORWARD = 0;
2347 static const int SYM_DEFINE = 1;
2348
2349 /* tokens in string heap */
2350 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002351
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002352 static const int OP_INCREMENT = 0;
2353 static const int OP_DECREMENT = 1;
2354 static const int OP_MUL = 2;
2355 static const int OP_DIV = 3;
2356 static const int OP_MOD = 4;
2357 static const int OP_PLUS = 5;
2358 static const int OP_MINUS = 6;
2359 static const int OP_SHIFT_LEFT = 7;
2360 static const int OP_SHIFT_RIGHT = 8;
2361 static const int OP_LESS_EQUAL = 9;
2362 static const int OP_GREATER_EQUAL = 10;
2363 static const int OP_LESS = 11;
2364 static const int OP_GREATER = 12;
2365 static const int OP_EQUALS = 13;
2366 static const int OP_NOT_EQUALS = 14;
2367 static const int OP_LOGICAL_AND = 15;
2368 static const int OP_LOGICAL_OR = 16;
2369 static const int OP_BIT_AND = 17;
2370 static const int OP_BIT_XOR = 18;
2371 static const int OP_BIT_OR = 19;
2372 static const int OP_BIT_NOT = 20;
2373 static const int OP_LOGICAL_NOT = 21;
2374 static const int OP_COUNT = 22;
2375
2376 /* Operators are searched from front, the two-character operators appear
2377 * before the single-character operators with the same first character.
2378 * @ is used to pad out single-character operators.
2379 */
2380 static const char* operatorChars;
2381 static const char operatorLevel[];
2382
Jack Palevich569f1352009-06-29 14:29:08 -07002383 /* Called when we detect an internal problem. Does nothing in production.
2384 *
2385 */
2386 void internalError() {
2387 * (char*) 0 = 0;
2388 }
2389
Jack Palevich86351982009-06-30 18:09:56 -07002390 void assert(bool isTrue) {
2391 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002392 internalError();
2393 }
Jack Palevich86351982009-06-30 18:09:56 -07002394 }
2395
Jack Palevich40600de2009-07-01 15:32:35 -07002396 bool isSymbol(tokenid_t t) {
2397 return t >= TOK_SYMBOL &&
2398 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2399 }
2400
2401 bool isSymbolOrKeyword(tokenid_t t) {
2402 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002403 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002404 }
2405
Jack Palevich86351982009-06-30 18:09:56 -07002406 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002407 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002408 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2409 if (pV && pV->tok != t) {
2410 internalError();
2411 }
2412 return pV;
2413 }
2414
2415 inline bool isDefined(tokenid_t t) {
2416 return t >= TOK_SYMBOL && VI(t) != 0;
2417 }
2418
Jack Palevich40600de2009-07-01 15:32:35 -07002419 const char* nameof(tokenid_t t) {
2420 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002421 return mTokenTable[t].pText;
2422 }
2423
Jack Palevich21a15a22009-05-11 14:49:29 -07002424 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002425 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002426 }
2427
2428 void inp() {
2429 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002430 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002431 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002432 dptr = 0;
2433 ch = dch;
2434 }
2435 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002436 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002437#if 0
2438 printf("ch='%c' 0x%x\n", ch, ch);
2439#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002440 }
2441
2442 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002443 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002444 }
2445
Jack Palevichb4758ff2009-06-12 12:49:14 -07002446 /* read a character constant, advances ch to after end of constant */
2447 int getq() {
2448 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002449 if (ch == '\\') {
2450 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002451 if (isoctal(ch)) {
2452 // 1 to 3 octal characters.
2453 val = 0;
2454 for(int i = 0; i < 3; i++) {
2455 if (isoctal(ch)) {
2456 val = (val << 3) + ch - '0';
2457 inp();
2458 }
2459 }
2460 return val;
2461 } else if (ch == 'x' || ch == 'X') {
2462 // N hex chars
2463 inp();
2464 if (! isxdigit(ch)) {
2465 error("'x' character escape requires at least one digit.");
2466 } else {
2467 val = 0;
2468 while (isxdigit(ch)) {
2469 int d = ch;
2470 if (isdigit(d)) {
2471 d -= '0';
2472 } else if (d <= 'F') {
2473 d = d - 'A' + 10;
2474 } else {
2475 d = d - 'a' + 10;
2476 }
2477 val = (val << 4) + d;
2478 inp();
2479 }
2480 }
2481 } else {
2482 int val = ch;
2483 switch (ch) {
2484 case 'a':
2485 val = '\a';
2486 break;
2487 case 'b':
2488 val = '\b';
2489 break;
2490 case 'f':
2491 val = '\f';
2492 break;
2493 case 'n':
2494 val = '\n';
2495 break;
2496 case 'r':
2497 val = '\r';
2498 break;
2499 case 't':
2500 val = '\t';
2501 break;
2502 case 'v':
2503 val = '\v';
2504 break;
2505 case '\\':
2506 val = '\\';
2507 break;
2508 case '\'':
2509 val = '\'';
2510 break;
2511 case '"':
2512 val = '"';
2513 break;
2514 case '?':
2515 val = '?';
2516 break;
2517 default:
2518 error("Undefined character escape %c", ch);
2519 break;
2520 }
2521 inp();
2522 return val;
2523 }
2524 } else {
2525 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002526 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002527 return val;
2528 }
2529
2530 static bool isoctal(int ch) {
2531 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002532 }
2533
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002534 bool acceptCh(int c) {
2535 bool result = c == ch;
2536 if (result) {
2537 pdef(ch);
2538 inp();
2539 }
2540 return result;
2541 }
2542
2543 bool acceptDigitsCh() {
2544 bool result = false;
2545 while (isdigit(ch)) {
2546 result = true;
2547 pdef(ch);
2548 inp();
2549 }
2550 return result;
2551 }
2552
2553 void parseFloat() {
2554 tok = TOK_NUM_DOUBLE;
2555 // mTokenString already has the integral part of the number.
2556 acceptCh('.');
2557 acceptDigitsCh();
2558 bool doExp = true;
2559 if (acceptCh('e') || acceptCh('E')) {
2560 // Don't need to do any extra work
2561 } else if (ch == 'f' || ch == 'F') {
2562 pdef('e'); // So it can be parsed by strtof.
2563 inp();
2564 tok = TOK_NUM_FLOAT;
2565 } else {
2566 doExp = false;
2567 }
2568 if (doExp) {
2569 bool digitsRequired = acceptCh('-');
2570 bool digitsFound = acceptDigitsCh();
2571 if (digitsRequired && ! digitsFound) {
2572 error("malformed exponent");
2573 }
2574 }
2575 char* pText = mTokenString.getUnwrapped();
2576 if (tok == TOK_NUM_FLOAT) {
2577 tokd = strtof(pText, 0);
2578 } else {
2579 tokd = strtod(pText, 0);
2580 }
2581 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2582 }
2583
Jack Palevich21a15a22009-05-11 14:49:29 -07002584 void next() {
2585 int l, a;
2586
Jack Palevich546b2242009-05-13 15:10:04 -07002587 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002588 if (ch == '#') {
2589 inp();
2590 next();
2591 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002592 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002593 } else if (tok == TOK_PRAGMA) {
2594 doPragma();
2595 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002596 error("Unsupported preprocessor directive \"%s\"",
2597 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002598 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002599 }
2600 inp();
2601 }
2602 tokl = 0;
2603 tok = ch;
2604 /* encode identifiers & numbers */
2605 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002606 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002607 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002608 pdef(ch);
2609 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002610 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002611 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002612 // Start of a numeric constant. Could be integer, float, or
2613 // double, won't know until we look further.
2614 if (ch == '.' || ch == 'e' || ch == 'e'
2615 || ch == 'f' || ch == 'F') {
2616 parseFloat();
2617 } else {
2618 // It's an integer constant
2619 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2620 tok = TOK_NUM;
2621 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002622 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002623 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2624 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002625 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002626 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2627 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002628 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002629 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002630 dch = ch;
2631 inp();
2632 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002633 }
2634 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002635 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002636 inp();
2637 if (tok == '\'') {
2638 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002639 tokc = getq();
2640 if (ch != '\'') {
2641 error("Expected a ' character, got %c", ch);
2642 } else {
2643 inp();
2644 }
Jack Palevich546b2242009-05-13 15:10:04 -07002645 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002646 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002647 while (ch && ch != EOF) {
2648 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002649 inp();
2650 inp();
2651 if (ch == '/')
2652 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002653 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002654 if (ch == EOF) {
2655 error("End of file inside comment.");
2656 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002657 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002658 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002659 } else if ((tok == '/') & (ch == '/')) {
2660 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002661 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002662 inp();
2663 }
2664 inp();
2665 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002666 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002667 const char* t = operatorChars;
2668 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002669 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002670 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002671 tokl = operatorLevel[opIndex];
2672 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002673 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002674#if 0
2675 printf("%c%c -> tokl=%d tokc=0x%x\n",
2676 l, a, tokl, tokc);
2677#endif
2678 if (a == ch) {
2679 inp();
2680 tok = TOK_DUMMY; /* dummy token for double tokens */
2681 }
2682 break;
2683 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002684 opIndex++;
2685 }
2686 if (l == 0) {
2687 tokl = 0;
2688 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002689 }
2690 }
2691 }
2692#if 0
2693 {
Jack Palevich569f1352009-06-29 14:29:08 -07002694 String buf;
2695 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002696 fprintf(stderr, "%s\n", buf.getUnwrapped());
2697 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002698#endif
2699 }
2700
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002701 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002702 next();
2703 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002704 String* pName = new String();
2705 while (isspace(ch)) {
2706 inp();
2707 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002708 if (ch == '(') {
2709 delete pName;
2710 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002711 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002712 }
2713 while (isspace(ch)) {
2714 inp();
2715 }
Jack Palevich569f1352009-06-29 14:29:08 -07002716 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002717 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002718 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002719 inp();
2720 }
Jack Palevich569f1352009-06-29 14:29:08 -07002721 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2722 memcpy(pDefn, value.getUnwrapped(), value.len());
2723 pDefn[value.len()] = 0;
2724 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002725 }
2726
Jack Palevicheedf9d22009-06-04 16:23:40 -07002727 void doPragma() {
2728 // # pragma name(val)
2729 int state = 0;
2730 while(ch != EOF && ch != '\n' && state < 10) {
2731 switch(state) {
2732 case 0:
2733 if (isspace(ch)) {
2734 inp();
2735 } else {
2736 state++;
2737 }
2738 break;
2739 case 1:
2740 if (isalnum(ch)) {
2741 mPragmas.append(ch);
2742 inp();
2743 } else if (ch == '(') {
2744 mPragmas.append(0);
2745 inp();
2746 state++;
2747 } else {
2748 state = 11;
2749 }
2750 break;
2751 case 2:
2752 if (isalnum(ch)) {
2753 mPragmas.append(ch);
2754 inp();
2755 } else if (ch == ')') {
2756 mPragmas.append(0);
2757 inp();
2758 state = 10;
2759 } else {
2760 state = 11;
2761 }
2762 break;
2763 }
2764 }
2765 if(state != 10) {
2766 error("Unexpected pragma syntax");
2767 }
2768 mPragmaStringCount += 2;
2769 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002770
Jack Palevichac0e95e2009-05-29 13:53:44 -07002771 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002772 mErrorBuf.printf("%ld: ", file->getLine());
2773 mErrorBuf.vprintf(fmt, ap);
2774 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002775 }
2776
Jack Palevich8b0624c2009-05-20 12:12:06 -07002777 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002778 if (tok != c) {
2779 error("'%c' expected", c);
2780 }
2781 next();
2782 }
2783
Jack Palevich86351982009-06-30 18:09:56 -07002784 bool accept(intptr_t c) {
2785 if (tok == c) {
2786 next();
2787 return true;
2788 }
2789 return false;
2790 }
2791
Jack Palevich40600de2009-07-01 15:32:35 -07002792 bool acceptStringLiteral() {
2793 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07002794 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07002795 // This while loop merges multiple adjacent string constants.
2796 while (tok == '"') {
2797 while (ch != '"' && ch != EOF) {
2798 *allocGlobalSpace(1) = getq();
2799 }
2800 if (ch != '"') {
2801 error("Unterminated string constant.");
2802 }
2803 inp();
2804 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002805 }
Jack Palevich40600de2009-07-01 15:32:35 -07002806 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002807 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002808 /* align heap */
2809 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002810
2811 return true;
2812 }
2813 return false;
2814 }
2815 /* Parse and evaluate a unary expression.
2816 * allowAssignment is true if '=' parsing wanted (quick hack)
2817 */
2818 void unary(bool allowAssignment) {
2819 intptr_t n, t, a;
2820 t = 0;
2821 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2822 if (acceptStringLiteral()) {
2823 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002824 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002825 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002826 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002827 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07002828 t = tok;
2829 next();
2830 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07002831 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002832 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002833 // Align to 4-byte boundary
2834 glo = (char*) (((intptr_t) glo + 3) & -4);
2835 * (float*) glo = (float) ad;
2836 pGen->loadFloat((int) glo, mkpFloat);
2837 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002838 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002839 // Align to 8-byte boundary
2840 glo = (char*) (((intptr_t) glo + 7) & -8);
2841 * (double*) glo = ad;
2842 pGen->loadFloat((int) glo, mkpDouble);
2843 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07002844 } else if (c == 2) {
2845 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002846 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002847 if (t == '!')
Jack Palevich9eed7a22009-07-06 17:24:34 -07002848 pGen->gUnaryCmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002849 else
Jack Palevich9eed7a22009-07-06 17:24:34 -07002850 pGen->genUnaryOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002851 } else if (t == '(') {
2852 expr();
2853 skip(')');
2854 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002855 /* This is a pointer dereference, but we currently only
2856 * support a pointer dereference if it's immediately
2857 * in front of a cast. So parse the cast right here.
2858 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002859 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002860 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2861 // We currently only handle 3 types of cast:
2862 // (int*), (char*) , (int (*)())
2863 if(typeEqual(pCast, mkpIntPtr)) {
2864 t = TOK_INT;
2865 } else if (typeEqual(pCast, mkpCharPtr)) {
2866 t = TOK_CHAR;
2867 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002868 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002869 } else {
2870 String buffer;
2871 decodeType(buffer, pCast);
2872 error("Unsupported cast type %s", buffer.getUnwrapped());
2873 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002874 }
2875 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002876 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002877 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002878 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002879 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002880 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002881 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002882 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002883 }
Jack Palevich3f226492009-07-02 14:46:19 -07002884 // Else we fall through to the function call below, with
2885 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002886 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07002887 VariableInfo* pVI = VI(tok);
2888 pGen->leaR0((int) pVI->pAddress,
2889 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07002890 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002891 } else if (t == EOF ) {
2892 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002893 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002894 // Don't have to do anything special here, the error
2895 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002896 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002897 if (!isDefined(t)) {
2898 mGlobals.add(t);
2899 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002900 }
Jack Palevich8df46192009-07-07 14:48:51 -07002901 VariableInfo* pVI = VI(t);
2902 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002903 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002904 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002905 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07002906 if (tok == '(') {
2907 pVI->pType = mkpIntFn;
2908 } else {
2909 pVI->pType = mkpInt;
2910 }
Jack Palevich8df46192009-07-07 14:48:51 -07002911 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002912 }
Jack Palevich40600de2009-07-01 15:32:35 -07002913 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002914 /* assignment */
2915 next();
2916 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002917 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002918 } else if (tok != '(') {
2919 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002920 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002921 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07002922 }
Jack Palevich8df46192009-07-07 14:48:51 -07002923 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002924 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002925 next();
2926 }
2927 }
2928 }
2929 }
2930
2931 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07002932 if (accept('(')) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002933 Type* pArgList = NULL;
2934 VariableInfo* pVI = NULL;
2935 if (n == 1) { // Indirect function call, push address of fn.
2936 pArgList = pGen->getR0Type()->pTail;
Jack Palevich1cdef202009-05-22 12:06:27 -07002937 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07002938 } else {
2939 pVI = VI(t);
2940 pArgList = pVI->pType->pTail;
2941 }
2942 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07002943 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002944 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07002945 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002946 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002947 if (! varArgs && !pArgList) {
2948 error ("Unexpected argument.");
2949 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002950 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07002951 Type* pTargetType;
2952 if (pArgList) {
2953 pTargetType = pArgList->pHead;
2954 pArgList = pArgList->pTail;
2955 } else {
2956 pTargetType = pGen->getR0Type();
2957 if (pTargetType->tag == TY_FLOAT) {
2958 pTargetType = mkpDouble;
2959 }
2960 }
2961 pGen->convertR0(pTargetType);
2962 l += pGen->storeR0ToArg(l);
Jack Palevich95727a02009-07-06 12:07:15 -07002963 if (accept(',')) {
2964 // fine
2965 } else if ( tok != ')') {
2966 error("Expected ',' or ')'");
2967 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002968 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002969 if (! varArgs && pArgList) {
2970 error ("Expected more argument(s).");
2971 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002972 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002973 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002974 if (!n) {
2975 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07002976 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
2977 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002978 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07002979 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002980 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07002981 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
2982 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002983 }
-b master422972c2009-06-17 19:13:52 -07002984 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002985 }
2986 }
2987
Jack Palevich40600de2009-07-01 15:32:35 -07002988 /* Recursive descent parser for binary operations.
2989 */
2990 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002991 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002992 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002993 if (level-- == 1)
2994 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07002995 else {
Jack Palevich40600de2009-07-01 15:32:35 -07002996 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002997 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002998 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002999 n = tok;
3000 t = tokc;
3001 next();
3002
Jack Palevich40600de2009-07-01 15:32:35 -07003003 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003004 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003005 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003006 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003007 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003008 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003009
Jack Palevich40600de2009-07-01 15:32:35 -07003010 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003011 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003012 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003013 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003014 }
3015 }
3016 }
3017 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003018 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003019 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003020 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003021 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003022 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003023 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003024 }
3025 }
3026 }
3027
3028 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003029 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003030 }
3031
3032 int test_expr() {
3033 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003034 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003035 }
3036
Jack Palevicha6baa232009-06-12 11:25:59 -07003037 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003038 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003039
Jack Palevich95727a02009-07-06 12:07:15 -07003040 Type* pBaseType;
3041 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003042 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003043 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003044 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003045 next();
3046 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003047 a = test_expr();
3048 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003049 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003050 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003051 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003052 n = pGen->gjmp(0); /* jmp */
3053 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003054 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003055 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003056 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003057 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003058 }
Jack Palevich546b2242009-05-13 15:10:04 -07003059 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003060 t = tok;
3061 next();
3062 skip('(');
3063 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003064 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003065 a = test_expr();
3066 } else {
3067 if (tok != ';')
3068 expr();
3069 skip(';');
3070 n = codeBuf.getPC();
3071 a = 0;
3072 if (tok != ';')
3073 a = test_expr();
3074 skip(';');
3075 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003076 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003077 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003078 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003079 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003080 n = t + 4;
3081 }
3082 }
3083 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003084 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003085 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003086 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003087 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003088 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003089 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003090 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003091 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003092 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003093 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003094 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003095 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003096 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003097 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003098 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003099 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003100 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003101 expr();
Jack Palevich8df46192009-07-07 14:48:51 -07003102 pGen->convertR0(pReturnType);
3103 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003104 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003105 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003106 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003107 } else if (tok != ';')
3108 expr();
3109 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003110 }
3111 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003112
Jack Palevich3f226492009-07-02 14:46:19 -07003113 bool typeEqual(Type* a, Type* b) {
3114 if (a == b) {
3115 return true;
3116 }
3117 if (a == NULL || b == NULL) {
3118 return false;
3119 }
3120 TypeTag at = a->tag;
3121 if (at != b->tag) {
3122 return false;
3123 }
3124 if (at == TY_POINTER) {
3125 return typeEqual(a->pHead, b->pHead);
3126 } else if (at == TY_FUNC || at == TY_PARAM) {
3127 return typeEqual(a->pHead, b->pHead)
3128 && typeEqual(a->pTail, b->pTail);
3129 }
3130 return true;
3131 }
3132
Jack Palevich86351982009-06-30 18:09:56 -07003133 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3134 assert(tag >= TY_INT && tag <= TY_PARAM);
3135 Type* pType = (Type*) arena.alloc(sizeof(Type));
3136 memset(pType, 0, sizeof(*pType));
3137 pType->tag = tag;
3138 pType->pHead = pHead;
3139 pType->pTail = pTail;
3140 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003141 }
3142
Jack Palevich3f226492009-07-02 14:46:19 -07003143 Type* createPtrType(Type* pType, Arena& arena) {
3144 return createType(TY_POINTER, pType, NULL, arena);
3145 }
3146
3147 /**
3148 * Try to print a type in declaration order
3149 */
Jack Palevich86351982009-06-30 18:09:56 -07003150 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003151 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003152 if (pType == NULL) {
3153 buffer.appendCStr("null");
3154 return;
3155 }
Jack Palevich3f226492009-07-02 14:46:19 -07003156 decodeTypeImp(buffer, pType);
3157 }
3158
3159 void decodeTypeImp(String& buffer, Type* pType) {
3160 decodeTypeImpPrefix(buffer, pType);
3161
Jack Palevich86351982009-06-30 18:09:56 -07003162 String temp;
3163 if (pType->id != 0) {
3164 decodeToken(temp, pType->id);
3165 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003166 }
3167
3168 decodeTypeImpPostfix(buffer, pType);
3169 }
3170
3171 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3172 TypeTag tag = pType->tag;
3173
3174 if (tag >= TY_INT && tag <= TY_VOID) {
3175 switch (tag) {
3176 case TY_INT:
3177 buffer.appendCStr("int");
3178 break;
3179 case TY_CHAR:
3180 buffer.appendCStr("char");
3181 break;
3182 case TY_VOID:
3183 buffer.appendCStr("void");
3184 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003185 case TY_FLOAT:
3186 buffer.appendCStr("float");
3187 break;
3188 case TY_DOUBLE:
3189 buffer.appendCStr("double");
3190 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003191 default:
3192 break;
3193 }
Jack Palevich86351982009-06-30 18:09:56 -07003194 buffer.append(' ');
3195 }
Jack Palevich3f226492009-07-02 14:46:19 -07003196
3197 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003198 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003199 break;
3200 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003201 break;
3202 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003203 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003204 case TY_FLOAT:
3205 break;
3206 case TY_DOUBLE:
3207 break;
Jack Palevich86351982009-06-30 18:09:56 -07003208 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003209 decodeTypeImpPrefix(buffer, pType->pHead);
3210 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3211 buffer.append('(');
3212 }
3213 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003214 break;
3215 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003216 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003217 break;
3218 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003219 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003220 break;
3221 default:
3222 String temp;
3223 temp.printf("Unknown tag %d", pType->tag);
3224 buffer.append(temp);
3225 break;
3226 }
Jack Palevich3f226492009-07-02 14:46:19 -07003227 }
3228
3229 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3230 TypeTag tag = pType->tag;
3231
3232 switch(tag) {
3233 case TY_POINTER:
3234 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3235 buffer.append(')');
3236 }
3237 decodeTypeImpPostfix(buffer, pType->pHead);
3238 break;
3239 case TY_FUNC:
3240 buffer.append('(');
3241 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3242 decodeTypeImp(buffer, pArg);
3243 if (pArg->pTail) {
3244 buffer.appendCStr(", ");
3245 }
3246 }
3247 buffer.append(')');
3248 break;
3249 default:
3250 break;
Jack Palevich86351982009-06-30 18:09:56 -07003251 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003252 }
3253
Jack Palevich86351982009-06-30 18:09:56 -07003254 void printType(Type* pType) {
3255 String buffer;
3256 decodeType(buffer, pType);
3257 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003258 }
3259
Jack Palevich86351982009-06-30 18:09:56 -07003260 Type* acceptPrimitiveType(Arena& arena) {
3261 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003262 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003263 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003264 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003265 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003266 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003267 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003268 } else if (tok == TOK_FLOAT) {
3269 pType = mkpFloat;
3270 } else if (tok == TOK_DOUBLE) {
3271 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003272 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003273 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003274 }
3275 next();
Jack Palevich86351982009-06-30 18:09:56 -07003276 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003277 }
3278
Jack Palevich3f226492009-07-02 14:46:19 -07003279 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3280 Arena& arena) {
3281 tokenid_t declName = 0;
3282 pType = acceptDecl2(pType, declName, nameAllowed,
3283 nameRequired, arena);
3284 if (declName) {
3285 // Clone the parent type so we can set a unique ID
3286 pType = createType(pType->tag, pType->pHead,
3287 pType->pTail, arena);
3288
Jack Palevich86351982009-06-30 18:09:56 -07003289 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003290 }
Jack Palevich3f226492009-07-02 14:46:19 -07003291 // fprintf(stderr, "Parsed a declaration: ");
3292 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003293 return pType;
3294 }
3295
Jack Palevich3f226492009-07-02 14:46:19 -07003296 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3297 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003298 if (! pType) {
3299 error("Expected a declaration");
3300 }
3301 return pType;
3302 }
3303
Jack Palevich3f226492009-07-02 14:46:19 -07003304 /* Used for accepting types that appear in casts */
3305 Type* acceptCastTypeDeclaration(Arena& arena) {
3306 Type* pType = acceptPrimitiveType(arena);
3307 if (pType) {
3308 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003309 }
Jack Palevich86351982009-06-30 18:09:56 -07003310 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003311 }
3312
Jack Palevich3f226492009-07-02 14:46:19 -07003313 Type* expectCastTypeDeclaration(Arena& arena) {
3314 Type* pType = acceptCastTypeDeclaration(arena);
3315 if (! pType) {
3316 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003317 }
Jack Palevich3f226492009-07-02 14:46:19 -07003318 return pType;
3319 }
3320
3321 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3322 bool nameAllowed, bool nameRequired, Arena& arena) {
3323 int ptrCounter = 0;
3324 while (accept('*')) {
3325 ptrCounter++;
3326 }
3327 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3328 while (ptrCounter-- > 0) {
3329 pType = createType(TY_POINTER, pType, NULL, arena);
3330 }
3331 return pType;
3332 }
3333
3334 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3335 bool nameAllowed, bool nameRequired, Arena& arena) {
3336 // direct-dcl :
3337 // name
3338 // (dcl)
3339 // direct-dcl()
3340 // direct-dcl[]
3341 Type* pNewHead = NULL;
3342 if (accept('(')) {
3343 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3344 nameRequired, arena);
3345 skip(')');
3346 } else if ((declName = acceptSymbol()) != 0) {
3347 if (nameAllowed == false && declName) {
3348 error("Symbol %s not allowed here", nameof(declName));
3349 } else if (nameRequired && ! declName) {
3350 String temp;
3351 decodeToken(temp, tok);
3352 error("Expected symbol. Got %s", temp.getUnwrapped());
3353 }
3354 }
3355 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003356 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003357 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003358 pType = createType(TY_FUNC, pType, pTail, arena);
3359 skip(')');
3360 }
Jack Palevich3f226492009-07-02 14:46:19 -07003361
3362 if (pNewHead) {
3363 Type* pA = pNewHead;
3364 while (pA->pHead) {
3365 pA = pA->pHead;
3366 }
3367 pA->pHead = pType;
3368 pType = pNewHead;
3369 }
Jack Palevich86351982009-06-30 18:09:56 -07003370 return pType;
3371 }
3372
Jack Palevich3f226492009-07-02 14:46:19 -07003373 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003374 Type* pHead = NULL;
3375 Type* pTail = NULL;
3376 for(;;) {
3377 Type* pBaseArg = acceptPrimitiveType(arena);
3378 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003379 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3380 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003381 if (pArg) {
3382 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3383 if (!pHead) {
3384 pHead = pParam;
3385 pTail = pParam;
3386 } else {
3387 pTail->pTail = pParam;
3388 pTail = pParam;
3389 }
3390 }
3391 }
3392 if (! accept(',')) {
3393 break;
3394 }
3395 }
3396 return pHead;
3397 }
3398
3399 Type* expectPrimitiveType(Arena& arena) {
3400 Type* pType = acceptPrimitiveType(arena);
3401 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003402 String buf;
3403 decodeToken(buf, tok);
3404 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003405 }
Jack Palevich86351982009-06-30 18:09:56 -07003406 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003407 }
3408
Jack Palevich86351982009-06-30 18:09:56 -07003409 void addGlobalSymbol(Type* pDecl) {
3410 tokenid_t t = pDecl->id;
3411 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003412 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003413 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003414 }
Jack Palevich86351982009-06-30 18:09:56 -07003415 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003416 }
3417
Jack Palevich86351982009-06-30 18:09:56 -07003418 void reportDuplicate(tokenid_t t) {
3419 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003420 }
3421
Jack Palevich86351982009-06-30 18:09:56 -07003422 void addLocalSymbol(Type* pDecl) {
3423 tokenid_t t = pDecl->id;
3424 if (mLocals.isDefinedAtCurrentLevel(t)) {
3425 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003426 }
Jack Palevich86351982009-06-30 18:09:56 -07003427 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003428 }
3429
Jack Palevich95727a02009-07-06 12:07:15 -07003430 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003431 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003432
Jack Palevich95727a02009-07-06 12:07:15 -07003433 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003434 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003435 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3436 if (!pDecl) {
3437 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003438 }
Jack Palevich86351982009-06-30 18:09:56 -07003439 int variableAddress = 0;
3440 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003441 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003442 loc = loc + 4;
3443 variableAddress = -loc;
3444 VI(pDecl->id)->pAddress = (void*) variableAddress;
3445 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003446 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003447 expr();
3448 pGen->storeR0(variableAddress);
3449 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003450 if (tok == ',')
3451 next();
3452 }
3453 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003454 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003455 }
3456 }
3457
Jack Palevichf1728be2009-06-12 13:53:51 -07003458 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003459 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003460 }
3461
Jack Palevich569f1352009-06-29 14:29:08 -07003462 void decodeToken(String& buffer, tokenid_t token) {
3463 if (token == EOF ) {
3464 buffer.printf("EOF");
3465 } else if (token == TOK_NUM) {
3466 buffer.printf("numeric constant");
3467 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003468 if (token < 32) {
3469 buffer.printf("'\\x%02x'", token);
3470 } else {
3471 buffer.printf("'%c'", token);
3472 }
Jack Palevich569f1352009-06-29 14:29:08 -07003473 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3474 buffer.printf("keyword \"%s\"", nameof(token));
3475 } else {
3476 buffer.printf("symbol \"%s\"", nameof(token));
3477 }
3478 }
3479
Jack Palevich40600de2009-07-01 15:32:35 -07003480 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003481 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003482 if (!result) {
3483 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003484 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003485 error("Expected symbol. Got %s", temp.getUnwrapped());
3486 }
3487 return result;
3488 }
3489
Jack Palevich86351982009-06-30 18:09:56 -07003490 tokenid_t acceptSymbol() {
3491 tokenid_t result = 0;
3492 if (tok >= TOK_SYMBOL) {
3493 result = tok;
3494 next();
Jack Palevich86351982009-06-30 18:09:56 -07003495 }
3496 return result;
3497 }
3498
Jack Palevichb7c81e92009-06-04 19:56:13 -07003499 void globalDeclarations() {
3500 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003501 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3502 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003503 break;
3504 }
Jack Palevich86351982009-06-30 18:09:56 -07003505 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3506 if (!pDecl) {
3507 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003508 }
Jack Palevich86351982009-06-30 18:09:56 -07003509 if (! isDefined(pDecl->id)) {
3510 addGlobalSymbol(pDecl);
3511 }
3512 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003513 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003514 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003515 }
Jack Palevich86351982009-06-30 18:09:56 -07003516 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003517 // it's a variable declaration
3518 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003519 if (name && !name->pAddress) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003520 name->pAddress = (int*) allocGlobalSpace(4);
3521 }
Jack Palevich86351982009-06-30 18:09:56 -07003522 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003523 if (tok == TOK_NUM) {
3524 if (name) {
3525 * (int*) name->pAddress = tokc;
3526 }
3527 next();
3528 } else {
3529 error("Expected an integer constant");
3530 }
3531 }
Jack Palevich86351982009-06-30 18:09:56 -07003532 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003533 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003534 }
Jack Palevich86351982009-06-30 18:09:56 -07003535 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3536 if (!pDecl) {
3537 break;
3538 }
3539 if (! isDefined(pDecl->id)) {
3540 addGlobalSymbol(pDecl);
3541 }
3542 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003543 }
3544 skip(';');
3545 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003546 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003547 if (accept(';')) {
3548 // forward declaration.
3549 } else {
3550 if (name) {
3551 /* patch forward references (XXX: does not work for function
3552 pointers) */
3553 pGen->gsym((int) name->pForward);
3554 /* put function address */
3555 name->pAddress = (void*) codeBuf.getPC();
3556 }
3557 // Calculate stack offsets for parameters
3558 mLocals.pushLevel();
3559 intptr_t a = 8;
3560 int argCount = 0;
3561 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3562 Type* pArg = pP->pHead;
3563 addLocalSymbol(pArg);
3564 /* read param name and compute offset */
3565 VI(pArg->id)->pAddress = (void*) a;
3566 a = a + 4;
3567 argCount++;
3568 }
3569 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003570 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003571 a = pGen->functionEntry(argCount);
3572 block(0, true);
3573 pGen->gsym(rsym);
3574 pGen->functionExit(argCount, a, loc);
3575 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003576 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003577 }
3578 }
3579 }
3580
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003581 char* allocGlobalSpace(int bytes) {
3582 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
3583 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003584 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003585 }
3586 char* result = glo;
3587 glo += bytes;
3588 return result;
3589 }
3590
Jack Palevich21a15a22009-05-11 14:49:29 -07003591 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003592 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003593 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003594 pGlobalBase = 0;
3595 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003596 if (pGen) {
3597 delete pGen;
3598 pGen = 0;
3599 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003600 if (file) {
3601 delete file;
3602 file = 0;
3603 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003604 }
3605
3606 void clear() {
3607 tok = 0;
3608 tokc = 0;
3609 tokl = 0;
3610 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003611 rsym = 0;
3612 loc = 0;
3613 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003614 dptr = 0;
3615 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003616 file = 0;
3617 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003618 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003619 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003620 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003621
Jack Palevich22305132009-05-13 10:58:45 -07003622 void setArchitecture(const char* architecture) {
3623 delete pGen;
3624 pGen = 0;
3625
3626 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003627#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003628 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003629 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003630 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003631#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003632#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003633 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003634 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003635 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003636#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003637 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003638 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003639 }
3640 }
3641
3642 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003643#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003644 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003645#elif defined(DEFAULT_X86_CODEGEN)
3646 pGen = new X86CodeGenerator();
3647#endif
3648 }
3649 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003650 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003651 } else {
3652 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003653 }
3654 }
3655
Jack Palevich77ae76e2009-05-10 19:59:24 -07003656public:
Jack Palevich22305132009-05-13 10:58:45 -07003657 struct args {
3658 args() {
3659 architecture = 0;
3660 }
3661 const char* architecture;
3662 };
3663
Jack Paleviche7b59062009-05-19 17:12:17 -07003664 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003665 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003666 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003667
Jack Paleviche7b59062009-05-19 17:12:17 -07003668 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003669 cleanup();
3670 }
3671
Jack Palevich1cdef202009-05-22 12:06:27 -07003672 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003673 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003674
3675 cleanup();
3676 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003677 mTokenTable.setArena(&mGlobalArena);
3678 mGlobals.setArena(&mGlobalArena);
3679 mGlobals.setTokenTable(&mTokenTable);
3680 mLocals.setArena(&mLocalArena);
3681 mLocals.setTokenTable(&mTokenTable);
3682
3683 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003684 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003685 codeBuf.init(ALLOC_SIZE);
3686 setArchitecture(NULL);
3687 if (!pGen) {
3688 return -1;
3689 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003690#ifdef PROVIDE_TRACE_CODEGEN
3691 pGen = new TraceCodeGenerator(pGen);
3692#endif
3693 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003694 pGen->init(&codeBuf);
3695 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003696 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3697 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003698 inp();
3699 next();
3700 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003701 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003702 result = pGen->finishCompile();
3703 if (result == 0) {
3704 if (mErrorBuf.len()) {
3705 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003706 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003707 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003708 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003709 }
3710
Jack Palevich86351982009-06-30 18:09:56 -07003711 void createPrimitiveTypes() {
3712 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3713 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3714 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003715 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3716 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003717 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003718 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3719 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07003720 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
3721 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003722 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003723 }
3724
Jack Palevicha6baa232009-06-12 11:25:59 -07003725 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003726 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003727 }
3728
Jack Palevich569f1352009-06-29 14:29:08 -07003729 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003730 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003731 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003732 }
3733
Jack Palevich569f1352009-06-29 14:29:08 -07003734 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003735 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003736 error("Undefined forward reference: %s",
3737 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003738 }
3739 return true;
3740 }
3741
Jack Palevich21a15a22009-05-11 14:49:29 -07003742 int dump(FILE* out) {
3743 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3744 return 0;
3745 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003746
Jack Palevicha6535612009-05-13 16:24:17 -07003747 int disassemble(FILE* out) {
3748 return pGen->disassemble(out);
3749 }
3750
Jack Palevich1cdef202009-05-22 12:06:27 -07003751 /* Look through the symbol table to find a symbol.
3752 * If found, return its value.
3753 */
3754 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003755 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3756 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003757 if (pVariableInfo) {
3758 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003759 }
3760 return NULL;
3761 }
3762
Jack Palevicheedf9d22009-06-04 16:23:40 -07003763 void getPragmas(ACCsizei* actualStringCount,
3764 ACCsizei maxStringCount, ACCchar** strings) {
3765 int stringCount = mPragmaStringCount;
3766 if (actualStringCount) {
3767 *actualStringCount = stringCount;
3768 }
3769 if (stringCount > maxStringCount) {
3770 stringCount = maxStringCount;
3771 }
3772 if (strings) {
3773 char* pPragmas = mPragmas.getUnwrapped();
3774 while (stringCount-- > 0) {
3775 *strings++ = pPragmas;
3776 pPragmas += strlen(pPragmas) + 1;
3777 }
3778 }
3779 }
3780
Jack Palevichac0e95e2009-05-29 13:53:44 -07003781 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003782 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003783 }
3784
Jack Palevich77ae76e2009-05-10 19:59:24 -07003785};
3786
Jack Paleviche7b59062009-05-19 17:12:17 -07003787const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003788 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3789
Jack Paleviche7b59062009-05-19 17:12:17 -07003790const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003791 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3792 5, 5, /* ==, != */
3793 9, 10, /* &&, || */
3794 6, 7, 8, /* & ^ | */
3795 2, 2 /* ~ ! */
3796 };
3797
Jack Palevich8b0624c2009-05-20 12:12:06 -07003798#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003799FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003800#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003801
Jack Palevich8b0624c2009-05-20 12:12:06 -07003802#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003803const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003804 0x1, // ++
3805 0xff, // --
3806 0xc1af0f, // *
3807 0xf9f79991, // /
3808 0xf9f79991, // % (With manual assist to swap results)
3809 0xc801, // +
3810 0xd8f7c829, // -
3811 0xe0d391, // <<
3812 0xf8d391, // >>
3813 0xe, // <=
3814 0xd, // >=
3815 0xc, // <
3816 0xf, // >
3817 0x4, // ==
3818 0x5, // !=
3819 0x0, // &&
3820 0x1, // ||
3821 0xc821, // &
3822 0xc831, // ^
3823 0xc809, // |
3824 0xd0f7, // ~
3825 0x4 // !
3826};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003827#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003828
Jack Palevich1cdef202009-05-22 12:06:27 -07003829struct ACCscript {
3830 ACCscript() {
3831 text = 0;
3832 textLength = 0;
3833 accError = ACC_NO_ERROR;
3834 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003835
Jack Palevich1cdef202009-05-22 12:06:27 -07003836 ~ACCscript() {
3837 delete text;
3838 }
Jack Palevich546b2242009-05-13 15:10:04 -07003839
Jack Palevich1cdef202009-05-22 12:06:27 -07003840 void setError(ACCenum error) {
3841 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3842 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003843 }
3844 }
3845
Jack Palevich1cdef202009-05-22 12:06:27 -07003846 ACCenum getError() {
3847 ACCenum result = accError;
3848 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003849 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003850 }
3851
Jack Palevich1cdef202009-05-22 12:06:27 -07003852 Compiler compiler;
3853 char* text;
3854 int textLength;
3855 ACCenum accError;
3856};
3857
3858
3859extern "C"
3860ACCscript* accCreateScript() {
3861 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003862}
Jack Palevich1cdef202009-05-22 12:06:27 -07003863
3864extern "C"
3865ACCenum accGetError( ACCscript* script ) {
3866 return script->getError();
3867}
3868
3869extern "C"
3870void accDeleteScript(ACCscript* script) {
3871 delete script;
3872}
3873
3874extern "C"
3875void accScriptSource(ACCscript* script,
3876 ACCsizei count,
3877 const ACCchar ** string,
3878 const ACCint * length) {
3879 int totalLength = 0;
3880 for(int i = 0; i < count; i++) {
3881 int len = -1;
3882 const ACCchar* s = string[i];
3883 if (length) {
3884 len = length[i];
3885 }
3886 if (len < 0) {
3887 len = strlen(s);
3888 }
3889 totalLength += len;
3890 }
3891 delete script->text;
3892 char* text = new char[totalLength + 1];
3893 script->text = text;
3894 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003895 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003896 for(int i = 0; i < count; i++) {
3897 int len = -1;
3898 const ACCchar* s = string[i];
3899 if (length) {
3900 len = length[i];
3901 }
3902 if (len < 0) {
3903 len = strlen(s);
3904 }
Jack Palevich09555c72009-05-27 12:25:55 -07003905 memcpy(dest, s, len);
3906 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003907 }
3908 text[totalLength] = '\0';
3909}
3910
3911extern "C"
3912void accCompileScript(ACCscript* script) {
3913 int result = script->compiler.compile(script->text, script->textLength);
3914 if (result) {
3915 script->setError(ACC_INVALID_OPERATION);
3916 }
3917}
3918
3919extern "C"
3920void accGetScriptiv(ACCscript* script,
3921 ACCenum pname,
3922 ACCint * params) {
3923 switch (pname) {
3924 case ACC_INFO_LOG_LENGTH:
3925 *params = 0;
3926 break;
3927 }
3928}
3929
3930extern "C"
3931void accGetScriptInfoLog(ACCscript* script,
3932 ACCsizei maxLength,
3933 ACCsizei * length,
3934 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003935 char* message = script->compiler.getErrorMessage();
3936 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003937 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003938 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003939 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003940 if (infoLog && maxLength > 0) {
3941 int trimmedLength = maxLength < messageLength ?
3942 maxLength : messageLength;
3943 memcpy(infoLog, message, trimmedLength);
3944 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003945 }
3946}
3947
3948extern "C"
3949void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3950 ACCvoid ** address) {
3951 void* value = script->compiler.lookup(name);
3952 if (value) {
3953 *address = value;
3954 } else {
3955 script->setError(ACC_INVALID_VALUE);
3956 }
3957}
3958
Jack Palevicheedf9d22009-06-04 16:23:40 -07003959extern "C"
3960void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3961 ACCsizei maxStringCount, ACCchar** strings){
3962 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3963}
3964
-b master422972c2009-06-17 19:13:52 -07003965extern "C"
3966void accDisassemble(ACCscript* script) {
3967 script->compiler.disassemble(stderr);
3968}
3969
Jack Palevicheedf9d22009-06-04 16:23:40 -07003970
Jack Palevich1cdef202009-05-22 12:06:27 -07003971} // namespace acc
3972