blob: d9be2fdbcf0414158ed887ce5a7ffcf925cef9e4 [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
Jack Palevich9f51a262009-07-29 16:22:26 -070051#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 Palevich58c30ee2009-07-17 16:35:23 -0700285 /* Give the code generator some utility types so it can
286 * use its own types as needed for the results of some
287 * operations like gcmp.
288 */
289
Jack Palevicha8f427f2009-07-13 18:40:08 -0700290 void setTypes(Type* pInt) {
291 mkpInt = pInt;
292 }
293
Jack Palevich1cdef202009-05-22 12:06:27 -0700294 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700295 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700296 * Save the old value of the FP.
297 * Set the new value of the FP.
298 * Convert from the native platform calling convention to
299 * our stack-based calling convention. This may require
300 * pushing arguments from registers to the stack.
301 * Allocate "N" bytes of stack space. N isn't known yet, so
302 * just emit the instructions for adjusting the stack, and return
303 * the address to patch up. The patching will be done in
304 * functionExit().
305 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700306 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700307 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700308
Jack Palevich1cdef202009-05-22 12:06:27 -0700309 /* Emit a function epilog.
310 * Restore the old SP and FP register values.
311 * Return to the calling function.
312 * argCount - the number of arguments to the function.
313 * localVariableAddress - returned from functionEntry()
314 * localVariableSize - the size in bytes of the local variables.
315 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700316 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700318
Jack Palevich1cdef202009-05-22 12:06:27 -0700319 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700320 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700321
Jack Palevich1a539db2009-07-08 13:04:41 -0700322 /* Load floating point value from global address. */
323 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700324
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 /* Jump to a target, and return the address of the word that
326 * holds the target data, in case it needs to be fixed up later.
327 */
Jack Palevich22305132009-05-13 10:58:45 -0700328 virtual int gjmp(int t) = 0;
329
Jack Palevich1cdef202009-05-22 12:06:27 -0700330 /* Test R0 and jump to a target if the test succeeds.
331 * l = 0: je, l == 1: jne
332 * Return the address of the word that holds the targed data, in
333 * case it needs to be fixed up later.
334 */
Jack Palevich22305132009-05-13 10:58:45 -0700335 virtual int gtst(bool l, int t) = 0;
336
Jack Palevich9eed7a22009-07-06 17:24:34 -0700337 /* Compare TOS against R0, and store the boolean result in R0.
338 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 * op specifies the comparison.
340 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700341 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700342
Jack Palevich9eed7a22009-07-06 17:24:34 -0700343 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 */
Jack Palevich546b2242009-05-13 15:10:04 -0700347 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700348
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 /* Compare 0 against R0, and store the boolean result in R0.
350 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700352 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353
354 /* Perform the arithmetic op specified by op. 0 is the
355 * left argument, R0 is the right argument.
356 */
357 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700359 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 */
361 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700363 /* Turn R0, TOS into R0 TOS R0 */
364
365 virtual void over() = 0;
366
367 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700368 */
369 virtual void popR0() = 0;
370
Jack Palevich9eed7a22009-07-06 17:24:34 -0700371 /* Store R0 to the address stored in TOS.
372 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700373 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700374 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700378 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700379
Jack Palevich1cdef202009-05-22 12:06:27 -0700380 /* Load the absolute address of a variable to R0.
381 * If ea <= LOCAL, then this is a local variable, or an
382 * argument, addressed relative to FP.
383 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700384 *
Jack Palevich1cdef202009-05-22 12:06:27 -0700385 */
Jack Palevich8df46192009-07-07 14:48:51 -0700386 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700387
Jack Palevich9f51a262009-07-29 16:22:26 -0700388 /* Load the pc-relative address of a forward-referenced variable to R0.
389 * Return the address of the 4-byte constant so that it can be filled
390 * in later.
391 */
392 virtual int leaForward(int ea, Type* pPointerType) = 0;
393
Jack Palevich8df46192009-07-07 14:48:51 -0700394 /**
395 * Convert R0 to the given type.
396 */
397 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700398
Jack Palevich1cdef202009-05-22 12:06:27 -0700399 /* Emit code to adjust the stack for a function call. Return the
400 * label for the address of the instruction that adjusts the
401 * stack size. This will be passed as argument "a" to
402 * endFunctionCallArguments.
403 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700404 virtual int beginFunctionCallArguments() = 0;
405
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700407 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700408 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700409 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700410
Jack Palevich1cdef202009-05-22 12:06:27 -0700411 /* Patch the function call preamble.
412 * a is the address returned from beginFunctionCallArguments
413 * l is the number of bytes the arguments took on the stack.
414 * Typically you would also emit code to convert the argument
415 * list into whatever the native function calling convention is.
416 * On ARM for example you would pop the first 5 arguments into
417 * R0..R4
418 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700419 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700420
Jack Palevich1cdef202009-05-22 12:06:27 -0700421 /* Emit a call to an unknown function. The argument "symbol" needs to
422 * be stored in the location where the address should go. It forms
423 * a chain. The address will be patched later.
424 * Return the address of the word that has to be patched.
425 */
Jack Palevich8df46192009-07-07 14:48:51 -0700426 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevich1cdef202009-05-22 12:06:27 -0700428 /* Call a function pointer. L is the number of bytes the arguments
429 * take on the stack. The address of the function is stored at
430 * location SP + l.
431 */
Jack Palevich8df46192009-07-07 14:48:51 -0700432 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700433
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 /* Adjust SP after returning from a function call. l is the
435 * number of bytes of arguments stored on the stack. isIndirect
436 * is true if this was an indirect call. (In which case the
437 * address of the function is stored at location SP + l.)
438 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700439 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /* Print a disassembly of the assembled code to out. Return
442 * non-zero if there is an error.
443 */
Jack Palevicha6535612009-05-13 16:24:17 -0700444 virtual int disassemble(FILE* out) = 0;
445
Jack Palevich1cdef202009-05-22 12:06:27 -0700446 /* Generate a symbol at the current PC. t is the head of a
447 * linked list of addresses to patch.
448 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700449 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700450
Jack Palevich9f51a262009-07-29 16:22:26 -0700451 /* Resolve a forward reference function at the current PC.
452 * t is the head of a
453 * linked list of addresses to patch.
454 * (Like gsym, but using absolute address, not PC relative address.)
455 */
456 virtual void resolveForward(int t) = 0;
457
Jack Palevich1cdef202009-05-22 12:06:27 -0700458 /*
459 * Do any cleanup work required at the end of a compile.
460 * For example, an instruction cache might need to be
461 * invalidated.
462 * Return non-zero if there is an error.
463 */
464 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700465
Jack Palevicha6535612009-05-13 16:24:17 -0700466 /**
467 * Adjust relative branches by this amount.
468 */
469 virtual int jumpOffset() = 0;
470
Jack Palevich9eed7a22009-07-06 17:24:34 -0700471 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700472 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700473 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700474 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700475
476 /**
477 * Array element alignment (in bytes) for this type of data.
478 */
479 virtual size_t sizeOf(Type* type) = 0;
480
Jack Palevich9cbd2262009-07-08 16:48:41 -0700481 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700482 * Stack alignment of this type of data
483 */
484 virtual size_t stackAlignmentOf(Type* pType) = 0;
485
486 /**
487 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700488 */
489 virtual size_t stackSizeOf(Type* pType) = 0;
490
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700491 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700492 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700493 }
494
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700495 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700496 return mExpressionStack.back().et;
497 }
498
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700499 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700500 mExpressionStack.back().et = et;
501 }
502
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700503 virtual size_t getExpressionStackDepth() {
504 return mExpressionStack.size();
505 }
506
Jack Palevich21a15a22009-05-11 14:49:29 -0700507 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700508 /*
509 * Output a byte. Handles all values, 0..ff.
510 */
511 void ob(int n) {
512 pCodeBuf->ob(n);
513 }
514
Jack Palevich8b0624c2009-05-20 12:12:06 -0700515 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700516 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700517 }
518
Jack Palevich8b0624c2009-05-20 12:12:06 -0700519 intptr_t getBase() {
520 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700521 }
522
Jack Palevich8b0624c2009-05-20 12:12:06 -0700523 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700524 return pCodeBuf->getPC();
525 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700526
527 intptr_t getSize() {
528 return pCodeBuf->getSize();
529 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700530
531 void error(const char* fmt,...) {
532 va_list ap;
533 va_start(ap, fmt);
534 mErrorSink->verror(fmt, ap);
535 va_end(ap);
536 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700537
538 void assert(bool test) {
539 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700540 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700541 error("code generator assertion failed.");
542 }
543 }
Jack Palevich8df46192009-07-07 14:48:51 -0700544
545 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700546 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700547 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700548 }
549
Jack Palevich8df46192009-07-07 14:48:51 -0700550 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700551 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700552 }
553
554 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700555 if (mExpressionStack.size()) {
556 mExpressionStack.push_back(mExpressionStack.back());
557 } else {
558 mExpressionStack.push_back(ExpressionValue());
559 }
560
Jack Palevich8df46192009-07-07 14:48:51 -0700561 }
562
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700563 void overType() {
564 size_t size = mExpressionStack.size();
565 if (size >= 2) {
566 mExpressionStack.push_back(mExpressionStack.back());
567 mExpressionStack[size-1] = mExpressionStack[size-2];
568 mExpressionStack[size-2] = mExpressionStack[size];
569 }
570 }
571
Jack Palevich8df46192009-07-07 14:48:51 -0700572 void popType() {
573 mExpressionStack.pop_back();
574 }
575
576 bool bitsSame(Type* pA, Type* pB) {
577 return collapseType(pA->tag) == collapseType(pB->tag);
578 }
579
580 TypeTag collapseType(TypeTag tag) {
581 static const TypeTag collapsedTag[] = {
582 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
583 TY_VOID, TY_VOID};
584 return collapsedTag[tag];
585 }
586
Jack Palevich1a539db2009-07-08 13:04:41 -0700587 TypeTag collapseTypeR0() {
588 return collapseType(getR0Type()->tag);
589 }
590
591 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700592 return isFloatTag(pType->tag);
593 }
594
595 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700596 return tag == TY_FLOAT || tag == TY_DOUBLE;
597 }
598
Jack Palevicha8f427f2009-07-13 18:40:08 -0700599 Type* mkpInt;
600
Jack Palevich21a15a22009-05-11 14:49:29 -0700601 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700602 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700603 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700604 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700605 };
606
Jack Paleviche7b59062009-05-19 17:12:17 -0700607#ifdef PROVIDE_ARM_CODEGEN
608
Jack Palevich22305132009-05-13 10:58:45 -0700609 class ARMCodeGenerator : public CodeGenerator {
610 public:
611 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700612
Jack Palevich22305132009-05-13 10:58:45 -0700613 virtual ~ARMCodeGenerator() {}
614
615 /* returns address to patch with local variable size
616 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700617 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700618 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700619 // sp -> arg4 arg5 ...
620 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700621 int regArgCount = calcRegArgCount(pDecl);
622 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700623 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700624 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700625 }
626 // sp -> arg0 arg1 ...
627 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700628 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700629 // sp, fp -> oldfp, retadr, arg0 arg1 ....
630 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700631 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700632 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700633 // We don't know how many local variables we are going to use,
634 // but we will round the allocation up to a multiple of
635 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700636 }
637
Jack Palevichb7718b92009-07-09 22:00:24 -0700638 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700639 // Round local variable size up to a multiple of stack alignment
640 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
641 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700642 // Patch local variable allocation code:
643 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700644 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700645 }
Jack Palevich69796b62009-05-14 15:42:26 -0700646 *(char*) (localVariableAddress) = localVariableSize;
647
648 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
649 o4(0xE1A0E00B); // mov lr, fp
650 o4(0xE59BB000); // ldr fp, [fp]
651 o4(0xE28ED004); // add sp, lr, #4
652 // sp -> retadr, arg0, ...
653 o4(0xE8BD4000); // ldmfd sp!, {lr}
654 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700655
656 // We store the PC into the lr so we can adjust the sp before
657 // returning. We need to pull off the registers we pushed
658 // earlier. We don't need to actually store them anywhere,
659 // just adjust the stack.
660 int regArgCount = calcRegArgCount(pDecl);
661 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700662 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
663 }
664 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700665 }
666
667 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700668 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700669 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700670 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700671 }
672
Jack Palevich1a539db2009-07-08 13:04:41 -0700673 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700674 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700675 // Global, absolute address
676 o4(0xE59F0000); // ldr r0, .L1
677 o4(0xEA000000); // b .L99
678 o4(address); // .L1: .word ea
679 // .L99:
680
681 switch (pType->tag) {
682 case TY_FLOAT:
683 o4(0xE5900000); // ldr r0, [r0]
684 break;
685 case TY_DOUBLE:
686 o4(0xE1C000D0); // ldrd r0, [r0]
687 break;
688 default:
689 assert(false);
690 break;
691 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700692 }
693
Jack Palevich22305132009-05-13 10:58:45 -0700694 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700695 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700696 }
697
698 /* l = 0: je, l == 1: jne */
699 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700700 Type* pR0Type = getR0Type();
701 TypeTag tagR0 = pR0Type->tag;
702 switch(tagR0) {
703 case TY_FLOAT:
704 callRuntime((void*) runtime_is_non_zero_f);
705 break;
706 case TY_DOUBLE:
707 callRuntime((void*) runtime_is_non_zero_d);
708 break;
709 default:
710 break;
711 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700712 o4(0xE3500000); // cmp r0,#0
713 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
714 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700715 }
716
Jack Palevich58c30ee2009-07-17 16:35:23 -0700717 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700718 Type* pR0Type = getR0Type();
719 Type* pTOSType = getTOSType();
720 TypeTag tagR0 = collapseType(pR0Type->tag);
721 TypeTag tagTOS = collapseType(pTOSType->tag);
722 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700723 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700724 o4(0xE1510000); // cmp r1, r1
725 switch(op) {
726 case OP_EQUALS:
727 o4(0x03A00001); // moveq r0,#1
728 o4(0x13A00000); // movne r0,#0
729 break;
730 case OP_NOT_EQUALS:
731 o4(0x03A00000); // moveq r0,#0
732 o4(0x13A00001); // movne r0,#1
733 break;
734 case OP_LESS_EQUAL:
735 o4(0xD3A00001); // movle r0,#1
736 o4(0xC3A00000); // movgt r0,#0
737 break;
738 case OP_GREATER:
739 o4(0xD3A00000); // movle r0,#0
740 o4(0xC3A00001); // movgt r0,#1
741 break;
742 case OP_GREATER_EQUAL:
743 o4(0xA3A00001); // movge r0,#1
744 o4(0xB3A00000); // movlt r0,#0
745 break;
746 case OP_LESS:
747 o4(0xA3A00000); // movge r0,#0
748 o4(0xB3A00001); // movlt r0,#1
749 break;
750 default:
751 error("Unknown comparison op %d", op);
752 break;
753 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700754 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
755 setupDoubleArgs();
756 switch(op) {
757 case OP_EQUALS:
758 callRuntime((void*) runtime_cmp_eq_dd);
759 break;
760 case OP_NOT_EQUALS:
761 callRuntime((void*) runtime_cmp_ne_dd);
762 break;
763 case OP_LESS_EQUAL:
764 callRuntime((void*) runtime_cmp_le_dd);
765 break;
766 case OP_GREATER:
767 callRuntime((void*) runtime_cmp_gt_dd);
768 break;
769 case OP_GREATER_EQUAL:
770 callRuntime((void*) runtime_cmp_ge_dd);
771 break;
772 case OP_LESS:
773 callRuntime((void*) runtime_cmp_lt_dd);
774 break;
775 default:
776 error("Unknown comparison op %d", op);
777 break;
778 }
779 } else {
780 setupFloatArgs();
781 switch(op) {
782 case OP_EQUALS:
783 callRuntime((void*) runtime_cmp_eq_ff);
784 break;
785 case OP_NOT_EQUALS:
786 callRuntime((void*) runtime_cmp_ne_ff);
787 break;
788 case OP_LESS_EQUAL:
789 callRuntime((void*) runtime_cmp_le_ff);
790 break;
791 case OP_GREATER:
792 callRuntime((void*) runtime_cmp_gt_ff);
793 break;
794 case OP_GREATER_EQUAL:
795 callRuntime((void*) runtime_cmp_ge_ff);
796 break;
797 case OP_LESS:
798 callRuntime((void*) runtime_cmp_lt_ff);
799 break;
800 default:
801 error("Unknown comparison op %d", op);
802 break;
803 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700804 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700805 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700806 }
807
Jack Palevich546b2242009-05-13 15:10:04 -0700808 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700809 Type* pR0Type = getR0Type();
810 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700811 TypeTag tagR0 = pR0Type->tag;
812 TypeTag tagTOS = pTOSType->tag;
813 bool isFloatR0 = isFloatTag(tagR0);
814 bool isFloatTOS = isFloatTag(tagTOS);
815 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700816 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700817 bool isPtrR0 = tagR0 == TY_POINTER;
818 bool isPtrTOS = tagTOS == TY_POINTER;
819 if (isPtrR0 || isPtrTOS) {
820 if (isPtrR0 && isPtrTOS) {
821 if (op != OP_MINUS) {
822 error("Unsupported pointer-pointer operation %d.", op);
823 }
824 if (! typeEqual(pR0Type, pTOSType)) {
825 error("Incompatible pointer types for subtraction.");
826 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700827 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700828 setR0Type(mkpInt);
829 int size = sizeOf(pR0Type->pHead);
830 if (size != 1) {
831 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700832 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700833 // TODO: Optimize for power-of-two.
834 genOp(OP_DIV);
835 }
836 } else {
837 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
838 error("Unsupported pointer-scalar operation %d", op);
839 }
840 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700841 int size = sizeOf(pPtrType->pHead);
842 if (size != 1) {
843 // TODO: Optimize for power-of-two.
844 liReg(size, 2);
845 if (isPtrR0) {
846 o4(0x0E0010192); // mul r1,r2,r1
847 } else {
848 o4(0x0E0000092); // mul r0,r2,r0
849 }
850 }
851 switch(op) {
852 case OP_PLUS:
853 o4(0xE0810000); // add r0,r1,r0
854 break;
855 case OP_MINUS:
856 o4(0xE0410000); // sub r0,r1,r0
857 break;
858 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700859 setR0Type(pPtrType);
860 }
861 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700862 switch(op) {
863 case OP_MUL:
864 o4(0x0E0000091); // mul r0,r1,r0
865 break;
866 case OP_DIV:
867 callRuntime((void*) runtime_DIV);
868 break;
869 case OP_MOD:
870 callRuntime((void*) runtime_MOD);
871 break;
872 case OP_PLUS:
873 o4(0xE0810000); // add r0,r1,r0
874 break;
875 case OP_MINUS:
876 o4(0xE0410000); // sub r0,r1,r0
877 break;
878 case OP_SHIFT_LEFT:
879 o4(0xE1A00011); // lsl r0,r1,r0
880 break;
881 case OP_SHIFT_RIGHT:
882 o4(0xE1A00051); // asr r0,r1,r0
883 break;
884 case OP_BIT_AND:
885 o4(0xE0010000); // and r0,r1,r0
886 break;
887 case OP_BIT_XOR:
888 o4(0xE0210000); // eor r0,r1,r0
889 break;
890 case OP_BIT_OR:
891 o4(0xE1810000); // orr r0,r1,r0
892 break;
893 case OP_BIT_NOT:
894 o4(0xE1E00000); // mvn r0, r0
895 break;
896 default:
897 error("Unimplemented op %d\n", op);
898 break;
899 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700900 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700901 } else {
902 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
903 if (pResultType->tag == TY_DOUBLE) {
904 setupDoubleArgs();
905 switch(op) {
906 case OP_MUL:
907 callRuntime((void*) runtime_op_mul_dd);
908 break;
909 case OP_DIV:
910 callRuntime((void*) runtime_op_div_dd);
911 break;
912 case OP_PLUS:
913 callRuntime((void*) runtime_op_add_dd);
914 break;
915 case OP_MINUS:
916 callRuntime((void*) runtime_op_sub_dd);
917 break;
918 default:
919 error("Unsupported binary floating operation %d\n", op);
920 break;
921 }
922 } else {
923 setupFloatArgs();
924 switch(op) {
925 case OP_MUL:
926 callRuntime((void*) runtime_op_mul_ff);
927 break;
928 case OP_DIV:
929 callRuntime((void*) runtime_op_div_ff);
930 break;
931 case OP_PLUS:
932 callRuntime((void*) runtime_op_add_ff);
933 break;
934 case OP_MINUS:
935 callRuntime((void*) runtime_op_sub_ff);
936 break;
937 default:
938 error("Unsupported binary floating operation %d\n", op);
939 break;
940 }
941 }
942 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700943 }
Jack Palevich22305132009-05-13 10:58:45 -0700944 }
945
Jack Palevich58c30ee2009-07-17 16:35:23 -0700946 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700947 if (op != OP_LOGICAL_NOT) {
948 error("Unknown unary cmp %d", op);
949 } else {
950 Type* pR0Type = getR0Type();
951 TypeTag tag = collapseType(pR0Type->tag);
952 switch(tag) {
953 case TY_INT:
954 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700955 o4(0xE1510000); // cmp r1, r0
956 o4(0x03A00001); // moveq r0,#1
957 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700958 break;
959 case TY_FLOAT:
960 callRuntime((void*) runtime_is_zero_f);
961 break;
962 case TY_DOUBLE:
963 callRuntime((void*) runtime_is_zero_d);
964 break;
965 default:
966 error("gUnaryCmp unsupported type");
967 break;
968 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700969 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700970 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700971 }
972
973 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700974 Type* pR0Type = getR0Type();
975 TypeTag tag = collapseType(pR0Type->tag);
976 switch(tag) {
977 case TY_INT:
978 switch(op) {
979 case OP_MINUS:
980 o4(0xE3A01000); // mov r1, #0
981 o4(0xE0410000); // sub r0,r1,r0
982 break;
983 case OP_BIT_NOT:
984 o4(0xE1E00000); // mvn r0, r0
985 break;
986 default:
987 error("Unknown unary op %d\n", op);
988 break;
989 }
990 break;
991 case TY_FLOAT:
992 case TY_DOUBLE:
993 switch (op) {
994 case OP_MINUS:
995 if (tag == TY_FLOAT) {
996 callRuntime((void*) runtime_op_neg_f);
997 } else {
998 callRuntime((void*) runtime_op_neg_d);
999 }
1000 break;
1001 case OP_BIT_NOT:
1002 error("Can't apply '~' operator to a float or double.");
1003 break;
1004 default:
1005 error("Unknown unary op %d\n", op);
1006 break;
1007 }
1008 break;
1009 default:
1010 error("genUnaryOp unsupported type");
1011 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001012 }
Jack Palevich22305132009-05-13 10:58:45 -07001013 }
1014
Jack Palevich1cdef202009-05-22 12:06:27 -07001015 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001016 Type* pR0Type = getR0Type();
1017 TypeTag r0ct = collapseType(pR0Type->tag);
1018 if (r0ct != TY_DOUBLE) {
1019 o4(0xE92D0001); // stmfd sp!,{r0}
1020 mStackUse += 4;
1021 } else {
1022 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1023 mStackUse += 8;
1024 }
Jack Palevich8df46192009-07-07 14:48:51 -07001025 pushType();
-b master422972c2009-06-17 19:13:52 -07001026 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001027 }
1028
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001029 virtual void over() {
1030 // We know it's only used for int-ptr ops (++/--)
1031
1032 Type* pR0Type = getR0Type();
1033 TypeTag r0ct = collapseType(pR0Type->tag);
1034
1035 Type* pTOSType = getTOSType();
1036 TypeTag tosct = collapseType(pTOSType->tag);
1037
1038 assert (r0ct == TY_INT && tosct == TY_INT);
1039
1040 o4(0xE8BD0002); // ldmfd sp!,{r1}
1041 o4(0xE92D0001); // stmfd sp!,{r0}
1042 o4(0xE92D0002); // stmfd sp!,{r1}
1043 overType();
1044 mStackUse += 4;
1045 }
1046
Jack Palevich58c30ee2009-07-17 16:35:23 -07001047 virtual void popR0() {
1048 Type* pTOSType = getTOSType();
1049 switch (collapseType(pTOSType->tag)){
1050 case TY_INT:
1051 case TY_FLOAT:
1052 o4(0xE8BD0001); // ldmfd sp!,{r0}
1053 mStackUse -= 4;
1054 break;
1055 case TY_DOUBLE:
1056 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1057 mStackUse -= 8;
1058 break;
1059 default:
1060 error("Can't pop this type.");
1061 break;
1062 }
1063 popType();
1064 LOG_STACK("popR0: %d\n", mStackUse);
1065 }
1066
1067 virtual void storeR0ToTOS() {
1068 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001069 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001070 Type* pDestType = pPointerType->pHead;
1071 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001072 o4(0xE8BD0004); // ldmfd sp!,{r2}
1073 popType();
-b master422972c2009-06-17 19:13:52 -07001074 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001075 switch (pDestType->tag) {
1076 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001077 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001078 case TY_FLOAT:
1079 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001080 break;
1081 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001082 o4(0xE5C20000); // strb r0, [r2]
1083 break;
1084 case TY_DOUBLE:
1085 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001086 break;
1087 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001088 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001089 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001090 }
Jack Palevich22305132009-05-13 10:58:45 -07001091 }
1092
Jack Palevich58c30ee2009-07-17 16:35:23 -07001093 virtual void loadR0FromR0() {
1094 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001095 assert(pPointerType->tag == TY_POINTER);
1096 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001097 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001098 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001099 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001100 o4(0xE5900000); // ldr r0, [r0]
1101 break;
1102 case TY_CHAR:
1103 o4(0xE5D00000); // ldrb r0, [r0]
1104 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001105 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001106 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001107 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001108 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001109 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001110 break;
1111 }
Jack Palevich8df46192009-07-07 14:48:51 -07001112 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001113 }
1114
Jack Palevich8df46192009-07-07 14:48:51 -07001115 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001116 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001117 // Local, fp relative
1118 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1119 error("Offset out of range: %08x", ea);
1120 }
1121 if (ea < 0) {
1122 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1123 } else {
1124 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1125 }
Jack Palevichbd894902009-05-14 19:35:31 -07001126 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001127 // Global, absolute.
1128 o4(0xE59F0000); // ldr r0, .L1
1129 o4(0xEA000000); // b .L99
1130 o4(ea); // .L1: .word 0
1131 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001132 }
Jack Palevich8df46192009-07-07 14:48:51 -07001133 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001134 }
1135
Jack Palevich9f51a262009-07-29 16:22:26 -07001136 virtual int leaForward(int ea, Type* pPointerType) {
1137 setR0Type(pPointerType);
1138 int result = ea;
1139 int pc = getPC();
1140 int offset = 0;
1141 if (ea) {
1142 offset = (pc - ea - 8) >> 2;
1143 if ((offset & 0xffff) != offset) {
1144 error("function forward reference out of bounds");
1145 }
1146 } else {
1147 offset = 0;
1148 }
1149 o4(0xE59F0000 | offset); // ldr r0, .L1
1150
1151 if (ea == 0) {
1152 o4(0xEA000000); // b .L99
1153 result = o4(ea); // .L1: .word 0
1154 // .L99:
1155 }
1156 return result;
1157 }
1158
Jack Palevich8df46192009-07-07 14:48:51 -07001159 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001160 Type* pR0Type = getR0Type();
1161 if (bitsSame(pType, pR0Type)) {
1162 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001163 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001164 TypeTag r0Tag = collapseType(pR0Type->tag);
1165 TypeTag destTag = collapseType(pType->tag);
1166 if (r0Tag == TY_INT) {
1167 if (destTag == TY_FLOAT) {
1168 callRuntime((void*) runtime_int_to_float);
1169 } else {
1170 assert(destTag == TY_DOUBLE);
1171 callRuntime((void*) runtime_int_to_double);
1172 }
1173 } else if (r0Tag == TY_FLOAT) {
1174 if (destTag == TY_INT) {
1175 callRuntime((void*) runtime_float_to_int);
1176 } else {
1177 assert(destTag == TY_DOUBLE);
1178 callRuntime((void*) runtime_float_to_double);
1179 }
1180 } else {
1181 assert (r0Tag == TY_DOUBLE);
1182 if (destTag == TY_INT) {
1183 callRuntime((void*) runtime_double_to_int);
1184 } else {
1185 assert(destTag == TY_FLOAT);
1186 callRuntime((void*) runtime_double_to_float);
1187 }
1188 }
Jack Palevich8df46192009-07-07 14:48:51 -07001189 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001190 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001191 }
1192
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001193 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001194 return o4(0xE24DDF00); // Placeholder
1195 }
1196
Jack Palevich8148c5b2009-07-16 18:24:47 -07001197 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001198 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001199 Type* pR0Type = getR0Type();
1200 TypeTag r0ct = collapseType(pR0Type->tag);
1201 switch(r0ct) {
1202 case TY_INT:
1203 case TY_FLOAT:
1204 if (l < 0 || l > 4096-4) {
1205 error("l out of range for stack offset: 0x%08x", l);
1206 }
1207 o4(0xE58D0000 + l); // str r0, [sp, #l]
1208 return 4;
1209 case TY_DOUBLE: {
1210 // Align to 8 byte boundary
1211 int l2 = (l + 7) & ~7;
1212 if (l2 < 0 || l2 > 4096-8) {
1213 error("l out of range for stack offset: 0x%08x", l);
1214 }
1215 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1216 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1217 return (l2 - l) + 8;
1218 }
1219 default:
1220 assert(false);
1221 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001222 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001223 }
1224
Jack Palevichb7718b92009-07-09 22:00:24 -07001225 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001226 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001227 // Have to calculate register arg count from actual stack size,
1228 // in order to properly handle ... functions.
1229 int regArgCount = l >> 2;
1230 if (regArgCount > 4) {
1231 regArgCount = 4;
1232 }
1233 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001234 argumentStackUse -= regArgCount * 4;
1235 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1236 }
1237 mStackUse += argumentStackUse;
1238
1239 // Align stack.
1240 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1241 * STACK_ALIGNMENT);
1242 mStackAlignmentAdjustment = 0;
1243 if (missalignment > 0) {
1244 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1245 }
1246 l += mStackAlignmentAdjustment;
1247
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001248 if (l < 0 || l > 0x3FC) {
1249 error("L out of range for stack adjustment: 0x%08x", l);
1250 }
1251 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001252 mStackUse += mStackAlignmentAdjustment;
1253 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1254 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001255 }
1256
Jack Palevich8df46192009-07-07 14:48:51 -07001257 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001258 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001259 // Forward calls are always short (local)
1260 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001261 }
1262
Jack Palevich8df46192009-07-07 14:48:51 -07001263 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001264 assert(pFunc->tag == TY_FUNC);
1265 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07001266 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001267 int argCount = l >> 2;
1268 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001269 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001270 if (adjustedL < 0 || adjustedL > 4096-4) {
1271 error("l out of range for stack offset: 0x%08x", l);
1272 }
1273 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1274 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001275 }
1276
Jack Palevichb7718b92009-07-09 22:00:24 -07001277 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001278 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001279 // Have to calculate register arg count from actual stack size,
1280 // in order to properly handle ... functions.
1281 int regArgCount = l >> 2;
1282 if (regArgCount > 4) {
1283 regArgCount = 4;
1284 }
1285 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001286 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1287 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001288 if (stackUse) {
1289 if (stackUse < 0 || stackUse > 255) {
1290 error("L out of range for stack adjustment: 0x%08x", l);
1291 }
1292 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001293 mStackUse -= stackUse * 4;
1294 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001295 }
Jack Palevich22305132009-05-13 10:58:45 -07001296 }
1297
Jack Palevicha6535612009-05-13 16:24:17 -07001298 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001299 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001300 }
1301
1302 /* output a symbol and patch all calls to it */
1303 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001304 int n;
1305 int base = getBase();
1306 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001307 while (t) {
1308 int data = * (int*) t;
1309 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1310 if (decodedOffset == 0) {
1311 n = 0;
1312 } else {
1313 n = base + decodedOffset; /* next value */
1314 }
1315 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1316 | encodeRelAddress(pc - t - 8);
1317 t = n;
1318 }
1319 }
1320
Jack Palevich9f51a262009-07-29 16:22:26 -07001321 /* output a symbol and patch all calls to it */
1322 virtual void resolveForward(int t) {
1323 if (t) {
1324 int pc = getPC();
1325 *(int *) t = pc;
1326 }
1327 }
1328
Jack Palevich1cdef202009-05-22 12:06:27 -07001329 virtual int finishCompile() {
1330#if defined(__arm__)
1331 const long base = long(getBase());
1332 const long curr = long(getPC());
1333 int err = cacheflush(base, curr, 0);
1334 return err;
1335#else
1336 return 0;
1337#endif
1338 }
1339
Jack Palevicha6535612009-05-13 16:24:17 -07001340 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001341#ifdef ENABLE_ARM_DISASSEMBLY
1342 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001343 disasm_interface_t di;
1344 di.di_readword = disassemble_readword;
1345 di.di_printaddr = disassemble_printaddr;
1346 di.di_printf = disassemble_printf;
1347
1348 int base = getBase();
1349 int pc = getPC();
1350 for(int i = base; i < pc; i += 4) {
1351 fprintf(out, "%08x: %08x ", i, *(int*) i);
1352 ::disasm(&di, i, 0);
1353 }
Jack Palevich09555c72009-05-27 12:25:55 -07001354#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001355 return 0;
1356 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001357
Jack Palevich9eed7a22009-07-06 17:24:34 -07001358 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001359 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001360 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001361 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001362 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001363 case TY_CHAR:
1364 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001365 case TY_DOUBLE:
1366 return 8;
1367 default:
1368 return 4;
1369 }
1370 }
1371
1372 /**
1373 * Array element alignment (in bytes) for this type of data.
1374 */
1375 virtual size_t sizeOf(Type* pType){
1376 switch(pType->tag) {
1377 case TY_INT:
1378 return 4;
1379 case TY_CHAR:
1380 return 1;
1381 default:
1382 return 0;
1383 case TY_FLOAT:
1384 return 4;
1385 case TY_DOUBLE:
1386 return 8;
1387 case TY_POINTER:
1388 return 4;
1389 }
1390 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001391
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001392 virtual size_t stackAlignmentOf(Type* pType) {
1393 switch(pType->tag) {
1394 case TY_DOUBLE:
1395 return 8;
1396 default:
1397 return 4;
1398 }
1399 }
1400
Jack Palevich9cbd2262009-07-08 16:48:41 -07001401 virtual size_t stackSizeOf(Type* pType) {
1402 switch(pType->tag) {
1403 case TY_DOUBLE:
1404 return 8;
1405 default:
1406 return 4;
1407 }
1408 }
1409
Jack Palevich22305132009-05-13 10:58:45 -07001410 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001411 static FILE* disasmOut;
1412
1413 static u_int
1414 disassemble_readword(u_int address)
1415 {
1416 return(*((u_int *)address));
1417 }
1418
1419 static void
1420 disassemble_printaddr(u_int address)
1421 {
1422 fprintf(disasmOut, "0x%08x", address);
1423 }
1424
1425 static void
1426 disassemble_printf(const char *fmt, ...) {
1427 va_list ap;
1428 va_start(ap, fmt);
1429 vfprintf(disasmOut, fmt, ap);
1430 va_end(ap);
1431 }
1432
1433 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1434
1435 /** Encode a relative address that might also be
1436 * a label.
1437 */
1438 int encodeAddress(int value) {
1439 int base = getBase();
1440 if (value >= base && value <= getPC() ) {
1441 // This is a label, encode it relative to the base.
1442 value = value - base;
1443 }
1444 return encodeRelAddress(value);
1445 }
1446
1447 int encodeRelAddress(int value) {
1448 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1449 }
Jack Palevich22305132009-05-13 10:58:45 -07001450
Jack Palevichb7718b92009-07-09 22:00:24 -07001451 int calcRegArgCount(Type* pDecl) {
1452 int reg = 0;
1453 Type* pArgs = pDecl->pTail;
1454 while (pArgs && reg < 4) {
1455 Type* pArg = pArgs->pHead;
1456 if ( pArg->tag == TY_DOUBLE) {
1457 int evenReg = (reg + 1) & ~1;
1458 if (evenReg >= 4) {
1459 break;
1460 }
1461 reg = evenReg + 2;
1462 } else {
1463 reg++;
1464 }
1465 pArgs = pArgs->pTail;
1466 }
1467 return reg;
1468 }
1469
Jack Palevich58c30ee2009-07-17 16:35:23 -07001470 void setupIntPtrArgs() {
1471 o4(0xE8BD0002); // ldmfd sp!,{r1}
1472 mStackUse -= 4;
1473 popType();
1474 }
1475
Jack Palevichb7718b92009-07-09 22:00:24 -07001476 /* Pop TOS to R1
1477 * Make sure both R0 and TOS are floats. (Could be ints)
1478 * We know that at least one of R0 and TOS is already a float
1479 */
1480 void setupFloatArgs() {
1481 Type* pR0Type = getR0Type();
1482 Type* pTOSType = getTOSType();
1483 TypeTag tagR0 = collapseType(pR0Type->tag);
1484 TypeTag tagTOS = collapseType(pTOSType->tag);
1485 if (tagR0 != TY_FLOAT) {
1486 assert(tagR0 == TY_INT);
1487 callRuntime((void*) runtime_int_to_float);
1488 }
1489 if (tagTOS != TY_FLOAT) {
1490 assert(tagTOS == TY_INT);
1491 assert(tagR0 == TY_FLOAT);
1492 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1493 o4(0xE59D0004); // ldr r0, [sp, #4]
1494 callRuntime((void*) runtime_int_to_float);
1495 o4(0xE1A01000); // mov r1, r0
1496 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1497 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1498 } else {
1499 // Pop TOS
1500 o4(0xE8BD0002); // ldmfd sp!,{r1}
1501 }
1502 mStackUse -= 4;
1503 popType();
1504 }
1505
1506 /* Pop TOS into R2..R3
1507 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1508 * We know that at least one of R0 and TOS are already a double.
1509 */
1510
1511 void setupDoubleArgs() {
1512 Type* pR0Type = getR0Type();
1513 Type* pTOSType = getTOSType();
1514 TypeTag tagR0 = collapseType(pR0Type->tag);
1515 TypeTag tagTOS = collapseType(pTOSType->tag);
1516 if (tagR0 != TY_DOUBLE) {
1517 if (tagR0 == TY_INT) {
1518 callRuntime((void*) runtime_int_to_double);
1519 } else {
1520 assert(tagR0 == TY_FLOAT);
1521 callRuntime((void*) runtime_float_to_double);
1522 }
1523 }
1524 if (tagTOS != TY_DOUBLE) {
1525 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1526 o4(0xE59D0008); // ldr r0, [sp, #8]
1527 if (tagTOS == TY_INT) {
1528 callRuntime((void*) runtime_int_to_double);
1529 } else {
1530 assert(tagTOS == TY_FLOAT);
1531 callRuntime((void*) runtime_float_to_double);
1532 }
1533 o4(0xE1A02000); // mov r2, r0
1534 o4(0xE1A03001); // mov r3, r1
1535 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1536 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1537 mStackUse -= 4;
1538 } else {
1539 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1540 mStackUse -= 8;
1541 }
1542 popType();
1543 }
1544
Jack Palevicha8f427f2009-07-13 18:40:08 -07001545 void liReg(int t, int reg) {
1546 assert(reg >= 0 && reg < 16);
1547 int rN = (reg & 0xf) << 12;
1548 if (t >= 0 && t < 255) {
1549 o4((0xE3A00000 + t) | rN); // mov rN, #0
1550 } else if (t >= -256 && t < 0) {
1551 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001552 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001553 } else {
1554 o4(0xE51F0000 | rN); // ldr rN, .L3
1555 o4(0xEA000000); // b .L99
1556 o4(t); // .L3: .word 0
1557 // .L99:
1558 }
1559 }
1560
Jack Palevichb7718b92009-07-09 22:00:24 -07001561 void callRuntime(void* fn) {
1562 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001563 o4(0xEA000000); // b .L99
1564 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001565 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001566 }
1567
Jack Palevichb7718b92009-07-09 22:00:24 -07001568 // Integer math:
1569
1570 static int runtime_DIV(int b, int a) {
1571 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001572 }
1573
Jack Palevichb7718b92009-07-09 22:00:24 -07001574 static int runtime_MOD(int b, int a) {
1575 return a % b;
1576 }
1577
1578 // Comparison to zero
1579
1580 static int runtime_is_non_zero_f(float a) {
1581 return a != 0;
1582 }
1583
1584 static int runtime_is_non_zero_d(double a) {
1585 return a != 0;
1586 }
1587
1588 // Comparison to zero
1589
1590 static int runtime_is_zero_f(float a) {
1591 return a == 0;
1592 }
1593
1594 static int runtime_is_zero_d(double a) {
1595 return a == 0;
1596 }
1597
1598 // Type conversion
1599
1600 static int runtime_float_to_int(float a) {
1601 return (int) a;
1602 }
1603
1604 static double runtime_float_to_double(float a) {
1605 return (double) a;
1606 }
1607
1608 static int runtime_double_to_int(double a) {
1609 return (int) a;
1610 }
1611
1612 static float runtime_double_to_float(double a) {
1613 return (float) a;
1614 }
1615
1616 static float runtime_int_to_float(int a) {
1617 return (float) a;
1618 }
1619
1620 static double runtime_int_to_double(int a) {
1621 return (double) a;
1622 }
1623
1624 // Comparisons float
1625
1626 static int runtime_cmp_eq_ff(float b, float a) {
1627 return a == b;
1628 }
1629
1630 static int runtime_cmp_ne_ff(float b, float a) {
1631 return a != b;
1632 }
1633
1634 static int runtime_cmp_lt_ff(float b, float a) {
1635 return a < b;
1636 }
1637
1638 static int runtime_cmp_le_ff(float b, float a) {
1639 return a <= b;
1640 }
1641
1642 static int runtime_cmp_ge_ff(float b, float a) {
1643 return a >= b;
1644 }
1645
1646 static int runtime_cmp_gt_ff(float b, float a) {
1647 return a > b;
1648 }
1649
1650 // Comparisons double
1651
1652 static int runtime_cmp_eq_dd(double b, double a) {
1653 return a == b;
1654 }
1655
1656 static int runtime_cmp_ne_dd(double b, double a) {
1657 return a != b;
1658 }
1659
1660 static int runtime_cmp_lt_dd(double b, double a) {
1661 return a < b;
1662 }
1663
1664 static int runtime_cmp_le_dd(double b, double a) {
1665 return a <= b;
1666 }
1667
1668 static int runtime_cmp_ge_dd(double b, double a) {
1669 return a >= b;
1670 }
1671
1672 static int runtime_cmp_gt_dd(double b, double a) {
1673 return a > b;
1674 }
1675
1676 // Math float
1677
1678 static float runtime_op_add_ff(float b, float a) {
1679 return a + b;
1680 }
1681
1682 static float runtime_op_sub_ff(float b, float a) {
1683 return a - b;
1684 }
1685
1686 static float runtime_op_mul_ff(float b, float a) {
1687 return a * b;
1688 }
1689
1690 static float runtime_op_div_ff(float b, float a) {
1691 return a / b;
1692 }
1693
1694 static float runtime_op_neg_f(float a) {
1695 return -a;
1696 }
1697
1698 // Math double
1699
1700 static double runtime_op_add_dd(double b, double a) {
1701 return a + b;
1702 }
1703
1704 static double runtime_op_sub_dd(double b, double a) {
1705 return a - b;
1706 }
1707
1708 static double runtime_op_mul_dd(double b, double a) {
1709 return a * b;
1710 }
1711
1712 static double runtime_op_div_dd(double b, double a) {
1713 return a / b;
1714 }
1715
1716 static double runtime_op_neg_d(double a) {
1717 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001718 }
-b master422972c2009-06-17 19:13:52 -07001719
1720 static const int STACK_ALIGNMENT = 8;
1721 int mStackUse;
1722 // This variable holds the amount we adjusted the stack in the most
1723 // recent endFunctionCallArguments call. It's examined by the
1724 // following adjustStackAfterCall call.
1725 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001726 };
1727
Jack Palevich09555c72009-05-27 12:25:55 -07001728#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001729
1730#ifdef PROVIDE_X86_CODEGEN
1731
Jack Palevich21a15a22009-05-11 14:49:29 -07001732 class X86CodeGenerator : public CodeGenerator {
1733 public:
1734 X86CodeGenerator() {}
1735 virtual ~X86CodeGenerator() {}
1736
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001737 /* returns address to patch with local variable size
1738 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001739 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001740 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1741 return oad(0xec81, 0); /* sub $xxx, %esp */
1742 }
1743
Jack Palevichb7718b92009-07-09 22:00:24 -07001744 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001745 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001746 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001747 }
1748
Jack Palevich21a15a22009-05-11 14:49:29 -07001749 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001750 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001751 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001752 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001753 }
1754
Jack Palevich1a539db2009-07-08 13:04:41 -07001755 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001756 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001757 switch (pType->tag) {
1758 case TY_FLOAT:
1759 oad(0x05D9, address); // flds
1760 break;
1761 case TY_DOUBLE:
1762 oad(0x05DD, address); // fldl
1763 break;
1764 default:
1765 assert(false);
1766 break;
1767 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001768 }
1769
Jack Palevich22305132009-05-13 10:58:45 -07001770 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001771 return psym(0xe9, t);
1772 }
1773
1774 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001775 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001776 Type* pR0Type = getR0Type();
1777 TypeTag tagR0 = pR0Type->tag;
1778 bool isFloatR0 = isFloatTag(tagR0);
1779 if (isFloatR0) {
1780 o(0xeed9); // fldz
1781 o(0xe9da); // fucompp
1782 o(0xe0df); // fnstsw %ax
1783 o(0x9e); // sahf
1784 } else {
1785 o(0xc085); // test %eax, %eax
1786 }
1787 // Use two output statements to generate one instruction.
1788 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001789 return psym(0x84 + l, t);
1790 }
1791
Jack Palevich58c30ee2009-07-17 16:35:23 -07001792 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001793 Type* pR0Type = getR0Type();
1794 Type* pTOSType = getTOSType();
1795 TypeTag tagR0 = pR0Type->tag;
1796 TypeTag tagTOS = pTOSType->tag;
1797 bool isFloatR0 = isFloatTag(tagR0);
1798 bool isFloatTOS = isFloatTag(tagTOS);
1799 if (!isFloatR0 && !isFloatTOS) {
1800 int t = decodeOp(op);
1801 o(0x59); /* pop %ecx */
1802 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001803 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001804 o(0x0f); /* setxx %al */
1805 o(t + 0x90);
1806 o(0xc0);
1807 popType();
1808 } else {
1809 setupFloatOperands();
1810 switch (op) {
1811 case OP_EQUALS:
1812 o(0xe9da); // fucompp
1813 o(0xe0df); // fnstsw %ax
1814 o(0x9e); // sahf
1815 o(0xc0940f); // sete %al
1816 o(0xc29b0f); // setnp %dl
1817 o(0xd021); // andl %edx, %eax
1818 break;
1819 case OP_NOT_EQUALS:
1820 o(0xe9da); // fucompp
1821 o(0xe0df); // fnstsw %ax
1822 o(0x9e); // sahf
1823 o(0xc0950f); // setne %al
1824 o(0xc29a0f); // setp %dl
1825 o(0xd009); // orl %edx, %eax
1826 break;
1827 case OP_GREATER_EQUAL:
1828 o(0xe9da); // fucompp
1829 o(0xe0df); // fnstsw %ax
1830 o(0x05c4f6); // testb $5, %ah
1831 o(0xc0940f); // sete %al
1832 break;
1833 case OP_LESS:
1834 o(0xc9d9); // fxch %st(1)
1835 o(0xe9da); // fucompp
1836 o(0xe0df); // fnstsw %ax
1837 o(0x9e); // sahf
1838 o(0xc0970f); // seta %al
1839 break;
1840 case OP_LESS_EQUAL:
1841 o(0xc9d9); // fxch %st(1)
1842 o(0xe9da); // fucompp
1843 o(0xe0df); // fnstsw %ax
1844 o(0x9e); // sahf
1845 o(0xc0930f); // setea %al
1846 break;
1847 case OP_GREATER:
1848 o(0xe9da); // fucompp
1849 o(0xe0df); // fnstsw %ax
1850 o(0x45c4f6); // testb $69, %ah
1851 o(0xc0940f); // sete %al
1852 break;
1853 default:
1854 error("Unknown comparison op");
1855 }
1856 o(0xc0b60f); // movzbl %al, %eax
1857 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001858 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001859 }
1860
Jack Palevich546b2242009-05-13 15:10:04 -07001861 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001862 Type* pR0Type = getR0Type();
1863 Type* pTOSType = getTOSType();
1864 TypeTag tagR0 = pR0Type->tag;
1865 TypeTag tagTOS = pTOSType->tag;
1866 bool isFloatR0 = isFloatTag(tagR0);
1867 bool isFloatTOS = isFloatTag(tagTOS);
1868 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001869 bool isPtrR0 = tagR0 == TY_POINTER;
1870 bool isPtrTOS = tagTOS == TY_POINTER;
1871 if (isPtrR0 || isPtrTOS) {
1872 if (isPtrR0 && isPtrTOS) {
1873 if (op != OP_MINUS) {
1874 error("Unsupported pointer-pointer operation %d.", op);
1875 }
1876 if (! typeEqual(pR0Type, pTOSType)) {
1877 error("Incompatible pointer types for subtraction.");
1878 }
1879 o(0x59); /* pop %ecx */
1880 o(decodeOp(op));
1881 popType();
1882 setR0Type(mkpInt);
1883 int size = sizeOf(pR0Type->pHead);
1884 if (size != 1) {
1885 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001886 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001887 // TODO: Optimize for power-of-two.
1888 genOp(OP_DIV);
1889 }
1890 } else {
1891 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1892 error("Unsupported pointer-scalar operation %d", op);
1893 }
1894 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1895 o(0x59); /* pop %ecx */
1896 int size = sizeOf(pPtrType->pHead);
1897 if (size != 1) {
1898 // TODO: Optimize for power-of-two.
1899 if (isPtrR0) {
1900 oad(0xC969, size); // imull $size, %ecx
1901 } else {
1902 oad(0xC069, size); // mul $size, %eax
1903 }
1904 }
1905 o(decodeOp(op));
1906 popType();
1907 setR0Type(pPtrType);
1908 }
1909 } else {
1910 o(0x59); /* pop %ecx */
1911 o(decodeOp(op));
1912 if (op == OP_MOD)
1913 o(0x92); /* xchg %edx, %eax */
1914 popType();
1915 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001916 } else {
1917 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1918 setupFloatOperands();
1919 // Both float. x87 R0 == left hand, x87 R1 == right hand
1920 switch (op) {
1921 case OP_MUL:
1922 o(0xc9de); // fmulp
1923 break;
1924 case OP_DIV:
1925 o(0xf1de); // fdivp
1926 break;
1927 case OP_PLUS:
1928 o(0xc1de); // faddp
1929 break;
1930 case OP_MINUS:
1931 o(0xe1de); // fsubp
1932 break;
1933 default:
1934 error("Unsupported binary floating operation.");
1935 break;
1936 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001937 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07001938 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001939 }
1940
Jack Palevich58c30ee2009-07-17 16:35:23 -07001941 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001942 if (op != OP_LOGICAL_NOT) {
1943 error("Unknown unary cmp %d", op);
1944 } else {
1945 Type* pR0Type = getR0Type();
1946 TypeTag tag = collapseType(pR0Type->tag);
1947 switch(tag) {
1948 case TY_INT: {
1949 oad(0xb9, 0); /* movl $0, %ecx */
1950 int t = decodeOp(op);
1951 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001952 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001953 o(0x0f); /* setxx %al */
1954 o(t + 0x90);
1955 o(0xc0);
1956 }
1957 break;
1958 case TY_FLOAT:
1959 case TY_DOUBLE:
1960 o(0xeed9); // fldz
1961 o(0xe9da); // fucompp
1962 o(0xe0df); // fnstsw %ax
1963 o(0x9e); // sahf
1964 o(0xc0950f); // setne %al
1965 o(0xc29a0f); // setp %dl
1966 o(0xd009); // orl %edx, %eax
1967 o(0xc0b60f); // movzbl %al, %eax
1968 o(0x01f083); // xorl $1, %eax
1969 break;
1970 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001971 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07001972 break;
1973 }
1974 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001975 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001976 }
1977
1978 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001979 Type* pR0Type = getR0Type();
1980 TypeTag tag = collapseType(pR0Type->tag);
1981 switch(tag) {
1982 case TY_INT:
1983 oad(0xb9, 0); /* movl $0, %ecx */
1984 o(decodeOp(op));
1985 break;
1986 case TY_FLOAT:
1987 case TY_DOUBLE:
1988 switch (op) {
1989 case OP_MINUS:
1990 o(0xe0d9); // fchs
1991 break;
1992 case OP_BIT_NOT:
1993 error("Can't apply '~' operator to a float or double.");
1994 break;
1995 default:
1996 error("Unknown unary op %d\n", op);
1997 break;
1998 }
1999 break;
2000 default:
2001 error("genUnaryOp unsupported type");
2002 break;
2003 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002004 }
2005
Jack Palevich1cdef202009-05-22 12:06:27 -07002006 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002007 Type* pR0Type = getR0Type();
2008 TypeTag r0ct = collapseType(pR0Type->tag);
2009 switch(r0ct) {
2010 case TY_INT:
2011 o(0x50); /* push %eax */
2012 break;
2013 case TY_FLOAT:
2014 o(0x50); /* push %eax */
2015 o(0x241cd9); // fstps 0(%esp)
2016 break;
2017 case TY_DOUBLE:
2018 o(0x50); /* push %eax */
2019 o(0x50); /* push %eax */
2020 o(0x241cdd); // fstpl 0(%esp)
2021 break;
2022 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002023 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002024 break;
2025 }
Jack Palevich8df46192009-07-07 14:48:51 -07002026 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002027 }
2028
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002029 virtual void over() {
2030 // We know it's only used for int-ptr ops (++/--)
2031
2032 Type* pR0Type = getR0Type();
2033 TypeTag r0ct = collapseType(pR0Type->tag);
2034
2035 Type* pTOSType = getTOSType();
2036 TypeTag tosct = collapseType(pTOSType->tag);
2037
2038 assert (r0ct == TY_INT && tosct == TY_INT);
2039
2040 o(0x59); /* pop %ecx */
2041 o(0x50); /* push %eax */
2042 o(0x51); /* push %ecx */
2043
2044 overType();
2045 }
2046
Jack Palevich58c30ee2009-07-17 16:35:23 -07002047 virtual void popR0() {
2048 Type* pR0Type = getR0Type();
2049 TypeTag r0ct = collapseType(pR0Type->tag);
2050 switch(r0ct) {
2051 case TY_INT:
2052 o(0x58); /* popl %eax */
2053 break;
2054 case TY_FLOAT:
2055 o(0x2404d9); // flds (%esp)
2056 o(0x58); /* popl %eax */
2057 break;
2058 case TY_DOUBLE:
2059 o(0x2404dd); // fldl (%esp)
2060 o(0x58); /* popl %eax */
2061 o(0x58); /* popl %eax */
2062 break;
2063 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002064 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002065 break;
2066 }
2067 popType();
2068 }
2069
2070 virtual void storeR0ToTOS() {
2071 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002072 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002073 Type* pTargetType = pPointerType->pHead;
2074 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002075 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002076 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002077 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002078 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002079 case TY_INT:
2080 o(0x0189); /* movl %eax/%al, (%ecx) */
2081 break;
2082 case TY_CHAR:
2083 o(0x0188); /* movl %eax/%al, (%ecx) */
2084 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002085 case TY_FLOAT:
2086 o(0x19d9); /* fstps (%ecx) */
2087 break;
2088 case TY_DOUBLE:
2089 o(0x19dd); /* fstpl (%ecx) */
2090 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002091 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002092 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002093 break;
2094 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002095 }
2096
Jack Palevich58c30ee2009-07-17 16:35:23 -07002097 virtual void loadR0FromR0() {
2098 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002099 assert(pPointerType->tag == TY_POINTER);
2100 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002101 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002102 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002103 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002104 break;
2105 case TY_CHAR:
2106 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002107 ob(0); /* add zero in code */
2108 break;
2109 case TY_FLOAT:
2110 o2(0x00d9); // flds (%eax)
2111 break;
2112 case TY_DOUBLE:
2113 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002114 break;
2115 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002116 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002117 break;
2118 }
Jack Palevich8df46192009-07-07 14:48:51 -07002119 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002120 }
2121
Jack Palevich8df46192009-07-07 14:48:51 -07002122 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002123 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002124 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002125 }
2126
Jack Palevich9f51a262009-07-29 16:22:26 -07002127 virtual int leaForward(int ea, Type* pPointerType) {
2128 oad(0xb8, ea); /* mov $xx, %eax */
2129 setR0Type(pPointerType);
2130 return getPC() - 4;
2131 }
2132
Jack Palevich8df46192009-07-07 14:48:51 -07002133 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002134 Type* pR0Type = getR0Type();
2135 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002136 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002137 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002138 return;
2139 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002140 if (bitsSame(pType, pR0Type)) {
2141 // do nothing special
2142 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2143 // do nothing special, both held in same register on x87.
2144 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002145 TypeTag r0Tag = collapseType(pR0Type->tag);
2146 TypeTag destTag = collapseType(pType->tag);
2147 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2148 // Convert R0 from int to float
2149 o(0x50); // push %eax
2150 o(0x2404DB); // fildl 0(%esp)
2151 o(0x58); // pop %eax
2152 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2153 // Convert R0 from float to int. Complicated because
2154 // need to save and restore the rounding mode.
2155 o(0x50); // push %eax
2156 o(0x50); // push %eax
2157 o(0x02247cD9); // fnstcw 2(%esp)
2158 o(0x2444b70f); // movzwl 2(%esp), %eax
2159 o(0x02);
2160 o(0x0cb4); // movb $12, %ah
2161 o(0x24048966); // movw %ax, 0(%esp)
2162 o(0x242cd9); // fldcw 0(%esp)
2163 o(0x04245cdb); // fistpl 4(%esp)
2164 o(0x02246cd9); // fldcw 2(%esp)
2165 o(0x58); // pop %eax
2166 o(0x58); // pop %eax
2167 } else {
2168 error("Incompatible types old: %d new: %d",
2169 pR0Type->tag, pType->tag);
2170 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002171 }
2172 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002173 }
2174
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002175 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002176 return oad(0xec81, 0); /* sub $xxx, %esp */
2177 }
2178
Jack Palevich8148c5b2009-07-16 18:24:47 -07002179 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2180 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002181 Type* pR0Type = getR0Type();
2182 TypeTag r0ct = collapseType(pR0Type->tag);
2183 switch(r0ct) {
2184 case TY_INT:
2185 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2186 return 4;
2187 case TY_FLOAT:
2188 oad(0x249CD9, l); /* fstps xxx(%esp) */
2189 return 4;
2190 case TY_DOUBLE:
2191 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2192 return 8;
2193 default:
2194 assert(false);
2195 return 0;
2196 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002197 }
2198
Jack Palevichb7718b92009-07-09 22:00:24 -07002199 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002200 * (int*) a = l;
2201 }
2202
Jack Palevich8df46192009-07-07 14:48:51 -07002203 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002204 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002205 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002206 return psym(0xe8, symbol); /* call xxx */
2207 }
2208
Jack Palevich8df46192009-07-07 14:48:51 -07002209 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002210 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002211 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002212 oad(0x2494ff, l); /* call *xxx(%esp) */
2213 }
2214
Jack Palevichb7718b92009-07-09 22:00:24 -07002215 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002216 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002217 if (isIndirect) {
2218 l += 4;
2219 }
-b master422972c2009-06-17 19:13:52 -07002220 if (l > 0) {
2221 oad(0xc481, l); /* add $xxx, %esp */
2222 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002223 }
2224
Jack Palevicha6535612009-05-13 16:24:17 -07002225 virtual int jumpOffset() {
2226 return 5;
2227 }
2228
2229 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002230 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002231 }
2232
Jack Paleviche7b59062009-05-19 17:12:17 -07002233 /* output a symbol and patch all calls to it */
2234 virtual void gsym(int t) {
2235 int n;
2236 int pc = getPC();
2237 while (t) {
2238 n = *(int *) t; /* next value */
2239 *(int *) t = pc - t - 4;
2240 t = n;
2241 }
2242 }
2243
Jack Palevich9f51a262009-07-29 16:22:26 -07002244 /* output a symbol and patch all calls to it, using absolute address */
2245 virtual void resolveForward(int t) {
2246 int n;
2247 int pc = getPC();
2248 while (t) {
2249 n = *(int *) t; /* next value */
2250 *(int *) t = pc;
2251 t = n;
2252 }
2253 }
2254
Jack Palevich1cdef202009-05-22 12:06:27 -07002255 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002256 size_t pagesize = 4096;
2257 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2258 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2259 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2260 if (err) {
2261 error("mprotect() failed: %d", errno);
2262 }
2263 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002264 }
2265
Jack Palevich9eed7a22009-07-06 17:24:34 -07002266 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002267 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002268 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002269 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002270 switch (pType->tag) {
2271 case TY_CHAR:
2272 return 1;
2273 default:
2274 return 4;
2275 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002276 }
2277
2278 /**
2279 * Array element alignment (in bytes) for this type of data.
2280 */
2281 virtual size_t sizeOf(Type* pType){
2282 switch(pType->tag) {
2283 case TY_INT:
2284 return 4;
2285 case TY_CHAR:
2286 return 1;
2287 default:
2288 return 0;
2289 case TY_FLOAT:
2290 return 4;
2291 case TY_DOUBLE:
2292 return 8;
2293 case TY_POINTER:
2294 return 4;
2295 }
2296 }
2297
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002298 virtual size_t stackAlignmentOf(Type* pType){
2299 return 4;
2300 }
2301
Jack Palevich9cbd2262009-07-08 16:48:41 -07002302 virtual size_t stackSizeOf(Type* pType) {
2303 switch(pType->tag) {
2304 case TY_DOUBLE:
2305 return 8;
2306 default:
2307 return 4;
2308 }
2309 }
2310
Jack Palevich21a15a22009-05-11 14:49:29 -07002311 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002312
2313 /** Output 1 to 4 bytes.
2314 *
2315 */
2316 void o(int n) {
2317 /* cannot use unsigned, so we must do a hack */
2318 while (n && n != -1) {
2319 ob(n & 0xff);
2320 n = n >> 8;
2321 }
2322 }
2323
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002324 /* Output exactly 2 bytes
2325 */
2326 void o2(int n) {
2327 ob(n & 0xff);
2328 ob(0xff & (n >> 8));
2329 }
2330
Jack Paleviche7b59062009-05-19 17:12:17 -07002331 /* psym is used to put an instruction with a data field which is a
2332 reference to a symbol. It is in fact the same as oad ! */
2333 int psym(int n, int t) {
2334 return oad(n, t);
2335 }
2336
2337 /* instruction + address */
2338 int oad(int n, int t) {
2339 o(n);
2340 int result = getPC();
2341 o4(t);
2342 return result;
2343 }
2344
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002345 static const int operatorHelper[];
2346
2347 int decodeOp(int op) {
2348 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002349 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002350 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002351 }
2352 return operatorHelper[op];
2353 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002354
Jack Palevich546b2242009-05-13 15:10:04 -07002355 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002356 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002357 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002358 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002359
2360 void setupFloatOperands() {
2361 Type* pR0Type = getR0Type();
2362 Type* pTOSType = getTOSType();
2363 TypeTag tagR0 = pR0Type->tag;
2364 TypeTag tagTOS = pTOSType->tag;
2365 bool isFloatR0 = isFloatTag(tagR0);
2366 bool isFloatTOS = isFloatTag(tagTOS);
2367 if (! isFloatR0) {
2368 // Convert R0 from int to float
2369 o(0x50); // push %eax
2370 o(0x2404DB); // fildl 0(%esp)
2371 o(0x58); // pop %eax
2372 }
2373 if (! isFloatTOS){
2374 o(0x2404DB); // fildl 0(%esp);
2375 o(0x58); // pop %eax
2376 } else {
2377 if (tagTOS == TY_FLOAT) {
2378 o(0x2404d9); // flds (%esp)
2379 o(0x58); // pop %eax
2380 } else {
2381 o(0x2404dd); // fldl (%esp)
2382 o(0x58); // pop %eax
2383 o(0x58); // pop %eax
2384 }
2385 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002386 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002387 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002388 };
2389
Jack Paleviche7b59062009-05-19 17:12:17 -07002390#endif // PROVIDE_X86_CODEGEN
2391
Jack Palevichb67b18f2009-06-11 21:12:23 -07002392#ifdef PROVIDE_TRACE_CODEGEN
2393 class TraceCodeGenerator : public CodeGenerator {
2394 private:
2395 CodeGenerator* mpBase;
2396
2397 public:
2398 TraceCodeGenerator(CodeGenerator* pBase) {
2399 mpBase = pBase;
2400 }
2401
2402 virtual ~TraceCodeGenerator() {
2403 delete mpBase;
2404 }
2405
2406 virtual void init(CodeBuf* pCodeBuf) {
2407 mpBase->init(pCodeBuf);
2408 }
2409
2410 void setErrorSink(ErrorSink* pErrorSink) {
2411 mpBase->setErrorSink(pErrorSink);
2412 }
2413
2414 /* returns address to patch with local variable size
2415 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002416 virtual int functionEntry(Type* pDecl) {
2417 int result = mpBase->functionEntry(pDecl);
2418 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002419 return result;
2420 }
2421
Jack Palevichb7718b92009-07-09 22:00:24 -07002422 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2423 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2424 localVariableAddress, localVariableSize);
2425 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002426 }
2427
2428 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002429 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002430 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002431 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002432 }
2433
Jack Palevich1a539db2009-07-08 13:04:41 -07002434 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002435 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002436 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002437 }
2438
Jack Palevichb67b18f2009-06-11 21:12:23 -07002439 virtual int gjmp(int t) {
2440 int result = mpBase->gjmp(t);
2441 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2442 return result;
2443 }
2444
2445 /* l = 0: je, l == 1: jne */
2446 virtual int gtst(bool l, int t) {
2447 int result = mpBase->gtst(l, t);
2448 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2449 return result;
2450 }
2451
Jack Palevich58c30ee2009-07-17 16:35:23 -07002452 virtual void gcmp(int op) {
2453 fprintf(stderr, "gcmp(%d)\n", op);
2454 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002455 }
2456
2457 virtual void genOp(int op) {
2458 fprintf(stderr, "genOp(%d)\n", op);
2459 mpBase->genOp(op);
2460 }
2461
Jack Palevich9eed7a22009-07-06 17:24:34 -07002462
Jack Palevich58c30ee2009-07-17 16:35:23 -07002463 virtual void gUnaryCmp(int op) {
2464 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2465 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002466 }
2467
2468 virtual void genUnaryOp(int op) {
2469 fprintf(stderr, "genUnaryOp(%d)\n", op);
2470 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002471 }
2472
2473 virtual void pushR0() {
2474 fprintf(stderr, "pushR0()\n");
2475 mpBase->pushR0();
2476 }
2477
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002478 virtual void over() {
2479 fprintf(stderr, "over()\n");
2480 mpBase->over();
2481 }
2482
Jack Palevich58c30ee2009-07-17 16:35:23 -07002483 virtual void popR0() {
2484 fprintf(stderr, "popR0()\n");
2485 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002486 }
2487
Jack Palevich58c30ee2009-07-17 16:35:23 -07002488 virtual void storeR0ToTOS() {
2489 fprintf(stderr, "storeR0ToTOS()\n");
2490 mpBase->storeR0ToTOS();
2491 }
2492
2493 virtual void loadR0FromR0() {
2494 fprintf(stderr, "loadR0FromR0()\n");
2495 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002496 }
2497
Jack Palevich8df46192009-07-07 14:48:51 -07002498 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002499 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002500 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002501 }
2502
Jack Palevich9f51a262009-07-29 16:22:26 -07002503 virtual int leaForward(int ea, Type* pPointerType) {
2504 fprintf(stderr, "leaForward(%d)\n", ea);
2505 return mpBase->leaForward(ea, pPointerType);
2506 }
2507
Jack Palevich8df46192009-07-07 14:48:51 -07002508 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002509 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002510 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002511 }
2512
2513 virtual int beginFunctionCallArguments() {
2514 int result = mpBase->beginFunctionCallArguments();
2515 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2516 return result;
2517 }
2518
Jack Palevich8148c5b2009-07-16 18:24:47 -07002519 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2520 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2521 pArgType->tag);
2522 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002523 }
2524
Jack Palevichb7718b92009-07-09 22:00:24 -07002525 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002526 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002527 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002528 }
2529
Jack Palevich8df46192009-07-07 14:48:51 -07002530 virtual int callForward(int symbol, Type* pFunc) {
2531 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002532 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2533 return result;
2534 }
2535
Jack Palevich8df46192009-07-07 14:48:51 -07002536 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002537 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
2538 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002539 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002540 }
2541
Jack Palevichb7718b92009-07-09 22:00:24 -07002542 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2543 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2544 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002545 }
2546
2547 virtual int jumpOffset() {
2548 return mpBase->jumpOffset();
2549 }
2550
2551 virtual int disassemble(FILE* out) {
2552 return mpBase->disassemble(out);
2553 }
2554
2555 /* output a symbol and patch all calls to it */
2556 virtual void gsym(int t) {
2557 fprintf(stderr, "gsym(%d)\n", t);
2558 mpBase->gsym(t);
2559 }
2560
Jack Palevich9f51a262009-07-29 16:22:26 -07002561 virtual void resolveForward(int t) {
2562 mpBase->resolveForward(t);
2563 }
2564
Jack Palevichb67b18f2009-06-11 21:12:23 -07002565 virtual int finishCompile() {
2566 int result = mpBase->finishCompile();
2567 fprintf(stderr, "finishCompile() = %d\n", result);
2568 return result;
2569 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002570
2571 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002572 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002573 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002574 virtual size_t alignmentOf(Type* pType){
2575 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002576 }
2577
2578 /**
2579 * Array element alignment (in bytes) for this type of data.
2580 */
2581 virtual size_t sizeOf(Type* pType){
2582 return mpBase->sizeOf(pType);
2583 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002584
Jack Palevich9cbd2262009-07-08 16:48:41 -07002585
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002586 virtual size_t stackAlignmentOf(Type* pType) {
2587 return mpBase->stackAlignmentOf(pType);
2588 }
2589
2590
Jack Palevich9cbd2262009-07-08 16:48:41 -07002591 virtual size_t stackSizeOf(Type* pType) {
2592 return mpBase->stackSizeOf(pType);
2593 }
2594
Jack Palevich1a539db2009-07-08 13:04:41 -07002595 virtual Type* getR0Type() {
2596 return mpBase->getR0Type();
2597 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002598
2599 virtual ExpressionType getR0ExpressionType() {
2600 return mpBase->getR0ExpressionType();
2601 }
2602
2603 virtual void setR0ExpressionType(ExpressionType et) {
2604 mpBase->setR0ExpressionType(et);
2605 }
2606
2607 virtual size_t getExpressionStackDepth() {
2608 return mpBase->getExpressionStackDepth();
2609 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002610 };
2611
2612#endif // PROVIDE_TRACE_CODEGEN
2613
Jack Palevich569f1352009-06-29 14:29:08 -07002614 class Arena {
2615 public:
2616 // Used to record a given allocation amount.
2617 // Used:
2618 // Mark mark = arena.mark();
2619 // ... lots of arena.allocate()
2620 // arena.free(mark);
2621
2622 struct Mark {
2623 size_t chunk;
2624 size_t offset;
2625 };
2626
2627 Arena() {
2628 mCurrentChunk = 0;
2629 Chunk start(CHUNK_SIZE);
2630 mData.push_back(start);
2631 }
2632
2633 ~Arena() {
2634 for(size_t i = 0; i < mData.size(); i++) {
2635 mData[i].free();
2636 }
2637 }
2638
2639 // Alloc using the standard alignment size safe for any variable
2640 void* alloc(size_t size) {
2641 return alloc(size, 8);
2642 }
2643
2644 Mark mark(){
2645 Mark result;
2646 result.chunk = mCurrentChunk;
2647 result.offset = mData[mCurrentChunk].mOffset;
2648 return result;
2649 }
2650
2651 void freeToMark(const Mark& mark) {
2652 mCurrentChunk = mark.chunk;
2653 mData[mCurrentChunk].mOffset = mark.offset;
2654 }
2655
2656 private:
2657 // Allocate memory aligned to a given size
2658 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2659 // Memory is not zero filled.
2660
2661 void* alloc(size_t size, size_t alignment) {
2662 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2663 if (mCurrentChunk + 1 < mData.size()) {
2664 mCurrentChunk++;
2665 } else {
2666 size_t allocSize = CHUNK_SIZE;
2667 if (allocSize < size + alignment - 1) {
2668 allocSize = size + alignment - 1;
2669 }
2670 Chunk chunk(allocSize);
2671 mData.push_back(chunk);
2672 mCurrentChunk++;
2673 }
2674 }
2675 return mData[mCurrentChunk].allocate(size, alignment);
2676 }
2677
2678 static const size_t CHUNK_SIZE = 128*1024;
2679 // Note: this class does not deallocate its
2680 // memory when it's destroyed. It depends upon
2681 // its parent to deallocate the memory.
2682 struct Chunk {
2683 Chunk() {
2684 mpData = 0;
2685 mSize = 0;
2686 mOffset = 0;
2687 }
2688
2689 Chunk(size_t size) {
2690 mSize = size;
2691 mpData = (char*) malloc(size);
2692 mOffset = 0;
2693 }
2694
2695 ~Chunk() {
2696 // Doesn't deallocate memory.
2697 }
2698
2699 void* allocate(size_t size, size_t alignment) {
2700 size_t alignedOffset = aligned(mOffset, alignment);
2701 void* result = mpData + alignedOffset;
2702 mOffset = alignedOffset + size;
2703 return result;
2704 }
2705
2706 void free() {
2707 if (mpData) {
2708 ::free(mpData);
2709 mpData = 0;
2710 }
2711 }
2712
2713 size_t remainingCapacity(size_t alignment) {
2714 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2715 }
2716
2717 // Assume alignment is a power of two
2718 inline size_t aligned(size_t v, size_t alignment) {
2719 size_t mask = alignment-1;
2720 return (v + mask) & ~mask;
2721 }
2722
2723 char* mpData;
2724 size_t mSize;
2725 size_t mOffset;
2726 };
2727
2728 size_t mCurrentChunk;
2729
2730 Vector<Chunk> mData;
2731 };
2732
Jack Palevich569f1352009-06-29 14:29:08 -07002733 struct VariableInfo;
2734
2735 struct Token {
2736 int hash;
2737 size_t length;
2738 char* pText;
2739 tokenid_t id;
2740
2741 // Current values for the token
2742 char* mpMacroDefinition;
2743 VariableInfo* mpVariableInfo;
2744 };
2745
2746 class TokenTable {
2747 public:
2748 // Don't use 0..0xff, allows characters and operators to be tokens too.
2749
2750 static const int TOKEN_BASE = 0x100;
2751 TokenTable() {
2752 mpMap = hashmapCreate(128, hashFn, equalsFn);
2753 }
2754
2755 ~TokenTable() {
2756 hashmapFree(mpMap);
2757 }
2758
2759 void setArena(Arena* pArena) {
2760 mpArena = pArena;
2761 }
2762
2763 // Returns a token for a given string of characters.
2764 tokenid_t intern(const char* pText, size_t length) {
2765 Token probe;
2766 int hash = hashmapHash((void*) pText, length);
2767 {
2768 Token probe;
2769 probe.hash = hash;
2770 probe.length = length;
2771 probe.pText = (char*) pText;
2772 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2773 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002774 return pValue->id;
2775 }
2776 }
2777
2778 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2779 memset(pToken, 0, sizeof(*pToken));
2780 pToken->hash = hash;
2781 pToken->length = length;
2782 pToken->pText = (char*) mpArena->alloc(length + 1);
2783 memcpy(pToken->pText, pText, length);
2784 pToken->pText[length] = 0;
2785 pToken->id = mTokens.size() + TOKEN_BASE;
2786 mTokens.push_back(pToken);
2787 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002788 return pToken->id;
2789 }
2790
2791 // Return the Token for a given tokenid.
2792 Token& operator[](tokenid_t id) {
2793 return *mTokens[id - TOKEN_BASE];
2794 }
2795
2796 inline size_t size() {
2797 return mTokens.size();
2798 }
2799
2800 private:
2801
2802 static int hashFn(void* pKey) {
2803 Token* pToken = (Token*) pKey;
2804 return pToken->hash;
2805 }
2806
2807 static bool equalsFn(void* keyA, void* keyB) {
2808 Token* pTokenA = (Token*) keyA;
2809 Token* pTokenB = (Token*) keyB;
2810 // Don't need to compare hash values, they should always be equal
2811 return pTokenA->length == pTokenB->length
2812 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2813 }
2814
2815 Hashmap* mpMap;
2816 Vector<Token*> mTokens;
2817 Arena* mpArena;
2818 };
2819
Jack Palevich1cdef202009-05-22 12:06:27 -07002820 class InputStream {
2821 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002822 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002823 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002824 };
2825
2826 class TextInputStream : public InputStream {
2827 public:
2828 TextInputStream(const char* text, size_t textLength)
2829 : pText(text), mTextLength(textLength), mPosition(0) {
2830 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002831
Jack Palevichdc456462009-07-16 16:50:56 -07002832 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002833 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2834 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002835
Jack Palevichdc456462009-07-16 16:50:56 -07002836 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002837 const char* pText;
2838 size_t mTextLength;
2839 size_t mPosition;
2840 };
2841
Jack Palevicheedf9d22009-06-04 16:23:40 -07002842 class String {
2843 public:
2844 String() {
2845 mpBase = 0;
2846 mUsed = 0;
2847 mSize = 0;
2848 }
2849
Jack Palevich303d8ff2009-06-11 19:06:24 -07002850 String(const char* item, int len, bool adopt) {
2851 if (len < 0) {
2852 len = strlen(item);
2853 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002854 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002855 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002856 mUsed = len;
2857 mSize = len + 1;
2858 } else {
2859 mpBase = 0;
2860 mUsed = 0;
2861 mSize = 0;
2862 appendBytes(item, len);
2863 }
2864 }
2865
Jack Palevich303d8ff2009-06-11 19:06:24 -07002866 String(const String& other) {
2867 mpBase = 0;
2868 mUsed = 0;
2869 mSize = 0;
2870 appendBytes(other.getUnwrapped(), other.len());
2871 }
2872
Jack Palevicheedf9d22009-06-04 16:23:40 -07002873 ~String() {
2874 if (mpBase) {
2875 free(mpBase);
2876 }
2877 }
2878
Jack Palevicha6baa232009-06-12 11:25:59 -07002879 String& operator=(const String& other) {
2880 clear();
2881 appendBytes(other.getUnwrapped(), other.len());
2882 return *this;
2883 }
2884
Jack Palevich303d8ff2009-06-11 19:06:24 -07002885 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002886 return mpBase;
2887 }
2888
Jack Palevich303d8ff2009-06-11 19:06:24 -07002889 void clear() {
2890 mUsed = 0;
2891 if (mSize > 0) {
2892 mpBase[0] = 0;
2893 }
2894 }
2895
Jack Palevicheedf9d22009-06-04 16:23:40 -07002896 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002897 appendBytes(s, strlen(s));
2898 }
2899
2900 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002901 memcpy(ensure(n), s, n + 1);
2902 }
2903
2904 void append(char c) {
2905 * ensure(1) = c;
2906 }
2907
Jack Palevich86351982009-06-30 18:09:56 -07002908 void append(String& other) {
2909 appendBytes(other.getUnwrapped(), other.len());
2910 }
2911
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002912 char* orphan() {
2913 char* result = mpBase;
2914 mpBase = 0;
2915 mUsed = 0;
2916 mSize = 0;
2917 return result;
2918 }
2919
Jack Palevicheedf9d22009-06-04 16:23:40 -07002920 void printf(const char* fmt,...) {
2921 va_list ap;
2922 va_start(ap, fmt);
2923 vprintf(fmt, ap);
2924 va_end(ap);
2925 }
2926
2927 void vprintf(const char* fmt, va_list ap) {
2928 char* temp;
2929 int numChars = vasprintf(&temp, fmt, ap);
2930 memcpy(ensure(numChars), temp, numChars+1);
2931 free(temp);
2932 }
2933
Jack Palevich303d8ff2009-06-11 19:06:24 -07002934 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002935 return mUsed;
2936 }
2937
2938 private:
2939 char* ensure(int n) {
2940 size_t newUsed = mUsed + n;
2941 if (newUsed > mSize) {
2942 size_t newSize = mSize * 2 + 10;
2943 if (newSize < newUsed) {
2944 newSize = newUsed;
2945 }
2946 mpBase = (char*) realloc(mpBase, newSize + 1);
2947 mSize = newSize;
2948 }
2949 mpBase[newUsed] = '\0';
2950 char* result = mpBase + mUsed;
2951 mUsed = newUsed;
2952 return result;
2953 }
2954
2955 char* mpBase;
2956 size_t mUsed;
2957 size_t mSize;
2958 };
2959
Jack Palevich569f1352009-06-29 14:29:08 -07002960 void internKeywords() {
2961 // Note: order has to match TOK_ constants
2962 static const char* keywords[] = {
2963 "int",
2964 "char",
2965 "void",
2966 "if",
2967 "else",
2968 "while",
2969 "break",
2970 "return",
2971 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07002972 "auto",
2973 "case",
2974 "const",
2975 "continue",
2976 "default",
2977 "do",
2978 "double",
2979 "enum",
2980 "extern",
2981 "float",
2982 "goto",
2983 "long",
2984 "register",
2985 "short",
2986 "signed",
2987 "sizeof",
2988 "static",
2989 "struct",
2990 "switch",
2991 "typedef",
2992 "union",
2993 "unsigned",
2994 "volatile",
2995 "_Bool",
2996 "_Complex",
2997 "_Imaginary",
2998 "inline",
2999 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003000
3001 // predefined tokens that can also be symbols start here:
3002 "pragma",
3003 "define",
3004 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003005 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003006
Jack Palevich569f1352009-06-29 14:29:08 -07003007 for(int i = 0; keywords[i]; i++) {
3008 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003009 }
Jack Palevich569f1352009-06-29 14:29:08 -07003010 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003011
Jack Palevich36d94142009-06-08 15:55:32 -07003012 struct InputState {
3013 InputStream* pStream;
3014 int oldCh;
3015 };
3016
Jack Palevich2db168f2009-06-11 14:29:47 -07003017 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003018 void* pAddress;
3019 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003020 tokenid_t tok;
3021 size_t level;
3022 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003023 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003024 };
3025
Jack Palevich303d8ff2009-06-11 19:06:24 -07003026 class SymbolStack {
3027 public:
3028 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003029 mpArena = 0;
3030 mpTokenTable = 0;
3031 }
3032
3033 void setArena(Arena* pArena) {
3034 mpArena = pArena;
3035 }
3036
3037 void setTokenTable(TokenTable* pTokenTable) {
3038 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003039 }
3040
3041 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003042 Mark mark;
3043 mark.mArenaMark = mpArena->mark();
3044 mark.mSymbolHead = mStack.size();
3045 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003046 }
3047
3048 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003049 // Undo any shadowing that was done:
3050 Mark mark = mLevelStack.back();
3051 mLevelStack.pop_back();
3052 while (mStack.size() > mark.mSymbolHead) {
3053 VariableInfo* pV = mStack.back();
3054 mStack.pop_back();
3055 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003056 }
Jack Palevich569f1352009-06-29 14:29:08 -07003057 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003058 }
3059
Jack Palevich569f1352009-06-29 14:29:08 -07003060 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3061 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3062 return pV && pV->level == level();
3063 }
3064
3065 VariableInfo* add(tokenid_t tok) {
3066 Token& token = (*mpTokenTable)[tok];
3067 VariableInfo* pOldV = token.mpVariableInfo;
3068 VariableInfo* pNewV =
3069 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3070 memset(pNewV, 0, sizeof(VariableInfo));
3071 pNewV->tok = tok;
3072 pNewV->level = level();
3073 pNewV->pOldDefinition = pOldV;
3074 token.mpVariableInfo = pNewV;
3075 mStack.push_back(pNewV);
3076 return pNewV;
3077 }
3078
Jack Palevich86351982009-06-30 18:09:56 -07003079 VariableInfo* add(Type* pType) {
3080 VariableInfo* pVI = add(pType->id);
3081 pVI->pType = pType;
3082 return pVI;
3083 }
3084
Jack Palevich569f1352009-06-29 14:29:08 -07003085 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3086 for (size_t i = 0; i < mStack.size(); i++) {
3087 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003088 break;
3089 }
3090 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003091 }
3092
Jack Palevich303d8ff2009-06-11 19:06:24 -07003093 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003094 inline size_t level() {
3095 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003096 }
3097
Jack Palevich569f1352009-06-29 14:29:08 -07003098 struct Mark {
3099 Arena::Mark mArenaMark;
3100 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003101 };
3102
Jack Palevich569f1352009-06-29 14:29:08 -07003103 Arena* mpArena;
3104 TokenTable* mpTokenTable;
3105 Vector<VariableInfo*> mStack;
3106 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003107 };
Jack Palevich36d94142009-06-08 15:55:32 -07003108
3109 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003110 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003111 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003112 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003113 int tokl; // token operator level
3114 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003115 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003116 intptr_t loc; // local variable index
3117 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003118 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003119 char* dptr; // Macro state: Points to macro text during macro playback.
3120 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003121 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003122 ACCSymbolLookupFn mpSymbolLookupFn;
3123 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003124
3125 // Arena for the duration of the compile
3126 Arena mGlobalArena;
3127 // Arena for data that's only needed when compiling a single function
3128 Arena mLocalArena;
3129
Jack Palevich2ff5c222009-07-23 15:11:22 -07003130 Arena* mpCurrentArena;
3131
Jack Palevich569f1352009-06-29 14:29:08 -07003132 TokenTable mTokenTable;
3133 SymbolStack mGlobals;
3134 SymbolStack mLocals;
3135
Jack Palevich40600de2009-07-01 15:32:35 -07003136 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003137 Type* mkpInt; // int
3138 Type* mkpChar; // char
3139 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003140 Type* mkpFloat;
3141 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003142 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003143 Type* mkpIntPtr;
3144 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003145 Type* mkpFloatPtr;
3146 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003147 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003148
Jack Palevich36d94142009-06-08 15:55:32 -07003149 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003150 int mLineNumber;
3151 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003152
3153 CodeBuf codeBuf;
3154 CodeGenerator* pGen;
3155
Jack Palevicheedf9d22009-06-04 16:23:40 -07003156 String mErrorBuf;
3157
Jack Palevicheedf9d22009-06-04 16:23:40 -07003158 String mPragmas;
3159 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003160 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003161
Jack Palevich21a15a22009-05-11 14:49:29 -07003162 static const int ALLOC_SIZE = 99999;
3163
Jack Palevich303d8ff2009-06-11 19:06:24 -07003164 static const int TOK_DUMMY = 1;
3165 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003166 static const int TOK_NUM_FLOAT = 3;
3167 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003168
3169 // 3..255 are character and/or operators
3170
Jack Palevich2db168f2009-06-11 14:29:47 -07003171 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003172 // Order has to match string list in "internKeywords".
3173 enum {
3174 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3175 TOK_INT = TOK_KEYWORD,
3176 TOK_CHAR,
3177 TOK_VOID,
3178 TOK_IF,
3179 TOK_ELSE,
3180 TOK_WHILE,
3181 TOK_BREAK,
3182 TOK_RETURN,
3183 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003184 TOK_AUTO,
3185 TOK_CASE,
3186 TOK_CONST,
3187 TOK_CONTINUE,
3188 TOK_DEFAULT,
3189 TOK_DO,
3190 TOK_DOUBLE,
3191 TOK_ENUM,
3192 TOK_EXTERN,
3193 TOK_FLOAT,
3194 TOK_GOTO,
3195 TOK_LONG,
3196 TOK_REGISTER,
3197 TOK_SHORT,
3198 TOK_SIGNED,
3199 TOK_SIZEOF,
3200 TOK_STATIC,
3201 TOK_STRUCT,
3202 TOK_SWITCH,
3203 TOK_TYPEDEF,
3204 TOK_UNION,
3205 TOK_UNSIGNED,
3206 TOK_VOLATILE,
3207 TOK__BOOL,
3208 TOK__COMPLEX,
3209 TOK__IMAGINARY,
3210 TOK_INLINE,
3211 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003212
3213 // Symbols start after keywords
3214
3215 TOK_SYMBOL,
3216 TOK_PRAGMA = TOK_SYMBOL,
3217 TOK_DEFINE,
3218 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003219 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003220
3221 static const int LOCAL = 0x200;
3222
3223 static const int SYM_FORWARD = 0;
3224 static const int SYM_DEFINE = 1;
3225
3226 /* tokens in string heap */
3227 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003228
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003229 static const int OP_INCREMENT = 0;
3230 static const int OP_DECREMENT = 1;
3231 static const int OP_MUL = 2;
3232 static const int OP_DIV = 3;
3233 static const int OP_MOD = 4;
3234 static const int OP_PLUS = 5;
3235 static const int OP_MINUS = 6;
3236 static const int OP_SHIFT_LEFT = 7;
3237 static const int OP_SHIFT_RIGHT = 8;
3238 static const int OP_LESS_EQUAL = 9;
3239 static const int OP_GREATER_EQUAL = 10;
3240 static const int OP_LESS = 11;
3241 static const int OP_GREATER = 12;
3242 static const int OP_EQUALS = 13;
3243 static const int OP_NOT_EQUALS = 14;
3244 static const int OP_LOGICAL_AND = 15;
3245 static const int OP_LOGICAL_OR = 16;
3246 static const int OP_BIT_AND = 17;
3247 static const int OP_BIT_XOR = 18;
3248 static const int OP_BIT_OR = 19;
3249 static const int OP_BIT_NOT = 20;
3250 static const int OP_LOGICAL_NOT = 21;
3251 static const int OP_COUNT = 22;
3252
3253 /* Operators are searched from front, the two-character operators appear
3254 * before the single-character operators with the same first character.
3255 * @ is used to pad out single-character operators.
3256 */
3257 static const char* operatorChars;
3258 static const char operatorLevel[];
3259
Jack Palevich569f1352009-06-29 14:29:08 -07003260 /* Called when we detect an internal problem. Does nothing in production.
3261 *
3262 */
3263 void internalError() {
3264 * (char*) 0 = 0;
3265 }
3266
Jack Palevich86351982009-06-30 18:09:56 -07003267 void assert(bool isTrue) {
3268 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003269 internalError();
3270 }
Jack Palevich86351982009-06-30 18:09:56 -07003271 }
3272
Jack Palevich40600de2009-07-01 15:32:35 -07003273 bool isSymbol(tokenid_t t) {
3274 return t >= TOK_SYMBOL &&
3275 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3276 }
3277
3278 bool isSymbolOrKeyword(tokenid_t t) {
3279 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003280 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003281 }
3282
Jack Palevich86351982009-06-30 18:09:56 -07003283 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003284 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003285 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3286 if (pV && pV->tok != t) {
3287 internalError();
3288 }
3289 return pV;
3290 }
3291
3292 inline bool isDefined(tokenid_t t) {
3293 return t >= TOK_SYMBOL && VI(t) != 0;
3294 }
3295
Jack Palevich40600de2009-07-01 15:32:35 -07003296 const char* nameof(tokenid_t t) {
3297 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003298 return mTokenTable[t].pText;
3299 }
3300
Jack Palevich21a15a22009-05-11 14:49:29 -07003301 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003302 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003303 }
3304
3305 void inp() {
3306 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003307 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003308 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003309 dptr = 0;
3310 ch = dch;
3311 }
Jack Palevichdc456462009-07-16 16:50:56 -07003312 } else {
3313 if (mbBumpLine) {
3314 mLineNumber++;
3315 mbBumpLine = false;
3316 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003317 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003318 if (ch == '\n') {
3319 mbBumpLine = true;
3320 }
3321 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003322#if 0
3323 printf("ch='%c' 0x%x\n", ch, ch);
3324#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003325 }
3326
3327 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003328 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003329 }
3330
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003331 int decodeHex(int c) {
3332 if (isdigit(c)) {
3333 c -= '0';
3334 } else if (c <= 'F') {
3335 c = c - 'A' + 10;
3336 } else {
3337 c =c - 'a' + 10;
3338 }
3339 return c;
3340 }
3341
Jack Palevichb4758ff2009-06-12 12:49:14 -07003342 /* read a character constant, advances ch to after end of constant */
3343 int getq() {
3344 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003345 if (ch == '\\') {
3346 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003347 if (isoctal(ch)) {
3348 // 1 to 3 octal characters.
3349 val = 0;
3350 for(int i = 0; i < 3; i++) {
3351 if (isoctal(ch)) {
3352 val = (val << 3) + ch - '0';
3353 inp();
3354 }
3355 }
3356 return val;
3357 } else if (ch == 'x' || ch == 'X') {
3358 // N hex chars
3359 inp();
3360 if (! isxdigit(ch)) {
3361 error("'x' character escape requires at least one digit.");
3362 } else {
3363 val = 0;
3364 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003365 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003366 inp();
3367 }
3368 }
3369 } else {
3370 int val = ch;
3371 switch (ch) {
3372 case 'a':
3373 val = '\a';
3374 break;
3375 case 'b':
3376 val = '\b';
3377 break;
3378 case 'f':
3379 val = '\f';
3380 break;
3381 case 'n':
3382 val = '\n';
3383 break;
3384 case 'r':
3385 val = '\r';
3386 break;
3387 case 't':
3388 val = '\t';
3389 break;
3390 case 'v':
3391 val = '\v';
3392 break;
3393 case '\\':
3394 val = '\\';
3395 break;
3396 case '\'':
3397 val = '\'';
3398 break;
3399 case '"':
3400 val = '"';
3401 break;
3402 case '?':
3403 val = '?';
3404 break;
3405 default:
3406 error("Undefined character escape %c", ch);
3407 break;
3408 }
3409 inp();
3410 return val;
3411 }
3412 } else {
3413 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003414 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003415 return val;
3416 }
3417
3418 static bool isoctal(int ch) {
3419 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003420 }
3421
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003422 bool acceptCh(int c) {
3423 bool result = c == ch;
3424 if (result) {
3425 pdef(ch);
3426 inp();
3427 }
3428 return result;
3429 }
3430
3431 bool acceptDigitsCh() {
3432 bool result = false;
3433 while (isdigit(ch)) {
3434 result = true;
3435 pdef(ch);
3436 inp();
3437 }
3438 return result;
3439 }
3440
3441 void parseFloat() {
3442 tok = TOK_NUM_DOUBLE;
3443 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003444 if(mTokenString.len() == 0) {
3445 mTokenString.append('0');
3446 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003447 acceptCh('.');
3448 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003449 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003450 acceptCh('-') || acceptCh('+');
3451 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003452 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003453 if (ch == 'f' || ch == 'F') {
3454 tok = TOK_NUM_FLOAT;
3455 inp();
3456 } else if (ch == 'l' || ch == 'L') {
3457 inp();
3458 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003459 }
3460 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003461 char* pEnd = pText + strlen(pText);
3462 char* pEndPtr = 0;
3463 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003464 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003465 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003466 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003467 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003468 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003469 if (errno || pEndPtr != pEnd) {
3470 error("Can't parse constant: %s", pText);
3471 }
3472 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003473 }
3474
Jack Palevich21a15a22009-05-11 14:49:29 -07003475 void next() {
3476 int l, a;
3477
Jack Palevich546b2242009-05-13 15:10:04 -07003478 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003479 if (ch == '#') {
3480 inp();
3481 next();
3482 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003483 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003484 } else if (tok == TOK_PRAGMA) {
3485 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003486 } else if (tok == TOK_LINE) {
3487 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003488 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003489 error("Unsupported preprocessor directive \"%s\"",
3490 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003491 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003492 }
3493 inp();
3494 }
3495 tokl = 0;
3496 tok = ch;
3497 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003498 if (isdigit(ch) || ch == '.') {
3499 // Start of a numeric constant. Could be integer, float, or
3500 // double, won't know until we look further.
3501 mTokenString.clear();
3502 pdef(ch);
3503 inp();
3504 int base = 10;
3505 if (tok == '0') {
3506 if (ch == 'x' || ch == 'X') {
3507 base = 16;
3508 tok = TOK_NUM;
3509 tokc = 0;
3510 inp();
3511 while ( isxdigit(ch) ) {
3512 tokc = (tokc << 4) + decodeHex(ch);
3513 inp();
3514 }
3515 } else if (isoctal(ch)){
3516 base = 8;
3517 tok = TOK_NUM;
3518 tokc = 0;
3519 while ( isoctal(ch) ) {
3520 tokc = (tokc << 3) + (ch - '0');
3521 inp();
3522 }
3523 }
3524 } else if (isdigit(tok)){
3525 acceptDigitsCh();
3526 }
3527 if (base == 10) {
3528 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3529 parseFloat();
3530 } else {
3531 // It's an integer constant
3532 char* pText = mTokenString.getUnwrapped();
3533 char* pEnd = pText + strlen(pText);
3534 char* pEndPtr = 0;
3535 errno = 0;
3536 tokc = strtol(pText, &pEndPtr, base);
3537 if (errno || pEndPtr != pEnd) {
3538 error("Can't parse constant: %s %d %d", pText, base, errno);
3539 }
3540 tok = TOK_NUM;
3541 }
3542 }
3543 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003544 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003545 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003546 pdef(ch);
3547 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003548 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003549 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3550 // Is this a macro?
3551 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3552 if (pMacroDefinition) {
3553 // Yes, it is a macro
3554 dptr = pMacroDefinition;
3555 dch = ch;
3556 inp();
3557 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003558 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003559 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003560 inp();
3561 if (tok == '\'') {
3562 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003563 tokc = getq();
3564 if (ch != '\'') {
3565 error("Expected a ' character, got %c", ch);
3566 } else {
3567 inp();
3568 }
Jack Palevich546b2242009-05-13 15:10:04 -07003569 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003570 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003571 while (ch && ch != EOF) {
3572 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003573 inp();
3574 inp();
3575 if (ch == '/')
3576 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003577 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003578 if (ch == EOF) {
3579 error("End of file inside comment.");
3580 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003581 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003582 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003583 } else if ((tok == '/') & (ch == '/')) {
3584 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003585 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003586 inp();
3587 }
3588 inp();
3589 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003590 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003591 const char* t = operatorChars;
3592 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003593 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003594 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003595 tokl = operatorLevel[opIndex];
3596 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003597 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003598#if 0
3599 printf("%c%c -> tokl=%d tokc=0x%x\n",
3600 l, a, tokl, tokc);
3601#endif
3602 if (a == ch) {
3603 inp();
3604 tok = TOK_DUMMY; /* dummy token for double tokens */
3605 }
3606 break;
3607 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003608 opIndex++;
3609 }
3610 if (l == 0) {
3611 tokl = 0;
3612 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003613 }
3614 }
3615 }
3616#if 0
3617 {
Jack Palevich569f1352009-06-29 14:29:08 -07003618 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003619 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003620 fprintf(stderr, "%s\n", buf.getUnwrapped());
3621 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003622#endif
3623 }
3624
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003625 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003626 next();
3627 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003628 String* pName = new String();
3629 while (isspace(ch)) {
3630 inp();
3631 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003632 if (ch == '(') {
3633 delete pName;
3634 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003635 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003636 }
3637 while (isspace(ch)) {
3638 inp();
3639 }
Jack Palevich569f1352009-06-29 14:29:08 -07003640 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003641 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003642 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003643 inp();
3644 }
Jack Palevich569f1352009-06-29 14:29:08 -07003645 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3646 memcpy(pDefn, value.getUnwrapped(), value.len());
3647 pDefn[value.len()] = 0;
3648 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003649 }
3650
Jack Palevicheedf9d22009-06-04 16:23:40 -07003651 void doPragma() {
3652 // # pragma name(val)
3653 int state = 0;
3654 while(ch != EOF && ch != '\n' && state < 10) {
3655 switch(state) {
3656 case 0:
3657 if (isspace(ch)) {
3658 inp();
3659 } else {
3660 state++;
3661 }
3662 break;
3663 case 1:
3664 if (isalnum(ch)) {
3665 mPragmas.append(ch);
3666 inp();
3667 } else if (ch == '(') {
3668 mPragmas.append(0);
3669 inp();
3670 state++;
3671 } else {
3672 state = 11;
3673 }
3674 break;
3675 case 2:
3676 if (isalnum(ch)) {
3677 mPragmas.append(ch);
3678 inp();
3679 } else if (ch == ')') {
3680 mPragmas.append(0);
3681 inp();
3682 state = 10;
3683 } else {
3684 state = 11;
3685 }
3686 break;
3687 }
3688 }
3689 if(state != 10) {
3690 error("Unexpected pragma syntax");
3691 }
3692 mPragmaStringCount += 2;
3693 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003694
Jack Palevichdc456462009-07-16 16:50:56 -07003695 void doLine() {
3696 // # line number { "filename "}
3697 next();
3698 if (tok != TOK_NUM) {
3699 error("Expected a line-number");
3700 } else {
3701 mLineNumber = tokc-1; // The end-of-line will increment it.
3702 }
3703 while(ch != EOF && ch != '\n') {
3704 inp();
3705 }
3706 }
3707
Jack Palevichac0e95e2009-05-29 13:53:44 -07003708 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003709 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003710 mErrorBuf.vprintf(fmt, ap);
3711 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003712 }
3713
Jack Palevich8b0624c2009-05-20 12:12:06 -07003714 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003715 if (tok != c) {
3716 error("'%c' expected", c);
3717 }
3718 next();
3719 }
3720
Jack Palevich86351982009-06-30 18:09:56 -07003721 bool accept(intptr_t c) {
3722 if (tok == c) {
3723 next();
3724 return true;
3725 }
3726 return false;
3727 }
3728
Jack Palevich40600de2009-07-01 15:32:35 -07003729 bool acceptStringLiteral() {
3730 if (tok == '"') {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003731 pGen->leaR0((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003732 // This while loop merges multiple adjacent string constants.
3733 while (tok == '"') {
3734 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003735 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003736 }
3737 if (ch != '"') {
3738 error("Unterminated string constant.");
3739 }
3740 inp();
3741 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003742 }
Jack Palevich40600de2009-07-01 15:32:35 -07003743 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003744 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003745 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003746 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003747
3748 return true;
3749 }
3750 return false;
3751 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003752
Jack Palevichb1544ca2009-07-16 15:09:20 -07003753 void linkGlobal(tokenid_t t, bool isFunction) {
3754 VariableInfo* pVI = VI(t);
3755 void* n = NULL;
3756 if (mpSymbolLookupFn) {
3757 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3758 }
3759 if (pVI->pType == NULL) {
3760 if (isFunction) {
3761 pVI->pType = mkpIntFn;
3762 } else {
3763 pVI->pType = mkpInt;
3764 }
3765 }
3766 pVI->pAddress = n;
3767 }
3768
Jack Palevich40600de2009-07-01 15:32:35 -07003769 /* Parse and evaluate a unary expression.
3770 * allowAssignment is true if '=' parsing wanted (quick hack)
3771 */
3772 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003773 tokenid_t t;
3774 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003775 t = 0;
3776 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3777 if (acceptStringLiteral()) {
3778 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003779 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003780 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003781 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003782 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003783 t = tok;
3784 next();
3785 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003786 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003787 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003788 // Align to 4-byte boundary
3789 glo = (char*) (((intptr_t) glo + 3) & -4);
3790 * (float*) glo = (float) ad;
3791 pGen->loadFloat((int) glo, mkpFloat);
3792 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003793 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003794 // Align to 8-byte boundary
3795 glo = (char*) (((intptr_t) glo + 7) & -8);
3796 * (double*) glo = ad;
3797 pGen->loadFloat((int) glo, mkpDouble);
3798 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003799 } else if (c == 2) {
3800 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003801 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003802 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003803 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003804 else if (t == '+') {
3805 // ignore unary plus.
3806 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003807 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003808 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003809 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003810 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07003811 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07003812 if (pCast) {
3813 skip(')');
3814 unary(false);
3815 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003816 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003817 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003818 skip(')');
3819 }
3820 } else if (t == '*') {
3821 /* This is a pointer dereference.
3822 */
3823 unary(false);
3824 Type* pR0Type = pGen->getR0Type();
3825 if (pR0Type->tag != TY_POINTER) {
3826 error("Expected a pointer type.");
3827 } else {
3828 if (pR0Type->pHead->tag == TY_FUNC) {
3829 t = 0;
3830 }
3831 if (accept('=')) {
3832 pGen->pushR0();
3833 expr();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003834 pGen->storeR0ToTOS();
Jack Palevich45431bc2009-07-13 15:57:26 -07003835 } else if (t) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003836 pGen->loadR0FromR0();
Jack Palevich45431bc2009-07-13 15:57:26 -07003837 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003838 }
Jack Palevich3f226492009-07-02 14:46:19 -07003839 // Else we fall through to the function call below, with
3840 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003841 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003842 VariableInfo* pVI = VI(tok);
Jack Palevich2ff5c222009-07-23 15:11:22 -07003843 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType));
Jack Palevich21a15a22009-05-11 14:49:29 -07003844 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003845 } else if (t == EOF ) {
3846 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003847 } else if (t == ';') {
3848 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003849 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003850 // Don't have to do anything special here, the error
3851 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003852 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003853 if (!isDefined(t)) {
3854 mGlobals.add(t);
3855 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003856 }
Jack Palevich8df46192009-07-07 14:48:51 -07003857 VariableInfo* pVI = VI(t);
3858 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003859 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003860 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003861 linkGlobal(t, tok == '(');
3862 n = (intptr_t) pVI->pAddress;
3863 if (!n && tok != '(') {
3864 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003865 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003866 }
Jack Palevich40600de2009-07-01 15:32:35 -07003867 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003868 /* assignment */
3869 next();
Jack Palevich8968e8e2009-07-30 16:57:33 -07003870 pGen->leaR0(n, createPtrType(pVI->pType));
3871 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003872 expr();
Jack Palevich8968e8e2009-07-30 16:57:33 -07003873 pGen->storeR0ToTOS();
Jack Palevich21a15a22009-05-11 14:49:29 -07003874 } else if (tok != '(') {
3875 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003876 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003877 linkGlobal(t, false);
3878 n = (intptr_t) pVI->pAddress;
3879 if (!n) {
3880 error("Undeclared variable %s\n", nameof(t));
3881 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003882 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07003883 // load a variable
Jack Palevich21a15a22009-05-11 14:49:29 -07003884 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003885 // post inc / post dec
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003886 pGen->leaR0(n, createPtrType(pVI->pType));
3887
Jack Palevich58c30ee2009-07-17 16:35:23 -07003888 pGen->pushR0();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003889 pGen->loadR0FromR0();
3890 pGen->over();
3891 int lit = 1;
3892 if (tokc == OP_DECREMENT) {
3893 lit = -1;
3894 }
3895 switch (pVI->pType->tag) {
3896 case TY_INT:
3897 case TY_CHAR:
3898 case TY_POINTER:
3899 pGen->pushR0();
3900 pGen->li(lit);
3901 pGen->genOp(OP_PLUS);
3902 break;
3903 default:
3904 error("++/-- illegal for this type.");
3905 break;
3906 }
3907
3908 pGen->storeR0ToTOS();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003909 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003910 next();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003911 } else {
Jack Palevicha7813bd2009-07-29 11:36:04 -07003912 pGen->leaR0(n, createPtrType(pVI->pType));
3913 pGen->loadR0FromR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003914 }
3915 }
3916 }
3917 }
3918
3919 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003920 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003921 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003922 VariableInfo* pVI = NULL;
3923 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevich9f51a262009-07-29 16:22:26 -07003924 Type* pFn = pGen->getR0Type();
3925 assert(pFn->tag == TY_POINTER);
3926 assert(pFn->pHead->tag == TY_FUNC);
3927 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07003928 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003929 } else {
3930 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003931 pDecl = pVI->pType;
Jack Palevich9f51a262009-07-29 16:22:26 -07003932 Type* pFn = createPtrType(pDecl);
3933 if (n == 0) {
3934 pVI->pForward = (void*) pGen->leaForward(
3935 (int) pVI->pForward, pFn);
3936 } else {
3937 pGen->leaR0(n, pFn);
3938 }
3939 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003940 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003941 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003942 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003943 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003944 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003945 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003946 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003947 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003948 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07003949 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07003950 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003951 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003952 Type* pTargetType;
3953 if (pArgList) {
3954 pTargetType = pArgList->pHead;
3955 pArgList = pArgList->pTail;
3956 } else {
Jack Palevich9f51a262009-07-29 16:22:26 -07003957 // This is a ... function, just pass arguments in their
3958 // natural type.
Jack Palevich1a539db2009-07-08 13:04:41 -07003959 pTargetType = pGen->getR0Type();
3960 if (pTargetType->tag == TY_FLOAT) {
3961 pTargetType = mkpDouble;
3962 }
3963 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003964 if (pTargetType->tag == TY_VOID) {
3965 error("Can't pass void value for argument %d",
3966 argCount + 1);
3967 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003968 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003969 }
Jack Palevich95727a02009-07-06 12:07:15 -07003970 if (accept(',')) {
3971 // fine
3972 } else if ( tok != ')') {
3973 error("Expected ',' or ')'");
3974 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003975 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003976 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003977 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07003978 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003979 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003980 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003981 skip(')');
Jack Palevich9f51a262009-07-29 16:22:26 -07003982 pGen->callIndirect(l, pDecl);
3983 pGen->adjustStackAfterCall(pDecl, l, true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003984 }
3985 }
3986
Jack Palevich40600de2009-07-01 15:32:35 -07003987 /* Recursive descent parser for binary operations.
3988 */
3989 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07003990 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003991 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003992 if (level-- == 1)
3993 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003994 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003995 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003996 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003997 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003998 t = tokc;
3999 next();
4000
Jack Palevich40600de2009-07-01 15:32:35 -07004001 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004002 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004003 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004004 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004005 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004006 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004007 // Check for syntax error.
4008 if (pGen->getR0Type() == NULL) {
4009 // We failed to parse a right-hand argument.
4010 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004011 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004012 }
Jack Palevich40600de2009-07-01 15:32:35 -07004013 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004014 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004015 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004016 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004017 }
4018 }
4019 }
4020 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004021 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004022 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004023 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004024 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004025 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004026 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004027 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004028 }
4029 }
4030 }
4031
4032 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004033 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004034 }
4035
4036 int test_expr() {
4037 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004038 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004039 }
4040
Jack Palevicha6baa232009-06-12 11:25:59 -07004041 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004042 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004043
Jack Palevich95727a02009-07-06 12:07:15 -07004044 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004045 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004046 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004047 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004048 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004049 next();
4050 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004051 a = test_expr();
4052 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004053 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004054 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004055 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004056 n = pGen->gjmp(0); /* jmp */
4057 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004058 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004059 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004060 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004061 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004062 }
Jack Palevich546b2242009-05-13 15:10:04 -07004063 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004064 t = tok;
4065 next();
4066 skip('(');
4067 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004068 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004069 a = test_expr();
4070 } else {
4071 if (tok != ';')
4072 expr();
4073 skip(';');
4074 n = codeBuf.getPC();
4075 a = 0;
4076 if (tok != ';')
4077 a = test_expr();
4078 skip(';');
4079 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004080 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004081 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004082 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004083 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004084 n = t + 4;
4085 }
4086 }
4087 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004088 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004089 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004090 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004091 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004092 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004093 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004094 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004095 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004096 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004097 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004098 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004099 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004100 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004101 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004102 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004103 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004104 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004105 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004106 if (pReturnType->tag == TY_VOID) {
4107 error("Must not return a value from a void function");
4108 } else {
4109 pGen->convertR0(pReturnType);
4110 }
4111 } else {
4112 if (pReturnType->tag != TY_VOID) {
4113 error("Must specify a value here");
4114 }
Jack Palevich8df46192009-07-07 14:48:51 -07004115 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004116 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004117 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004118 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004119 } else if (tok != ';')
4120 expr();
4121 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004122 }
4123 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004124
Jack Palevicha8f427f2009-07-13 18:40:08 -07004125 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004126 if (a == b) {
4127 return true;
4128 }
4129 if (a == NULL || b == NULL) {
4130 return false;
4131 }
4132 TypeTag at = a->tag;
4133 if (at != b->tag) {
4134 return false;
4135 }
4136 if (at == TY_POINTER) {
4137 return typeEqual(a->pHead, b->pHead);
4138 } else if (at == TY_FUNC || at == TY_PARAM) {
4139 return typeEqual(a->pHead, b->pHead)
4140 && typeEqual(a->pTail, b->pTail);
4141 }
4142 return true;
4143 }
4144
Jack Palevich2ff5c222009-07-23 15:11:22 -07004145 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004146 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004147 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004148 memset(pType, 0, sizeof(*pType));
4149 pType->tag = tag;
4150 pType->pHead = pHead;
4151 pType->pTail = pTail;
4152 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004153 }
4154
Jack Palevich2ff5c222009-07-23 15:11:22 -07004155 Type* createPtrType(Type* pType) {
4156 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004157 }
4158
4159 /**
4160 * Try to print a type in declaration order
4161 */
Jack Palevich86351982009-06-30 18:09:56 -07004162 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004163 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004164 if (pType == NULL) {
4165 buffer.appendCStr("null");
4166 return;
4167 }
Jack Palevich3f226492009-07-02 14:46:19 -07004168 decodeTypeImp(buffer, pType);
4169 }
4170
4171 void decodeTypeImp(String& buffer, Type* pType) {
4172 decodeTypeImpPrefix(buffer, pType);
4173
Jack Palevich86351982009-06-30 18:09:56 -07004174 String temp;
4175 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004176 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004177 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004178 }
4179
4180 decodeTypeImpPostfix(buffer, pType);
4181 }
4182
4183 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4184 TypeTag tag = pType->tag;
4185
Jack Palevich37c54bd2009-07-14 18:35:36 -07004186 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004187 switch (tag) {
4188 case TY_INT:
4189 buffer.appendCStr("int");
4190 break;
4191 case TY_CHAR:
4192 buffer.appendCStr("char");
4193 break;
4194 case TY_VOID:
4195 buffer.appendCStr("void");
4196 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004197 case TY_FLOAT:
4198 buffer.appendCStr("float");
4199 break;
4200 case TY_DOUBLE:
4201 buffer.appendCStr("double");
4202 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004203 default:
4204 break;
4205 }
Jack Palevich86351982009-06-30 18:09:56 -07004206 buffer.append(' ');
4207 }
Jack Palevich3f226492009-07-02 14:46:19 -07004208
4209 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004210 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004211 break;
4212 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004213 break;
4214 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004215 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004216 case TY_FLOAT:
4217 break;
4218 case TY_DOUBLE:
4219 break;
Jack Palevich86351982009-06-30 18:09:56 -07004220 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004221 decodeTypeImpPrefix(buffer, pType->pHead);
4222 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4223 buffer.append('(');
4224 }
4225 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004226 break;
4227 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004228 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004229 break;
4230 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004231 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004232 break;
4233 default:
4234 String temp;
4235 temp.printf("Unknown tag %d", pType->tag);
4236 buffer.append(temp);
4237 break;
4238 }
Jack Palevich3f226492009-07-02 14:46:19 -07004239 }
4240
4241 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4242 TypeTag tag = pType->tag;
4243
4244 switch(tag) {
4245 case TY_POINTER:
4246 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4247 buffer.append(')');
4248 }
4249 decodeTypeImpPostfix(buffer, pType->pHead);
4250 break;
4251 case TY_FUNC:
4252 buffer.append('(');
4253 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4254 decodeTypeImp(buffer, pArg);
4255 if (pArg->pTail) {
4256 buffer.appendCStr(", ");
4257 }
4258 }
4259 buffer.append(')');
4260 break;
4261 default:
4262 break;
Jack Palevich86351982009-06-30 18:09:56 -07004263 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004264 }
4265
Jack Palevich86351982009-06-30 18:09:56 -07004266 void printType(Type* pType) {
4267 String buffer;
4268 decodeType(buffer, pType);
4269 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004270 }
4271
Jack Palevich2ff5c222009-07-23 15:11:22 -07004272 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004273 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004274 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004275 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004276 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004277 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004278 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004279 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004280 } else if (tok == TOK_FLOAT) {
4281 pType = mkpFloat;
4282 } else if (tok == TOK_DOUBLE) {
4283 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004284 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004285 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004286 }
4287 next();
Jack Palevich86351982009-06-30 18:09:56 -07004288 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004289 }
4290
Jack Palevich2ff5c222009-07-23 15:11:22 -07004291 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004292 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004293 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004294 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004295 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004296 if (declName) {
4297 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004298 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004299
Jack Palevich86351982009-06-30 18:09:56 -07004300 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004301 }
Jack Palevich3f226492009-07-02 14:46:19 -07004302 // fprintf(stderr, "Parsed a declaration: ");
4303 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004304 if (reportFailure) {
4305 return NULL;
4306 }
Jack Palevich86351982009-06-30 18:09:56 -07004307 return pType;
4308 }
4309
Jack Palevich2ff5c222009-07-23 15:11:22 -07004310 Type* expectDeclaration(Type* pBaseType) {
4311 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004312 if (! pType) {
4313 error("Expected a declaration");
4314 }
4315 return pType;
4316 }
4317
Jack Palevich3f226492009-07-02 14:46:19 -07004318 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004319 Type* acceptCastTypeDeclaration() {
4320 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004321 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004322 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004323 }
Jack Palevich86351982009-06-30 18:09:56 -07004324 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004325 }
4326
Jack Palevich2ff5c222009-07-23 15:11:22 -07004327 Type* expectCastTypeDeclaration() {
4328 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004329 if (! pType) {
4330 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004331 }
Jack Palevich3f226492009-07-02 14:46:19 -07004332 return pType;
4333 }
4334
4335 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004336 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004337 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004338 int ptrCounter = 0;
4339 while (accept('*')) {
4340 ptrCounter++;
4341 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004342 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004343 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004344 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004345 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004346 }
4347 return pType;
4348 }
4349
4350 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004351 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004352 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004353 // direct-dcl :
4354 // name
4355 // (dcl)
4356 // direct-dcl()
4357 // direct-dcl[]
4358 Type* pNewHead = NULL;
4359 if (accept('(')) {
4360 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004361 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004362 skip(')');
4363 } else if ((declName = acceptSymbol()) != 0) {
4364 if (nameAllowed == false && declName) {
4365 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004366 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004367 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004368 } else if (nameRequired && ! declName) {
4369 String temp;
4370 decodeToken(temp, tok, true);
4371 error("Expected name. Got %s", temp.getUnwrapped());
4372 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004373 }
4374 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004375 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004376 Type* pTail = acceptArgs(nameAllowed);
4377 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004378 skip(')');
4379 }
Jack Palevich3f226492009-07-02 14:46:19 -07004380
4381 if (pNewHead) {
4382 Type* pA = pNewHead;
4383 while (pA->pHead) {
4384 pA = pA->pHead;
4385 }
4386 pA->pHead = pType;
4387 pType = pNewHead;
4388 }
Jack Palevich86351982009-06-30 18:09:56 -07004389 return pType;
4390 }
4391
Jack Palevich2ff5c222009-07-23 15:11:22 -07004392 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004393 Type* pHead = NULL;
4394 Type* pTail = NULL;
4395 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004396 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004397 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004398 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004399 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004400 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004401 if (!pHead) {
4402 pHead = pParam;
4403 pTail = pParam;
4404 } else {
4405 pTail->pTail = pParam;
4406 pTail = pParam;
4407 }
4408 }
4409 }
4410 if (! accept(',')) {
4411 break;
4412 }
4413 }
4414 return pHead;
4415 }
4416
Jack Palevich2ff5c222009-07-23 15:11:22 -07004417 Type* expectPrimitiveType() {
4418 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004419 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004420 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004421 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004422 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004423 }
Jack Palevich86351982009-06-30 18:09:56 -07004424 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004425 }
4426
Jack Palevich86351982009-06-30 18:09:56 -07004427 void addGlobalSymbol(Type* pDecl) {
4428 tokenid_t t = pDecl->id;
4429 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004430 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004431 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004432 }
Jack Palevich86351982009-06-30 18:09:56 -07004433 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004434 }
4435
Jack Palevich86351982009-06-30 18:09:56 -07004436 void reportDuplicate(tokenid_t t) {
4437 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004438 }
4439
Jack Palevich86351982009-06-30 18:09:56 -07004440 void addLocalSymbol(Type* pDecl) {
4441 tokenid_t t = pDecl->id;
4442 if (mLocals.isDefinedAtCurrentLevel(t)) {
4443 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004444 }
Jack Palevich86351982009-06-30 18:09:56 -07004445 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004446 }
4447
Jack Palevich95727a02009-07-06 12:07:15 -07004448 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004449 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004450
Jack Palevich95727a02009-07-06 12:07:15 -07004451 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004452 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004453 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004454 if (!pDecl) {
4455 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004456 }
Jack Palevich86351982009-06-30 18:09:56 -07004457 int variableAddress = 0;
4458 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004459 size_t alignment = pGen->stackAlignmentOf(pDecl);
4460 size_t alignmentMask = ~ (alignment - 1);
4461 size_t sizeOf = pGen->sizeOf(pDecl);
4462 loc = (loc + alignment - 1) & alignmentMask;
4463 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4464 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004465 variableAddress = -loc;
4466 VI(pDecl->id)->pAddress = (void*) variableAddress;
4467 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004468 /* assignment */
Jack Palevich8968e8e2009-07-30 16:57:33 -07004469 pGen->leaR0(variableAddress, createPtrType(pDecl));
4470 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004471 expr();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004472 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004473 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004474 if (tok == ',')
4475 next();
4476 }
4477 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004478 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004479 }
4480 }
4481
Jack Palevichf1728be2009-06-12 13:53:51 -07004482 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004483 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004484 }
4485
Jack Palevich37c54bd2009-07-14 18:35:36 -07004486 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004487 if (token == EOF ) {
4488 buffer.printf("EOF");
4489 } else if (token == TOK_NUM) {
4490 buffer.printf("numeric constant");
4491 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004492 if (token < 32) {
4493 buffer.printf("'\\x%02x'", token);
4494 } else {
4495 buffer.printf("'%c'", token);
4496 }
Jack Palevich569f1352009-06-29 14:29:08 -07004497 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004498 if (quote) {
4499 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4500 buffer.printf("keyword \"%s\"", nameof(token));
4501 } else {
4502 buffer.printf("symbol \"%s\"", nameof(token));
4503 }
4504 } else {
4505 buffer.printf("%s", nameof(token));
4506 }
Jack Palevich569f1352009-06-29 14:29:08 -07004507 }
4508 }
4509
Jack Palevich40600de2009-07-01 15:32:35 -07004510 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004511 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004512 if (!result) {
4513 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004514 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004515 error("Expected symbol. Got %s", temp.getUnwrapped());
4516 }
4517 return result;
4518 }
4519
Jack Palevich86351982009-06-30 18:09:56 -07004520 tokenid_t acceptSymbol() {
4521 tokenid_t result = 0;
4522 if (tok >= TOK_SYMBOL) {
4523 result = tok;
4524 next();
Jack Palevich86351982009-06-30 18:09:56 -07004525 }
4526 return result;
4527 }
4528
Jack Palevichb7c81e92009-06-04 19:56:13 -07004529 void globalDeclarations() {
4530 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004531 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004532 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004533 break;
4534 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004535 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004536 if (!pDecl) {
4537 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004538 }
Jack Palevich86351982009-06-30 18:09:56 -07004539 if (! isDefined(pDecl->id)) {
4540 addGlobalSymbol(pDecl);
4541 }
4542 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004543 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004544 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004545 }
Jack Palevich86351982009-06-30 18:09:56 -07004546 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004547 // it's a variable declaration
4548 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004549 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004550 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004551 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004552 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004553 }
Jack Palevich86351982009-06-30 18:09:56 -07004554 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004555 if (tok == TOK_NUM) {
4556 if (name) {
4557 * (int*) name->pAddress = tokc;
4558 }
4559 next();
4560 } else {
4561 error("Expected an integer constant");
4562 }
4563 }
Jack Palevich86351982009-06-30 18:09:56 -07004564 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004565 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004566 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004567 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004568 if (!pDecl) {
4569 break;
4570 }
4571 if (! isDefined(pDecl->id)) {
4572 addGlobalSymbol(pDecl);
4573 }
4574 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004575 }
4576 skip(';');
4577 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004578 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004579 if (accept(';')) {
4580 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004581 } else if (tok != '{') {
4582 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004583 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004584 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004585 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004586 /* patch forward references */
4587 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004588 /* put function address */
4589 name->pAddress = (void*) codeBuf.getPC();
4590 }
4591 // Calculate stack offsets for parameters
4592 mLocals.pushLevel();
4593 intptr_t a = 8;
4594 int argCount = 0;
4595 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4596 Type* pArg = pP->pHead;
4597 addLocalSymbol(pArg);
4598 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004599 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004600 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004601 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004602 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004603 argCount++;
4604 }
4605 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004606 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004607 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004608 block(0, true);
4609 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004610 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004611 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004612 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004613 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004614 }
4615 }
4616 }
4617
Jack Palevich9cbd2262009-07-08 16:48:41 -07004618 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4619 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4620 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004621 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004622 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004623 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004624 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004625 char* result = (char*) base;
4626 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004627 return result;
4628 }
4629
Jack Palevich21a15a22009-05-11 14:49:29 -07004630 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004631 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004632 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004633 pGlobalBase = 0;
4634 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004635 if (pGen) {
4636 delete pGen;
4637 pGen = 0;
4638 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004639 if (file) {
4640 delete file;
4641 file = 0;
4642 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004643 }
4644
Jack Palevich8c246a92009-07-14 21:14:10 -07004645 // One-time initialization, when class is constructed.
4646 void init() {
4647 mpSymbolLookupFn = 0;
4648 mpSymbolLookupContext = 0;
4649 }
4650
Jack Palevich21a15a22009-05-11 14:49:29 -07004651 void clear() {
4652 tok = 0;
4653 tokc = 0;
4654 tokl = 0;
4655 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004656 rsym = 0;
4657 loc = 0;
4658 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004659 dptr = 0;
4660 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004661 file = 0;
4662 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004663 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004664 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004665 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004666 mLineNumber = 1;
4667 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004668 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004669
Jack Palevich22305132009-05-13 10:58:45 -07004670 void setArchitecture(const char* architecture) {
4671 delete pGen;
4672 pGen = 0;
4673
4674 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004675#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004676 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004677 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004678 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004679#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004680#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004681 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004682 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004683 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004684#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004685 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004686 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004687 }
4688 }
4689
4690 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004691#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004692 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004693#elif defined(DEFAULT_X86_CODEGEN)
4694 pGen = new X86CodeGenerator();
4695#endif
4696 }
4697 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004698 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004699 } else {
4700 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004701 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004702 }
4703 }
4704
Jack Palevich77ae76e2009-05-10 19:59:24 -07004705public:
Jack Palevich22305132009-05-13 10:58:45 -07004706 struct args {
4707 args() {
4708 architecture = 0;
4709 }
4710 const char* architecture;
4711 };
4712
Jack Paleviche7b59062009-05-19 17:12:17 -07004713 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004714 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004715 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004716 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004717
Jack Paleviche7b59062009-05-19 17:12:17 -07004718 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004719 cleanup();
4720 }
4721
Jack Palevich8c246a92009-07-14 21:14:10 -07004722 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4723 mpSymbolLookupFn = pFn;
4724 mpSymbolLookupContext = pContext;
4725 }
4726
Jack Palevich1cdef202009-05-22 12:06:27 -07004727 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004728 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004729
Jack Palevich2ff5c222009-07-23 15:11:22 -07004730 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004731 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004732 cleanup();
4733 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004734 mTokenTable.setArena(&mGlobalArena);
4735 mGlobals.setArena(&mGlobalArena);
4736 mGlobals.setTokenTable(&mTokenTable);
4737 mLocals.setArena(&mLocalArena);
4738 mLocals.setTokenTable(&mTokenTable);
4739
4740 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004741 codeBuf.init(ALLOC_SIZE);
4742 setArchitecture(NULL);
4743 if (!pGen) {
4744 return -1;
4745 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004746#ifdef PROVIDE_TRACE_CODEGEN
4747 pGen = new TraceCodeGenerator(pGen);
4748#endif
4749 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004750 pGen->init(&codeBuf);
4751 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004752 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4753 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004754 inp();
4755 next();
4756 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004757 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004758 result = pGen->finishCompile();
4759 if (result == 0) {
4760 if (mErrorBuf.len()) {
4761 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004762 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004763 }
Jack Palevichce105a92009-07-16 14:30:33 -07004764 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004765 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004766 }
4767
Jack Palevich86351982009-06-30 18:09:56 -07004768 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004769 mkpInt = createType(TY_INT, NULL, NULL);
4770 mkpChar = createType(TY_CHAR, NULL, NULL);
4771 mkpVoid = createType(TY_VOID, NULL, NULL);
4772 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4773 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4774 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4775 mkpIntPtr = createPtrType(mkpInt);
4776 mkpCharPtr = createPtrType(mkpChar);
4777 mkpFloatPtr = createPtrType(mkpFloat);
4778 mkpDoublePtr = createPtrType(mkpDouble);
4779 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004780 }
4781
Jack Palevicha6baa232009-06-12 11:25:59 -07004782 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004783 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004784 }
4785
Jack Palevich569f1352009-06-29 14:29:08 -07004786 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004787 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004788 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004789 }
4790
Jack Palevich569f1352009-06-29 14:29:08 -07004791 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004792 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004793 error("Undefined forward reference: %s",
4794 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004795 }
4796 return true;
4797 }
4798
Jack Palevich21a15a22009-05-11 14:49:29 -07004799 int dump(FILE* out) {
4800 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4801 return 0;
4802 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004803
Jack Palevicha6535612009-05-13 16:24:17 -07004804 int disassemble(FILE* out) {
4805 return pGen->disassemble(out);
4806 }
4807
Jack Palevich1cdef202009-05-22 12:06:27 -07004808 /* Look through the symbol table to find a symbol.
4809 * If found, return its value.
4810 */
4811 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004812 if (mCompileResult == 0) {
4813 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4814 VariableInfo* pVariableInfo = VI(tok);
4815 if (pVariableInfo) {
4816 return pVariableInfo->pAddress;
4817 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004818 }
4819 return NULL;
4820 }
4821
Jack Palevicheedf9d22009-06-04 16:23:40 -07004822 void getPragmas(ACCsizei* actualStringCount,
4823 ACCsizei maxStringCount, ACCchar** strings) {
4824 int stringCount = mPragmaStringCount;
4825 if (actualStringCount) {
4826 *actualStringCount = stringCount;
4827 }
4828 if (stringCount > maxStringCount) {
4829 stringCount = maxStringCount;
4830 }
4831 if (strings) {
4832 char* pPragmas = mPragmas.getUnwrapped();
4833 while (stringCount-- > 0) {
4834 *strings++ = pPragmas;
4835 pPragmas += strlen(pPragmas) + 1;
4836 }
4837 }
4838 }
4839
Jack Palevichac0e95e2009-05-29 13:53:44 -07004840 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004841 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004842 }
4843
Jack Palevich77ae76e2009-05-10 19:59:24 -07004844};
4845
Jack Paleviche7b59062009-05-19 17:12:17 -07004846const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004847 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4848
Jack Paleviche7b59062009-05-19 17:12:17 -07004849const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004850 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4851 5, 5, /* ==, != */
4852 9, 10, /* &&, || */
4853 6, 7, 8, /* & ^ | */
4854 2, 2 /* ~ ! */
4855 };
4856
Jack Palevich8b0624c2009-05-20 12:12:06 -07004857#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004858FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004859#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004860
Jack Palevich8b0624c2009-05-20 12:12:06 -07004861#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004862const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004863 0x1, // ++
4864 0xff, // --
4865 0xc1af0f, // *
4866 0xf9f79991, // /
4867 0xf9f79991, // % (With manual assist to swap results)
4868 0xc801, // +
4869 0xd8f7c829, // -
4870 0xe0d391, // <<
4871 0xf8d391, // >>
4872 0xe, // <=
4873 0xd, // >=
4874 0xc, // <
4875 0xf, // >
4876 0x4, // ==
4877 0x5, // !=
4878 0x0, // &&
4879 0x1, // ||
4880 0xc821, // &
4881 0xc831, // ^
4882 0xc809, // |
4883 0xd0f7, // ~
4884 0x4 // !
4885};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004886#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004887
Jack Palevich1cdef202009-05-22 12:06:27 -07004888struct ACCscript {
4889 ACCscript() {
4890 text = 0;
4891 textLength = 0;
4892 accError = ACC_NO_ERROR;
4893 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004894
Jack Palevich1cdef202009-05-22 12:06:27 -07004895 ~ACCscript() {
4896 delete text;
4897 }
Jack Palevich546b2242009-05-13 15:10:04 -07004898
Jack Palevich8c246a92009-07-14 21:14:10 -07004899 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4900 compiler.registerSymbolCallback(pFn, pContext);
4901 }
4902
Jack Palevich1cdef202009-05-22 12:06:27 -07004903 void setError(ACCenum error) {
4904 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4905 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004906 }
4907 }
4908
Jack Palevich1cdef202009-05-22 12:06:27 -07004909 ACCenum getError() {
4910 ACCenum result = accError;
4911 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004912 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004913 }
4914
Jack Palevich1cdef202009-05-22 12:06:27 -07004915 Compiler compiler;
4916 char* text;
4917 int textLength;
4918 ACCenum accError;
4919};
4920
4921
4922extern "C"
4923ACCscript* accCreateScript() {
4924 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004925}
Jack Palevich1cdef202009-05-22 12:06:27 -07004926
4927extern "C"
4928ACCenum accGetError( ACCscript* script ) {
4929 return script->getError();
4930}
4931
4932extern "C"
4933void accDeleteScript(ACCscript* script) {
4934 delete script;
4935}
4936
4937extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004938void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4939 ACCvoid* pContext) {
4940 script->registerSymbolCallback(pFn, pContext);
4941}
4942
4943extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07004944void accScriptSource(ACCscript* script,
4945 ACCsizei count,
4946 const ACCchar ** string,
4947 const ACCint * length) {
4948 int totalLength = 0;
4949 for(int i = 0; i < count; i++) {
4950 int len = -1;
4951 const ACCchar* s = string[i];
4952 if (length) {
4953 len = length[i];
4954 }
4955 if (len < 0) {
4956 len = strlen(s);
4957 }
4958 totalLength += len;
4959 }
4960 delete script->text;
4961 char* text = new char[totalLength + 1];
4962 script->text = text;
4963 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004964 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004965 for(int i = 0; i < count; i++) {
4966 int len = -1;
4967 const ACCchar* s = string[i];
4968 if (length) {
4969 len = length[i];
4970 }
4971 if (len < 0) {
4972 len = strlen(s);
4973 }
Jack Palevich09555c72009-05-27 12:25:55 -07004974 memcpy(dest, s, len);
4975 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004976 }
4977 text[totalLength] = '\0';
4978}
4979
4980extern "C"
4981void accCompileScript(ACCscript* script) {
4982 int result = script->compiler.compile(script->text, script->textLength);
4983 if (result) {
4984 script->setError(ACC_INVALID_OPERATION);
4985 }
4986}
4987
4988extern "C"
4989void accGetScriptiv(ACCscript* script,
4990 ACCenum pname,
4991 ACCint * params) {
4992 switch (pname) {
4993 case ACC_INFO_LOG_LENGTH:
4994 *params = 0;
4995 break;
4996 }
4997}
4998
4999extern "C"
5000void accGetScriptInfoLog(ACCscript* script,
5001 ACCsizei maxLength,
5002 ACCsizei * length,
5003 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005004 char* message = script->compiler.getErrorMessage();
5005 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005006 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005007 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005008 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005009 if (infoLog && maxLength > 0) {
5010 int trimmedLength = maxLength < messageLength ?
5011 maxLength : messageLength;
5012 memcpy(infoLog, message, trimmedLength);
5013 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005014 }
5015}
5016
5017extern "C"
5018void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5019 ACCvoid ** address) {
5020 void* value = script->compiler.lookup(name);
5021 if (value) {
5022 *address = value;
5023 } else {
5024 script->setError(ACC_INVALID_VALUE);
5025 }
5026}
5027
Jack Palevicheedf9d22009-06-04 16:23:40 -07005028extern "C"
5029void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5030 ACCsizei maxStringCount, ACCchar** strings){
5031 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5032}
5033
-b master422972c2009-06-17 19:13:52 -07005034extern "C"
5035void accDisassemble(ACCscript* script) {
5036 script->compiler.disassemble(stderr);
5037}
5038
Jack Palevicheedf9d22009-06-04 16:23:40 -07005039
Jack Palevich1cdef202009-05-22 12:06:27 -07005040} // namespace acc
5041