blob: e097608fcc2b88db28522303064ea7d4aaf0889e [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>
Jack Palevich8dc662e2009-06-09 22:53:47 +000012#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070013#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070014#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070015#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070016#include <stdlib.h>
17#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070018#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019
Jack Palevich8dc662e2009-06-09 22:53:47 +000020#if defined(__i386__)
21#include <sys/mman.h>
22#endif
23
Jack Palevich546b2242009-05-13 15:10:04 -070024#if defined(__arm__)
25#include <unistd.h>
26#endif
27
Jack Paleviche7b59062009-05-19 17:12:17 -070028#if defined(__arm__)
29#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__i386__)
32#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__x86_64__)
35#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
38
Jack Paleviche7b59062009-05-19 17:12:17 -070039#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070040#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070041#endif
Jack Palevicha6535612009-05-13 16:24:17 -070042
Jack Palevich1cdef202009-05-22 12:06:27 -070043#include <acc/acc.h>
44
Jack Palevich09555c72009-05-27 12:25:55 -070045#define LOG_API(...) do {} while(0)
46// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070047
-b master422972c2009-06-17 19:13:52 -070048#define LOG_STACK(...) do {} while(0)
49// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
50
51// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070052// #define PROVIDE_TRACE_CODEGEN
53
Jack Palevichbbf8ab52009-05-11 11:54:30 -070054namespace acc {
55
Jack Palevich8df46192009-07-07 14:48:51 -070056// Subset of STL vector.
57template<class E> class Vector {
58 public:
59 Vector() {
60 mpBase = 0;
61 mUsed = 0;
62 mSize = 0;
63 }
64
65 ~Vector() {
66 if (mpBase) {
67 for(size_t i = 0; i < mUsed; i++) {
68 mpBase[mUsed].~E();
69 }
70 free(mpBase);
71 }
72 }
73
74 inline E& operator[](size_t i) {
75 return mpBase[i];
76 }
77
78 inline E& front() {
79 return mpBase[0];
80 }
81
82 inline E& back() {
83 return mpBase[mUsed - 1];
84 }
85
86 void pop_back() {
87 mUsed -= 1;
88 mpBase[mUsed].~E();
89 }
90
91 void push_back(const E& item) {
92 * ensure(1) = item;
93 }
94
95 size_t size() {
96 return mUsed;
97 }
98
99private:
100 E* ensure(int n) {
101 size_t newUsed = mUsed + n;
102 if (newUsed > mSize) {
103 size_t newSize = mSize * 2 + 10;
104 if (newSize < newUsed) {
105 newSize = newUsed;
106 }
107 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
108 mSize = newSize;
109 }
110 E* result = mpBase + mUsed;
111 mUsed = newUsed;
112 return result;
113 }
114
115 E* mpBase;
116 size_t mUsed;
117 size_t mSize;
118};
119
Jack Palevichac0e95e2009-05-29 13:53:44 -0700120class ErrorSink {
121public:
122 void error(const char *fmt, ...) {
123 va_list ap;
124 va_start(ap, fmt);
125 verror(fmt, ap);
126 va_end(ap);
127 }
128
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700129 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700130 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 Palevichba929a42009-07-17 10:20:32 -0700147 enum ExpressionType {
148 ET_RVALUE,
149 ET_LVALUE
150 };
151
152 struct ExpressionValue {
153 ExpressionValue() {
154 et = ET_RVALUE;
155 pType = NULL;
156 }
157 ExpressionType et;
158 Type* pType;
159 };
160
Jack Palevich21a15a22009-05-11 14:49:29 -0700161 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700162 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700163 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700164 ErrorSink* mErrorSink;
165 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700166 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700167
Jack Palevich21a15a22009-05-11 14:49:29 -0700168 void release() {
169 if (pProgramBase != 0) {
170 free(pProgramBase);
171 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700172 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 }
174
Jack Palevich0a280a02009-06-11 10:53:51 -0700175 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700176 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700177 bool overflow = newSize > mSize;
178 if (overflow && !mOverflowed) {
179 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700180 if (mErrorSink) {
181 mErrorSink->error("Code too large: %d bytes", newSize);
182 }
183 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700184 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 }
186
Jack Palevich21a15a22009-05-11 14:49:29 -0700187 public:
188 CodeBuf() {
189 pProgramBase = 0;
190 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700191 mErrorSink = 0;
192 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700193 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700194 }
195
196 ~CodeBuf() {
197 release();
198 }
199
200 void init(int size) {
201 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700202 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700203 pProgramBase = (char*) calloc(1, size);
204 ind = pProgramBase;
205 }
206
Jack Palevichac0e95e2009-05-29 13:53:44 -0700207 void setErrorSink(ErrorSink* pErrorSink) {
208 mErrorSink = pErrorSink;
209 }
210
Jack Palevich546b2242009-05-13 15:10:04 -0700211 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(4)) {
213 return 0;
214 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700215 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700216 * (int*) ind = n;
217 ind += 4;
218 return result;
219 }
220
Jack Palevich21a15a22009-05-11 14:49:29 -0700221 /*
222 * Output a byte. Handles all values, 0..ff.
223 */
224 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700225 if(check(1)) {
226 return;
227 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 *ind++ = n;
229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 inline void* getBase() {
232 return (void*) pProgramBase;
233 }
234
Jack Palevich8b0624c2009-05-20 12:12:06 -0700235 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700236 return ind - pProgramBase;
237 }
238
Jack Palevich8b0624c2009-05-20 12:12:06 -0700239 intptr_t getPC() {
240 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 }
242 };
243
Jack Palevich1cdef202009-05-22 12:06:27 -0700244 /**
245 * A code generator creates an in-memory program, generating the code on
246 * the fly. There is one code generator implementation for each supported
247 * architecture.
248 *
249 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700250 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700251 * FP - a frame pointer for accessing function arguments and local
252 * variables.
253 * SP - a stack pointer for storing intermediate results while evaluating
254 * expressions. The stack pointer grows downwards.
255 *
256 * The function calling convention is that all arguments are placed on the
257 * stack such that the first argument has the lowest address.
258 * After the call, the result is in R0. The caller is responsible for
259 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700260 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700261 * FP and SP registers are saved.
262 */
263
Jack Palevich21a15a22009-05-11 14:49:29 -0700264 class CodeGenerator {
265 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 CodeGenerator() {
267 mErrorSink = 0;
268 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700269 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700270 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700271 virtual ~CodeGenerator() {}
272
Jack Palevich22305132009-05-13 10:58:45 -0700273 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700275 pCodeBuf->setErrorSink(mErrorSink);
276 }
277
Jack Palevichb67b18f2009-06-11 21:12:23 -0700278 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700279 mErrorSink = pErrorSink;
280 if (pCodeBuf) {
281 pCodeBuf->setErrorSink(mErrorSink);
282 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 }
284
Jack Palevicha8f427f2009-07-13 18:40:08 -0700285 void setTypes(Type* pInt) {
286 mkpInt = pInt;
287 }
288
Jack Palevich1cdef202009-05-22 12:06:27 -0700289 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700290 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700291 * Save the old value of the FP.
292 * Set the new value of the FP.
293 * Convert from the native platform calling convention to
294 * our stack-based calling convention. This may require
295 * pushing arguments from registers to the stack.
296 * Allocate "N" bytes of stack space. N isn't known yet, so
297 * just emit the instructions for adjusting the stack, and return
298 * the address to patch up. The patching will be done in
299 * functionExit().
300 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700301 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700302 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700303
Jack Palevich1cdef202009-05-22 12:06:27 -0700304 /* Emit a function epilog.
305 * Restore the old SP and FP register values.
306 * Return to the calling function.
307 * argCount - the number of arguments to the function.
308 * localVariableAddress - returned from functionEntry()
309 * localVariableSize - the size in bytes of the local variables.
310 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700311 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700312 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700313
Jack Palevich1cdef202009-05-22 12:06:27 -0700314 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700315 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700316
Jack Palevich1a539db2009-07-08 13:04:41 -0700317 /* Load floating point value from global address. */
318 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700319
Jack Palevich1cdef202009-05-22 12:06:27 -0700320 /* Jump to a target, and return the address of the word that
321 * holds the target data, in case it needs to be fixed up later.
322 */
Jack Palevich22305132009-05-13 10:58:45 -0700323 virtual int gjmp(int t) = 0;
324
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 /* Test R0 and jump to a target if the test succeeds.
326 * l = 0: je, l == 1: jne
327 * Return the address of the word that holds the targed data, in
328 * case it needs to be fixed up later.
329 */
Jack Palevich22305132009-05-13 10:58:45 -0700330 virtual int gtst(bool l, int t) = 0;
331
Jack Palevich9eed7a22009-07-06 17:24:34 -0700332 /* Compare TOS against R0, and store the boolean result in R0.
333 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700334 * op specifies the comparison.
335 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700336 virtual void gcmp(int op, Type* pResultType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700337
Jack Palevich9eed7a22009-07-06 17:24:34 -0700338 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700340 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700341 */
Jack Palevich546b2242009-05-13 15:10:04 -0700342 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700343
Jack Palevich9eed7a22009-07-06 17:24:34 -0700344 /* Compare 0 against R0, and store the boolean result in R0.
345 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700347 virtual void gUnaryCmp(int op, Type* pResultType) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700348
349 /* Perform the arithmetic op specified by op. 0 is the
350 * left argument, R0 is the right argument.
351 */
352 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700353
Jack Palevich1cdef202009-05-22 12:06:27 -0700354 /* Push R0 onto the stack.
355 */
356 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700357
Jack Palevich9eed7a22009-07-06 17:24:34 -0700358 /* Store R0 to the address stored in TOS.
359 * The TOS is popped.
360 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700362 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700363
Jack Palevich1cdef202009-05-22 12:06:27 -0700364 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700365 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700366 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700367 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevich1cdef202009-05-22 12:06:27 -0700369 /* Load the absolute address of a variable to R0.
370 * If ea <= LOCAL, then this is a local variable, or an
371 * argument, addressed relative to FP.
372 * else it is an absolute global address.
373 */
Jack Palevich8df46192009-07-07 14:48:51 -0700374 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 /* Store R0 to a variable.
377 * If ea <= LOCAL, then this is a local variable, or an
378 * argument, addressed relative to FP.
379 * else it is an absolute global address.
380 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700381 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700382
Jack Palevich1cdef202009-05-22 12:06:27 -0700383 /* load R0 from a variable.
384 * If ea <= LOCAL, then this is a local variable, or an
385 * argument, addressed relative to FP.
386 * else it is an absolute global address.
387 * If isIncDec is true, then the stored variable's value
388 * should be post-incremented or post-decremented, based
389 * on the value of op.
390 */
Jack Palevich8df46192009-07-07 14:48:51 -0700391 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
392
393 /**
394 * Convert R0 to the given type.
395 */
396 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700397
Jack Palevich1cdef202009-05-22 12:06:27 -0700398 /* Emit code to adjust the stack for a function call. Return the
399 * label for the address of the instruction that adjusts the
400 * stack size. This will be passed as argument "a" to
401 * endFunctionCallArguments.
402 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700403 virtual int beginFunctionCallArguments() = 0;
404
Jack Palevich1cdef202009-05-22 12:06:27 -0700405 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700406 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700408 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700409
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 /* Patch the function call preamble.
411 * a is the address returned from beginFunctionCallArguments
412 * l is the number of bytes the arguments took on the stack.
413 * Typically you would also emit code to convert the argument
414 * list into whatever the native function calling convention is.
415 * On ARM for example you would pop the first 5 arguments into
416 * R0..R4
417 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700418 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700419
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 /* Emit a call to an unknown function. The argument "symbol" needs to
421 * be stored in the location where the address should go. It forms
422 * a chain. The address will be patched later.
423 * Return the address of the word that has to be patched.
424 */
Jack Palevich8df46192009-07-07 14:48:51 -0700425 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700426
Jack Palevich1cdef202009-05-22 12:06:27 -0700427 /* Call a function using PC-relative addressing. t is the PC-relative
428 * address of the function. It has already been adjusted for the
429 * architectural jump offset, so just store it as-is.
430 */
Jack Palevich8df46192009-07-07 14:48:51 -0700431 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700432
Jack Palevich1cdef202009-05-22 12:06:27 -0700433 /* Call a function pointer. L is the number of bytes the arguments
434 * take on the stack. The address of the function is stored at
435 * location SP + l.
436 */
Jack Palevich8df46192009-07-07 14:48:51 -0700437 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700438
Jack Palevich1cdef202009-05-22 12:06:27 -0700439 /* Adjust SP after returning from a function call. l is the
440 * number of bytes of arguments stored on the stack. isIndirect
441 * is true if this was an indirect call. (In which case the
442 * address of the function is stored at location SP + l.)
443 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700444 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700445
Jack Palevich1cdef202009-05-22 12:06:27 -0700446 /* Print a disassembly of the assembled code to out. Return
447 * non-zero if there is an error.
448 */
Jack Palevicha6535612009-05-13 16:24:17 -0700449 virtual int disassemble(FILE* out) = 0;
450
Jack Palevich1cdef202009-05-22 12:06:27 -0700451 /* Generate a symbol at the current PC. t is the head of a
452 * linked list of addresses to patch.
453 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700454 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700455
Jack Palevich1cdef202009-05-22 12:06:27 -0700456 /*
457 * Do any cleanup work required at the end of a compile.
458 * For example, an instruction cache might need to be
459 * invalidated.
460 * Return non-zero if there is an error.
461 */
462 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700463
Jack Palevicha6535612009-05-13 16:24:17 -0700464 /**
465 * Adjust relative branches by this amount.
466 */
467 virtual int jumpOffset() = 0;
468
Jack Palevich9eed7a22009-07-06 17:24:34 -0700469 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700470 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700471 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700472 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700473
474 /**
475 * Array element alignment (in bytes) for this type of data.
476 */
477 virtual size_t sizeOf(Type* type) = 0;
478
Jack Palevich9cbd2262009-07-08 16:48:41 -0700479 /**
480 * Stack argument size of this data type.
481 */
482 virtual size_t stackSizeOf(Type* pType) = 0;
483
Jack Palevich1a539db2009-07-08 13:04:41 -0700484 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700485 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700486 }
487
Jack Palevich21a15a22009-05-11 14:49:29 -0700488 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700489 /*
490 * Output a byte. Handles all values, 0..ff.
491 */
492 void ob(int n) {
493 pCodeBuf->ob(n);
494 }
495
Jack Palevich8b0624c2009-05-20 12:12:06 -0700496 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700497 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700498 }
499
Jack Palevich8b0624c2009-05-20 12:12:06 -0700500 intptr_t getBase() {
501 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700502 }
503
Jack Palevich8b0624c2009-05-20 12:12:06 -0700504 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700505 return pCodeBuf->getPC();
506 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700507
508 intptr_t getSize() {
509 return pCodeBuf->getSize();
510 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700511
512 void error(const char* fmt,...) {
513 va_list ap;
514 va_start(ap, fmt);
515 mErrorSink->verror(fmt, ap);
516 va_end(ap);
517 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700518
519 void assert(bool test) {
520 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700521 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700522 error("code generator assertion failed.");
523 }
524 }
Jack Palevich8df46192009-07-07 14:48:51 -0700525
526 void setR0Type(Type* pType) {
Jack Palevichba929a42009-07-17 10:20:32 -0700527 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700528 }
529
Jack Palevich8df46192009-07-07 14:48:51 -0700530 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700531 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700532 }
533
534 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700535 if (mExpressionStack.size()) {
536 mExpressionStack.push_back(mExpressionStack.back());
537 } else {
538 mExpressionStack.push_back(ExpressionValue());
539 }
540
Jack Palevich8df46192009-07-07 14:48:51 -0700541 }
542
543 void popType() {
544 mExpressionStack.pop_back();
545 }
546
547 bool bitsSame(Type* pA, Type* pB) {
548 return collapseType(pA->tag) == collapseType(pB->tag);
549 }
550
551 TypeTag collapseType(TypeTag tag) {
552 static const TypeTag collapsedTag[] = {
553 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
554 TY_VOID, TY_VOID};
555 return collapsedTag[tag];
556 }
557
Jack Palevich1a539db2009-07-08 13:04:41 -0700558 TypeTag collapseTypeR0() {
559 return collapseType(getR0Type()->tag);
560 }
561
562 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700563 return isFloatTag(pType->tag);
564 }
565
566 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700567 return tag == TY_FLOAT || tag == TY_DOUBLE;
568 }
569
Jack Palevicha8f427f2009-07-13 18:40:08 -0700570 Type* mkpInt;
571
Jack Palevich21a15a22009-05-11 14:49:29 -0700572 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700573 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700574 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700575 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700576 };
577
Jack Paleviche7b59062009-05-19 17:12:17 -0700578#ifdef PROVIDE_ARM_CODEGEN
579
Jack Palevich22305132009-05-13 10:58:45 -0700580 class ARMCodeGenerator : public CodeGenerator {
581 public:
582 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700583
Jack Palevich22305132009-05-13 10:58:45 -0700584 virtual ~ARMCodeGenerator() {}
585
586 /* returns address to patch with local variable size
587 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700588 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700589 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700590 // sp -> arg4 arg5 ...
591 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700592 int regArgCount = calcRegArgCount(pDecl);
593 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700594 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700595 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700596 }
597 // sp -> arg0 arg1 ...
598 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700599 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700600 // sp, fp -> oldfp, retadr, arg0 arg1 ....
601 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700602 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700603 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700604 // We don't know how many local variables we are going to use,
605 // but we will round the allocation up to a multiple of
606 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700607 }
608
Jack Palevichb7718b92009-07-09 22:00:24 -0700609 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700610 // Round local variable size up to a multiple of stack alignment
611 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
612 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700613 // Patch local variable allocation code:
614 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700615 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700616 }
Jack Palevich69796b62009-05-14 15:42:26 -0700617 *(char*) (localVariableAddress) = localVariableSize;
618
619 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
620 o4(0xE1A0E00B); // mov lr, fp
621 o4(0xE59BB000); // ldr fp, [fp]
622 o4(0xE28ED004); // add sp, lr, #4
623 // sp -> retadr, arg0, ...
624 o4(0xE8BD4000); // ldmfd sp!, {lr}
625 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700626
627 // We store the PC into the lr so we can adjust the sp before
628 // returning. We need to pull off the registers we pushed
629 // earlier. We don't need to actually store them anywhere,
630 // just adjust the stack.
631 int regArgCount = calcRegArgCount(pDecl);
632 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700633 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
634 }
635 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700636 }
637
638 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700639 virtual void li(int t, Type* pType) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700640 liReg(t, 0);
Jack Palevich8df46192009-07-07 14:48:51 -0700641 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700642 }
643
Jack Palevich1a539db2009-07-08 13:04:41 -0700644 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700645 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700646 // Global, absolute address
647 o4(0xE59F0000); // ldr r0, .L1
648 o4(0xEA000000); // b .L99
649 o4(address); // .L1: .word ea
650 // .L99:
651
652 switch (pType->tag) {
653 case TY_FLOAT:
654 o4(0xE5900000); // ldr r0, [r0]
655 break;
656 case TY_DOUBLE:
657 o4(0xE1C000D0); // ldrd r0, [r0]
658 break;
659 default:
660 assert(false);
661 break;
662 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700663 }
664
Jack Palevich22305132009-05-13 10:58:45 -0700665 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700666 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700667 }
668
669 /* l = 0: je, l == 1: jne */
670 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700671 Type* pR0Type = getR0Type();
672 TypeTag tagR0 = pR0Type->tag;
673 switch(tagR0) {
674 case TY_FLOAT:
675 callRuntime((void*) runtime_is_non_zero_f);
676 break;
677 case TY_DOUBLE:
678 callRuntime((void*) runtime_is_non_zero_d);
679 break;
680 default:
681 break;
682 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700683 o4(0xE3500000); // cmp r0,#0
684 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
685 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700686 }
687
Jack Palevicha39749f2009-07-08 20:40:31 -0700688 virtual void gcmp(int op, Type* pResultType) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700689 Type* pR0Type = getR0Type();
690 Type* pTOSType = getTOSType();
691 TypeTag tagR0 = collapseType(pR0Type->tag);
692 TypeTag tagTOS = collapseType(pTOSType->tag);
693 if (tagR0 == TY_INT && tagTOS == TY_INT) {
694 o4(0xE8BD0002); // ldmfd sp!,{r1}
695 mStackUse -= 4;
696 o4(0xE1510000); // cmp r1, r1
697 switch(op) {
698 case OP_EQUALS:
699 o4(0x03A00001); // moveq r0,#1
700 o4(0x13A00000); // movne r0,#0
701 break;
702 case OP_NOT_EQUALS:
703 o4(0x03A00000); // moveq r0,#0
704 o4(0x13A00001); // movne r0,#1
705 break;
706 case OP_LESS_EQUAL:
707 o4(0xD3A00001); // movle r0,#1
708 o4(0xC3A00000); // movgt r0,#0
709 break;
710 case OP_GREATER:
711 o4(0xD3A00000); // movle r0,#0
712 o4(0xC3A00001); // movgt r0,#1
713 break;
714 case OP_GREATER_EQUAL:
715 o4(0xA3A00001); // movge r0,#1
716 o4(0xB3A00000); // movlt r0,#0
717 break;
718 case OP_LESS:
719 o4(0xA3A00000); // movge r0,#0
720 o4(0xB3A00001); // movlt r0,#1
721 break;
722 default:
723 error("Unknown comparison op %d", op);
724 break;
725 }
726 popType();
727 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
728 setupDoubleArgs();
729 switch(op) {
730 case OP_EQUALS:
731 callRuntime((void*) runtime_cmp_eq_dd);
732 break;
733 case OP_NOT_EQUALS:
734 callRuntime((void*) runtime_cmp_ne_dd);
735 break;
736 case OP_LESS_EQUAL:
737 callRuntime((void*) runtime_cmp_le_dd);
738 break;
739 case OP_GREATER:
740 callRuntime((void*) runtime_cmp_gt_dd);
741 break;
742 case OP_GREATER_EQUAL:
743 callRuntime((void*) runtime_cmp_ge_dd);
744 break;
745 case OP_LESS:
746 callRuntime((void*) runtime_cmp_lt_dd);
747 break;
748 default:
749 error("Unknown comparison op %d", op);
750 break;
751 }
752 } else {
753 setupFloatArgs();
754 switch(op) {
755 case OP_EQUALS:
756 callRuntime((void*) runtime_cmp_eq_ff);
757 break;
758 case OP_NOT_EQUALS:
759 callRuntime((void*) runtime_cmp_ne_ff);
760 break;
761 case OP_LESS_EQUAL:
762 callRuntime((void*) runtime_cmp_le_ff);
763 break;
764 case OP_GREATER:
765 callRuntime((void*) runtime_cmp_gt_ff);
766 break;
767 case OP_GREATER_EQUAL:
768 callRuntime((void*) runtime_cmp_ge_ff);
769 break;
770 case OP_LESS:
771 callRuntime((void*) runtime_cmp_lt_ff);
772 break;
773 default:
774 error("Unknown comparison op %d", op);
775 break;
776 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700777 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700778 setR0Type(pResultType);
Jack Palevich22305132009-05-13 10:58:45 -0700779 }
780
Jack Palevich546b2242009-05-13 15:10:04 -0700781 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700782 Type* pR0Type = getR0Type();
783 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700784 TypeTag tagR0 = pR0Type->tag;
785 TypeTag tagTOS = pTOSType->tag;
786 bool isFloatR0 = isFloatTag(tagR0);
787 bool isFloatTOS = isFloatTag(tagTOS);
788 if (!isFloatR0 && !isFloatTOS) {
789 bool isPtrR0 = tagR0 == TY_POINTER;
790 bool isPtrTOS = tagTOS == TY_POINTER;
791 if (isPtrR0 || isPtrTOS) {
792 if (isPtrR0 && isPtrTOS) {
793 if (op != OP_MINUS) {
794 error("Unsupported pointer-pointer operation %d.", op);
795 }
796 if (! typeEqual(pR0Type, pTOSType)) {
797 error("Incompatible pointer types for subtraction.");
798 }
799 o4(0xE8BD0002); // ldmfd sp!,{r1}
800 o4(0xE0410000); // sub r0,r1,r0
801 popType();
802 setR0Type(mkpInt);
803 int size = sizeOf(pR0Type->pHead);
804 if (size != 1) {
805 pushR0();
806 li(size, mkpInt);
807 // TODO: Optimize for power-of-two.
808 genOp(OP_DIV);
809 }
810 } else {
811 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
812 error("Unsupported pointer-scalar operation %d", op);
813 }
814 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
815 o4(0xE8BD0002); // ldmfd sp!,{r1}
816 int size = sizeOf(pPtrType->pHead);
817 if (size != 1) {
818 // TODO: Optimize for power-of-two.
819 liReg(size, 2);
820 if (isPtrR0) {
821 o4(0x0E0010192); // mul r1,r2,r1
822 } else {
823 o4(0x0E0000092); // mul r0,r2,r0
824 }
825 }
826 switch(op) {
827 case OP_PLUS:
828 o4(0xE0810000); // add r0,r1,r0
829 break;
830 case OP_MINUS:
831 o4(0xE0410000); // sub r0,r1,r0
832 break;
833 }
834 popType();
835 setR0Type(pPtrType);
836 }
837 } else {
838 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevichb7718b92009-07-09 22:00:24 -0700839 mStackUse -= 4;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700840 switch(op) {
841 case OP_MUL:
842 o4(0x0E0000091); // mul r0,r1,r0
843 break;
844 case OP_DIV:
845 callRuntime((void*) runtime_DIV);
846 break;
847 case OP_MOD:
848 callRuntime((void*) runtime_MOD);
849 break;
850 case OP_PLUS:
851 o4(0xE0810000); // add r0,r1,r0
852 break;
853 case OP_MINUS:
854 o4(0xE0410000); // sub r0,r1,r0
855 break;
856 case OP_SHIFT_LEFT:
857 o4(0xE1A00011); // lsl r0,r1,r0
858 break;
859 case OP_SHIFT_RIGHT:
860 o4(0xE1A00051); // asr r0,r1,r0
861 break;
862 case OP_BIT_AND:
863 o4(0xE0010000); // and r0,r1,r0
864 break;
865 case OP_BIT_XOR:
866 o4(0xE0210000); // eor r0,r1,r0
867 break;
868 case OP_BIT_OR:
869 o4(0xE1810000); // orr r0,r1,r0
870 break;
871 case OP_BIT_NOT:
872 o4(0xE1E00000); // mvn r0, r0
873 break;
874 default:
875 error("Unimplemented op %d\n", op);
876 break;
877 }
878 popType();
Jack Palevichb7718b92009-07-09 22:00:24 -0700879 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700880 } else {
881 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
882 if (pResultType->tag == TY_DOUBLE) {
883 setupDoubleArgs();
884 switch(op) {
885 case OP_MUL:
886 callRuntime((void*) runtime_op_mul_dd);
887 break;
888 case OP_DIV:
889 callRuntime((void*) runtime_op_div_dd);
890 break;
891 case OP_PLUS:
892 callRuntime((void*) runtime_op_add_dd);
893 break;
894 case OP_MINUS:
895 callRuntime((void*) runtime_op_sub_dd);
896 break;
897 default:
898 error("Unsupported binary floating operation %d\n", op);
899 break;
900 }
901 } else {
902 setupFloatArgs();
903 switch(op) {
904 case OP_MUL:
905 callRuntime((void*) runtime_op_mul_ff);
906 break;
907 case OP_DIV:
908 callRuntime((void*) runtime_op_div_ff);
909 break;
910 case OP_PLUS:
911 callRuntime((void*) runtime_op_add_ff);
912 break;
913 case OP_MINUS:
914 callRuntime((void*) runtime_op_sub_ff);
915 break;
916 default:
917 error("Unsupported binary floating operation %d\n", op);
918 break;
919 }
920 }
921 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700922 }
Jack Palevich22305132009-05-13 10:58:45 -0700923 }
924
Jack Palevicha39749f2009-07-08 20:40:31 -0700925 virtual void gUnaryCmp(int op, Type* pResultType) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700926 if (op != OP_LOGICAL_NOT) {
927 error("Unknown unary cmp %d", op);
928 } else {
929 Type* pR0Type = getR0Type();
930 TypeTag tag = collapseType(pR0Type->tag);
931 switch(tag) {
932 case TY_INT:
933 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700934 o4(0xE1510000); // cmp r1, r0
935 o4(0x03A00001); // moveq r0,#1
936 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700937 break;
938 case TY_FLOAT:
939 callRuntime((void*) runtime_is_zero_f);
940 break;
941 case TY_DOUBLE:
942 callRuntime((void*) runtime_is_zero_d);
943 break;
944 default:
945 error("gUnaryCmp unsupported type");
946 break;
947 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700948 }
Jack Palevicha39749f2009-07-08 20:40:31 -0700949 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700950 }
951
952 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700953 Type* pR0Type = getR0Type();
954 TypeTag tag = collapseType(pR0Type->tag);
955 switch(tag) {
956 case TY_INT:
957 switch(op) {
958 case OP_MINUS:
959 o4(0xE3A01000); // mov r1, #0
960 o4(0xE0410000); // sub r0,r1,r0
961 break;
962 case OP_BIT_NOT:
963 o4(0xE1E00000); // mvn r0, r0
964 break;
965 default:
966 error("Unknown unary op %d\n", op);
967 break;
968 }
969 break;
970 case TY_FLOAT:
971 case TY_DOUBLE:
972 switch (op) {
973 case OP_MINUS:
974 if (tag == TY_FLOAT) {
975 callRuntime((void*) runtime_op_neg_f);
976 } else {
977 callRuntime((void*) runtime_op_neg_d);
978 }
979 break;
980 case OP_BIT_NOT:
981 error("Can't apply '~' operator to a float or double.");
982 break;
983 default:
984 error("Unknown unary op %d\n", op);
985 break;
986 }
987 break;
988 default:
989 error("genUnaryOp unsupported type");
990 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700991 }
Jack Palevich22305132009-05-13 10:58:45 -0700992 }
993
Jack Palevich1cdef202009-05-22 12:06:27 -0700994 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -0700995 Type* pR0Type = getR0Type();
996 TypeTag r0ct = collapseType(pR0Type->tag);
997 if (r0ct != TY_DOUBLE) {
998 o4(0xE92D0001); // stmfd sp!,{r0}
999 mStackUse += 4;
1000 } else {
1001 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1002 mStackUse += 8;
1003 }
Jack Palevich8df46192009-07-07 14:48:51 -07001004 pushType();
-b master422972c2009-06-17 19:13:52 -07001005 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001006 }
1007
Jack Palevich9eed7a22009-07-06 17:24:34 -07001008 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001009 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001010 o4(0xE8BD0004); // ldmfd sp!,{r2}
1011 popType();
-b master422972c2009-06-17 19:13:52 -07001012 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001013 switch (pPointerType->pHead->tag) {
1014 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001015 case TY_FLOAT:
1016 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001017 break;
1018 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001019 o4(0xE5C20000); // strb r0, [r2]
1020 break;
1021 case TY_DOUBLE:
1022 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001023 break;
1024 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001025 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001026 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001027 }
Jack Palevich22305132009-05-13 10:58:45 -07001028 }
1029
Jack Palevich9eed7a22009-07-06 17:24:34 -07001030 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001031 assert(pPointerType->tag == TY_POINTER);
1032 switch (pPointerType->pHead->tag) {
1033 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001034 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001035 o4(0xE5900000); // ldr r0, [r0]
1036 break;
1037 case TY_CHAR:
1038 o4(0xE5D00000); // ldrb r0, [r0]
1039 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001040 case TY_DOUBLE:
1041 o4(0xE1C000D0); // ldrd r0, [r0]
1042 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001043 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001044 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001045 break;
1046 }
Jack Palevich8df46192009-07-07 14:48:51 -07001047 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001048 }
1049
Jack Palevich8df46192009-07-07 14:48:51 -07001050 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001051 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001052 // Local, fp relative
1053 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1054 error("Offset out of range: %08x", ea);
1055 }
1056 if (ea < 0) {
1057 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1058 } else {
1059 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1060 }
Jack Palevichbd894902009-05-14 19:35:31 -07001061 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001062 // Global, absolute.
1063 o4(0xE59F0000); // ldr r0, .L1
1064 o4(0xEA000000); // b .L99
1065 o4(ea); // .L1: .word 0
1066 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001067 }
Jack Palevich8df46192009-07-07 14:48:51 -07001068 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001069 }
1070
Jack Palevich9cbd2262009-07-08 16:48:41 -07001071 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001072 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001073 TypeTag tag = pType->tag;
1074 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001075 case TY_CHAR:
1076 if (ea > -LOCAL && ea < LOCAL) {
1077 // Local, fp relative
1078 if (ea < -4095 || ea > 4095) {
1079 error("Offset out of range: %08x", ea);
1080 }
1081 if (ea < 0) {
1082 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1083 } else {
1084 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1085 }
1086 } else{
1087 // Global, absolute
1088 o4(0xE59F1000); // ldr r1, .L1
1089 o4(0xEA000000); // b .L99
1090 o4(ea); // .L1: .word 0
1091 o4(0xE5C10000); // .L99: strb r0, [r1]
1092 }
1093 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001094 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001095 case TY_INT:
1096 case TY_FLOAT:
1097 if (ea > -LOCAL && ea < LOCAL) {
1098 // Local, fp relative
1099 if (ea < -4095 || ea > 4095) {
1100 error("Offset out of range: %08x", ea);
1101 }
1102 if (ea < 0) {
1103 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1104 } else {
1105 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1106 }
1107 } else{
1108 // Global, absolute
1109 o4(0xE59F1000); // ldr r1, .L1
1110 o4(0xEA000000); // b .L99
1111 o4(ea); // .L1: .word 0
1112 o4(0xE5810000); // .L99: str r0, [r1]
1113 }
1114 break;
1115 case TY_DOUBLE:
1116 if ((ea & 0x7) != 0) {
1117 error("double address is not aligned: %d", ea);
1118 }
1119 if (ea > -LOCAL && ea < LOCAL) {
1120 // Local, fp relative
1121 if (ea < -4095 || ea > 4095) {
1122 error("Offset out of range: %08x", ea);
1123 }
1124 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001125 o4(0xE50B0000 | (0xfff & (4-ea))); // str r0, [fp,#-ea]
1126 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001127#if 0
1128 // strd doesn't seem to work. Is encoding wrong?
1129 } else if (ea < 0) {
1130 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1131 } else if (ea < 256) {
1132 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1133#endif
1134 } else {
1135 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1136 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1137 }
1138 } else{
1139 // Global, absolute
1140 o4(0xE59F2000); // ldr r2, .L1
1141 o4(0xEA000000); // b .L99
1142 o4(ea); // .L1: .word 0
1143 o4(0xE1C200F0); // .L99: strd r0, [r2]
1144 }
1145 break;
1146 default:
1147 error("Unable to store to type %d", tag);
1148 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001149 }
Jack Palevich22305132009-05-13 10:58:45 -07001150 }
1151
Jack Palevich8df46192009-07-07 14:48:51 -07001152 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001153 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001154 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001155 case TY_CHAR:
1156 if (ea < LOCAL) {
1157 // Local, fp relative
1158 if (ea < -4095 || ea > 4095) {
1159 error("Offset out of range: %08x", ea);
1160 }
1161 if (ea < 0) {
1162 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1163 } else {
1164 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1165 }
1166 } else {
1167 // Global, absolute
1168 o4(0xE59F2000); // ldr r2, .L1
1169 o4(0xEA000000); // b .L99
1170 o4(ea); // .L1: .word ea
1171 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1172 }
1173
1174 if (isIncDec) {
1175 error("inc/dec not implemented for char.");
1176 }
1177 break;
1178 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001179 case TY_INT:
1180 case TY_FLOAT:
1181 if (ea < LOCAL) {
1182 // Local, fp relative
1183 if (ea < -4095 || ea > 4095) {
1184 error("Offset out of range: %08x", ea);
1185 }
1186 if (ea < 0) {
1187 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1188 } else {
1189 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1190 }
1191 } else {
1192 // Global, absolute
1193 o4(0xE59F2000); // ldr r2, .L1
1194 o4(0xEA000000); // b .L99
1195 o4(ea); // .L1: .word ea
1196 o4(0xE5920000); // .L99: ldr r0, [r2]
1197 }
Jack Palevich22305132009-05-13 10:58:45 -07001198
Jack Palevichb7718b92009-07-09 22:00:24 -07001199 if (isIncDec) {
1200 if (tag == TY_INT) {
1201 switch (op) {
1202 case OP_INCREMENT:
1203 o4(0xE2801001); // add r1, r0, #1
1204 break;
1205 case OP_DECREMENT:
1206 o4(0xE2401001); // sub r1, r0, #1
1207 break;
1208 default:
1209 error("unknown opcode: %d", op);
1210 }
1211 if (ea < LOCAL) {
1212 // Local, fp relative
1213 // Don't need range check, was already checked above
1214 if (ea < 0) {
1215 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1216 } else {
1217 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1218 }
1219 } else{
1220 // Global, absolute
1221 // r2 is already set up from before.
1222 o4(0xE5821000); // str r1, [r2]
1223 }
1224 }
1225 else {
1226 error("inc/dec not implemented for float.");
1227 }
1228 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001229 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001230 case TY_DOUBLE:
1231 if ((ea & 0x7) != 0) {
1232 error("double address is not aligned: %d", ea);
1233 }
1234 if (ea < LOCAL) {
1235 // Local, fp relative
1236 if (ea < -4095 || ea > 4095) {
1237 error("Offset out of range: %08x", ea);
1238 }
1239 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001240 o4(0xE51B0000 | (0xfff & (4-ea))); // ldr r0, [fp,#-ea]
1241 o4(0xE51B1000 | (0xfff & (-ea))); // ldr r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001242 } else {
1243 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1244 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1245 }
1246 } else {
1247 // Global, absolute
1248 o4(0xE59F2000); // ldr r2, .L1
1249 o4(0xEA000000); // b .L99
1250 o4(ea); // .L1: .word ea
1251 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1252 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001253 break;
1254 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001255 error("Unable to load type %d", tag);
1256 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001257 }
Jack Palevich8df46192009-07-07 14:48:51 -07001258 setR0Type(pType);
1259 }
1260
1261 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001262 Type* pR0Type = getR0Type();
1263 if (bitsSame(pType, pR0Type)) {
1264 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001265 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001266 TypeTag r0Tag = collapseType(pR0Type->tag);
1267 TypeTag destTag = collapseType(pType->tag);
1268 if (r0Tag == TY_INT) {
1269 if (destTag == TY_FLOAT) {
1270 callRuntime((void*) runtime_int_to_float);
1271 } else {
1272 assert(destTag == TY_DOUBLE);
1273 callRuntime((void*) runtime_int_to_double);
1274 }
1275 } else if (r0Tag == TY_FLOAT) {
1276 if (destTag == TY_INT) {
1277 callRuntime((void*) runtime_float_to_int);
1278 } else {
1279 assert(destTag == TY_DOUBLE);
1280 callRuntime((void*) runtime_float_to_double);
1281 }
1282 } else {
1283 assert (r0Tag == TY_DOUBLE);
1284 if (destTag == TY_INT) {
1285 callRuntime((void*) runtime_double_to_int);
1286 } else {
1287 assert(destTag == TY_FLOAT);
1288 callRuntime((void*) runtime_double_to_float);
1289 }
1290 }
Jack Palevich8df46192009-07-07 14:48:51 -07001291 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001292 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001293 }
1294
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001295 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001296 return o4(0xE24DDF00); // Placeholder
1297 }
1298
Jack Palevich8148c5b2009-07-16 18:24:47 -07001299 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001300 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001301 Type* pR0Type = getR0Type();
1302 TypeTag r0ct = collapseType(pR0Type->tag);
1303 switch(r0ct) {
1304 case TY_INT:
1305 case TY_FLOAT:
1306 if (l < 0 || l > 4096-4) {
1307 error("l out of range for stack offset: 0x%08x", l);
1308 }
1309 o4(0xE58D0000 + l); // str r0, [sp, #l]
1310 return 4;
1311 case TY_DOUBLE: {
1312 // Align to 8 byte boundary
1313 int l2 = (l + 7) & ~7;
1314 if (l2 < 0 || l2 > 4096-8) {
1315 error("l out of range for stack offset: 0x%08x", l);
1316 }
1317 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1318 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1319 return (l2 - l) + 8;
1320 }
1321 default:
1322 assert(false);
1323 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001324 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001325 }
1326
Jack Palevichb7718b92009-07-09 22:00:24 -07001327 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001328 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001329 // Have to calculate register arg count from actual stack size,
1330 // in order to properly handle ... functions.
1331 int regArgCount = l >> 2;
1332 if (regArgCount > 4) {
1333 regArgCount = 4;
1334 }
1335 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001336 argumentStackUse -= regArgCount * 4;
1337 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1338 }
1339 mStackUse += argumentStackUse;
1340
1341 // Align stack.
1342 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1343 * STACK_ALIGNMENT);
1344 mStackAlignmentAdjustment = 0;
1345 if (missalignment > 0) {
1346 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1347 }
1348 l += mStackAlignmentAdjustment;
1349
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001350 if (l < 0 || l > 0x3FC) {
1351 error("L out of range for stack adjustment: 0x%08x", l);
1352 }
1353 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001354 mStackUse += mStackAlignmentAdjustment;
1355 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1356 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001357 }
1358
Jack Palevich8df46192009-07-07 14:48:51 -07001359 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001360 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001361 // Forward calls are always short (local)
1362 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001363 }
1364
Jack Palevich8df46192009-07-07 14:48:51 -07001365 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001366 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001367 int abs = t + getPC() + jumpOffset();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001368 if (t >= - (1 << 25) && t < (1 << 25)) {
1369 o4(0xEB000000 | encodeAddress(t));
1370 } else {
1371 // Long call.
1372 o4(0xE59FC000); // ldr r12, .L1
1373 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001374 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001375 o4(0xE08CC00F); // .L99: add r12,pc
1376 o4(0xE12FFF3C); // blx r12
1377 }
Jack Palevich22305132009-05-13 10:58:45 -07001378 }
1379
Jack Palevich8df46192009-07-07 14:48:51 -07001380 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001381 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001382 int argCount = l >> 2;
1383 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001384 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001385 if (adjustedL < 0 || adjustedL > 4096-4) {
1386 error("l out of range for stack offset: 0x%08x", l);
1387 }
1388 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1389 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001390 }
1391
Jack Palevichb7718b92009-07-09 22:00:24 -07001392 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001393 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001394 // Have to calculate register arg count from actual stack size,
1395 // in order to properly handle ... functions.
1396 int regArgCount = l >> 2;
1397 if (regArgCount > 4) {
1398 regArgCount = 4;
1399 }
1400 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001401 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1402 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001403 if (stackUse) {
1404 if (stackUse < 0 || stackUse > 255) {
1405 error("L out of range for stack adjustment: 0x%08x", l);
1406 }
1407 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001408 mStackUse -= stackUse * 4;
1409 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001410 }
Jack Palevich22305132009-05-13 10:58:45 -07001411 }
1412
Jack Palevicha6535612009-05-13 16:24:17 -07001413 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001414 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001415 }
1416
1417 /* output a symbol and patch all calls to it */
1418 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001419 int n;
1420 int base = getBase();
1421 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001422 while (t) {
1423 int data = * (int*) t;
1424 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1425 if (decodedOffset == 0) {
1426 n = 0;
1427 } else {
1428 n = base + decodedOffset; /* next value */
1429 }
1430 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1431 | encodeRelAddress(pc - t - 8);
1432 t = n;
1433 }
1434 }
1435
Jack Palevich1cdef202009-05-22 12:06:27 -07001436 virtual int finishCompile() {
1437#if defined(__arm__)
1438 const long base = long(getBase());
1439 const long curr = long(getPC());
1440 int err = cacheflush(base, curr, 0);
1441 return err;
1442#else
1443 return 0;
1444#endif
1445 }
1446
Jack Palevicha6535612009-05-13 16:24:17 -07001447 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001448#ifdef ENABLE_ARM_DISASSEMBLY
1449 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001450 disasm_interface_t di;
1451 di.di_readword = disassemble_readword;
1452 di.di_printaddr = disassemble_printaddr;
1453 di.di_printf = disassemble_printf;
1454
1455 int base = getBase();
1456 int pc = getPC();
1457 for(int i = base; i < pc; i += 4) {
1458 fprintf(out, "%08x: %08x ", i, *(int*) i);
1459 ::disasm(&di, i, 0);
1460 }
Jack Palevich09555c72009-05-27 12:25:55 -07001461#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001462 return 0;
1463 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001464
Jack Palevich9eed7a22009-07-06 17:24:34 -07001465 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001466 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001467 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001468 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001469 switch(pType->tag) {
1470 case TY_DOUBLE:
1471 return 8;
1472 default:
1473 return 4;
1474 }
1475 }
1476
1477 /**
1478 * Array element alignment (in bytes) for this type of data.
1479 */
1480 virtual size_t sizeOf(Type* pType){
1481 switch(pType->tag) {
1482 case TY_INT:
1483 return 4;
1484 case TY_CHAR:
1485 return 1;
1486 default:
1487 return 0;
1488 case TY_FLOAT:
1489 return 4;
1490 case TY_DOUBLE:
1491 return 8;
1492 case TY_POINTER:
1493 return 4;
1494 }
1495 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001496
1497 virtual size_t stackSizeOf(Type* pType) {
1498 switch(pType->tag) {
1499 case TY_DOUBLE:
1500 return 8;
1501 default:
1502 return 4;
1503 }
1504 }
1505
Jack Palevich22305132009-05-13 10:58:45 -07001506 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001507 static FILE* disasmOut;
1508
1509 static u_int
1510 disassemble_readword(u_int address)
1511 {
1512 return(*((u_int *)address));
1513 }
1514
1515 static void
1516 disassemble_printaddr(u_int address)
1517 {
1518 fprintf(disasmOut, "0x%08x", address);
1519 }
1520
1521 static void
1522 disassemble_printf(const char *fmt, ...) {
1523 va_list ap;
1524 va_start(ap, fmt);
1525 vfprintf(disasmOut, fmt, ap);
1526 va_end(ap);
1527 }
1528
1529 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1530
1531 /** Encode a relative address that might also be
1532 * a label.
1533 */
1534 int encodeAddress(int value) {
1535 int base = getBase();
1536 if (value >= base && value <= getPC() ) {
1537 // This is a label, encode it relative to the base.
1538 value = value - base;
1539 }
1540 return encodeRelAddress(value);
1541 }
1542
1543 int encodeRelAddress(int value) {
1544 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1545 }
Jack Palevich22305132009-05-13 10:58:45 -07001546
Jack Palevichb7718b92009-07-09 22:00:24 -07001547 int calcRegArgCount(Type* pDecl) {
1548 int reg = 0;
1549 Type* pArgs = pDecl->pTail;
1550 while (pArgs && reg < 4) {
1551 Type* pArg = pArgs->pHead;
1552 if ( pArg->tag == TY_DOUBLE) {
1553 int evenReg = (reg + 1) & ~1;
1554 if (evenReg >= 4) {
1555 break;
1556 }
1557 reg = evenReg + 2;
1558 } else {
1559 reg++;
1560 }
1561 pArgs = pArgs->pTail;
1562 }
1563 return reg;
1564 }
1565
1566 /* Pop TOS to R1
1567 * Make sure both R0 and TOS are floats. (Could be ints)
1568 * We know that at least one of R0 and TOS is already a float
1569 */
1570 void setupFloatArgs() {
1571 Type* pR0Type = getR0Type();
1572 Type* pTOSType = getTOSType();
1573 TypeTag tagR0 = collapseType(pR0Type->tag);
1574 TypeTag tagTOS = collapseType(pTOSType->tag);
1575 if (tagR0 != TY_FLOAT) {
1576 assert(tagR0 == TY_INT);
1577 callRuntime((void*) runtime_int_to_float);
1578 }
1579 if (tagTOS != TY_FLOAT) {
1580 assert(tagTOS == TY_INT);
1581 assert(tagR0 == TY_FLOAT);
1582 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1583 o4(0xE59D0004); // ldr r0, [sp, #4]
1584 callRuntime((void*) runtime_int_to_float);
1585 o4(0xE1A01000); // mov r1, r0
1586 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1587 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1588 } else {
1589 // Pop TOS
1590 o4(0xE8BD0002); // ldmfd sp!,{r1}
1591 }
1592 mStackUse -= 4;
1593 popType();
1594 }
1595
1596 /* Pop TOS into R2..R3
1597 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1598 * We know that at least one of R0 and TOS are already a double.
1599 */
1600
1601 void setupDoubleArgs() {
1602 Type* pR0Type = getR0Type();
1603 Type* pTOSType = getTOSType();
1604 TypeTag tagR0 = collapseType(pR0Type->tag);
1605 TypeTag tagTOS = collapseType(pTOSType->tag);
1606 if (tagR0 != TY_DOUBLE) {
1607 if (tagR0 == TY_INT) {
1608 callRuntime((void*) runtime_int_to_double);
1609 } else {
1610 assert(tagR0 == TY_FLOAT);
1611 callRuntime((void*) runtime_float_to_double);
1612 }
1613 }
1614 if (tagTOS != TY_DOUBLE) {
1615 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1616 o4(0xE59D0008); // ldr r0, [sp, #8]
1617 if (tagTOS == TY_INT) {
1618 callRuntime((void*) runtime_int_to_double);
1619 } else {
1620 assert(tagTOS == TY_FLOAT);
1621 callRuntime((void*) runtime_float_to_double);
1622 }
1623 o4(0xE1A02000); // mov r2, r0
1624 o4(0xE1A03001); // mov r3, r1
1625 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1626 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1627 mStackUse -= 4;
1628 } else {
1629 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1630 mStackUse -= 8;
1631 }
1632 popType();
1633 }
1634
Jack Palevicha8f427f2009-07-13 18:40:08 -07001635 void liReg(int t, int reg) {
1636 assert(reg >= 0 && reg < 16);
1637 int rN = (reg & 0xf) << 12;
1638 if (t >= 0 && t < 255) {
1639 o4((0xE3A00000 + t) | rN); // mov rN, #0
1640 } else if (t >= -256 && t < 0) {
1641 // mvn means move constant ^ ~0
1642 o4((0xE3E00001 - t) | rN); // mvn rN, #0
1643 } else {
1644 o4(0xE51F0000 | rN); // ldr rN, .L3
1645 o4(0xEA000000); // b .L99
1646 o4(t); // .L3: .word 0
1647 // .L99:
1648 }
1649 }
1650
Jack Palevichb7718b92009-07-09 22:00:24 -07001651 void callRuntime(void* fn) {
1652 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001653 o4(0xEA000000); // b .L99
1654 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001655 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001656 }
1657
Jack Palevichb7718b92009-07-09 22:00:24 -07001658 // Integer math:
1659
1660 static int runtime_DIV(int b, int a) {
1661 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001662 }
1663
Jack Palevichb7718b92009-07-09 22:00:24 -07001664 static int runtime_MOD(int b, int a) {
1665 return a % b;
1666 }
1667
1668 // Comparison to zero
1669
1670 static int runtime_is_non_zero_f(float a) {
1671 return a != 0;
1672 }
1673
1674 static int runtime_is_non_zero_d(double a) {
1675 return a != 0;
1676 }
1677
1678 // Comparison to zero
1679
1680 static int runtime_is_zero_f(float a) {
1681 return a == 0;
1682 }
1683
1684 static int runtime_is_zero_d(double a) {
1685 return a == 0;
1686 }
1687
1688 // Type conversion
1689
1690 static int runtime_float_to_int(float a) {
1691 return (int) a;
1692 }
1693
1694 static double runtime_float_to_double(float a) {
1695 return (double) a;
1696 }
1697
1698 static int runtime_double_to_int(double a) {
1699 return (int) a;
1700 }
1701
1702 static float runtime_double_to_float(double a) {
1703 return (float) a;
1704 }
1705
1706 static float runtime_int_to_float(int a) {
1707 return (float) a;
1708 }
1709
1710 static double runtime_int_to_double(int a) {
1711 return (double) a;
1712 }
1713
1714 // Comparisons float
1715
1716 static int runtime_cmp_eq_ff(float b, float a) {
1717 return a == b;
1718 }
1719
1720 static int runtime_cmp_ne_ff(float b, float a) {
1721 return a != b;
1722 }
1723
1724 static int runtime_cmp_lt_ff(float b, float a) {
1725 return a < b;
1726 }
1727
1728 static int runtime_cmp_le_ff(float b, float a) {
1729 return a <= b;
1730 }
1731
1732 static int runtime_cmp_ge_ff(float b, float a) {
1733 return a >= b;
1734 }
1735
1736 static int runtime_cmp_gt_ff(float b, float a) {
1737 return a > b;
1738 }
1739
1740 // Comparisons double
1741
1742 static int runtime_cmp_eq_dd(double b, double a) {
1743 return a == b;
1744 }
1745
1746 static int runtime_cmp_ne_dd(double b, double a) {
1747 return a != b;
1748 }
1749
1750 static int runtime_cmp_lt_dd(double b, double a) {
1751 return a < b;
1752 }
1753
1754 static int runtime_cmp_le_dd(double b, double a) {
1755 return a <= b;
1756 }
1757
1758 static int runtime_cmp_ge_dd(double b, double a) {
1759 return a >= b;
1760 }
1761
1762 static int runtime_cmp_gt_dd(double b, double a) {
1763 return a > b;
1764 }
1765
1766 // Math float
1767
1768 static float runtime_op_add_ff(float b, float a) {
1769 return a + b;
1770 }
1771
1772 static float runtime_op_sub_ff(float b, float a) {
1773 return a - b;
1774 }
1775
1776 static float runtime_op_mul_ff(float b, float a) {
1777 return a * b;
1778 }
1779
1780 static float runtime_op_div_ff(float b, float a) {
1781 return a / b;
1782 }
1783
1784 static float runtime_op_neg_f(float a) {
1785 return -a;
1786 }
1787
1788 // Math double
1789
1790 static double runtime_op_add_dd(double b, double a) {
1791 return a + b;
1792 }
1793
1794 static double runtime_op_sub_dd(double b, double a) {
1795 return a - b;
1796 }
1797
1798 static double runtime_op_mul_dd(double b, double a) {
1799 return a * b;
1800 }
1801
1802 static double runtime_op_div_dd(double b, double a) {
1803 return a / b;
1804 }
1805
1806 static double runtime_op_neg_d(double a) {
1807 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001808 }
-b master422972c2009-06-17 19:13:52 -07001809
1810 static const int STACK_ALIGNMENT = 8;
1811 int mStackUse;
1812 // This variable holds the amount we adjusted the stack in the most
1813 // recent endFunctionCallArguments call. It's examined by the
1814 // following adjustStackAfterCall call.
1815 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001816 };
1817
Jack Palevich09555c72009-05-27 12:25:55 -07001818#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001819
1820#ifdef PROVIDE_X86_CODEGEN
1821
Jack Palevich21a15a22009-05-11 14:49:29 -07001822 class X86CodeGenerator : public CodeGenerator {
1823 public:
1824 X86CodeGenerator() {}
1825 virtual ~X86CodeGenerator() {}
1826
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001827 /* returns address to patch with local variable size
1828 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001829 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001830 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1831 return oad(0xec81, 0); /* sub $xxx, %esp */
1832 }
1833
Jack Palevichb7718b92009-07-09 22:00:24 -07001834 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001835 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001836 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001837 }
1838
Jack Palevich21a15a22009-05-11 14:49:29 -07001839 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001840 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001841 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001842 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001843 }
1844
Jack Palevich1a539db2009-07-08 13:04:41 -07001845 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001846 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001847 switch (pType->tag) {
1848 case TY_FLOAT:
1849 oad(0x05D9, address); // flds
1850 break;
1851 case TY_DOUBLE:
1852 oad(0x05DD, address); // fldl
1853 break;
1854 default:
1855 assert(false);
1856 break;
1857 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001858 }
1859
Jack Palevich22305132009-05-13 10:58:45 -07001860 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001861 return psym(0xe9, t);
1862 }
1863
1864 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001865 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001866 Type* pR0Type = getR0Type();
1867 TypeTag tagR0 = pR0Type->tag;
1868 bool isFloatR0 = isFloatTag(tagR0);
1869 if (isFloatR0) {
1870 o(0xeed9); // fldz
1871 o(0xe9da); // fucompp
1872 o(0xe0df); // fnstsw %ax
1873 o(0x9e); // sahf
1874 } else {
1875 o(0xc085); // test %eax, %eax
1876 }
1877 // Use two output statements to generate one instruction.
1878 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001879 return psym(0x84 + l, t);
1880 }
1881
Jack Palevicha39749f2009-07-08 20:40:31 -07001882 virtual void gcmp(int op, Type* pResultType) {
1883 Type* pR0Type = getR0Type();
1884 Type* pTOSType = getTOSType();
1885 TypeTag tagR0 = pR0Type->tag;
1886 TypeTag tagTOS = pTOSType->tag;
1887 bool isFloatR0 = isFloatTag(tagR0);
1888 bool isFloatTOS = isFloatTag(tagTOS);
1889 if (!isFloatR0 && !isFloatTOS) {
1890 int t = decodeOp(op);
1891 o(0x59); /* pop %ecx */
1892 o(0xc139); /* cmp %eax,%ecx */
1893 li(0, NULL);
1894 o(0x0f); /* setxx %al */
1895 o(t + 0x90);
1896 o(0xc0);
1897 popType();
1898 } else {
1899 setupFloatOperands();
1900 switch (op) {
1901 case OP_EQUALS:
1902 o(0xe9da); // fucompp
1903 o(0xe0df); // fnstsw %ax
1904 o(0x9e); // sahf
1905 o(0xc0940f); // sete %al
1906 o(0xc29b0f); // setnp %dl
1907 o(0xd021); // andl %edx, %eax
1908 break;
1909 case OP_NOT_EQUALS:
1910 o(0xe9da); // fucompp
1911 o(0xe0df); // fnstsw %ax
1912 o(0x9e); // sahf
1913 o(0xc0950f); // setne %al
1914 o(0xc29a0f); // setp %dl
1915 o(0xd009); // orl %edx, %eax
1916 break;
1917 case OP_GREATER_EQUAL:
1918 o(0xe9da); // fucompp
1919 o(0xe0df); // fnstsw %ax
1920 o(0x05c4f6); // testb $5, %ah
1921 o(0xc0940f); // sete %al
1922 break;
1923 case OP_LESS:
1924 o(0xc9d9); // fxch %st(1)
1925 o(0xe9da); // fucompp
1926 o(0xe0df); // fnstsw %ax
1927 o(0x9e); // sahf
1928 o(0xc0970f); // seta %al
1929 break;
1930 case OP_LESS_EQUAL:
1931 o(0xc9d9); // fxch %st(1)
1932 o(0xe9da); // fucompp
1933 o(0xe0df); // fnstsw %ax
1934 o(0x9e); // sahf
1935 o(0xc0930f); // setea %al
1936 break;
1937 case OP_GREATER:
1938 o(0xe9da); // fucompp
1939 o(0xe0df); // fnstsw %ax
1940 o(0x45c4f6); // testb $69, %ah
1941 o(0xc0940f); // sete %al
1942 break;
1943 default:
1944 error("Unknown comparison op");
1945 }
1946 o(0xc0b60f); // movzbl %al, %eax
1947 }
1948 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001949 }
1950
Jack Palevich546b2242009-05-13 15:10:04 -07001951 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001952 Type* pR0Type = getR0Type();
1953 Type* pTOSType = getTOSType();
1954 TypeTag tagR0 = pR0Type->tag;
1955 TypeTag tagTOS = pTOSType->tag;
1956 bool isFloatR0 = isFloatTag(tagR0);
1957 bool isFloatTOS = isFloatTag(tagTOS);
1958 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001959 bool isPtrR0 = tagR0 == TY_POINTER;
1960 bool isPtrTOS = tagTOS == TY_POINTER;
1961 if (isPtrR0 || isPtrTOS) {
1962 if (isPtrR0 && isPtrTOS) {
1963 if (op != OP_MINUS) {
1964 error("Unsupported pointer-pointer operation %d.", op);
1965 }
1966 if (! typeEqual(pR0Type, pTOSType)) {
1967 error("Incompatible pointer types for subtraction.");
1968 }
1969 o(0x59); /* pop %ecx */
1970 o(decodeOp(op));
1971 popType();
1972 setR0Type(mkpInt);
1973 int size = sizeOf(pR0Type->pHead);
1974 if (size != 1) {
1975 pushR0();
1976 li(size, mkpInt);
1977 // TODO: Optimize for power-of-two.
1978 genOp(OP_DIV);
1979 }
1980 } else {
1981 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1982 error("Unsupported pointer-scalar operation %d", op);
1983 }
1984 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1985 o(0x59); /* pop %ecx */
1986 int size = sizeOf(pPtrType->pHead);
1987 if (size != 1) {
1988 // TODO: Optimize for power-of-two.
1989 if (isPtrR0) {
1990 oad(0xC969, size); // imull $size, %ecx
1991 } else {
1992 oad(0xC069, size); // mul $size, %eax
1993 }
1994 }
1995 o(decodeOp(op));
1996 popType();
1997 setR0Type(pPtrType);
1998 }
1999 } else {
2000 o(0x59); /* pop %ecx */
2001 o(decodeOp(op));
2002 if (op == OP_MOD)
2003 o(0x92); /* xchg %edx, %eax */
2004 popType();
2005 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002006 } else {
2007 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2008 setupFloatOperands();
2009 // Both float. x87 R0 == left hand, x87 R1 == right hand
2010 switch (op) {
2011 case OP_MUL:
2012 o(0xc9de); // fmulp
2013 break;
2014 case OP_DIV:
2015 o(0xf1de); // fdivp
2016 break;
2017 case OP_PLUS:
2018 o(0xc1de); // faddp
2019 break;
2020 case OP_MINUS:
2021 o(0xe1de); // fsubp
2022 break;
2023 default:
2024 error("Unsupported binary floating operation.");
2025 break;
2026 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002027 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002028 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002029 }
2030
Jack Palevicha39749f2009-07-08 20:40:31 -07002031 virtual void gUnaryCmp(int op, Type* pResultType) {
2032 if (op != OP_LOGICAL_NOT) {
2033 error("Unknown unary cmp %d", op);
2034 } else {
2035 Type* pR0Type = getR0Type();
2036 TypeTag tag = collapseType(pR0Type->tag);
2037 switch(tag) {
2038 case TY_INT: {
2039 oad(0xb9, 0); /* movl $0, %ecx */
2040 int t = decodeOp(op);
2041 o(0xc139); /* cmp %eax,%ecx */
2042 li(0, NULL);
2043 o(0x0f); /* setxx %al */
2044 o(t + 0x90);
2045 o(0xc0);
2046 }
2047 break;
2048 case TY_FLOAT:
2049 case TY_DOUBLE:
2050 o(0xeed9); // fldz
2051 o(0xe9da); // fucompp
2052 o(0xe0df); // fnstsw %ax
2053 o(0x9e); // sahf
2054 o(0xc0950f); // setne %al
2055 o(0xc29a0f); // setp %dl
2056 o(0xd009); // orl %edx, %eax
2057 o(0xc0b60f); // movzbl %al, %eax
2058 o(0x01f083); // xorl $1, %eax
2059 break;
2060 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002061 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002062 break;
2063 }
2064 }
2065 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002066 }
2067
2068 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002069 Type* pR0Type = getR0Type();
2070 TypeTag tag = collapseType(pR0Type->tag);
2071 switch(tag) {
2072 case TY_INT:
2073 oad(0xb9, 0); /* movl $0, %ecx */
2074 o(decodeOp(op));
2075 break;
2076 case TY_FLOAT:
2077 case TY_DOUBLE:
2078 switch (op) {
2079 case OP_MINUS:
2080 o(0xe0d9); // fchs
2081 break;
2082 case OP_BIT_NOT:
2083 error("Can't apply '~' operator to a float or double.");
2084 break;
2085 default:
2086 error("Unknown unary op %d\n", op);
2087 break;
2088 }
2089 break;
2090 default:
2091 error("genUnaryOp unsupported type");
2092 break;
2093 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002094 }
2095
Jack Palevich1cdef202009-05-22 12:06:27 -07002096 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002097 Type* pR0Type = getR0Type();
2098 TypeTag r0ct = collapseType(pR0Type->tag);
2099 switch(r0ct) {
2100 case TY_INT:
2101 o(0x50); /* push %eax */
2102 break;
2103 case TY_FLOAT:
2104 o(0x50); /* push %eax */
2105 o(0x241cd9); // fstps 0(%esp)
2106 break;
2107 case TY_DOUBLE:
2108 o(0x50); /* push %eax */
2109 o(0x50); /* push %eax */
2110 o(0x241cdd); // fstpl 0(%esp)
2111 break;
2112 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002113 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002114 break;
2115 }
Jack Palevich8df46192009-07-07 14:48:51 -07002116 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002117 }
2118
Jack Palevich9eed7a22009-07-06 17:24:34 -07002119 virtual void storeR0ToTOS(Type* pPointerType) {
2120 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002121 Type* pTargetType = pPointerType->pHead;
2122 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002123 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002124 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002125 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002126 case TY_INT:
2127 o(0x0189); /* movl %eax/%al, (%ecx) */
2128 break;
2129 case TY_CHAR:
2130 o(0x0188); /* movl %eax/%al, (%ecx) */
2131 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002132 case TY_FLOAT:
2133 o(0x19d9); /* fstps (%ecx) */
2134 break;
2135 case TY_DOUBLE:
2136 o(0x19dd); /* fstpl (%ecx) */
2137 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002138 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002139 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002140 break;
2141 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002142 }
2143
Jack Palevich9eed7a22009-07-06 17:24:34 -07002144 virtual void loadR0FromR0(Type* pPointerType) {
2145 assert(pPointerType->tag == TY_POINTER);
2146 switch (pPointerType->pHead->tag) {
2147 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002148 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002149 break;
2150 case TY_CHAR:
2151 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002152 ob(0); /* add zero in code */
2153 break;
2154 case TY_FLOAT:
2155 o2(0x00d9); // flds (%eax)
2156 break;
2157 case TY_DOUBLE:
2158 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002159 break;
2160 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002161 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002162 break;
2163 }
Jack Palevich8df46192009-07-07 14:48:51 -07002164 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002165 }
2166
Jack Palevich8df46192009-07-07 14:48:51 -07002167 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002168 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002169 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002170 }
2171
Jack Palevich9cbd2262009-07-08 16:48:41 -07002172 virtual void storeR0(int ea, Type* pType) {
2173 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002174 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002175 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002176 case TY_CHAR:
2177 if (ea < -LOCAL || ea > LOCAL) {
2178 oad(0xa2, ea); // movb %al,ea
2179 } else {
2180 oad(0x8588, ea); // movb %al,ea(%ebp)
2181 }
2182 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002183 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002184 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002185 gmov(6, ea); /* mov %eax, EA */
2186 break;
2187 case TY_FLOAT:
2188 if (ea < -LOCAL || ea > LOCAL) {
2189 oad(0x1dd9, ea); // fstps ea
2190 } else {
2191 oad(0x9dd9, ea); // fstps ea(%ebp)
2192 }
2193 break;
2194 case TY_DOUBLE:
2195 if (ea < -LOCAL || ea > LOCAL) {
2196 oad(0x1ddd, ea); // fstpl ea
2197 } else {
2198 oad(0x9ddd, ea); // fstpl ea(%ebp)
2199 }
2200 break;
2201 default:
2202 error("Unable to store to type %d", tag);
2203 break;
2204 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002205 }
2206
Jack Palevich8df46192009-07-07 14:48:51 -07002207 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002208 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002209 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002210 case TY_CHAR:
2211 if (ea < -LOCAL || ea > LOCAL) {
2212 oad(0x05BE0F, ea); // movsbl ea,%eax
2213 } else {
2214 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2215 }
2216 if (isIncDec) {
2217 error("inc/dec not implemented for char.");
2218 }
2219 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002220 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002221 case TY_POINTER:
2222 if (tag == TY_CHAR) {
2223 } else {
2224 gmov(8, ea); /* mov EA, %eax */
2225 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002226 if (isIncDec) {
2227 /* Implement post-increment or post decrement.
2228 */
2229 gmov(0, ea); /* 83 ADD */
2230 o(decodeOp(op));
2231 }
2232 break;
2233 case TY_FLOAT:
2234 if (ea < -LOCAL || ea > LOCAL) {
2235 oad(0x05d9, ea); // flds ea
2236 } else {
2237 oad(0x85d9, ea); // flds ea(%ebp)
2238 }
2239 if (isIncDec) {
2240 error("inc/dec not implemented for float.");
2241 }
2242 break;
2243 case TY_DOUBLE:
2244 if (ea < -LOCAL || ea > LOCAL) {
2245 oad(0x05dd, ea); // fldl ea
2246 } else {
2247 oad(0x85dd, ea); // fldl ea(%ebp)
2248 }
2249 if (isIncDec) {
2250 error("inc/dec not implemented for double.");
2251 }
2252 break;
2253 default:
2254 error("Unable to load type %d", tag);
2255 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002256 }
Jack Palevich8df46192009-07-07 14:48:51 -07002257 setR0Type(pType);
2258 }
2259
2260 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002261 Type* pR0Type = getR0Type();
2262 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002263 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002264 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002265 return;
2266 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002267 if (bitsSame(pType, pR0Type)) {
2268 // do nothing special
2269 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2270 // do nothing special, both held in same register on x87.
2271 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002272 TypeTag r0Tag = collapseType(pR0Type->tag);
2273 TypeTag destTag = collapseType(pType->tag);
2274 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2275 // Convert R0 from int to float
2276 o(0x50); // push %eax
2277 o(0x2404DB); // fildl 0(%esp)
2278 o(0x58); // pop %eax
2279 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2280 // Convert R0 from float to int. Complicated because
2281 // need to save and restore the rounding mode.
2282 o(0x50); // push %eax
2283 o(0x50); // push %eax
2284 o(0x02247cD9); // fnstcw 2(%esp)
2285 o(0x2444b70f); // movzwl 2(%esp), %eax
2286 o(0x02);
2287 o(0x0cb4); // movb $12, %ah
2288 o(0x24048966); // movw %ax, 0(%esp)
2289 o(0x242cd9); // fldcw 0(%esp)
2290 o(0x04245cdb); // fistpl 4(%esp)
2291 o(0x02246cd9); // fldcw 2(%esp)
2292 o(0x58); // pop %eax
2293 o(0x58); // pop %eax
2294 } else {
2295 error("Incompatible types old: %d new: %d",
2296 pR0Type->tag, pType->tag);
2297 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002298 }
2299 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002300 }
2301
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002302 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002303 return oad(0xec81, 0); /* sub $xxx, %esp */
2304 }
2305
Jack Palevich8148c5b2009-07-16 18:24:47 -07002306 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2307 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002308 Type* pR0Type = getR0Type();
2309 TypeTag r0ct = collapseType(pR0Type->tag);
2310 switch(r0ct) {
2311 case TY_INT:
2312 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2313 return 4;
2314 case TY_FLOAT:
2315 oad(0x249CD9, l); /* fstps xxx(%esp) */
2316 return 4;
2317 case TY_DOUBLE:
2318 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2319 return 8;
2320 default:
2321 assert(false);
2322 return 0;
2323 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002324 }
2325
Jack Palevichb7718b92009-07-09 22:00:24 -07002326 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002327 * (int*) a = l;
2328 }
2329
Jack Palevich8df46192009-07-07 14:48:51 -07002330 virtual int callForward(int symbol, Type* pFunc) {
2331 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002332 return psym(0xe8, symbol); /* call xxx */
2333 }
2334
Jack Palevich8df46192009-07-07 14:48:51 -07002335 virtual void callRelative(int t, Type* pFunc) {
2336 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002337 psym(0xe8, t); /* call xxx */
2338 }
2339
Jack Palevich8df46192009-07-07 14:48:51 -07002340 virtual void callIndirect(int l, Type* pFunc) {
2341 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002342 oad(0x2494ff, l); /* call *xxx(%esp) */
2343 }
2344
Jack Palevichb7718b92009-07-09 22:00:24 -07002345 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002346 if (isIndirect) {
2347 l += 4;
2348 }
-b master422972c2009-06-17 19:13:52 -07002349 if (l > 0) {
2350 oad(0xc481, l); /* add $xxx, %esp */
2351 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002352 }
2353
Jack Palevicha6535612009-05-13 16:24:17 -07002354 virtual int jumpOffset() {
2355 return 5;
2356 }
2357
2358 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002359 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002360 }
2361
Jack Paleviche7b59062009-05-19 17:12:17 -07002362 /* output a symbol and patch all calls to it */
2363 virtual void gsym(int t) {
2364 int n;
2365 int pc = getPC();
2366 while (t) {
2367 n = *(int *) t; /* next value */
2368 *(int *) t = pc - t - 4;
2369 t = n;
2370 }
2371 }
2372
Jack Palevich1cdef202009-05-22 12:06:27 -07002373 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002374 size_t pagesize = 4096;
2375 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2376 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2377 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2378 if (err) {
2379 error("mprotect() failed: %d", errno);
2380 }
2381 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002382 }
2383
Jack Palevich9eed7a22009-07-06 17:24:34 -07002384 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002385 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002386 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002387 virtual size_t alignmentOf(Type* pType){
2388 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002389 }
2390
2391 /**
2392 * Array element alignment (in bytes) for this type of data.
2393 */
2394 virtual size_t sizeOf(Type* pType){
2395 switch(pType->tag) {
2396 case TY_INT:
2397 return 4;
2398 case TY_CHAR:
2399 return 1;
2400 default:
2401 return 0;
2402 case TY_FLOAT:
2403 return 4;
2404 case TY_DOUBLE:
2405 return 8;
2406 case TY_POINTER:
2407 return 4;
2408 }
2409 }
2410
Jack Palevich9cbd2262009-07-08 16:48:41 -07002411 virtual size_t stackSizeOf(Type* pType) {
2412 switch(pType->tag) {
2413 case TY_DOUBLE:
2414 return 8;
2415 default:
2416 return 4;
2417 }
2418 }
2419
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002421
2422 /** Output 1 to 4 bytes.
2423 *
2424 */
2425 void o(int n) {
2426 /* cannot use unsigned, so we must do a hack */
2427 while (n && n != -1) {
2428 ob(n & 0xff);
2429 n = n >> 8;
2430 }
2431 }
2432
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002433 /* Output exactly 2 bytes
2434 */
2435 void o2(int n) {
2436 ob(n & 0xff);
2437 ob(0xff & (n >> 8));
2438 }
2439
Jack Paleviche7b59062009-05-19 17:12:17 -07002440 /* psym is used to put an instruction with a data field which is a
2441 reference to a symbol. It is in fact the same as oad ! */
2442 int psym(int n, int t) {
2443 return oad(n, t);
2444 }
2445
2446 /* instruction + address */
2447 int oad(int n, int t) {
2448 o(n);
2449 int result = getPC();
2450 o4(t);
2451 return result;
2452 }
2453
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002454 static const int operatorHelper[];
2455
2456 int decodeOp(int op) {
2457 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002458 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002459 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002460 }
2461 return operatorHelper[op];
2462 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002463
Jack Palevich546b2242009-05-13 15:10:04 -07002464 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002465 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002466 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002467 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002468
2469 void setupFloatOperands() {
2470 Type* pR0Type = getR0Type();
2471 Type* pTOSType = getTOSType();
2472 TypeTag tagR0 = pR0Type->tag;
2473 TypeTag tagTOS = pTOSType->tag;
2474 bool isFloatR0 = isFloatTag(tagR0);
2475 bool isFloatTOS = isFloatTag(tagTOS);
2476 if (! isFloatR0) {
2477 // Convert R0 from int to float
2478 o(0x50); // push %eax
2479 o(0x2404DB); // fildl 0(%esp)
2480 o(0x58); // pop %eax
2481 }
2482 if (! isFloatTOS){
2483 o(0x2404DB); // fildl 0(%esp);
2484 o(0x58); // pop %eax
2485 } else {
2486 if (tagTOS == TY_FLOAT) {
2487 o(0x2404d9); // flds (%esp)
2488 o(0x58); // pop %eax
2489 } else {
2490 o(0x2404dd); // fldl (%esp)
2491 o(0x58); // pop %eax
2492 o(0x58); // pop %eax
2493 }
2494 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002495 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002496 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002497 };
2498
Jack Paleviche7b59062009-05-19 17:12:17 -07002499#endif // PROVIDE_X86_CODEGEN
2500
Jack Palevichb67b18f2009-06-11 21:12:23 -07002501#ifdef PROVIDE_TRACE_CODEGEN
2502 class TraceCodeGenerator : public CodeGenerator {
2503 private:
2504 CodeGenerator* mpBase;
2505
2506 public:
2507 TraceCodeGenerator(CodeGenerator* pBase) {
2508 mpBase = pBase;
2509 }
2510
2511 virtual ~TraceCodeGenerator() {
2512 delete mpBase;
2513 }
2514
2515 virtual void init(CodeBuf* pCodeBuf) {
2516 mpBase->init(pCodeBuf);
2517 }
2518
2519 void setErrorSink(ErrorSink* pErrorSink) {
2520 mpBase->setErrorSink(pErrorSink);
2521 }
2522
2523 /* returns address to patch with local variable size
2524 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002525 virtual int functionEntry(Type* pDecl) {
2526 int result = mpBase->functionEntry(pDecl);
2527 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002528 return result;
2529 }
2530
Jack Palevichb7718b92009-07-09 22:00:24 -07002531 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2532 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2533 localVariableAddress, localVariableSize);
2534 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002535 }
2536
2537 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002538 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002539 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002540 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002541 }
2542
Jack Palevich1a539db2009-07-08 13:04:41 -07002543 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002544 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002545 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002546 }
2547
Jack Palevichb67b18f2009-06-11 21:12:23 -07002548 virtual int gjmp(int t) {
2549 int result = mpBase->gjmp(t);
2550 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2551 return result;
2552 }
2553
2554 /* l = 0: je, l == 1: jne */
2555 virtual int gtst(bool l, int t) {
2556 int result = mpBase->gtst(l, t);
2557 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2558 return result;
2559 }
2560
Jack Palevicha39749f2009-07-08 20:40:31 -07002561 virtual void gcmp(int op, Type* pResultType) {
2562 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2563 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002564 }
2565
2566 virtual void genOp(int op) {
2567 fprintf(stderr, "genOp(%d)\n", op);
2568 mpBase->genOp(op);
2569 }
2570
Jack Palevich9eed7a22009-07-06 17:24:34 -07002571
Jack Palevicha39749f2009-07-08 20:40:31 -07002572 virtual void gUnaryCmp(int op, Type* pResultType) {
2573 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2574 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002575 }
2576
2577 virtual void genUnaryOp(int op) {
2578 fprintf(stderr, "genUnaryOp(%d)\n", op);
2579 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002580 }
2581
2582 virtual void pushR0() {
2583 fprintf(stderr, "pushR0()\n");
2584 mpBase->pushR0();
2585 }
2586
Jack Palevich9eed7a22009-07-06 17:24:34 -07002587 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002588 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002589 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002590 }
2591
Jack Palevich9eed7a22009-07-06 17:24:34 -07002592 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002593 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002594 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002595 }
2596
Jack Palevich8df46192009-07-07 14:48:51 -07002597 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002598 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002599 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002600 }
2601
Jack Palevich9cbd2262009-07-08 16:48:41 -07002602 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002603 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002604 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002605 }
2606
Jack Palevich8df46192009-07-07 14:48:51 -07002607 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002608 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002609 mpBase->loadR0(ea, isIncDec, op, pType);
2610 }
2611
2612 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002613 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002614 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002615 }
2616
2617 virtual int beginFunctionCallArguments() {
2618 int result = mpBase->beginFunctionCallArguments();
2619 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2620 return result;
2621 }
2622
Jack Palevich8148c5b2009-07-16 18:24:47 -07002623 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2624 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2625 pArgType->tag);
2626 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002627 }
2628
Jack Palevichb7718b92009-07-09 22:00:24 -07002629 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002630 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002631 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002632 }
2633
Jack Palevich8df46192009-07-07 14:48:51 -07002634 virtual int callForward(int symbol, Type* pFunc) {
2635 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002636 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2637 return result;
2638 }
2639
Jack Palevich8df46192009-07-07 14:48:51 -07002640 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002641 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002642 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002643 }
2644
Jack Palevich8df46192009-07-07 14:48:51 -07002645 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002646 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002647 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002648 }
2649
Jack Palevichb7718b92009-07-09 22:00:24 -07002650 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2651 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2652 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002653 }
2654
2655 virtual int jumpOffset() {
2656 return mpBase->jumpOffset();
2657 }
2658
2659 virtual int disassemble(FILE* out) {
2660 return mpBase->disassemble(out);
2661 }
2662
2663 /* output a symbol and patch all calls to it */
2664 virtual void gsym(int t) {
2665 fprintf(stderr, "gsym(%d)\n", t);
2666 mpBase->gsym(t);
2667 }
2668
2669 virtual int finishCompile() {
2670 int result = mpBase->finishCompile();
2671 fprintf(stderr, "finishCompile() = %d\n", result);
2672 return result;
2673 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002674
2675 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002676 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002677 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002678 virtual size_t alignmentOf(Type* pType){
2679 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002680 }
2681
2682 /**
2683 * Array element alignment (in bytes) for this type of data.
2684 */
2685 virtual size_t sizeOf(Type* pType){
2686 return mpBase->sizeOf(pType);
2687 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002688
Jack Palevich9cbd2262009-07-08 16:48:41 -07002689
2690 virtual size_t stackSizeOf(Type* pType) {
2691 return mpBase->stackSizeOf(pType);
2692 }
2693
2694
Jack Palevich1a539db2009-07-08 13:04:41 -07002695 virtual Type* getR0Type() {
2696 return mpBase->getR0Type();
2697 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002698 };
2699
2700#endif // PROVIDE_TRACE_CODEGEN
2701
Jack Palevich569f1352009-06-29 14:29:08 -07002702 class Arena {
2703 public:
2704 // Used to record a given allocation amount.
2705 // Used:
2706 // Mark mark = arena.mark();
2707 // ... lots of arena.allocate()
2708 // arena.free(mark);
2709
2710 struct Mark {
2711 size_t chunk;
2712 size_t offset;
2713 };
2714
2715 Arena() {
2716 mCurrentChunk = 0;
2717 Chunk start(CHUNK_SIZE);
2718 mData.push_back(start);
2719 }
2720
2721 ~Arena() {
2722 for(size_t i = 0; i < mData.size(); i++) {
2723 mData[i].free();
2724 }
2725 }
2726
2727 // Alloc using the standard alignment size safe for any variable
2728 void* alloc(size_t size) {
2729 return alloc(size, 8);
2730 }
2731
2732 Mark mark(){
2733 Mark result;
2734 result.chunk = mCurrentChunk;
2735 result.offset = mData[mCurrentChunk].mOffset;
2736 return result;
2737 }
2738
2739 void freeToMark(const Mark& mark) {
2740 mCurrentChunk = mark.chunk;
2741 mData[mCurrentChunk].mOffset = mark.offset;
2742 }
2743
2744 private:
2745 // Allocate memory aligned to a given size
2746 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2747 // Memory is not zero filled.
2748
2749 void* alloc(size_t size, size_t alignment) {
2750 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2751 if (mCurrentChunk + 1 < mData.size()) {
2752 mCurrentChunk++;
2753 } else {
2754 size_t allocSize = CHUNK_SIZE;
2755 if (allocSize < size + alignment - 1) {
2756 allocSize = size + alignment - 1;
2757 }
2758 Chunk chunk(allocSize);
2759 mData.push_back(chunk);
2760 mCurrentChunk++;
2761 }
2762 }
2763 return mData[mCurrentChunk].allocate(size, alignment);
2764 }
2765
2766 static const size_t CHUNK_SIZE = 128*1024;
2767 // Note: this class does not deallocate its
2768 // memory when it's destroyed. It depends upon
2769 // its parent to deallocate the memory.
2770 struct Chunk {
2771 Chunk() {
2772 mpData = 0;
2773 mSize = 0;
2774 mOffset = 0;
2775 }
2776
2777 Chunk(size_t size) {
2778 mSize = size;
2779 mpData = (char*) malloc(size);
2780 mOffset = 0;
2781 }
2782
2783 ~Chunk() {
2784 // Doesn't deallocate memory.
2785 }
2786
2787 void* allocate(size_t size, size_t alignment) {
2788 size_t alignedOffset = aligned(mOffset, alignment);
2789 void* result = mpData + alignedOffset;
2790 mOffset = alignedOffset + size;
2791 return result;
2792 }
2793
2794 void free() {
2795 if (mpData) {
2796 ::free(mpData);
2797 mpData = 0;
2798 }
2799 }
2800
2801 size_t remainingCapacity(size_t alignment) {
2802 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2803 }
2804
2805 // Assume alignment is a power of two
2806 inline size_t aligned(size_t v, size_t alignment) {
2807 size_t mask = alignment-1;
2808 return (v + mask) & ~mask;
2809 }
2810
2811 char* mpData;
2812 size_t mSize;
2813 size_t mOffset;
2814 };
2815
2816 size_t mCurrentChunk;
2817
2818 Vector<Chunk> mData;
2819 };
2820
Jack Palevich569f1352009-06-29 14:29:08 -07002821 struct VariableInfo;
2822
2823 struct Token {
2824 int hash;
2825 size_t length;
2826 char* pText;
2827 tokenid_t id;
2828
2829 // Current values for the token
2830 char* mpMacroDefinition;
2831 VariableInfo* mpVariableInfo;
2832 };
2833
2834 class TokenTable {
2835 public:
2836 // Don't use 0..0xff, allows characters and operators to be tokens too.
2837
2838 static const int TOKEN_BASE = 0x100;
2839 TokenTable() {
2840 mpMap = hashmapCreate(128, hashFn, equalsFn);
2841 }
2842
2843 ~TokenTable() {
2844 hashmapFree(mpMap);
2845 }
2846
2847 void setArena(Arena* pArena) {
2848 mpArena = pArena;
2849 }
2850
2851 // Returns a token for a given string of characters.
2852 tokenid_t intern(const char* pText, size_t length) {
2853 Token probe;
2854 int hash = hashmapHash((void*) pText, length);
2855 {
2856 Token probe;
2857 probe.hash = hash;
2858 probe.length = length;
2859 probe.pText = (char*) pText;
2860 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2861 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002862 return pValue->id;
2863 }
2864 }
2865
2866 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2867 memset(pToken, 0, sizeof(*pToken));
2868 pToken->hash = hash;
2869 pToken->length = length;
2870 pToken->pText = (char*) mpArena->alloc(length + 1);
2871 memcpy(pToken->pText, pText, length);
2872 pToken->pText[length] = 0;
2873 pToken->id = mTokens.size() + TOKEN_BASE;
2874 mTokens.push_back(pToken);
2875 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002876 return pToken->id;
2877 }
2878
2879 // Return the Token for a given tokenid.
2880 Token& operator[](tokenid_t id) {
2881 return *mTokens[id - TOKEN_BASE];
2882 }
2883
2884 inline size_t size() {
2885 return mTokens.size();
2886 }
2887
2888 private:
2889
2890 static int hashFn(void* pKey) {
2891 Token* pToken = (Token*) pKey;
2892 return pToken->hash;
2893 }
2894
2895 static bool equalsFn(void* keyA, void* keyB) {
2896 Token* pTokenA = (Token*) keyA;
2897 Token* pTokenB = (Token*) keyB;
2898 // Don't need to compare hash values, they should always be equal
2899 return pTokenA->length == pTokenB->length
2900 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2901 }
2902
2903 Hashmap* mpMap;
2904 Vector<Token*> mTokens;
2905 Arena* mpArena;
2906 };
2907
Jack Palevich1cdef202009-05-22 12:06:27 -07002908 class InputStream {
2909 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002910 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002911 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002912 };
2913
2914 class TextInputStream : public InputStream {
2915 public:
2916 TextInputStream(const char* text, size_t textLength)
2917 : pText(text), mTextLength(textLength), mPosition(0) {
2918 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002919
Jack Palevichdc456462009-07-16 16:50:56 -07002920 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002921 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2922 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002923
Jack Palevichdc456462009-07-16 16:50:56 -07002924 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002925 const char* pText;
2926 size_t mTextLength;
2927 size_t mPosition;
2928 };
2929
Jack Palevicheedf9d22009-06-04 16:23:40 -07002930 class String {
2931 public:
2932 String() {
2933 mpBase = 0;
2934 mUsed = 0;
2935 mSize = 0;
2936 }
2937
Jack Palevich303d8ff2009-06-11 19:06:24 -07002938 String(const char* item, int len, bool adopt) {
2939 if (len < 0) {
2940 len = strlen(item);
2941 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002942 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002943 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002944 mUsed = len;
2945 mSize = len + 1;
2946 } else {
2947 mpBase = 0;
2948 mUsed = 0;
2949 mSize = 0;
2950 appendBytes(item, len);
2951 }
2952 }
2953
Jack Palevich303d8ff2009-06-11 19:06:24 -07002954 String(const String& other) {
2955 mpBase = 0;
2956 mUsed = 0;
2957 mSize = 0;
2958 appendBytes(other.getUnwrapped(), other.len());
2959 }
2960
Jack Palevicheedf9d22009-06-04 16:23:40 -07002961 ~String() {
2962 if (mpBase) {
2963 free(mpBase);
2964 }
2965 }
2966
Jack Palevicha6baa232009-06-12 11:25:59 -07002967 String& operator=(const String& other) {
2968 clear();
2969 appendBytes(other.getUnwrapped(), other.len());
2970 return *this;
2971 }
2972
Jack Palevich303d8ff2009-06-11 19:06:24 -07002973 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002974 return mpBase;
2975 }
2976
Jack Palevich303d8ff2009-06-11 19:06:24 -07002977 void clear() {
2978 mUsed = 0;
2979 if (mSize > 0) {
2980 mpBase[0] = 0;
2981 }
2982 }
2983
Jack Palevicheedf9d22009-06-04 16:23:40 -07002984 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002985 appendBytes(s, strlen(s));
2986 }
2987
2988 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002989 memcpy(ensure(n), s, n + 1);
2990 }
2991
2992 void append(char c) {
2993 * ensure(1) = c;
2994 }
2995
Jack Palevich86351982009-06-30 18:09:56 -07002996 void append(String& other) {
2997 appendBytes(other.getUnwrapped(), other.len());
2998 }
2999
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003000 char* orphan() {
3001 char* result = mpBase;
3002 mpBase = 0;
3003 mUsed = 0;
3004 mSize = 0;
3005 return result;
3006 }
3007
Jack Palevicheedf9d22009-06-04 16:23:40 -07003008 void printf(const char* fmt,...) {
3009 va_list ap;
3010 va_start(ap, fmt);
3011 vprintf(fmt, ap);
3012 va_end(ap);
3013 }
3014
3015 void vprintf(const char* fmt, va_list ap) {
3016 char* temp;
3017 int numChars = vasprintf(&temp, fmt, ap);
3018 memcpy(ensure(numChars), temp, numChars+1);
3019 free(temp);
3020 }
3021
Jack Palevich303d8ff2009-06-11 19:06:24 -07003022 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003023 return mUsed;
3024 }
3025
3026 private:
3027 char* ensure(int n) {
3028 size_t newUsed = mUsed + n;
3029 if (newUsed > mSize) {
3030 size_t newSize = mSize * 2 + 10;
3031 if (newSize < newUsed) {
3032 newSize = newUsed;
3033 }
3034 mpBase = (char*) realloc(mpBase, newSize + 1);
3035 mSize = newSize;
3036 }
3037 mpBase[newUsed] = '\0';
3038 char* result = mpBase + mUsed;
3039 mUsed = newUsed;
3040 return result;
3041 }
3042
3043 char* mpBase;
3044 size_t mUsed;
3045 size_t mSize;
3046 };
3047
Jack Palevich569f1352009-06-29 14:29:08 -07003048 void internKeywords() {
3049 // Note: order has to match TOK_ constants
3050 static const char* keywords[] = {
3051 "int",
3052 "char",
3053 "void",
3054 "if",
3055 "else",
3056 "while",
3057 "break",
3058 "return",
3059 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003060 "auto",
3061 "case",
3062 "const",
3063 "continue",
3064 "default",
3065 "do",
3066 "double",
3067 "enum",
3068 "extern",
3069 "float",
3070 "goto",
3071 "long",
3072 "register",
3073 "short",
3074 "signed",
3075 "sizeof",
3076 "static",
3077 "struct",
3078 "switch",
3079 "typedef",
3080 "union",
3081 "unsigned",
3082 "volatile",
3083 "_Bool",
3084 "_Complex",
3085 "_Imaginary",
3086 "inline",
3087 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003088
3089 // predefined tokens that can also be symbols start here:
3090 "pragma",
3091 "define",
3092 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003093 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003094
Jack Palevich569f1352009-06-29 14:29:08 -07003095 for(int i = 0; keywords[i]; i++) {
3096 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003097 }
Jack Palevich569f1352009-06-29 14:29:08 -07003098 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003099
Jack Palevich36d94142009-06-08 15:55:32 -07003100 struct InputState {
3101 InputStream* pStream;
3102 int oldCh;
3103 };
3104
Jack Palevich2db168f2009-06-11 14:29:47 -07003105 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003106 void* pAddress;
3107 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003108 tokenid_t tok;
3109 size_t level;
3110 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003111 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003112 };
3113
Jack Palevich303d8ff2009-06-11 19:06:24 -07003114 class SymbolStack {
3115 public:
3116 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003117 mpArena = 0;
3118 mpTokenTable = 0;
3119 }
3120
3121 void setArena(Arena* pArena) {
3122 mpArena = pArena;
3123 }
3124
3125 void setTokenTable(TokenTable* pTokenTable) {
3126 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003127 }
3128
3129 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003130 Mark mark;
3131 mark.mArenaMark = mpArena->mark();
3132 mark.mSymbolHead = mStack.size();
3133 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003134 }
3135
3136 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003137 // Undo any shadowing that was done:
3138 Mark mark = mLevelStack.back();
3139 mLevelStack.pop_back();
3140 while (mStack.size() > mark.mSymbolHead) {
3141 VariableInfo* pV = mStack.back();
3142 mStack.pop_back();
3143 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003144 }
Jack Palevich569f1352009-06-29 14:29:08 -07003145 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003146 }
3147
Jack Palevich569f1352009-06-29 14:29:08 -07003148 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3149 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3150 return pV && pV->level == level();
3151 }
3152
3153 VariableInfo* add(tokenid_t tok) {
3154 Token& token = (*mpTokenTable)[tok];
3155 VariableInfo* pOldV = token.mpVariableInfo;
3156 VariableInfo* pNewV =
3157 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3158 memset(pNewV, 0, sizeof(VariableInfo));
3159 pNewV->tok = tok;
3160 pNewV->level = level();
3161 pNewV->pOldDefinition = pOldV;
3162 token.mpVariableInfo = pNewV;
3163 mStack.push_back(pNewV);
3164 return pNewV;
3165 }
3166
Jack Palevich86351982009-06-30 18:09:56 -07003167 VariableInfo* add(Type* pType) {
3168 VariableInfo* pVI = add(pType->id);
3169 pVI->pType = pType;
3170 return pVI;
3171 }
3172
Jack Palevich569f1352009-06-29 14:29:08 -07003173 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3174 for (size_t i = 0; i < mStack.size(); i++) {
3175 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003176 break;
3177 }
3178 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003179 }
3180
Jack Palevich303d8ff2009-06-11 19:06:24 -07003181 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003182 inline size_t level() {
3183 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003184 }
3185
Jack Palevich569f1352009-06-29 14:29:08 -07003186 struct Mark {
3187 Arena::Mark mArenaMark;
3188 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003189 };
3190
Jack Palevich569f1352009-06-29 14:29:08 -07003191 Arena* mpArena;
3192 TokenTable* mpTokenTable;
3193 Vector<VariableInfo*> mStack;
3194 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003195 };
Jack Palevich36d94142009-06-08 15:55:32 -07003196
3197 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003198 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003199 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003200 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003201 int tokl; // token operator level
3202 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003203 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003204 intptr_t loc; // local variable index
3205 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003206 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003207 char* dptr; // Macro state: Points to macro text during macro playback.
3208 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003209 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003210 ACCSymbolLookupFn mpSymbolLookupFn;
3211 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003212
3213 // Arena for the duration of the compile
3214 Arena mGlobalArena;
3215 // Arena for data that's only needed when compiling a single function
3216 Arena mLocalArena;
3217
3218 TokenTable mTokenTable;
3219 SymbolStack mGlobals;
3220 SymbolStack mLocals;
3221
Jack Palevich40600de2009-07-01 15:32:35 -07003222 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003223 Type* mkpInt; // int
3224 Type* mkpChar; // char
3225 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003226 Type* mkpFloat;
3227 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003228 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003229 Type* mkpIntPtr;
3230 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003231 Type* mkpFloatPtr;
3232 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003233 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003234
Jack Palevich36d94142009-06-08 15:55:32 -07003235 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003236 int mLineNumber;
3237 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003238
3239 CodeBuf codeBuf;
3240 CodeGenerator* pGen;
3241
Jack Palevicheedf9d22009-06-04 16:23:40 -07003242 String mErrorBuf;
3243
Jack Palevicheedf9d22009-06-04 16:23:40 -07003244 String mPragmas;
3245 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003246 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003247
Jack Palevich21a15a22009-05-11 14:49:29 -07003248 static const int ALLOC_SIZE = 99999;
3249
Jack Palevich303d8ff2009-06-11 19:06:24 -07003250 static const int TOK_DUMMY = 1;
3251 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003252 static const int TOK_NUM_FLOAT = 3;
3253 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003254
3255 // 3..255 are character and/or operators
3256
Jack Palevich2db168f2009-06-11 14:29:47 -07003257 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003258 // Order has to match string list in "internKeywords".
3259 enum {
3260 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3261 TOK_INT = TOK_KEYWORD,
3262 TOK_CHAR,
3263 TOK_VOID,
3264 TOK_IF,
3265 TOK_ELSE,
3266 TOK_WHILE,
3267 TOK_BREAK,
3268 TOK_RETURN,
3269 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003270 TOK_AUTO,
3271 TOK_CASE,
3272 TOK_CONST,
3273 TOK_CONTINUE,
3274 TOK_DEFAULT,
3275 TOK_DO,
3276 TOK_DOUBLE,
3277 TOK_ENUM,
3278 TOK_EXTERN,
3279 TOK_FLOAT,
3280 TOK_GOTO,
3281 TOK_LONG,
3282 TOK_REGISTER,
3283 TOK_SHORT,
3284 TOK_SIGNED,
3285 TOK_SIZEOF,
3286 TOK_STATIC,
3287 TOK_STRUCT,
3288 TOK_SWITCH,
3289 TOK_TYPEDEF,
3290 TOK_UNION,
3291 TOK_UNSIGNED,
3292 TOK_VOLATILE,
3293 TOK__BOOL,
3294 TOK__COMPLEX,
3295 TOK__IMAGINARY,
3296 TOK_INLINE,
3297 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003298
3299 // Symbols start after keywords
3300
3301 TOK_SYMBOL,
3302 TOK_PRAGMA = TOK_SYMBOL,
3303 TOK_DEFINE,
3304 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003305 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003306
3307 static const int LOCAL = 0x200;
3308
3309 static const int SYM_FORWARD = 0;
3310 static const int SYM_DEFINE = 1;
3311
3312 /* tokens in string heap */
3313 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003314
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003315 static const int OP_INCREMENT = 0;
3316 static const int OP_DECREMENT = 1;
3317 static const int OP_MUL = 2;
3318 static const int OP_DIV = 3;
3319 static const int OP_MOD = 4;
3320 static const int OP_PLUS = 5;
3321 static const int OP_MINUS = 6;
3322 static const int OP_SHIFT_LEFT = 7;
3323 static const int OP_SHIFT_RIGHT = 8;
3324 static const int OP_LESS_EQUAL = 9;
3325 static const int OP_GREATER_EQUAL = 10;
3326 static const int OP_LESS = 11;
3327 static const int OP_GREATER = 12;
3328 static const int OP_EQUALS = 13;
3329 static const int OP_NOT_EQUALS = 14;
3330 static const int OP_LOGICAL_AND = 15;
3331 static const int OP_LOGICAL_OR = 16;
3332 static const int OP_BIT_AND = 17;
3333 static const int OP_BIT_XOR = 18;
3334 static const int OP_BIT_OR = 19;
3335 static const int OP_BIT_NOT = 20;
3336 static const int OP_LOGICAL_NOT = 21;
3337 static const int OP_COUNT = 22;
3338
3339 /* Operators are searched from front, the two-character operators appear
3340 * before the single-character operators with the same first character.
3341 * @ is used to pad out single-character operators.
3342 */
3343 static const char* operatorChars;
3344 static const char operatorLevel[];
3345
Jack Palevich569f1352009-06-29 14:29:08 -07003346 /* Called when we detect an internal problem. Does nothing in production.
3347 *
3348 */
3349 void internalError() {
3350 * (char*) 0 = 0;
3351 }
3352
Jack Palevich86351982009-06-30 18:09:56 -07003353 void assert(bool isTrue) {
3354 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003355 internalError();
3356 }
Jack Palevich86351982009-06-30 18:09:56 -07003357 }
3358
Jack Palevich40600de2009-07-01 15:32:35 -07003359 bool isSymbol(tokenid_t t) {
3360 return t >= TOK_SYMBOL &&
3361 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3362 }
3363
3364 bool isSymbolOrKeyword(tokenid_t t) {
3365 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003366 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003367 }
3368
Jack Palevich86351982009-06-30 18:09:56 -07003369 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003370 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003371 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3372 if (pV && pV->tok != t) {
3373 internalError();
3374 }
3375 return pV;
3376 }
3377
3378 inline bool isDefined(tokenid_t t) {
3379 return t >= TOK_SYMBOL && VI(t) != 0;
3380 }
3381
Jack Palevich40600de2009-07-01 15:32:35 -07003382 const char* nameof(tokenid_t t) {
3383 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003384 return mTokenTable[t].pText;
3385 }
3386
Jack Palevich21a15a22009-05-11 14:49:29 -07003387 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003388 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003389 }
3390
3391 void inp() {
3392 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003393 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003394 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003395 dptr = 0;
3396 ch = dch;
3397 }
Jack Palevichdc456462009-07-16 16:50:56 -07003398 } else {
3399 if (mbBumpLine) {
3400 mLineNumber++;
3401 mbBumpLine = false;
3402 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003403 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003404 if (ch == '\n') {
3405 mbBumpLine = true;
3406 }
3407 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003408#if 0
3409 printf("ch='%c' 0x%x\n", ch, ch);
3410#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003411 }
3412
3413 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003414 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003415 }
3416
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003417 int decodeHex(int c) {
3418 if (isdigit(c)) {
3419 c -= '0';
3420 } else if (c <= 'F') {
3421 c = c - 'A' + 10;
3422 } else {
3423 c =c - 'a' + 10;
3424 }
3425 return c;
3426 }
3427
Jack Palevichb4758ff2009-06-12 12:49:14 -07003428 /* read a character constant, advances ch to after end of constant */
3429 int getq() {
3430 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003431 if (ch == '\\') {
3432 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003433 if (isoctal(ch)) {
3434 // 1 to 3 octal characters.
3435 val = 0;
3436 for(int i = 0; i < 3; i++) {
3437 if (isoctal(ch)) {
3438 val = (val << 3) + ch - '0';
3439 inp();
3440 }
3441 }
3442 return val;
3443 } else if (ch == 'x' || ch == 'X') {
3444 // N hex chars
3445 inp();
3446 if (! isxdigit(ch)) {
3447 error("'x' character escape requires at least one digit.");
3448 } else {
3449 val = 0;
3450 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003451 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003452 inp();
3453 }
3454 }
3455 } else {
3456 int val = ch;
3457 switch (ch) {
3458 case 'a':
3459 val = '\a';
3460 break;
3461 case 'b':
3462 val = '\b';
3463 break;
3464 case 'f':
3465 val = '\f';
3466 break;
3467 case 'n':
3468 val = '\n';
3469 break;
3470 case 'r':
3471 val = '\r';
3472 break;
3473 case 't':
3474 val = '\t';
3475 break;
3476 case 'v':
3477 val = '\v';
3478 break;
3479 case '\\':
3480 val = '\\';
3481 break;
3482 case '\'':
3483 val = '\'';
3484 break;
3485 case '"':
3486 val = '"';
3487 break;
3488 case '?':
3489 val = '?';
3490 break;
3491 default:
3492 error("Undefined character escape %c", ch);
3493 break;
3494 }
3495 inp();
3496 return val;
3497 }
3498 } else {
3499 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003500 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003501 return val;
3502 }
3503
3504 static bool isoctal(int ch) {
3505 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003506 }
3507
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003508 bool acceptCh(int c) {
3509 bool result = c == ch;
3510 if (result) {
3511 pdef(ch);
3512 inp();
3513 }
3514 return result;
3515 }
3516
3517 bool acceptDigitsCh() {
3518 bool result = false;
3519 while (isdigit(ch)) {
3520 result = true;
3521 pdef(ch);
3522 inp();
3523 }
3524 return result;
3525 }
3526
3527 void parseFloat() {
3528 tok = TOK_NUM_DOUBLE;
3529 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003530 if(mTokenString.len() == 0) {
3531 mTokenString.append('0');
3532 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003533 acceptCh('.');
3534 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003535 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003536 acceptCh('-') || acceptCh('+');
3537 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003538 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003539 if (ch == 'f' || ch == 'F') {
3540 tok = TOK_NUM_FLOAT;
3541 inp();
3542 } else if (ch == 'l' || ch == 'L') {
3543 inp();
3544 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003545 }
3546 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003547 char* pEnd = pText + strlen(pText);
3548 char* pEndPtr = 0;
3549 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003550 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003551 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003552 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003553 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003554 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003555 if (errno || pEndPtr != pEnd) {
3556 error("Can't parse constant: %s", pText);
3557 }
3558 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003559 }
3560
Jack Palevich21a15a22009-05-11 14:49:29 -07003561 void next() {
3562 int l, a;
3563
Jack Palevich546b2242009-05-13 15:10:04 -07003564 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003565 if (ch == '#') {
3566 inp();
3567 next();
3568 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003569 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003570 } else if (tok == TOK_PRAGMA) {
3571 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003572 } else if (tok == TOK_LINE) {
3573 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003574 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003575 error("Unsupported preprocessor directive \"%s\"",
3576 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003577 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003578 }
3579 inp();
3580 }
3581 tokl = 0;
3582 tok = ch;
3583 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003584 if (isdigit(ch) || ch == '.') {
3585 // Start of a numeric constant. Could be integer, float, or
3586 // double, won't know until we look further.
3587 mTokenString.clear();
3588 pdef(ch);
3589 inp();
3590 int base = 10;
3591 if (tok == '0') {
3592 if (ch == 'x' || ch == 'X') {
3593 base = 16;
3594 tok = TOK_NUM;
3595 tokc = 0;
3596 inp();
3597 while ( isxdigit(ch) ) {
3598 tokc = (tokc << 4) + decodeHex(ch);
3599 inp();
3600 }
3601 } else if (isoctal(ch)){
3602 base = 8;
3603 tok = TOK_NUM;
3604 tokc = 0;
3605 while ( isoctal(ch) ) {
3606 tokc = (tokc << 3) + (ch - '0');
3607 inp();
3608 }
3609 }
3610 } else if (isdigit(tok)){
3611 acceptDigitsCh();
3612 }
3613 if (base == 10) {
3614 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3615 parseFloat();
3616 } else {
3617 // It's an integer constant
3618 char* pText = mTokenString.getUnwrapped();
3619 char* pEnd = pText + strlen(pText);
3620 char* pEndPtr = 0;
3621 errno = 0;
3622 tokc = strtol(pText, &pEndPtr, base);
3623 if (errno || pEndPtr != pEnd) {
3624 error("Can't parse constant: %s %d %d", pText, base, errno);
3625 }
3626 tok = TOK_NUM;
3627 }
3628 }
3629 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003630 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003631 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003632 pdef(ch);
3633 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003634 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003635 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3636 // Is this a macro?
3637 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3638 if (pMacroDefinition) {
3639 // Yes, it is a macro
3640 dptr = pMacroDefinition;
3641 dch = ch;
3642 inp();
3643 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003644 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003645 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003646 inp();
3647 if (tok == '\'') {
3648 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003649 tokc = getq();
3650 if (ch != '\'') {
3651 error("Expected a ' character, got %c", ch);
3652 } else {
3653 inp();
3654 }
Jack Palevich546b2242009-05-13 15:10:04 -07003655 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003656 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003657 while (ch && ch != EOF) {
3658 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003659 inp();
3660 inp();
3661 if (ch == '/')
3662 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003663 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003664 if (ch == EOF) {
3665 error("End of file inside comment.");
3666 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003667 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003668 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003669 } else if ((tok == '/') & (ch == '/')) {
3670 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003671 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003672 inp();
3673 }
3674 inp();
3675 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003676 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003677 const char* t = operatorChars;
3678 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003679 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003680 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003681 tokl = operatorLevel[opIndex];
3682 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003683 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003684#if 0
3685 printf("%c%c -> tokl=%d tokc=0x%x\n",
3686 l, a, tokl, tokc);
3687#endif
3688 if (a == ch) {
3689 inp();
3690 tok = TOK_DUMMY; /* dummy token for double tokens */
3691 }
3692 break;
3693 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003694 opIndex++;
3695 }
3696 if (l == 0) {
3697 tokl = 0;
3698 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003699 }
3700 }
3701 }
3702#if 0
3703 {
Jack Palevich569f1352009-06-29 14:29:08 -07003704 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003705 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003706 fprintf(stderr, "%s\n", buf.getUnwrapped());
3707 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003708#endif
3709 }
3710
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003711 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003712 next();
3713 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003714 String* pName = new String();
3715 while (isspace(ch)) {
3716 inp();
3717 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003718 if (ch == '(') {
3719 delete pName;
3720 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003721 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003722 }
3723 while (isspace(ch)) {
3724 inp();
3725 }
Jack Palevich569f1352009-06-29 14:29:08 -07003726 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003727 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003728 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003729 inp();
3730 }
Jack Palevich569f1352009-06-29 14:29:08 -07003731 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3732 memcpy(pDefn, value.getUnwrapped(), value.len());
3733 pDefn[value.len()] = 0;
3734 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003735 }
3736
Jack Palevicheedf9d22009-06-04 16:23:40 -07003737 void doPragma() {
3738 // # pragma name(val)
3739 int state = 0;
3740 while(ch != EOF && ch != '\n' && state < 10) {
3741 switch(state) {
3742 case 0:
3743 if (isspace(ch)) {
3744 inp();
3745 } else {
3746 state++;
3747 }
3748 break;
3749 case 1:
3750 if (isalnum(ch)) {
3751 mPragmas.append(ch);
3752 inp();
3753 } else if (ch == '(') {
3754 mPragmas.append(0);
3755 inp();
3756 state++;
3757 } else {
3758 state = 11;
3759 }
3760 break;
3761 case 2:
3762 if (isalnum(ch)) {
3763 mPragmas.append(ch);
3764 inp();
3765 } else if (ch == ')') {
3766 mPragmas.append(0);
3767 inp();
3768 state = 10;
3769 } else {
3770 state = 11;
3771 }
3772 break;
3773 }
3774 }
3775 if(state != 10) {
3776 error("Unexpected pragma syntax");
3777 }
3778 mPragmaStringCount += 2;
3779 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003780
Jack Palevichdc456462009-07-16 16:50:56 -07003781 void doLine() {
3782 // # line number { "filename "}
3783 next();
3784 if (tok != TOK_NUM) {
3785 error("Expected a line-number");
3786 } else {
3787 mLineNumber = tokc-1; // The end-of-line will increment it.
3788 }
3789 while(ch != EOF && ch != '\n') {
3790 inp();
3791 }
3792 }
3793
Jack Palevichac0e95e2009-05-29 13:53:44 -07003794 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003795 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003796 mErrorBuf.vprintf(fmt, ap);
3797 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003798 }
3799
Jack Palevich8b0624c2009-05-20 12:12:06 -07003800 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003801 if (tok != c) {
3802 error("'%c' expected", c);
3803 }
3804 next();
3805 }
3806
Jack Palevich86351982009-06-30 18:09:56 -07003807 bool accept(intptr_t c) {
3808 if (tok == c) {
3809 next();
3810 return true;
3811 }
3812 return false;
3813 }
3814
Jack Palevich40600de2009-07-01 15:32:35 -07003815 bool acceptStringLiteral() {
3816 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003817 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003818 // This while loop merges multiple adjacent string constants.
3819 while (tok == '"') {
3820 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003821 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003822 }
3823 if (ch != '"') {
3824 error("Unterminated string constant.");
3825 }
3826 inp();
3827 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003828 }
Jack Palevich40600de2009-07-01 15:32:35 -07003829 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003830 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003831 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003832 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003833
3834 return true;
3835 }
3836 return false;
3837 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003838
Jack Palevichb1544ca2009-07-16 15:09:20 -07003839 void linkGlobal(tokenid_t t, bool isFunction) {
3840 VariableInfo* pVI = VI(t);
3841 void* n = NULL;
3842 if (mpSymbolLookupFn) {
3843 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3844 }
3845 if (pVI->pType == NULL) {
3846 if (isFunction) {
3847 pVI->pType = mkpIntFn;
3848 } else {
3849 pVI->pType = mkpInt;
3850 }
3851 }
3852 pVI->pAddress = n;
3853 }
3854
Jack Palevich40600de2009-07-01 15:32:35 -07003855 /* Parse and evaluate a unary expression.
3856 * allowAssignment is true if '=' parsing wanted (quick hack)
3857 */
3858 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003859 tokenid_t t;
3860 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003861 t = 0;
3862 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3863 if (acceptStringLiteral()) {
3864 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003865 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003866 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003867 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003868 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003869 t = tok;
3870 next();
3871 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003872 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003873 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003874 // Align to 4-byte boundary
3875 glo = (char*) (((intptr_t) glo + 3) & -4);
3876 * (float*) glo = (float) ad;
3877 pGen->loadFloat((int) glo, mkpFloat);
3878 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003879 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003880 // Align to 8-byte boundary
3881 glo = (char*) (((intptr_t) glo + 7) & -8);
3882 * (double*) glo = ad;
3883 pGen->loadFloat((int) glo, mkpDouble);
3884 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003885 } else if (c == 2) {
3886 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003887 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003888 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003889 pGen->gUnaryCmp(a, mkpInt);
3890 else if (t == '+') {
3891 // ignore unary plus.
3892 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003893 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003894 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003895 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003896 // It's either a cast or an expression
3897 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3898 if (pCast) {
3899 skip(')');
3900 unary(false);
3901 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003902 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003903 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003904 skip(')');
3905 }
3906 } else if (t == '*') {
3907 /* This is a pointer dereference.
3908 */
3909 unary(false);
3910 Type* pR0Type = pGen->getR0Type();
3911 if (pR0Type->tag != TY_POINTER) {
3912 error("Expected a pointer type.");
3913 } else {
3914 if (pR0Type->pHead->tag == TY_FUNC) {
3915 t = 0;
3916 }
3917 if (accept('=')) {
3918 pGen->pushR0();
3919 expr();
3920 pGen->storeR0ToTOS(pR0Type);
3921 } else if (t) {
3922 pGen->loadR0FromR0(pR0Type);
3923 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003924 }
Jack Palevich3f226492009-07-02 14:46:19 -07003925 // Else we fall through to the function call below, with
3926 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003927 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003928 VariableInfo* pVI = VI(tok);
3929 pGen->leaR0((int) pVI->pAddress,
3930 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003931 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003932 } else if (t == EOF ) {
3933 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003934 } else if (t == ';') {
3935 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003936 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003937 // Don't have to do anything special here, the error
3938 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003939 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003940 if (!isDefined(t)) {
3941 mGlobals.add(t);
3942 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003943 }
Jack Palevich8df46192009-07-07 14:48:51 -07003944 VariableInfo* pVI = VI(t);
3945 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003946 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003947 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003948 linkGlobal(t, tok == '(');
3949 n = (intptr_t) pVI->pAddress;
3950 if (!n && tok != '(') {
3951 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003952 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003953 }
Jack Palevich40600de2009-07-01 15:32:35 -07003954 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003955 /* assignment */
3956 next();
3957 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003958 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003959 } else if (tok != '(') {
3960 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003961 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003962 linkGlobal(t, false);
3963 n = (intptr_t) pVI->pAddress;
3964 if (!n) {
3965 error("Undeclared variable %s\n", nameof(t));
3966 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003967 }
Jack Palevich8df46192009-07-07 14:48:51 -07003968 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003969 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003970 next();
3971 }
3972 }
3973 }
3974 }
3975
3976 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003977 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003978 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003979 VariableInfo* pVI = NULL;
3980 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003981 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003982 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003983 } else {
3984 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003985 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003986 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003987 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003988 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003989 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003990 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003991 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003992 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003993 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003994 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07003995 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07003996 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003997 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003998 Type* pTargetType;
3999 if (pArgList) {
4000 pTargetType = pArgList->pHead;
4001 pArgList = pArgList->pTail;
4002 } else {
4003 pTargetType = pGen->getR0Type();
4004 if (pTargetType->tag == TY_FLOAT) {
4005 pTargetType = mkpDouble;
4006 }
4007 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004008 if (pTargetType->tag == TY_VOID) {
4009 error("Can't pass void value for argument %d",
4010 argCount + 1);
4011 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004012 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004013 }
Jack Palevich95727a02009-07-06 12:07:15 -07004014 if (accept(',')) {
4015 // fine
4016 } else if ( tok != ')') {
4017 error("Expected ',' or ')'");
4018 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004019 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004020 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004021 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004022 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004023 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004024 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004025 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004026 if (!n) {
4027 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004028 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4029 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004030 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004031 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004032 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004033 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4034 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004035 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004036 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004037 }
4038 }
4039
Jack Palevich40600de2009-07-01 15:32:35 -07004040 /* Recursive descent parser for binary operations.
4041 */
4042 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004043 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004044 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004045 if (level-- == 1)
4046 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004047 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004048 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004049 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004050 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004051 t = tokc;
4052 next();
4053
Jack Palevich40600de2009-07-01 15:32:35 -07004054 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004055 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004056 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004057 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004058 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004059 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004060 // Check for syntax error.
4061 if (pGen->getR0Type() == NULL) {
4062 // We failed to parse a right-hand argument.
4063 // Push a dummy value so we don't fail
4064 pGen->li(0, mkpInt);
4065 }
Jack Palevich40600de2009-07-01 15:32:35 -07004066 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07004067 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004068 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004069 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004070 }
4071 }
4072 }
4073 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004074 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004075 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004076 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004077 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004078 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004079 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004080 }
4081 }
4082 }
4083
4084 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004085 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004086 }
4087
4088 int test_expr() {
4089 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004090 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004091 }
4092
Jack Palevicha6baa232009-06-12 11:25:59 -07004093 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004094 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004095
Jack Palevich95727a02009-07-06 12:07:15 -07004096 Type* pBaseType;
4097 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004098 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004099 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004100 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004101 next();
4102 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004103 a = test_expr();
4104 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004105 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004106 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004107 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004108 n = pGen->gjmp(0); /* jmp */
4109 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004110 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004111 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004112 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004113 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004114 }
Jack Palevich546b2242009-05-13 15:10:04 -07004115 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004116 t = tok;
4117 next();
4118 skip('(');
4119 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004120 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004121 a = test_expr();
4122 } else {
4123 if (tok != ';')
4124 expr();
4125 skip(';');
4126 n = codeBuf.getPC();
4127 a = 0;
4128 if (tok != ';')
4129 a = test_expr();
4130 skip(';');
4131 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004132 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004133 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004134 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004135 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004136 n = t + 4;
4137 }
4138 }
4139 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004140 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004141 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004142 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004143 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004144 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004145 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004146 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004147 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004148 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004149 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004150 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004151 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004152 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004153 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004154 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004155 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004156 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004157 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004158 if (pReturnType->tag == TY_VOID) {
4159 error("Must not return a value from a void function");
4160 } else {
4161 pGen->convertR0(pReturnType);
4162 }
4163 } else {
4164 if (pReturnType->tag != TY_VOID) {
4165 error("Must specify a value here");
4166 }
Jack Palevich8df46192009-07-07 14:48:51 -07004167 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004168 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004169 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004170 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004171 } else if (tok != ';')
4172 expr();
4173 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004174 }
4175 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004176
Jack Palevicha8f427f2009-07-13 18:40:08 -07004177 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004178 if (a == b) {
4179 return true;
4180 }
4181 if (a == NULL || b == NULL) {
4182 return false;
4183 }
4184 TypeTag at = a->tag;
4185 if (at != b->tag) {
4186 return false;
4187 }
4188 if (at == TY_POINTER) {
4189 return typeEqual(a->pHead, b->pHead);
4190 } else if (at == TY_FUNC || at == TY_PARAM) {
4191 return typeEqual(a->pHead, b->pHead)
4192 && typeEqual(a->pTail, b->pTail);
4193 }
4194 return true;
4195 }
4196
Jack Palevich86351982009-06-30 18:09:56 -07004197 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4198 assert(tag >= TY_INT && tag <= TY_PARAM);
4199 Type* pType = (Type*) arena.alloc(sizeof(Type));
4200 memset(pType, 0, sizeof(*pType));
4201 pType->tag = tag;
4202 pType->pHead = pHead;
4203 pType->pTail = pTail;
4204 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004205 }
4206
Jack Palevich3f226492009-07-02 14:46:19 -07004207 Type* createPtrType(Type* pType, Arena& arena) {
4208 return createType(TY_POINTER, pType, NULL, arena);
4209 }
4210
4211 /**
4212 * Try to print a type in declaration order
4213 */
Jack Palevich86351982009-06-30 18:09:56 -07004214 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004215 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004216 if (pType == NULL) {
4217 buffer.appendCStr("null");
4218 return;
4219 }
Jack Palevich3f226492009-07-02 14:46:19 -07004220 decodeTypeImp(buffer, pType);
4221 }
4222
4223 void decodeTypeImp(String& buffer, Type* pType) {
4224 decodeTypeImpPrefix(buffer, pType);
4225
Jack Palevich86351982009-06-30 18:09:56 -07004226 String temp;
4227 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004228 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004229 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004230 }
4231
4232 decodeTypeImpPostfix(buffer, pType);
4233 }
4234
4235 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4236 TypeTag tag = pType->tag;
4237
Jack Palevich37c54bd2009-07-14 18:35:36 -07004238 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004239 switch (tag) {
4240 case TY_INT:
4241 buffer.appendCStr("int");
4242 break;
4243 case TY_CHAR:
4244 buffer.appendCStr("char");
4245 break;
4246 case TY_VOID:
4247 buffer.appendCStr("void");
4248 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004249 case TY_FLOAT:
4250 buffer.appendCStr("float");
4251 break;
4252 case TY_DOUBLE:
4253 buffer.appendCStr("double");
4254 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004255 default:
4256 break;
4257 }
Jack Palevich86351982009-06-30 18:09:56 -07004258 buffer.append(' ');
4259 }
Jack Palevich3f226492009-07-02 14:46:19 -07004260
4261 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004262 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004263 break;
4264 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004265 break;
4266 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004267 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004268 case TY_FLOAT:
4269 break;
4270 case TY_DOUBLE:
4271 break;
Jack Palevich86351982009-06-30 18:09:56 -07004272 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004273 decodeTypeImpPrefix(buffer, pType->pHead);
4274 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4275 buffer.append('(');
4276 }
4277 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004278 break;
4279 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004280 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004281 break;
4282 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004283 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004284 break;
4285 default:
4286 String temp;
4287 temp.printf("Unknown tag %d", pType->tag);
4288 buffer.append(temp);
4289 break;
4290 }
Jack Palevich3f226492009-07-02 14:46:19 -07004291 }
4292
4293 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4294 TypeTag tag = pType->tag;
4295
4296 switch(tag) {
4297 case TY_POINTER:
4298 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4299 buffer.append(')');
4300 }
4301 decodeTypeImpPostfix(buffer, pType->pHead);
4302 break;
4303 case TY_FUNC:
4304 buffer.append('(');
4305 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4306 decodeTypeImp(buffer, pArg);
4307 if (pArg->pTail) {
4308 buffer.appendCStr(", ");
4309 }
4310 }
4311 buffer.append(')');
4312 break;
4313 default:
4314 break;
Jack Palevich86351982009-06-30 18:09:56 -07004315 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004316 }
4317
Jack Palevich86351982009-06-30 18:09:56 -07004318 void printType(Type* pType) {
4319 String buffer;
4320 decodeType(buffer, pType);
4321 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004322 }
4323
Jack Palevich86351982009-06-30 18:09:56 -07004324 Type* acceptPrimitiveType(Arena& arena) {
4325 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004326 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004327 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004328 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004329 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004330 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004331 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004332 } else if (tok == TOK_FLOAT) {
4333 pType = mkpFloat;
4334 } else if (tok == TOK_DOUBLE) {
4335 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004336 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004337 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004338 }
4339 next();
Jack Palevich86351982009-06-30 18:09:56 -07004340 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004341 }
4342
Jack Palevich3f226492009-07-02 14:46:19 -07004343 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4344 Arena& arena) {
4345 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004346 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004347 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004348 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004349 if (declName) {
4350 // Clone the parent type so we can set a unique ID
4351 pType = createType(pType->tag, pType->pHead,
4352 pType->pTail, arena);
4353
Jack Palevich86351982009-06-30 18:09:56 -07004354 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004355 }
Jack Palevich3f226492009-07-02 14:46:19 -07004356 // fprintf(stderr, "Parsed a declaration: ");
4357 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004358 if (reportFailure) {
4359 return NULL;
4360 }
Jack Palevich86351982009-06-30 18:09:56 -07004361 return pType;
4362 }
4363
Jack Palevich3f226492009-07-02 14:46:19 -07004364 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4365 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004366 if (! pType) {
4367 error("Expected a declaration");
4368 }
4369 return pType;
4370 }
4371
Jack Palevich3f226492009-07-02 14:46:19 -07004372 /* Used for accepting types that appear in casts */
4373 Type* acceptCastTypeDeclaration(Arena& arena) {
4374 Type* pType = acceptPrimitiveType(arena);
4375 if (pType) {
4376 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004377 }
Jack Palevich86351982009-06-30 18:09:56 -07004378 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004379 }
4380
Jack Palevich3f226492009-07-02 14:46:19 -07004381 Type* expectCastTypeDeclaration(Arena& arena) {
4382 Type* pType = acceptCastTypeDeclaration(arena);
4383 if (! pType) {
4384 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004385 }
Jack Palevich3f226492009-07-02 14:46:19 -07004386 return pType;
4387 }
4388
4389 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004390 bool nameAllowed, bool nameRequired, Arena& arena,
4391 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004392 int ptrCounter = 0;
4393 while (accept('*')) {
4394 ptrCounter++;
4395 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004396 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena,
4397 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004398 while (ptrCounter-- > 0) {
4399 pType = createType(TY_POINTER, pType, NULL, arena);
4400 }
4401 return pType;
4402 }
4403
4404 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004405 bool nameAllowed, bool nameRequired, Arena& arena,
4406 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004407 // direct-dcl :
4408 // name
4409 // (dcl)
4410 // direct-dcl()
4411 // direct-dcl[]
4412 Type* pNewHead = NULL;
4413 if (accept('(')) {
4414 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004415 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004416 skip(')');
4417 } else if ((declName = acceptSymbol()) != 0) {
4418 if (nameAllowed == false && declName) {
4419 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004420 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004421 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004422 } else if (nameRequired && ! declName) {
4423 String temp;
4424 decodeToken(temp, tok, true);
4425 error("Expected name. Got %s", temp.getUnwrapped());
4426 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004427 }
4428 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004429 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004430 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004431 pType = createType(TY_FUNC, pType, pTail, arena);
4432 skip(')');
4433 }
Jack Palevich3f226492009-07-02 14:46:19 -07004434
4435 if (pNewHead) {
4436 Type* pA = pNewHead;
4437 while (pA->pHead) {
4438 pA = pA->pHead;
4439 }
4440 pA->pHead = pType;
4441 pType = pNewHead;
4442 }
Jack Palevich86351982009-06-30 18:09:56 -07004443 return pType;
4444 }
4445
Jack Palevich3f226492009-07-02 14:46:19 -07004446 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004447 Type* pHead = NULL;
4448 Type* pTail = NULL;
4449 for(;;) {
4450 Type* pBaseArg = acceptPrimitiveType(arena);
4451 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004452 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4453 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004454 if (pArg) {
4455 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4456 if (!pHead) {
4457 pHead = pParam;
4458 pTail = pParam;
4459 } else {
4460 pTail->pTail = pParam;
4461 pTail = pParam;
4462 }
4463 }
4464 }
4465 if (! accept(',')) {
4466 break;
4467 }
4468 }
4469 return pHead;
4470 }
4471
4472 Type* expectPrimitiveType(Arena& arena) {
4473 Type* pType = acceptPrimitiveType(arena);
4474 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004475 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004476 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004477 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004478 }
Jack Palevich86351982009-06-30 18:09:56 -07004479 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004480 }
4481
Jack Palevich86351982009-06-30 18:09:56 -07004482 void addGlobalSymbol(Type* pDecl) {
4483 tokenid_t t = pDecl->id;
4484 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004485 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004486 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004487 }
Jack Palevich86351982009-06-30 18:09:56 -07004488 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004489 }
4490
Jack Palevich86351982009-06-30 18:09:56 -07004491 void reportDuplicate(tokenid_t t) {
4492 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004493 }
4494
Jack Palevich86351982009-06-30 18:09:56 -07004495 void addLocalSymbol(Type* pDecl) {
4496 tokenid_t t = pDecl->id;
4497 if (mLocals.isDefinedAtCurrentLevel(t)) {
4498 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004499 }
Jack Palevich86351982009-06-30 18:09:56 -07004500 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004501 }
4502
Jack Palevich95727a02009-07-06 12:07:15 -07004503 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004504 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004505
Jack Palevich95727a02009-07-06 12:07:15 -07004506 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004507 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004508 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4509 if (!pDecl) {
4510 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004511 }
Jack Palevich86351982009-06-30 18:09:56 -07004512 int variableAddress = 0;
4513 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004514 size_t alignment = pGen->alignmentOf(pDecl);
4515 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004516 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004517 variableAddress = -loc;
4518 VI(pDecl->id)->pAddress = (void*) variableAddress;
4519 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004520 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004521 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004522 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004523 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004524 if (tok == ',')
4525 next();
4526 }
4527 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004528 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004529 }
4530 }
4531
Jack Palevichf1728be2009-06-12 13:53:51 -07004532 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004533 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004534 }
4535
Jack Palevich37c54bd2009-07-14 18:35:36 -07004536 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004537 if (token == EOF ) {
4538 buffer.printf("EOF");
4539 } else if (token == TOK_NUM) {
4540 buffer.printf("numeric constant");
4541 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004542 if (token < 32) {
4543 buffer.printf("'\\x%02x'", token);
4544 } else {
4545 buffer.printf("'%c'", token);
4546 }
Jack Palevich569f1352009-06-29 14:29:08 -07004547 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004548 if (quote) {
4549 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4550 buffer.printf("keyword \"%s\"", nameof(token));
4551 } else {
4552 buffer.printf("symbol \"%s\"", nameof(token));
4553 }
4554 } else {
4555 buffer.printf("%s", nameof(token));
4556 }
Jack Palevich569f1352009-06-29 14:29:08 -07004557 }
4558 }
4559
Jack Palevich40600de2009-07-01 15:32:35 -07004560 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004561 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004562 if (!result) {
4563 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004564 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004565 error("Expected symbol. Got %s", temp.getUnwrapped());
4566 }
4567 return result;
4568 }
4569
Jack Palevich86351982009-06-30 18:09:56 -07004570 tokenid_t acceptSymbol() {
4571 tokenid_t result = 0;
4572 if (tok >= TOK_SYMBOL) {
4573 result = tok;
4574 next();
Jack Palevich86351982009-06-30 18:09:56 -07004575 }
4576 return result;
4577 }
4578
Jack Palevichb7c81e92009-06-04 19:56:13 -07004579 void globalDeclarations() {
4580 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004581 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4582 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004583 break;
4584 }
Jack Palevich86351982009-06-30 18:09:56 -07004585 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4586 if (!pDecl) {
4587 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004588 }
Jack Palevich86351982009-06-30 18:09:56 -07004589 if (! isDefined(pDecl->id)) {
4590 addGlobalSymbol(pDecl);
4591 }
4592 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004593 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004594 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004595 }
Jack Palevich86351982009-06-30 18:09:56 -07004596 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004597 // it's a variable declaration
4598 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004599 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004600 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004601 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004602 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004603 }
Jack Palevich86351982009-06-30 18:09:56 -07004604 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004605 if (tok == TOK_NUM) {
4606 if (name) {
4607 * (int*) name->pAddress = tokc;
4608 }
4609 next();
4610 } else {
4611 error("Expected an integer constant");
4612 }
4613 }
Jack Palevich86351982009-06-30 18:09:56 -07004614 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004615 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004616 }
Jack Palevich86351982009-06-30 18:09:56 -07004617 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4618 if (!pDecl) {
4619 break;
4620 }
4621 if (! isDefined(pDecl->id)) {
4622 addGlobalSymbol(pDecl);
4623 }
4624 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004625 }
4626 skip(';');
4627 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004628 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004629 if (accept(';')) {
4630 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004631 } else if (tok != '{') {
4632 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004633 } else {
4634 if (name) {
4635 /* patch forward references (XXX: does not work for function
4636 pointers) */
4637 pGen->gsym((int) name->pForward);
4638 /* put function address */
4639 name->pAddress = (void*) codeBuf.getPC();
4640 }
4641 // Calculate stack offsets for parameters
4642 mLocals.pushLevel();
4643 intptr_t a = 8;
4644 int argCount = 0;
4645 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4646 Type* pArg = pP->pHead;
4647 addLocalSymbol(pArg);
4648 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004649 size_t alignment = pGen->alignmentOf(pArg);
4650 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004651 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004652 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004653 argCount++;
4654 }
4655 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004656 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004657 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004658 block(0, true);
4659 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004660 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004661 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004662 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004663 }
4664 }
4665 }
4666
Jack Palevich9cbd2262009-07-08 16:48:41 -07004667 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4668 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4669 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004670 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004671 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004672 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004673 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004674 char* result = (char*) base;
4675 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004676 return result;
4677 }
4678
Jack Palevich21a15a22009-05-11 14:49:29 -07004679 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004680 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004681 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004682 pGlobalBase = 0;
4683 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004684 if (pGen) {
4685 delete pGen;
4686 pGen = 0;
4687 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004688 if (file) {
4689 delete file;
4690 file = 0;
4691 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004692 }
4693
Jack Palevich8c246a92009-07-14 21:14:10 -07004694 // One-time initialization, when class is constructed.
4695 void init() {
4696 mpSymbolLookupFn = 0;
4697 mpSymbolLookupContext = 0;
4698 }
4699
Jack Palevich21a15a22009-05-11 14:49:29 -07004700 void clear() {
4701 tok = 0;
4702 tokc = 0;
4703 tokl = 0;
4704 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004705 rsym = 0;
4706 loc = 0;
4707 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004708 dptr = 0;
4709 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004710 file = 0;
4711 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004712 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004713 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004714 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004715 mLineNumber = 1;
4716 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004717 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004718
Jack Palevich22305132009-05-13 10:58:45 -07004719 void setArchitecture(const char* architecture) {
4720 delete pGen;
4721 pGen = 0;
4722
4723 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004724#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004725 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004726 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004727 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004728#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004729#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004730 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004731 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004732 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004733#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004734 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004735 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004736 }
4737 }
4738
4739 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004740#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004741 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004742#elif defined(DEFAULT_X86_CODEGEN)
4743 pGen = new X86CodeGenerator();
4744#endif
4745 }
4746 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004747 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004748 } else {
4749 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004750 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004751 }
4752 }
4753
Jack Palevich77ae76e2009-05-10 19:59:24 -07004754public:
Jack Palevich22305132009-05-13 10:58:45 -07004755 struct args {
4756 args() {
4757 architecture = 0;
4758 }
4759 const char* architecture;
4760 };
4761
Jack Paleviche7b59062009-05-19 17:12:17 -07004762 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004763 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004764 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004765 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004766
Jack Paleviche7b59062009-05-19 17:12:17 -07004767 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004768 cleanup();
4769 }
4770
Jack Palevich8c246a92009-07-14 21:14:10 -07004771 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4772 mpSymbolLookupFn = pFn;
4773 mpSymbolLookupContext = pContext;
4774 }
4775
Jack Palevich1cdef202009-05-22 12:06:27 -07004776 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004777 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004778
Jack Palevicha8f427f2009-07-13 18:40:08 -07004779 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004780 cleanup();
4781 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004782 mTokenTable.setArena(&mGlobalArena);
4783 mGlobals.setArena(&mGlobalArena);
4784 mGlobals.setTokenTable(&mTokenTable);
4785 mLocals.setArena(&mLocalArena);
4786 mLocals.setTokenTable(&mTokenTable);
4787
4788 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004789 codeBuf.init(ALLOC_SIZE);
4790 setArchitecture(NULL);
4791 if (!pGen) {
4792 return -1;
4793 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004794#ifdef PROVIDE_TRACE_CODEGEN
4795 pGen = new TraceCodeGenerator(pGen);
4796#endif
4797 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004798 pGen->init(&codeBuf);
4799 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004800 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4801 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004802 inp();
4803 next();
4804 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004805 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004806 result = pGen->finishCompile();
4807 if (result == 0) {
4808 if (mErrorBuf.len()) {
4809 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004810 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004811 }
Jack Palevichce105a92009-07-16 14:30:33 -07004812 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004813 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004814 }
4815
Jack Palevich86351982009-06-30 18:09:56 -07004816 void createPrimitiveTypes() {
4817 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4818 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4819 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004820 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4821 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004822 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004823 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4824 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004825 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4826 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004827 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004828 }
4829
Jack Palevicha6baa232009-06-12 11:25:59 -07004830 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004831 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004832 }
4833
Jack Palevich569f1352009-06-29 14:29:08 -07004834 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004835 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004836 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004837 }
4838
Jack Palevich569f1352009-06-29 14:29:08 -07004839 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004840 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004841 error("Undefined forward reference: %s",
4842 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004843 }
4844 return true;
4845 }
4846
Jack Palevich21a15a22009-05-11 14:49:29 -07004847 int dump(FILE* out) {
4848 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4849 return 0;
4850 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004851
Jack Palevicha6535612009-05-13 16:24:17 -07004852 int disassemble(FILE* out) {
4853 return pGen->disassemble(out);
4854 }
4855
Jack Palevich1cdef202009-05-22 12:06:27 -07004856 /* Look through the symbol table to find a symbol.
4857 * If found, return its value.
4858 */
4859 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004860 if (mCompileResult == 0) {
4861 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4862 VariableInfo* pVariableInfo = VI(tok);
4863 if (pVariableInfo) {
4864 return pVariableInfo->pAddress;
4865 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004866 }
4867 return NULL;
4868 }
4869
Jack Palevicheedf9d22009-06-04 16:23:40 -07004870 void getPragmas(ACCsizei* actualStringCount,
4871 ACCsizei maxStringCount, ACCchar** strings) {
4872 int stringCount = mPragmaStringCount;
4873 if (actualStringCount) {
4874 *actualStringCount = stringCount;
4875 }
4876 if (stringCount > maxStringCount) {
4877 stringCount = maxStringCount;
4878 }
4879 if (strings) {
4880 char* pPragmas = mPragmas.getUnwrapped();
4881 while (stringCount-- > 0) {
4882 *strings++ = pPragmas;
4883 pPragmas += strlen(pPragmas) + 1;
4884 }
4885 }
4886 }
4887
Jack Palevichac0e95e2009-05-29 13:53:44 -07004888 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004889 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004890 }
4891
Jack Palevich77ae76e2009-05-10 19:59:24 -07004892};
4893
Jack Paleviche7b59062009-05-19 17:12:17 -07004894const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004895 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4896
Jack Paleviche7b59062009-05-19 17:12:17 -07004897const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004898 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4899 5, 5, /* ==, != */
4900 9, 10, /* &&, || */
4901 6, 7, 8, /* & ^ | */
4902 2, 2 /* ~ ! */
4903 };
4904
Jack Palevich8b0624c2009-05-20 12:12:06 -07004905#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004906FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004907#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004908
Jack Palevich8b0624c2009-05-20 12:12:06 -07004909#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004910const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004911 0x1, // ++
4912 0xff, // --
4913 0xc1af0f, // *
4914 0xf9f79991, // /
4915 0xf9f79991, // % (With manual assist to swap results)
4916 0xc801, // +
4917 0xd8f7c829, // -
4918 0xe0d391, // <<
4919 0xf8d391, // >>
4920 0xe, // <=
4921 0xd, // >=
4922 0xc, // <
4923 0xf, // >
4924 0x4, // ==
4925 0x5, // !=
4926 0x0, // &&
4927 0x1, // ||
4928 0xc821, // &
4929 0xc831, // ^
4930 0xc809, // |
4931 0xd0f7, // ~
4932 0x4 // !
4933};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004934#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004935
Jack Palevich1cdef202009-05-22 12:06:27 -07004936struct ACCscript {
4937 ACCscript() {
4938 text = 0;
4939 textLength = 0;
4940 accError = ACC_NO_ERROR;
4941 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004942
Jack Palevich1cdef202009-05-22 12:06:27 -07004943 ~ACCscript() {
4944 delete text;
4945 }
Jack Palevich546b2242009-05-13 15:10:04 -07004946
Jack Palevich8c246a92009-07-14 21:14:10 -07004947 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4948 compiler.registerSymbolCallback(pFn, pContext);
4949 }
4950
Jack Palevich1cdef202009-05-22 12:06:27 -07004951 void setError(ACCenum error) {
4952 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4953 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004954 }
4955 }
4956
Jack Palevich1cdef202009-05-22 12:06:27 -07004957 ACCenum getError() {
4958 ACCenum result = accError;
4959 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004960 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004961 }
4962
Jack Palevich1cdef202009-05-22 12:06:27 -07004963 Compiler compiler;
4964 char* text;
4965 int textLength;
4966 ACCenum accError;
4967};
4968
4969
4970extern "C"
4971ACCscript* accCreateScript() {
4972 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004973}
Jack Palevich1cdef202009-05-22 12:06:27 -07004974
4975extern "C"
4976ACCenum accGetError( ACCscript* script ) {
4977 return script->getError();
4978}
4979
4980extern "C"
4981void accDeleteScript(ACCscript* script) {
4982 delete script;
4983}
4984
4985extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004986void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4987 ACCvoid* pContext) {
4988 script->registerSymbolCallback(pFn, pContext);
4989}
4990
4991extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07004992void accScriptSource(ACCscript* script,
4993 ACCsizei count,
4994 const ACCchar ** string,
4995 const ACCint * length) {
4996 int totalLength = 0;
4997 for(int i = 0; i < count; i++) {
4998 int len = -1;
4999 const ACCchar* s = string[i];
5000 if (length) {
5001 len = length[i];
5002 }
5003 if (len < 0) {
5004 len = strlen(s);
5005 }
5006 totalLength += len;
5007 }
5008 delete script->text;
5009 char* text = new char[totalLength + 1];
5010 script->text = text;
5011 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005012 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005013 for(int i = 0; i < count; i++) {
5014 int len = -1;
5015 const ACCchar* s = string[i];
5016 if (length) {
5017 len = length[i];
5018 }
5019 if (len < 0) {
5020 len = strlen(s);
5021 }
Jack Palevich09555c72009-05-27 12:25:55 -07005022 memcpy(dest, s, len);
5023 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005024 }
5025 text[totalLength] = '\0';
5026}
5027
5028extern "C"
5029void accCompileScript(ACCscript* script) {
5030 int result = script->compiler.compile(script->text, script->textLength);
5031 if (result) {
5032 script->setError(ACC_INVALID_OPERATION);
5033 }
5034}
5035
5036extern "C"
5037void accGetScriptiv(ACCscript* script,
5038 ACCenum pname,
5039 ACCint * params) {
5040 switch (pname) {
5041 case ACC_INFO_LOG_LENGTH:
5042 *params = 0;
5043 break;
5044 }
5045}
5046
5047extern "C"
5048void accGetScriptInfoLog(ACCscript* script,
5049 ACCsizei maxLength,
5050 ACCsizei * length,
5051 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005052 char* message = script->compiler.getErrorMessage();
5053 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005054 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005055 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005056 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005057 if (infoLog && maxLength > 0) {
5058 int trimmedLength = maxLength < messageLength ?
5059 maxLength : messageLength;
5060 memcpy(infoLog, message, trimmedLength);
5061 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005062 }
5063}
5064
5065extern "C"
5066void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5067 ACCvoid ** address) {
5068 void* value = script->compiler.lookup(name);
5069 if (value) {
5070 *address = value;
5071 } else {
5072 script->setError(ACC_INVALID_VALUE);
5073 }
5074}
5075
Jack Palevicheedf9d22009-06-04 16:23:40 -07005076extern "C"
5077void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5078 ACCsizei maxStringCount, ACCchar** strings){
5079 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5080}
5081
-b master422972c2009-06-17 19:13:52 -07005082extern "C"
5083void accDisassemble(ACCscript* script) {
5084 script->compiler.disassemble(stderr);
5085}
5086
Jack Palevicheedf9d22009-06-04 16:23:40 -07005087
Jack Palevich1cdef202009-05-22 12:06:27 -07005088} // namespace acc
5089