blob: 60546f194c7bb29415c2309e63d43e85df9fb753 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040
41#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070042#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070043#endif
Jack Palevicha6535612009-05-13 16:24:17 -070044
Jack Palevich1cdef202009-05-22 12:06:27 -070045#include <acc/acc.h>
46
Jack Palevich09555c72009-05-27 12:25:55 -070047#define LOG_API(...) do {} while(0)
48// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070049
-b master422972c2009-06-17 19:13:52 -070050#define LOG_STACK(...) do {} while(0)
51// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
52
53// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichbbf8ab52009-05-11 11:54:30 -070056namespace acc {
57
Jack Palevichac0e95e2009-05-29 13:53:44 -070058class ErrorSink {
59public:
60 void error(const char *fmt, ...) {
61 va_list ap;
62 va_start(ap, fmt);
63 verror(fmt, ap);
64 va_end(ap);
65 }
66
67 virtual void verror(const char* fmt, va_list ap) = 0;
68};
69
70class Compiler : public ErrorSink {
Jack Palevich9eed7a22009-07-06 17:24:34 -070071 struct Type;
72
Jack Palevich21a15a22009-05-11 14:49:29 -070073 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070074 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070075 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070076 ErrorSink* mErrorSink;
77 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -070078 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -070079
Jack Palevich21a15a22009-05-11 14:49:29 -070080 void release() {
81 if (pProgramBase != 0) {
82 free(pProgramBase);
83 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070084 }
Jack Palevich21a15a22009-05-11 14:49:29 -070085 }
86
Jack Palevich0a280a02009-06-11 10:53:51 -070087 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -070088 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -070089 bool overflow = newSize > mSize;
90 if (overflow && !mOverflowed) {
91 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -070092 if (mErrorSink) {
93 mErrorSink->error("Code too large: %d bytes", newSize);
94 }
95 }
Jack Palevich0a280a02009-06-11 10:53:51 -070096 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -070097 }
98
Jack Palevich21a15a22009-05-11 14:49:29 -070099 public:
100 CodeBuf() {
101 pProgramBase = 0;
102 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700103 mErrorSink = 0;
104 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700105 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700106 }
107
108 ~CodeBuf() {
109 release();
110 }
111
112 void init(int size) {
113 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700114 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700115 pProgramBase = (char*) calloc(1, size);
116 ind = pProgramBase;
117 }
118
Jack Palevichac0e95e2009-05-29 13:53:44 -0700119 void setErrorSink(ErrorSink* pErrorSink) {
120 mErrorSink = pErrorSink;
121 }
122
Jack Palevich546b2242009-05-13 15:10:04 -0700123 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700124 if(check(4)) {
125 return 0;
126 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700127 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700128 * (int*) ind = n;
129 ind += 4;
130 return result;
131 }
132
Jack Palevich21a15a22009-05-11 14:49:29 -0700133 /*
134 * Output a byte. Handles all values, 0..ff.
135 */
136 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700137 if(check(1)) {
138 return;
139 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700140 *ind++ = n;
141 }
142
Jack Palevich21a15a22009-05-11 14:49:29 -0700143 inline void* getBase() {
144 return (void*) pProgramBase;
145 }
146
Jack Palevich8b0624c2009-05-20 12:12:06 -0700147 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 return ind - pProgramBase;
149 }
150
Jack Palevich8b0624c2009-05-20 12:12:06 -0700151 intptr_t getPC() {
152 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700153 }
154 };
155
Jack Palevich1cdef202009-05-22 12:06:27 -0700156 /**
157 * A code generator creates an in-memory program, generating the code on
158 * the fly. There is one code generator implementation for each supported
159 * architecture.
160 *
161 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700162 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700163 * FP - a frame pointer for accessing function arguments and local
164 * variables.
165 * SP - a stack pointer for storing intermediate results while evaluating
166 * expressions. The stack pointer grows downwards.
167 *
168 * The function calling convention is that all arguments are placed on the
169 * stack such that the first argument has the lowest address.
170 * After the call, the result is in R0. The caller is responsible for
171 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700172 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700173 * FP and SP registers are saved.
174 */
175
Jack Palevich21a15a22009-05-11 14:49:29 -0700176 class CodeGenerator {
177 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700178 CodeGenerator() {
179 mErrorSink = 0;
180 pCodeBuf = 0;
181 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700182 virtual ~CodeGenerator() {}
183
Jack Palevich22305132009-05-13 10:58:45 -0700184 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700185 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700186 pCodeBuf->setErrorSink(mErrorSink);
187 }
188
Jack Palevichb67b18f2009-06-11 21:12:23 -0700189 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700190 mErrorSink = pErrorSink;
191 if (pCodeBuf) {
192 pCodeBuf->setErrorSink(mErrorSink);
193 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700194 }
195
Jack Palevich1cdef202009-05-22 12:06:27 -0700196 /* Emit a function prolog.
197 * argCount is the number of arguments.
198 * Save the old value of the FP.
199 * Set the new value of the FP.
200 * Convert from the native platform calling convention to
201 * our stack-based calling convention. This may require
202 * pushing arguments from registers to the stack.
203 * Allocate "N" bytes of stack space. N isn't known yet, so
204 * just emit the instructions for adjusting the stack, and return
205 * the address to patch up. The patching will be done in
206 * functionExit().
207 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700208 */
Jack Palevich546b2242009-05-13 15:10:04 -0700209 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700210
Jack Palevich1cdef202009-05-22 12:06:27 -0700211 /* Emit a function epilog.
212 * Restore the old SP and FP register values.
213 * Return to the calling function.
214 * argCount - the number of arguments to the function.
215 * localVariableAddress - returned from functionEntry()
216 * localVariableSize - the size in bytes of the local variables.
217 */
218 virtual void functionExit(int argCount, int localVariableAddress,
219 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700220
Jack Palevich1cdef202009-05-22 12:06:27 -0700221 /* load immediate value to R0 */
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700222 virtual void li(int i) = 0;
223
224 /* load floating point immediate value to R0 */
225 virtual void lif(float f) = 0;
226
227 /* load double-precision floating point immediate value to R0 */
228 virtual void lid(double d) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700229
Jack Palevich1cdef202009-05-22 12:06:27 -0700230 /* Jump to a target, and return the address of the word that
231 * holds the target data, in case it needs to be fixed up later.
232 */
Jack Palevich22305132009-05-13 10:58:45 -0700233 virtual int gjmp(int t) = 0;
234
Jack Palevich1cdef202009-05-22 12:06:27 -0700235 /* Test R0 and jump to a target if the test succeeds.
236 * l = 0: je, l == 1: jne
237 * Return the address of the word that holds the targed data, in
238 * case it needs to be fixed up later.
239 */
Jack Palevich22305132009-05-13 10:58:45 -0700240 virtual int gtst(bool l, int t) = 0;
241
Jack Palevich9eed7a22009-07-06 17:24:34 -0700242 /* Compare TOS against R0, and store the boolean result in R0.
243 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700244 * op specifies the comparison.
245 */
Jack Palevich22305132009-05-13 10:58:45 -0700246 virtual void gcmp(int op) = 0;
247
Jack Palevich9eed7a22009-07-06 17:24:34 -0700248 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700249 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700250 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700251 */
Jack Palevich546b2242009-05-13 15:10:04 -0700252 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700253
Jack Palevich9eed7a22009-07-06 17:24:34 -0700254 /* Compare 0 against R0, and store the boolean result in R0.
255 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700256 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700257 virtual void gUnaryCmp(int op) = 0;
258
259 /* Perform the arithmetic op specified by op. 0 is the
260 * left argument, R0 is the right argument.
261 */
262 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700263
Jack Palevich1cdef202009-05-22 12:06:27 -0700264 /* Push R0 onto the stack.
265 */
266 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700267
Jack Palevich9eed7a22009-07-06 17:24:34 -0700268 /* Store R0 to the address stored in TOS.
269 * The TOS is popped.
270 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700272 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700273
Jack Palevich1cdef202009-05-22 12:06:27 -0700274 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700275 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700276 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700277 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700278
Jack Palevich1cdef202009-05-22 12:06:27 -0700279 /* Load the absolute address of a variable to R0.
280 * If ea <= LOCAL, then this is a local variable, or an
281 * argument, addressed relative to FP.
282 * else it is an absolute global address.
283 */
284 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700285
Jack Palevich1cdef202009-05-22 12:06:27 -0700286 /* Store R0 to a variable.
287 * If ea <= LOCAL, then this is a local variable, or an
288 * argument, addressed relative to FP.
289 * else it is an absolute global address.
290 */
291 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700292
Jack Palevich1cdef202009-05-22 12:06:27 -0700293 /* load R0 from a variable.
294 * If ea <= LOCAL, then this is a local variable, or an
295 * argument, addressed relative to FP.
296 * else it is an absolute global address.
297 * If isIncDec is true, then the stored variable's value
298 * should be post-incremented or post-decremented, based
299 * on the value of op.
300 */
301 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700302
Jack Palevich1cdef202009-05-22 12:06:27 -0700303 /* Emit code to adjust the stack for a function call. Return the
304 * label for the address of the instruction that adjusts the
305 * stack size. This will be passed as argument "a" to
306 * endFunctionCallArguments.
307 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700308 virtual int beginFunctionCallArguments() = 0;
309
Jack Palevich1cdef202009-05-22 12:06:27 -0700310 /* Emit code to store R0 to the stack at byte offset l.
311 */
312 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700313
Jack Palevich1cdef202009-05-22 12:06:27 -0700314 /* Patch the function call preamble.
315 * a is the address returned from beginFunctionCallArguments
316 * l is the number of bytes the arguments took on the stack.
317 * Typically you would also emit code to convert the argument
318 * list into whatever the native function calling convention is.
319 * On ARM for example you would pop the first 5 arguments into
320 * R0..R4
321 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700322 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700323
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 /* Emit a call to an unknown function. The argument "symbol" needs to
325 * be stored in the location where the address should go. It forms
326 * a chain. The address will be patched later.
327 * Return the address of the word that has to be patched.
328 */
Jack Palevich22305132009-05-13 10:58:45 -0700329 virtual int callForward(int symbol) = 0;
330
Jack Palevich1cdef202009-05-22 12:06:27 -0700331 /* Call a function using PC-relative addressing. t is the PC-relative
332 * address of the function. It has already been adjusted for the
333 * architectural jump offset, so just store it as-is.
334 */
Jack Palevich22305132009-05-13 10:58:45 -0700335 virtual void callRelative(int t) = 0;
336
Jack Palevich1cdef202009-05-22 12:06:27 -0700337 /* Call a function pointer. L is the number of bytes the arguments
338 * take on the stack. The address of the function is stored at
339 * location SP + l.
340 */
Jack Palevich22305132009-05-13 10:58:45 -0700341 virtual void callIndirect(int l) = 0;
342
Jack Palevich1cdef202009-05-22 12:06:27 -0700343 /* Adjust SP after returning from a function call. l is the
344 * number of bytes of arguments stored on the stack. isIndirect
345 * is true if this was an indirect call. (In which case the
346 * address of the function is stored at location SP + l.)
347 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700348 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700349
Jack Palevich1cdef202009-05-22 12:06:27 -0700350 /* Print a disassembly of the assembled code to out. Return
351 * non-zero if there is an error.
352 */
Jack Palevicha6535612009-05-13 16:24:17 -0700353 virtual int disassemble(FILE* out) = 0;
354
Jack Palevich1cdef202009-05-22 12:06:27 -0700355 /* Generate a symbol at the current PC. t is the head of a
356 * linked list of addresses to patch.
357 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700358 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700359
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 /*
361 * Do any cleanup work required at the end of a compile.
362 * For example, an instruction cache might need to be
363 * invalidated.
364 * Return non-zero if there is an error.
365 */
366 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700367
Jack Palevicha6535612009-05-13 16:24:17 -0700368 /**
369 * Adjust relative branches by this amount.
370 */
371 virtual int jumpOffset() = 0;
372
Jack Palevich9eed7a22009-07-06 17:24:34 -0700373 /**
374 * Stack alignment (in bytes) for this type of data
375 */
376 virtual size_t stackAlignment(Type* type) = 0;
377
378 /**
379 * Array element alignment (in bytes) for this type of data.
380 */
381 virtual size_t sizeOf(Type* type) = 0;
382
Jack Palevich21a15a22009-05-11 14:49:29 -0700383 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700384 /*
385 * Output a byte. Handles all values, 0..ff.
386 */
387 void ob(int n) {
388 pCodeBuf->ob(n);
389 }
390
Jack Palevich8b0624c2009-05-20 12:12:06 -0700391 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700392 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700393 }
394
Jack Palevich8b0624c2009-05-20 12:12:06 -0700395 intptr_t getBase() {
396 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700397 }
398
Jack Palevich8b0624c2009-05-20 12:12:06 -0700399 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700400 return pCodeBuf->getPC();
401 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700402
403 intptr_t getSize() {
404 return pCodeBuf->getSize();
405 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700406
407 void error(const char* fmt,...) {
408 va_list ap;
409 va_start(ap, fmt);
410 mErrorSink->verror(fmt, ap);
411 va_end(ap);
412 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700413
414 void assert(bool test) {
415 if (!test) {
416 error("code generator assertion failed.");
417 }
418 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700419 private:
420 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700421 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700422 };
423
Jack Paleviche7b59062009-05-19 17:12:17 -0700424#ifdef PROVIDE_ARM_CODEGEN
425
Jack Palevich22305132009-05-13 10:58:45 -0700426 class ARMCodeGenerator : public CodeGenerator {
427 public:
428 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700429
Jack Palevich22305132009-05-13 10:58:45 -0700430 virtual ~ARMCodeGenerator() {}
431
432 /* returns address to patch with local variable size
433 */
Jack Palevich546b2242009-05-13 15:10:04 -0700434 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700435 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700436 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700437 // sp -> arg4 arg5 ...
438 // Push our register-based arguments back on the stack
439 if (argCount > 0) {
440 int regArgCount = argCount <= 4 ? argCount : 4;
441 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700442 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700443 }
444 // sp -> arg0 arg1 ...
445 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700446 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700447 // sp, fp -> oldfp, retadr, arg0 arg1 ....
448 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700449 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700450 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700451 // We don't know how many local variables we are going to use,
452 // but we will round the allocation up to a multiple of
453 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700454 }
455
Jack Palevich546b2242009-05-13 15:10:04 -0700456 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700457 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700458 // Round local variable size up to a multiple of stack alignment
459 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
460 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700461 // Patch local variable allocation code:
462 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700463 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700464 }
Jack Palevich69796b62009-05-14 15:42:26 -0700465 *(char*) (localVariableAddress) = localVariableSize;
466
467 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
468 o4(0xE1A0E00B); // mov lr, fp
469 o4(0xE59BB000); // ldr fp, [fp]
470 o4(0xE28ED004); // add sp, lr, #4
471 // sp -> retadr, arg0, ...
472 o4(0xE8BD4000); // ldmfd sp!, {lr}
473 // sp -> arg0 ....
474 if (argCount > 0) {
475 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700476 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700477 // earlier. We don't need to actually store them anywhere,
478 // just adjust the stack.
479 int regArgCount = argCount <= 4 ? argCount : 4;
480 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
481 }
482 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700483 }
484
485 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700486 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700487 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700488 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700489 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700490 } else if (t >= -256 && t < 0) {
491 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700492 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700493 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700494 o4(0xE51F0000); // ldr r0, .L3
495 o4(0xEA000000); // b .L99
496 o4(t); // .L3: .word 0
497 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700498 }
Jack Palevich22305132009-05-13 10:58:45 -0700499 }
500
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700501 virtual void lif(float f) {
502 union { float f; int i; } converter;
503 converter.f = f;
504 li(converter.i);
505 }
506
507 virtual void lid(double d) {
508 union { double d; int i[2]; } converter;
509 converter.d = d;
510 assert(false);
511 }
512
Jack Palevich22305132009-05-13 10:58:45 -0700513 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700514 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700515 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700516 }
517
518 /* l = 0: je, l == 1: jne */
519 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700520 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700521 o4(0xE3500000); // cmp r0,#0
522 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
523 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700524 }
525
526 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700527 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700528 o4(0xE8BD0002); // ldmfd sp!,{r1}
529 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700530 o4(0xE1510000); // cmp r1, r1
531 switch(op) {
532 case OP_EQUALS:
533 o4(0x03A00001); // moveq r0,#1
534 o4(0x13A00000); // movne r0,#0
535 break;
536 case OP_NOT_EQUALS:
537 o4(0x03A00000); // moveq r0,#0
538 o4(0x13A00001); // movne r0,#1
539 break;
540 case OP_LESS_EQUAL:
541 o4(0xD3A00001); // movle r0,#1
542 o4(0xC3A00000); // movgt r0,#0
543 break;
544 case OP_GREATER:
545 o4(0xD3A00000); // movle r0,#0
546 o4(0xC3A00001); // movgt r0,#1
547 break;
548 case OP_GREATER_EQUAL:
549 o4(0xA3A00001); // movge r0,#1
550 o4(0xB3A00000); // movlt r0,#0
551 break;
552 case OP_LESS:
553 o4(0xA3A00000); // movge r0,#0
554 o4(0xB3A00001); // movlt r0,#1
555 break;
556 default:
557 error("Unknown comparison op %d", op);
558 break;
559 }
Jack Palevich22305132009-05-13 10:58:45 -0700560 }
561
Jack Palevich546b2242009-05-13 15:10:04 -0700562 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700563 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700564 o4(0xE8BD0002); // ldmfd sp!,{r1}
565 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700566 switch(op) {
567 case OP_MUL:
568 o4(0x0E0000091); // mul r0,r1,r0
569 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700570 case OP_DIV:
571 callRuntime(runtime_DIV);
572 break;
573 case OP_MOD:
574 callRuntime(runtime_MOD);
575 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700576 case OP_PLUS:
577 o4(0xE0810000); // add r0,r1,r0
578 break;
579 case OP_MINUS:
580 o4(0xE0410000); // sub r0,r1,r0
581 break;
582 case OP_SHIFT_LEFT:
583 o4(0xE1A00011); // lsl r0,r1,r0
584 break;
585 case OP_SHIFT_RIGHT:
586 o4(0xE1A00051); // asr r0,r1,r0
587 break;
588 case OP_BIT_AND:
589 o4(0xE0010000); // and r0,r1,r0
590 break;
591 case OP_BIT_XOR:
592 o4(0xE0210000); // eor r0,r1,r0
593 break;
594 case OP_BIT_OR:
595 o4(0xE1810000); // orr r0,r1,r0
596 break;
597 case OP_BIT_NOT:
598 o4(0xE1E00000); // mvn r0, r0
599 break;
600 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700601 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700602 break;
603 }
Jack Palevich22305132009-05-13 10:58:45 -0700604 }
605
Jack Palevich9eed7a22009-07-06 17:24:34 -0700606 virtual void gUnaryCmp(int op) {
607 LOG_API("gcmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700608 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700609 o4(0xE1510000); // cmp r1, r1
610 switch(op) {
611 case OP_NOT_EQUALS:
612 o4(0x03A00000); // moveq r0,#0
613 o4(0x13A00001); // movne r0,#1
614 break;
615 default:
616 error("Unknown unary comparison op %d", op);
617 break;
618 }
619 }
620
621 virtual void genUnaryOp(int op) {
622 LOG_API("genOp(%d);\n", op);
623 switch(op) {
624 case OP_PLUS:
625 // Do nothing
626 break;
627 case OP_MINUS:
628 o4(0xE3A01000); // mov r1, #0
629 o4(0xE0410000); // sub r0,r1,r0
630 break;
631 case OP_BIT_NOT:
632 o4(0xE1E00000); // mvn r0, r0
633 break;
634 default:
635 error("Unknown unary op %d\n", op);
636 break;
637 }
Jack Palevich22305132009-05-13 10:58:45 -0700638 }
639
Jack Palevich1cdef202009-05-22 12:06:27 -0700640 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700641 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700642 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700643 mStackUse += 4;
644 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700645 }
646
Jack Palevich9eed7a22009-07-06 17:24:34 -0700647 virtual void storeR0ToTOS(Type* pPointerType) {
648 LOG_API("storeR0ToTOS(%d);\n", isInt);
649 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700650 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700651 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700652 switch (pPointerType->pHead->tag) {
653 case TY_INT:
654 o4(0xE5810000); // str r0, [r1]
655 break;
656 case TY_CHAR:
657 o4(0xE5C10000); // strb r0, [r1]
658 break;
659 default:
660 assert(false);
661 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700662 }
Jack Palevich22305132009-05-13 10:58:45 -0700663 }
664
Jack Palevich9eed7a22009-07-06 17:24:34 -0700665 virtual void loadR0FromR0(Type* pPointerType) {
666 LOG_API("loadR0FromR0(%d);\n", pPointerType);
667 assert(pPointerType->tag == TY_POINTER);
668 switch (pPointerType->pHead->tag) {
669 case TY_INT:
670 o4(0xE5900000); // ldr r0, [r0]
671 break;
672 case TY_CHAR:
673 o4(0xE5D00000); // ldrb r0, [r0]
674 break;
675 default:
676 assert(false);
677 break;
678 }
Jack Palevich22305132009-05-13 10:58:45 -0700679 }
680
Jack Palevich1cdef202009-05-22 12:06:27 -0700681 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700682 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700683 if (ea < LOCAL) {
684 // Local, fp relative
685 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
686 error("Offset out of range: %08x", ea);
687 }
688 if (ea < 0) {
689 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
690 } else {
691 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
692 }
Jack Palevichbd894902009-05-14 19:35:31 -0700693 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700694 // Global, absolute.
695 o4(0xE59F0000); // ldr r0, .L1
696 o4(0xEA000000); // b .L99
697 o4(ea); // .L1: .word 0
698 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700699 }
Jack Palevich22305132009-05-13 10:58:45 -0700700 }
701
Jack Palevich1cdef202009-05-22 12:06:27 -0700702 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700703 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700704 if (ea < LOCAL) {
705 // Local, fp relative
706 if (ea < -4095 || ea > 4095) {
707 error("Offset out of range: %08x", ea);
708 }
709 if (ea < 0) {
710 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
711 } else {
712 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
713 }
714 } else{
715 // Global, absolute
716 o4(0xE59F1000); // ldr r1, .L1
717 o4(0xEA000000); // b .L99
718 o4(ea); // .L1: .word 0
719 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700720 }
Jack Palevich22305132009-05-13 10:58:45 -0700721 }
722
Jack Palevich1cdef202009-05-22 12:06:27 -0700723 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700724 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700725 if (ea < LOCAL) {
726 // Local, fp relative
727 if (ea < -4095 || ea > 4095) {
728 error("Offset out of range: %08x", ea);
729 }
730 if (ea < 0) {
731 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
732 } else {
733 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
734 }
Jack Palevich69796b62009-05-14 15:42:26 -0700735 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700736 // Global, absolute
737 o4(0xE59F2000); // ldr r2, .L1
738 o4(0xEA000000); // b .L99
739 o4(ea); // .L1: .word ea
740 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700741 }
Jack Palevich22305132009-05-13 10:58:45 -0700742
Jack Palevich4d93f302009-05-15 13:30:00 -0700743 if (isIncDec) {
744 switch (op) {
745 case OP_INCREMENT:
746 o4(0xE2801001); // add r1, r0, #1
747 break;
748 case OP_DECREMENT:
749 o4(0xE2401001); // sub r1, r0, #1
750 break;
751 default:
752 error("unknown opcode: %d", op);
753 }
754 if (ea < LOCAL) {
755 // Local, fp relative
756 // Don't need range check, was already checked above
757 if (ea < 0) {
758 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
759 } else {
760 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
761 }
762 } else{
763 // Global, absolute
764 // r2 is already set up from before.
765 o4(0xE5821000); // str r1, [r2]
766 }
Jack Palevichbd894902009-05-14 19:35:31 -0700767 }
Jack Palevich22305132009-05-13 10:58:45 -0700768 }
769
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700770 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700771 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700772 return o4(0xE24DDF00); // Placeholder
773 }
774
Jack Palevich1cdef202009-05-22 12:06:27 -0700775 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700776 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700777 if (l < 0 || l > 4096-4) {
778 error("l out of range for stack offset: 0x%08x", l);
779 }
780 o4(0xE58D0000 + l); // str r0, [sp, #4]
781 }
782
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700783 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700784 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700785 int argCount = l >> 2;
786 int argumentStackUse = l;
787 if (argCount > 0) {
788 int regArgCount = argCount > 4 ? 4 : argCount;
789 argumentStackUse -= regArgCount * 4;
790 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
791 }
792 mStackUse += argumentStackUse;
793
794 // Align stack.
795 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
796 * STACK_ALIGNMENT);
797 mStackAlignmentAdjustment = 0;
798 if (missalignment > 0) {
799 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
800 }
801 l += mStackAlignmentAdjustment;
802
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700803 if (l < 0 || l > 0x3FC) {
804 error("L out of range for stack adjustment: 0x%08x", l);
805 }
806 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700807 mStackUse += mStackAlignmentAdjustment;
808 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
809 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700810 }
811
Jack Palevich22305132009-05-13 10:58:45 -0700812 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700813 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700814 // Forward calls are always short (local)
815 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700816 }
817
818 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700819 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700820 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700821 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700822 if (t >= - (1 << 25) && t < (1 << 25)) {
823 o4(0xEB000000 | encodeAddress(t));
824 } else {
825 // Long call.
826 o4(0xE59FC000); // ldr r12, .L1
827 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700828 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700829 o4(0xE08CC00F); // .L99: add r12,pc
830 o4(0xE12FFF3C); // blx r12
831 }
Jack Palevich22305132009-05-13 10:58:45 -0700832 }
833
834 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700835 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700836 int argCount = l >> 2;
837 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700838 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700839 if (adjustedL < 0 || adjustedL > 4096-4) {
840 error("l out of range for stack offset: 0x%08x", l);
841 }
842 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
843 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700844 }
845
Jack Palevich7810bc92009-05-15 14:31:47 -0700846 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700847 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700848 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700849 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700850 int stackUse = stackArgs + (isIndirect ? 1 : 0)
851 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700852 if (stackUse) {
853 if (stackUse < 0 || stackUse > 255) {
854 error("L out of range for stack adjustment: 0x%08x", l);
855 }
856 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -0700857 mStackUse -= stackUse * 4;
858 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700859 }
Jack Palevich22305132009-05-13 10:58:45 -0700860 }
861
Jack Palevicha6535612009-05-13 16:24:17 -0700862 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700863 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700864 }
865
866 /* output a symbol and patch all calls to it */
867 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700868 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700869 int n;
870 int base = getBase();
871 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700872 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700873 while (t) {
874 int data = * (int*) t;
875 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
876 if (decodedOffset == 0) {
877 n = 0;
878 } else {
879 n = base + decodedOffset; /* next value */
880 }
881 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
882 | encodeRelAddress(pc - t - 8);
883 t = n;
884 }
885 }
886
Jack Palevich1cdef202009-05-22 12:06:27 -0700887 virtual int finishCompile() {
888#if defined(__arm__)
889 const long base = long(getBase());
890 const long curr = long(getPC());
891 int err = cacheflush(base, curr, 0);
892 return err;
893#else
894 return 0;
895#endif
896 }
897
Jack Palevicha6535612009-05-13 16:24:17 -0700898 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700899#ifdef ENABLE_ARM_DISASSEMBLY
900 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700901 disasm_interface_t di;
902 di.di_readword = disassemble_readword;
903 di.di_printaddr = disassemble_printaddr;
904 di.di_printf = disassemble_printf;
905
906 int base = getBase();
907 int pc = getPC();
908 for(int i = base; i < pc; i += 4) {
909 fprintf(out, "%08x: %08x ", i, *(int*) i);
910 ::disasm(&di, i, 0);
911 }
Jack Palevich09555c72009-05-27 12:25:55 -0700912#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700913 return 0;
914 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700915
Jack Palevich9eed7a22009-07-06 17:24:34 -0700916 /**
917 * Stack alignment (in bytes) for this type of data
918 */
919 virtual size_t stackAlignment(Type* pType){
920 switch(pType->tag) {
921 case TY_DOUBLE:
922 return 8;
923 default:
924 return 4;
925 }
926 }
927
928 /**
929 * Array element alignment (in bytes) for this type of data.
930 */
931 virtual size_t sizeOf(Type* pType){
932 switch(pType->tag) {
933 case TY_INT:
934 return 4;
935 case TY_CHAR:
936 return 1;
937 default:
938 return 0;
939 case TY_FLOAT:
940 return 4;
941 case TY_DOUBLE:
942 return 8;
943 case TY_POINTER:
944 return 4;
945 }
946 }
Jack Palevich22305132009-05-13 10:58:45 -0700947 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700948 static FILE* disasmOut;
949
950 static u_int
951 disassemble_readword(u_int address)
952 {
953 return(*((u_int *)address));
954 }
955
956 static void
957 disassemble_printaddr(u_int address)
958 {
959 fprintf(disasmOut, "0x%08x", address);
960 }
961
962 static void
963 disassemble_printf(const char *fmt, ...) {
964 va_list ap;
965 va_start(ap, fmt);
966 vfprintf(disasmOut, fmt, ap);
967 va_end(ap);
968 }
969
970 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
971
972 /** Encode a relative address that might also be
973 * a label.
974 */
975 int encodeAddress(int value) {
976 int base = getBase();
977 if (value >= base && value <= getPC() ) {
978 // This is a label, encode it relative to the base.
979 value = value - base;
980 }
981 return encodeRelAddress(value);
982 }
983
984 int encodeRelAddress(int value) {
985 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
986 }
Jack Palevich22305132009-05-13 10:58:45 -0700987
Jack Palevich3d474a72009-05-15 15:12:38 -0700988 typedef int (*int2FnPtr)(int a, int b);
989 void callRuntime(int2FnPtr fn) {
990 o4(0xE59F2000); // ldr r2, .L1
991 o4(0xEA000000); // b .L99
992 o4((int) fn); //.L1: .word fn
993 o4(0xE12FFF32); //.L99: blx r2
994 }
995
996 static int runtime_DIV(int a, int b) {
997 return b / a;
998 }
999
1000 static int runtime_MOD(int a, int b) {
1001 return b % a;
1002 }
-b master422972c2009-06-17 19:13:52 -07001003
1004 static const int STACK_ALIGNMENT = 8;
1005 int mStackUse;
1006 // This variable holds the amount we adjusted the stack in the most
1007 // recent endFunctionCallArguments call. It's examined by the
1008 // following adjustStackAfterCall call.
1009 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001010 };
1011
Jack Palevich09555c72009-05-27 12:25:55 -07001012#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001013
1014#ifdef PROVIDE_X86_CODEGEN
1015
Jack Palevich21a15a22009-05-11 14:49:29 -07001016 class X86CodeGenerator : public CodeGenerator {
1017 public:
1018 X86CodeGenerator() {}
1019 virtual ~X86CodeGenerator() {}
1020
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001021 /* returns address to patch with local variable size
1022 */
Jack Palevich546b2242009-05-13 15:10:04 -07001023 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001024 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1025 return oad(0xec81, 0); /* sub $xxx, %esp */
1026 }
1027
Jack Palevich546b2242009-05-13 15:10:04 -07001028 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001029 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001030 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001031 }
1032
Jack Palevich21a15a22009-05-11 14:49:29 -07001033 /* load immediate value */
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001034 virtual void li(int i) {
1035 oad(0xb8, i); /* mov $xx, %eax */
1036 }
1037
1038 virtual void lif(float f) {
1039 union { float f; int i; } converter;
1040 converter.f = f;
1041 assert(false);
1042 }
1043
1044 virtual void lid(double d) {
1045 union { double d; int i[2]; } converter;
1046 converter.d = d;
1047 assert(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07001048 }
1049
Jack Palevich22305132009-05-13 10:58:45 -07001050 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001051 return psym(0xe9, t);
1052 }
1053
1054 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001055 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001056 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1057 return psym(0x84 + l, t);
1058 }
1059
Jack Palevich22305132009-05-13 10:58:45 -07001060 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001061 int t = decodeOp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001062 o(0x59); /* pop %ecx */
Jack Palevich21a15a22009-05-11 14:49:29 -07001063 o(0xc139); /* cmp %eax,%ecx */
1064 li(0);
1065 o(0x0f); /* setxx %al */
1066 o(t + 0x90);
1067 o(0xc0);
1068 }
1069
Jack Palevich546b2242009-05-13 15:10:04 -07001070 virtual void genOp(int op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001071 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001072 o(decodeOp(op));
1073 if (op == OP_MOD)
1074 o(0x92); /* xchg %edx, %eax */
1075 }
1076
Jack Palevich9eed7a22009-07-06 17:24:34 -07001077 virtual void gUnaryCmp(int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001078 oad(0xb9, 0); /* movl $0, %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001079 int t = decodeOp(op);
1080 o(0xc139); /* cmp %eax,%ecx */
1081 li(0);
1082 o(0x0f); /* setxx %al */
1083 o(t + 0x90);
1084 o(0xc0);
1085 }
1086
1087 virtual void genUnaryOp(int op) {
1088 oad(0xb9, 0); /* movl $0, %ecx */
1089 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -07001090 }
1091
Jack Palevich1cdef202009-05-22 12:06:27 -07001092 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001093 o(0x50); /* push %eax */
1094 }
1095
Jack Palevich9eed7a22009-07-06 17:24:34 -07001096 virtual void storeR0ToTOS(Type* pPointerType) {
1097 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001098 o(0x59); /* pop %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001099 switch (pPointerType->pHead->tag) {
1100 case TY_INT:
1101 o(0x0189); /* movl %eax/%al, (%ecx) */
1102 break;
1103 case TY_CHAR:
1104 o(0x0188); /* movl %eax/%al, (%ecx) */
1105 break;
1106 default:
1107 assert(false);
1108 break;
1109 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001110 }
1111
Jack Palevich9eed7a22009-07-06 17:24:34 -07001112 virtual void loadR0FromR0(Type* pPointerType) {
1113 assert(pPointerType->tag == TY_POINTER);
1114 switch (pPointerType->pHead->tag) {
1115 case TY_INT:
1116 o(0x8b); /* mov (%eax), %eax */
1117 break;
1118 case TY_CHAR:
1119 o(0xbe0f); /* movsbl (%eax), %eax */
1120 break;
1121 default:
1122 assert(false);
1123 break;
1124 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001125 ob(0); /* add zero in code */
1126 }
1127
Jack Palevich1cdef202009-05-22 12:06:27 -07001128 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001129 gmov(10, ea); /* leal EA, %eax */
1130 }
1131
Jack Palevich1cdef202009-05-22 12:06:27 -07001132 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001133 gmov(6, ea); /* mov %eax, EA */
1134 }
1135
Jack Palevich1cdef202009-05-22 12:06:27 -07001136 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001137 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -07001138 if (isIncDec) {
1139 /* Implement post-increment or post decrement.
1140 */
1141 gmov(0, ea); /* 83 ADD */
1142 o(decodeOp(op));
1143 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001144 }
1145
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001146 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001147 return oad(0xec81, 0); /* sub $xxx, %esp */
1148 }
1149
Jack Palevich1cdef202009-05-22 12:06:27 -07001150 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001151 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1152 }
1153
Jack Palevich7810bc92009-05-15 14:31:47 -07001154 virtual void endFunctionCallArguments(int a, int l) {
1155 * (int*) a = l;
1156 }
1157
Jack Palevich22305132009-05-13 10:58:45 -07001158 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001159 return psym(0xe8, symbol); /* call xxx */
1160 }
1161
Jack Palevich22305132009-05-13 10:58:45 -07001162 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001163 psym(0xe8, t); /* call xxx */
1164 }
1165
Jack Palevich22305132009-05-13 10:58:45 -07001166 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001167 oad(0x2494ff, l); /* call *xxx(%esp) */
1168 }
1169
Jack Palevich7810bc92009-05-15 14:31:47 -07001170 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1171 if (isIndirect) {
1172 l += 4;
1173 }
-b master422972c2009-06-17 19:13:52 -07001174 if (l > 0) {
1175 oad(0xc481, l); /* add $xxx, %esp */
1176 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001177 }
1178
Jack Palevicha6535612009-05-13 16:24:17 -07001179 virtual int jumpOffset() {
1180 return 5;
1181 }
1182
1183 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001184 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001185 }
1186
Jack Paleviche7b59062009-05-19 17:12:17 -07001187 /* output a symbol and patch all calls to it */
1188 virtual void gsym(int t) {
1189 int n;
1190 int pc = getPC();
1191 while (t) {
1192 n = *(int *) t; /* next value */
1193 *(int *) t = pc - t - 4;
1194 t = n;
1195 }
1196 }
1197
Jack Palevich1cdef202009-05-22 12:06:27 -07001198 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001199 size_t pagesize = 4096;
1200 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1201 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1202 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1203 if (err) {
1204 error("mprotect() failed: %d", errno);
1205 }
1206 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001207 }
1208
Jack Palevich9eed7a22009-07-06 17:24:34 -07001209 /**
1210 * Stack alignment (in bytes) for this type of data
1211 */
1212 virtual size_t stackAlignment(Type* pType){
1213 switch(pType->tag) {
1214 case TY_DOUBLE:
1215 return 8;
1216 default:
1217 return 4;
1218 }
1219 }
1220
1221 /**
1222 * Array element alignment (in bytes) for this type of data.
1223 */
1224 virtual size_t sizeOf(Type* pType){
1225 switch(pType->tag) {
1226 case TY_INT:
1227 return 4;
1228 case TY_CHAR:
1229 return 1;
1230 default:
1231 return 0;
1232 case TY_FLOAT:
1233 return 4;
1234 case TY_DOUBLE:
1235 return 8;
1236 case TY_POINTER:
1237 return 4;
1238 }
1239 }
1240
Jack Palevich21a15a22009-05-11 14:49:29 -07001241 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001242
1243 /** Output 1 to 4 bytes.
1244 *
1245 */
1246 void o(int n) {
1247 /* cannot use unsigned, so we must do a hack */
1248 while (n && n != -1) {
1249 ob(n & 0xff);
1250 n = n >> 8;
1251 }
1252 }
1253
1254 /* psym is used to put an instruction with a data field which is a
1255 reference to a symbol. It is in fact the same as oad ! */
1256 int psym(int n, int t) {
1257 return oad(n, t);
1258 }
1259
1260 /* instruction + address */
1261 int oad(int n, int t) {
1262 o(n);
1263 int result = getPC();
1264 o4(t);
1265 return result;
1266 }
1267
1268
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001269 static const int operatorHelper[];
1270
1271 int decodeOp(int op) {
1272 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001273 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001274 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001275 }
1276 return operatorHelper[op];
1277 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001278
Jack Palevich546b2242009-05-13 15:10:04 -07001279 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001280 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001281 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001282 }
1283 };
1284
Jack Paleviche7b59062009-05-19 17:12:17 -07001285#endif // PROVIDE_X86_CODEGEN
1286
Jack Palevichb67b18f2009-06-11 21:12:23 -07001287#ifdef PROVIDE_TRACE_CODEGEN
1288 class TraceCodeGenerator : public CodeGenerator {
1289 private:
1290 CodeGenerator* mpBase;
1291
1292 public:
1293 TraceCodeGenerator(CodeGenerator* pBase) {
1294 mpBase = pBase;
1295 }
1296
1297 virtual ~TraceCodeGenerator() {
1298 delete mpBase;
1299 }
1300
1301 virtual void init(CodeBuf* pCodeBuf) {
1302 mpBase->init(pCodeBuf);
1303 }
1304
1305 void setErrorSink(ErrorSink* pErrorSink) {
1306 mpBase->setErrorSink(pErrorSink);
1307 }
1308
1309 /* returns address to patch with local variable size
1310 */
1311 virtual int functionEntry(int argCount) {
1312 int result = mpBase->functionEntry(argCount);
1313 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1314 return result;
1315 }
1316
1317 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1318 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1319 argCount, localVariableAddress, localVariableSize);
1320 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1321 }
1322
1323 /* load immediate value */
1324 virtual void li(int t) {
1325 fprintf(stderr, "li(%d)\n", t);
1326 mpBase->li(t);
1327 }
1328
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001329 virtual void lif(float f) {
1330 fprintf(stderr, "lif(%g)\n", f);
1331 mpBase->lif(f);
1332 }
1333
1334 virtual void lid(double d) {
1335 fprintf(stderr, "lid(%g)\n", d);
1336 mpBase->lid(d);
1337 }
1338
Jack Palevichb67b18f2009-06-11 21:12:23 -07001339 virtual int gjmp(int t) {
1340 int result = mpBase->gjmp(t);
1341 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1342 return result;
1343 }
1344
1345 /* l = 0: je, l == 1: jne */
1346 virtual int gtst(bool l, int t) {
1347 int result = mpBase->gtst(l, t);
1348 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1349 return result;
1350 }
1351
1352 virtual void gcmp(int op) {
1353 fprintf(stderr, "gcmp(%d)\n", op);
1354 mpBase->gcmp(op);
1355 }
1356
1357 virtual void genOp(int op) {
1358 fprintf(stderr, "genOp(%d)\n", op);
1359 mpBase->genOp(op);
1360 }
1361
Jack Palevich9eed7a22009-07-06 17:24:34 -07001362
1363 virtual void gUnaryCmp(int op) {
1364 fprintf(stderr, "gUnaryCmp(%d)\n", op);
1365 mpBase->gUnaryCmp(op);
1366 }
1367
1368 virtual void genUnaryOp(int op) {
1369 fprintf(stderr, "genUnaryOp(%d)\n", op);
1370 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001371 }
1372
1373 virtual void pushR0() {
1374 fprintf(stderr, "pushR0()\n");
1375 mpBase->pushR0();
1376 }
1377
Jack Palevich9eed7a22009-07-06 17:24:34 -07001378 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001379 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001380 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001381 }
1382
Jack Palevich9eed7a22009-07-06 17:24:34 -07001383 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001384 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001385 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001386 }
1387
1388 virtual void leaR0(int ea) {
1389 fprintf(stderr, "leaR0(%d)\n", ea);
1390 mpBase->leaR0(ea);
1391 }
1392
1393 virtual void storeR0(int ea) {
1394 fprintf(stderr, "storeR0(%d)\n", ea);
1395 mpBase->storeR0(ea);
1396 }
1397
1398 virtual void loadR0(int ea, bool isIncDec, int op) {
1399 fprintf(stderr, "loadR0(%d, %d, %d)\n", ea, isIncDec, op);
1400 mpBase->loadR0(ea, isIncDec, op);
1401 }
1402
1403 virtual int beginFunctionCallArguments() {
1404 int result = mpBase->beginFunctionCallArguments();
1405 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1406 return result;
1407 }
1408
1409 virtual void storeR0ToArg(int l) {
1410 fprintf(stderr, "storeR0ToArg(%d)\n", l);
1411 mpBase->storeR0ToArg(l);
1412 }
1413
1414 virtual void endFunctionCallArguments(int a, int l) {
1415 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1416 mpBase->endFunctionCallArguments(a, l);
1417 }
1418
1419 virtual int callForward(int symbol) {
1420 int result = mpBase->callForward(symbol);
1421 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1422 return result;
1423 }
1424
1425 virtual void callRelative(int t) {
1426 fprintf(stderr, "callRelative(%d)\n", t);
1427 mpBase->callRelative(t);
1428 }
1429
1430 virtual void callIndirect(int l) {
1431 fprintf(stderr, "callIndirect(%d)\n", l);
1432 mpBase->callIndirect(l);
1433 }
1434
1435 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1436 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1437 mpBase->adjustStackAfterCall(l, isIndirect);
1438 }
1439
1440 virtual int jumpOffset() {
1441 return mpBase->jumpOffset();
1442 }
1443
1444 virtual int disassemble(FILE* out) {
1445 return mpBase->disassemble(out);
1446 }
1447
1448 /* output a symbol and patch all calls to it */
1449 virtual void gsym(int t) {
1450 fprintf(stderr, "gsym(%d)\n", t);
1451 mpBase->gsym(t);
1452 }
1453
1454 virtual int finishCompile() {
1455 int result = mpBase->finishCompile();
1456 fprintf(stderr, "finishCompile() = %d\n", result);
1457 return result;
1458 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001459
1460 /**
1461 * Stack alignment (in bytes) for this type of data
1462 */
1463 virtual size_t stackAlignment(Type* pType){
1464 return mpBase->stackAlignment(pType);
1465 }
1466
1467 /**
1468 * Array element alignment (in bytes) for this type of data.
1469 */
1470 virtual size_t sizeOf(Type* pType){
1471 return mpBase->sizeOf(pType);
1472 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001473 };
1474
1475#endif // PROVIDE_TRACE_CODEGEN
1476
Jack Palevich569f1352009-06-29 14:29:08 -07001477
1478 // Subset of STL vector.
1479 template<class E> class Vector {
1480 public:
1481 Vector() {
1482 mpBase = 0;
1483 mUsed = 0;
1484 mSize = 0;
1485 }
1486
1487 ~Vector() {
1488 if (mpBase) {
1489 for(size_t i = 0; i < mUsed; i++) {
1490 mpBase[mUsed].~E();
1491 }
1492 free(mpBase);
1493 }
1494 }
1495
1496 inline E& operator[](size_t i) {
1497 return mpBase[i];
1498 }
1499
1500 inline E& front() {
1501 return mpBase[0];
1502 }
1503
1504 inline E& back() {
1505 return mpBase[mUsed - 1];
1506 }
1507
1508 void pop_back() {
1509 mUsed -= 1;
1510 mpBase[mUsed].~E();
1511 }
1512
1513 void push_back(const E& item) {
1514 * ensure(1) = item;
1515 }
1516
1517 size_t size() {
1518 return mUsed;
1519 }
1520
1521 private:
1522 E* ensure(int n) {
1523 size_t newUsed = mUsed + n;
1524 if (newUsed > mSize) {
1525 size_t newSize = mSize * 2 + 10;
1526 if (newSize < newUsed) {
1527 newSize = newUsed;
1528 }
1529 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1530 mSize = newSize;
1531 }
1532 E* result = mpBase + mUsed;
1533 mUsed = newUsed;
1534 return result;
1535 }
1536
1537 E* mpBase;
1538 size_t mUsed;
1539 size_t mSize;
1540 };
1541
1542 class Arena {
1543 public:
1544 // Used to record a given allocation amount.
1545 // Used:
1546 // Mark mark = arena.mark();
1547 // ... lots of arena.allocate()
1548 // arena.free(mark);
1549
1550 struct Mark {
1551 size_t chunk;
1552 size_t offset;
1553 };
1554
1555 Arena() {
1556 mCurrentChunk = 0;
1557 Chunk start(CHUNK_SIZE);
1558 mData.push_back(start);
1559 }
1560
1561 ~Arena() {
1562 for(size_t i = 0; i < mData.size(); i++) {
1563 mData[i].free();
1564 }
1565 }
1566
1567 // Alloc using the standard alignment size safe for any variable
1568 void* alloc(size_t size) {
1569 return alloc(size, 8);
1570 }
1571
1572 Mark mark(){
1573 Mark result;
1574 result.chunk = mCurrentChunk;
1575 result.offset = mData[mCurrentChunk].mOffset;
1576 return result;
1577 }
1578
1579 void freeToMark(const Mark& mark) {
1580 mCurrentChunk = mark.chunk;
1581 mData[mCurrentChunk].mOffset = mark.offset;
1582 }
1583
1584 private:
1585 // Allocate memory aligned to a given size
1586 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1587 // Memory is not zero filled.
1588
1589 void* alloc(size_t size, size_t alignment) {
1590 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1591 if (mCurrentChunk + 1 < mData.size()) {
1592 mCurrentChunk++;
1593 } else {
1594 size_t allocSize = CHUNK_SIZE;
1595 if (allocSize < size + alignment - 1) {
1596 allocSize = size + alignment - 1;
1597 }
1598 Chunk chunk(allocSize);
1599 mData.push_back(chunk);
1600 mCurrentChunk++;
1601 }
1602 }
1603 return mData[mCurrentChunk].allocate(size, alignment);
1604 }
1605
1606 static const size_t CHUNK_SIZE = 128*1024;
1607 // Note: this class does not deallocate its
1608 // memory when it's destroyed. It depends upon
1609 // its parent to deallocate the memory.
1610 struct Chunk {
1611 Chunk() {
1612 mpData = 0;
1613 mSize = 0;
1614 mOffset = 0;
1615 }
1616
1617 Chunk(size_t size) {
1618 mSize = size;
1619 mpData = (char*) malloc(size);
1620 mOffset = 0;
1621 }
1622
1623 ~Chunk() {
1624 // Doesn't deallocate memory.
1625 }
1626
1627 void* allocate(size_t size, size_t alignment) {
1628 size_t alignedOffset = aligned(mOffset, alignment);
1629 void* result = mpData + alignedOffset;
1630 mOffset = alignedOffset + size;
1631 return result;
1632 }
1633
1634 void free() {
1635 if (mpData) {
1636 ::free(mpData);
1637 mpData = 0;
1638 }
1639 }
1640
1641 size_t remainingCapacity(size_t alignment) {
1642 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1643 }
1644
1645 // Assume alignment is a power of two
1646 inline size_t aligned(size_t v, size_t alignment) {
1647 size_t mask = alignment-1;
1648 return (v + mask) & ~mask;
1649 }
1650
1651 char* mpData;
1652 size_t mSize;
1653 size_t mOffset;
1654 };
1655
1656 size_t mCurrentChunk;
1657
1658 Vector<Chunk> mData;
1659 };
1660
1661 typedef int tokenid_t;
1662 struct VariableInfo;
1663
1664 struct Token {
1665 int hash;
1666 size_t length;
1667 char* pText;
1668 tokenid_t id;
1669
1670 // Current values for the token
1671 char* mpMacroDefinition;
1672 VariableInfo* mpVariableInfo;
1673 };
1674
1675 class TokenTable {
1676 public:
1677 // Don't use 0..0xff, allows characters and operators to be tokens too.
1678
1679 static const int TOKEN_BASE = 0x100;
1680 TokenTable() {
1681 mpMap = hashmapCreate(128, hashFn, equalsFn);
1682 }
1683
1684 ~TokenTable() {
1685 hashmapFree(mpMap);
1686 }
1687
1688 void setArena(Arena* pArena) {
1689 mpArena = pArena;
1690 }
1691
1692 // Returns a token for a given string of characters.
1693 tokenid_t intern(const char* pText, size_t length) {
1694 Token probe;
1695 int hash = hashmapHash((void*) pText, length);
1696 {
1697 Token probe;
1698 probe.hash = hash;
1699 probe.length = length;
1700 probe.pText = (char*) pText;
1701 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1702 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001703 return pValue->id;
1704 }
1705 }
1706
1707 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1708 memset(pToken, 0, sizeof(*pToken));
1709 pToken->hash = hash;
1710 pToken->length = length;
1711 pToken->pText = (char*) mpArena->alloc(length + 1);
1712 memcpy(pToken->pText, pText, length);
1713 pToken->pText[length] = 0;
1714 pToken->id = mTokens.size() + TOKEN_BASE;
1715 mTokens.push_back(pToken);
1716 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001717 return pToken->id;
1718 }
1719
1720 // Return the Token for a given tokenid.
1721 Token& operator[](tokenid_t id) {
1722 return *mTokens[id - TOKEN_BASE];
1723 }
1724
1725 inline size_t size() {
1726 return mTokens.size();
1727 }
1728
1729 private:
1730
1731 static int hashFn(void* pKey) {
1732 Token* pToken = (Token*) pKey;
1733 return pToken->hash;
1734 }
1735
1736 static bool equalsFn(void* keyA, void* keyB) {
1737 Token* pTokenA = (Token*) keyA;
1738 Token* pTokenB = (Token*) keyB;
1739 // Don't need to compare hash values, they should always be equal
1740 return pTokenA->length == pTokenB->length
1741 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1742 }
1743
1744 Hashmap* mpMap;
1745 Vector<Token*> mTokens;
1746 Arena* mpArena;
1747 };
1748
Jack Palevich1cdef202009-05-22 12:06:27 -07001749 class InputStream {
1750 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001751 int getChar() {
1752 if (bumpLine) {
1753 line++;
1754 bumpLine = false;
1755 }
1756 int ch = get();
1757 if (ch == '\n') {
1758 bumpLine = true;
1759 }
1760 return ch;
1761 }
1762 int getLine() {
1763 return line;
1764 }
1765 protected:
1766 InputStream() :
1767 line(1), bumpLine(false) {
1768 }
1769 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001770 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001771 int line;
1772 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001773 };
1774
1775 class FileInputStream : public InputStream {
1776 public:
1777 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001778 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001779 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001780 FILE* f;
1781 };
1782
1783 class TextInputStream : public InputStream {
1784 public:
1785 TextInputStream(const char* text, size_t textLength)
1786 : pText(text), mTextLength(textLength), mPosition(0) {
1787 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001788
1789 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001790 virtual int get() {
1791 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1792 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001793
Jack Palevich1cdef202009-05-22 12:06:27 -07001794 const char* pText;
1795 size_t mTextLength;
1796 size_t mPosition;
1797 };
1798
Jack Palevicheedf9d22009-06-04 16:23:40 -07001799 class String {
1800 public:
1801 String() {
1802 mpBase = 0;
1803 mUsed = 0;
1804 mSize = 0;
1805 }
1806
Jack Palevich303d8ff2009-06-11 19:06:24 -07001807 String(const char* item, int len, bool adopt) {
1808 if (len < 0) {
1809 len = strlen(item);
1810 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001811 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001812 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001813 mUsed = len;
1814 mSize = len + 1;
1815 } else {
1816 mpBase = 0;
1817 mUsed = 0;
1818 mSize = 0;
1819 appendBytes(item, len);
1820 }
1821 }
1822
Jack Palevich303d8ff2009-06-11 19:06:24 -07001823 String(const String& other) {
1824 mpBase = 0;
1825 mUsed = 0;
1826 mSize = 0;
1827 appendBytes(other.getUnwrapped(), other.len());
1828 }
1829
Jack Palevicheedf9d22009-06-04 16:23:40 -07001830 ~String() {
1831 if (mpBase) {
1832 free(mpBase);
1833 }
1834 }
1835
Jack Palevicha6baa232009-06-12 11:25:59 -07001836 String& operator=(const String& other) {
1837 clear();
1838 appendBytes(other.getUnwrapped(), other.len());
1839 return *this;
1840 }
1841
Jack Palevich303d8ff2009-06-11 19:06:24 -07001842 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001843 return mpBase;
1844 }
1845
Jack Palevich303d8ff2009-06-11 19:06:24 -07001846 void clear() {
1847 mUsed = 0;
1848 if (mSize > 0) {
1849 mpBase[0] = 0;
1850 }
1851 }
1852
Jack Palevicheedf9d22009-06-04 16:23:40 -07001853 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001854 appendBytes(s, strlen(s));
1855 }
1856
1857 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001858 memcpy(ensure(n), s, n + 1);
1859 }
1860
1861 void append(char c) {
1862 * ensure(1) = c;
1863 }
1864
Jack Palevich86351982009-06-30 18:09:56 -07001865 void append(String& other) {
1866 appendBytes(other.getUnwrapped(), other.len());
1867 }
1868
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001869 char* orphan() {
1870 char* result = mpBase;
1871 mpBase = 0;
1872 mUsed = 0;
1873 mSize = 0;
1874 return result;
1875 }
1876
Jack Palevicheedf9d22009-06-04 16:23:40 -07001877 void printf(const char* fmt,...) {
1878 va_list ap;
1879 va_start(ap, fmt);
1880 vprintf(fmt, ap);
1881 va_end(ap);
1882 }
1883
1884 void vprintf(const char* fmt, va_list ap) {
1885 char* temp;
1886 int numChars = vasprintf(&temp, fmt, ap);
1887 memcpy(ensure(numChars), temp, numChars+1);
1888 free(temp);
1889 }
1890
Jack Palevich303d8ff2009-06-11 19:06:24 -07001891 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001892 return mUsed;
1893 }
1894
1895 private:
1896 char* ensure(int n) {
1897 size_t newUsed = mUsed + n;
1898 if (newUsed > mSize) {
1899 size_t newSize = mSize * 2 + 10;
1900 if (newSize < newUsed) {
1901 newSize = newUsed;
1902 }
1903 mpBase = (char*) realloc(mpBase, newSize + 1);
1904 mSize = newSize;
1905 }
1906 mpBase[newUsed] = '\0';
1907 char* result = mpBase + mUsed;
1908 mUsed = newUsed;
1909 return result;
1910 }
1911
1912 char* mpBase;
1913 size_t mUsed;
1914 size_t mSize;
1915 };
1916
Jack Palevich569f1352009-06-29 14:29:08 -07001917 void internKeywords() {
1918 // Note: order has to match TOK_ constants
1919 static const char* keywords[] = {
1920 "int",
1921 "char",
1922 "void",
1923 "if",
1924 "else",
1925 "while",
1926 "break",
1927 "return",
1928 "for",
1929 "pragma",
1930 "define",
1931 "auto",
1932 "case",
1933 "const",
1934 "continue",
1935 "default",
1936 "do",
1937 "double",
1938 "enum",
1939 "extern",
1940 "float",
1941 "goto",
1942 "long",
1943 "register",
1944 "short",
1945 "signed",
1946 "sizeof",
1947 "static",
1948 "struct",
1949 "switch",
1950 "typedef",
1951 "union",
1952 "unsigned",
1953 "volatile",
1954 "_Bool",
1955 "_Complex",
1956 "_Imaginary",
1957 "inline",
1958 "restrict",
1959 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001960
Jack Palevich569f1352009-06-29 14:29:08 -07001961 for(int i = 0; keywords[i]; i++) {
1962 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001963 }
Jack Palevich569f1352009-06-29 14:29:08 -07001964 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001965
Jack Palevich36d94142009-06-08 15:55:32 -07001966 struct InputState {
1967 InputStream* pStream;
1968 int oldCh;
1969 };
1970
Jack Palevich2db168f2009-06-11 14:29:47 -07001971 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001972 void* pAddress;
1973 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07001974 tokenid_t tok;
1975 size_t level;
1976 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07001977 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07001978 };
1979
Jack Palevich303d8ff2009-06-11 19:06:24 -07001980 class SymbolStack {
1981 public:
1982 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07001983 mpArena = 0;
1984 mpTokenTable = 0;
1985 }
1986
1987 void setArena(Arena* pArena) {
1988 mpArena = pArena;
1989 }
1990
1991 void setTokenTable(TokenTable* pTokenTable) {
1992 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001993 }
1994
1995 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07001996 Mark mark;
1997 mark.mArenaMark = mpArena->mark();
1998 mark.mSymbolHead = mStack.size();
1999 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002000 }
2001
2002 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002003 // Undo any shadowing that was done:
2004 Mark mark = mLevelStack.back();
2005 mLevelStack.pop_back();
2006 while (mStack.size() > mark.mSymbolHead) {
2007 VariableInfo* pV = mStack.back();
2008 mStack.pop_back();
2009 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002010 }
Jack Palevich569f1352009-06-29 14:29:08 -07002011 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002012 }
2013
Jack Palevich569f1352009-06-29 14:29:08 -07002014 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2015 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2016 return pV && pV->level == level();
2017 }
2018
2019 VariableInfo* add(tokenid_t tok) {
2020 Token& token = (*mpTokenTable)[tok];
2021 VariableInfo* pOldV = token.mpVariableInfo;
2022 VariableInfo* pNewV =
2023 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2024 memset(pNewV, 0, sizeof(VariableInfo));
2025 pNewV->tok = tok;
2026 pNewV->level = level();
2027 pNewV->pOldDefinition = pOldV;
2028 token.mpVariableInfo = pNewV;
2029 mStack.push_back(pNewV);
2030 return pNewV;
2031 }
2032
Jack Palevich86351982009-06-30 18:09:56 -07002033 VariableInfo* add(Type* pType) {
2034 VariableInfo* pVI = add(pType->id);
2035 pVI->pType = pType;
2036 return pVI;
2037 }
2038
Jack Palevich569f1352009-06-29 14:29:08 -07002039 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2040 for (size_t i = 0; i < mStack.size(); i++) {
2041 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002042 break;
2043 }
2044 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002045 }
2046
Jack Palevich303d8ff2009-06-11 19:06:24 -07002047 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002048 inline size_t level() {
2049 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002050 }
2051
Jack Palevich569f1352009-06-29 14:29:08 -07002052 struct Mark {
2053 Arena::Mark mArenaMark;
2054 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002055 };
2056
Jack Palevich569f1352009-06-29 14:29:08 -07002057 Arena* mpArena;
2058 TokenTable* mpTokenTable;
2059 Vector<VariableInfo*> mStack;
2060 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002061 };
Jack Palevich36d94142009-06-08 15:55:32 -07002062
2063 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002064 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002065 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002066 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002067 int tokl; // token operator level
2068 intptr_t rsym; // return symbol
2069 intptr_t loc; // local variable index
2070 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002071 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002072 char* dptr; // Macro state: Points to macro text during macro playback.
2073 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002074 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002075
2076 // Arena for the duration of the compile
2077 Arena mGlobalArena;
2078 // Arena for data that's only needed when compiling a single function
2079 Arena mLocalArena;
2080
2081 TokenTable mTokenTable;
2082 SymbolStack mGlobals;
2083 SymbolStack mLocals;
2084
Jack Palevich40600de2009-07-01 15:32:35 -07002085 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002086 Type* mkpInt; // int
2087 Type* mkpChar; // char
2088 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002089 Type* mkpFloat;
2090 Type* mkpDouble;
Jack Palevich3f226492009-07-02 14:46:19 -07002091 Type* mkpIntPtr;
2092 Type* mkpCharPtr;
2093 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002094
Jack Palevich36d94142009-06-08 15:55:32 -07002095 InputStream* file;
2096
2097 CodeBuf codeBuf;
2098 CodeGenerator* pGen;
2099
Jack Palevicheedf9d22009-06-04 16:23:40 -07002100 String mErrorBuf;
2101
Jack Palevicheedf9d22009-06-04 16:23:40 -07002102 String mPragmas;
2103 int mPragmaStringCount;
2104
Jack Palevich21a15a22009-05-11 14:49:29 -07002105 static const int ALLOC_SIZE = 99999;
2106
Jack Palevich303d8ff2009-06-11 19:06:24 -07002107 static const int TOK_DUMMY = 1;
2108 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002109 static const int TOK_NUM_FLOAT = 3;
2110 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002111
2112 // 3..255 are character and/or operators
2113
Jack Palevich2db168f2009-06-11 14:29:47 -07002114 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002115 // Order has to match string list in "internKeywords".
2116 enum {
2117 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2118 TOK_INT = TOK_KEYWORD,
2119 TOK_CHAR,
2120 TOK_VOID,
2121 TOK_IF,
2122 TOK_ELSE,
2123 TOK_WHILE,
2124 TOK_BREAK,
2125 TOK_RETURN,
2126 TOK_FOR,
2127 TOK_PRAGMA,
2128 TOK_DEFINE,
2129 TOK_AUTO,
2130 TOK_CASE,
2131 TOK_CONST,
2132 TOK_CONTINUE,
2133 TOK_DEFAULT,
2134 TOK_DO,
2135 TOK_DOUBLE,
2136 TOK_ENUM,
2137 TOK_EXTERN,
2138 TOK_FLOAT,
2139 TOK_GOTO,
2140 TOK_LONG,
2141 TOK_REGISTER,
2142 TOK_SHORT,
2143 TOK_SIGNED,
2144 TOK_SIZEOF,
2145 TOK_STATIC,
2146 TOK_STRUCT,
2147 TOK_SWITCH,
2148 TOK_TYPEDEF,
2149 TOK_UNION,
2150 TOK_UNSIGNED,
2151 TOK_VOLATILE,
2152 TOK__BOOL,
2153 TOK__COMPLEX,
2154 TOK__IMAGINARY,
2155 TOK_INLINE,
2156 TOK_RESTRICT,
2157 // Symbols start after tokens
2158 TOK_SYMBOL
2159 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002160
2161 static const int LOCAL = 0x200;
2162
2163 static const int SYM_FORWARD = 0;
2164 static const int SYM_DEFINE = 1;
2165
2166 /* tokens in string heap */
2167 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002168
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002169 static const int OP_INCREMENT = 0;
2170 static const int OP_DECREMENT = 1;
2171 static const int OP_MUL = 2;
2172 static const int OP_DIV = 3;
2173 static const int OP_MOD = 4;
2174 static const int OP_PLUS = 5;
2175 static const int OP_MINUS = 6;
2176 static const int OP_SHIFT_LEFT = 7;
2177 static const int OP_SHIFT_RIGHT = 8;
2178 static const int OP_LESS_EQUAL = 9;
2179 static const int OP_GREATER_EQUAL = 10;
2180 static const int OP_LESS = 11;
2181 static const int OP_GREATER = 12;
2182 static const int OP_EQUALS = 13;
2183 static const int OP_NOT_EQUALS = 14;
2184 static const int OP_LOGICAL_AND = 15;
2185 static const int OP_LOGICAL_OR = 16;
2186 static const int OP_BIT_AND = 17;
2187 static const int OP_BIT_XOR = 18;
2188 static const int OP_BIT_OR = 19;
2189 static const int OP_BIT_NOT = 20;
2190 static const int OP_LOGICAL_NOT = 21;
2191 static const int OP_COUNT = 22;
2192
2193 /* Operators are searched from front, the two-character operators appear
2194 * before the single-character operators with the same first character.
2195 * @ is used to pad out single-character operators.
2196 */
2197 static const char* operatorChars;
2198 static const char operatorLevel[];
2199
Jack Palevich569f1352009-06-29 14:29:08 -07002200 /* Called when we detect an internal problem. Does nothing in production.
2201 *
2202 */
2203 void internalError() {
2204 * (char*) 0 = 0;
2205 }
2206
Jack Palevich86351982009-06-30 18:09:56 -07002207 void assert(bool isTrue) {
2208 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002209 internalError();
2210 }
Jack Palevich86351982009-06-30 18:09:56 -07002211 }
2212
Jack Palevich40600de2009-07-01 15:32:35 -07002213 bool isSymbol(tokenid_t t) {
2214 return t >= TOK_SYMBOL &&
2215 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2216 }
2217
2218 bool isSymbolOrKeyword(tokenid_t t) {
2219 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002220 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002221 }
2222
Jack Palevich86351982009-06-30 18:09:56 -07002223 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002224 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002225 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2226 if (pV && pV->tok != t) {
2227 internalError();
2228 }
2229 return pV;
2230 }
2231
2232 inline bool isDefined(tokenid_t t) {
2233 return t >= TOK_SYMBOL && VI(t) != 0;
2234 }
2235
Jack Palevich40600de2009-07-01 15:32:35 -07002236 const char* nameof(tokenid_t t) {
2237 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002238 return mTokenTable[t].pText;
2239 }
2240
Jack Palevich21a15a22009-05-11 14:49:29 -07002241 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002242 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002243 }
2244
2245 void inp() {
2246 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002247 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002248 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002249 dptr = 0;
2250 ch = dch;
2251 }
2252 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002253 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002254#if 0
2255 printf("ch='%c' 0x%x\n", ch, ch);
2256#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002257 }
2258
2259 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002260 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002261 }
2262
Jack Palevichb4758ff2009-06-12 12:49:14 -07002263 /* read a character constant, advances ch to after end of constant */
2264 int getq() {
2265 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002266 if (ch == '\\') {
2267 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002268 if (isoctal(ch)) {
2269 // 1 to 3 octal characters.
2270 val = 0;
2271 for(int i = 0; i < 3; i++) {
2272 if (isoctal(ch)) {
2273 val = (val << 3) + ch - '0';
2274 inp();
2275 }
2276 }
2277 return val;
2278 } else if (ch == 'x' || ch == 'X') {
2279 // N hex chars
2280 inp();
2281 if (! isxdigit(ch)) {
2282 error("'x' character escape requires at least one digit.");
2283 } else {
2284 val = 0;
2285 while (isxdigit(ch)) {
2286 int d = ch;
2287 if (isdigit(d)) {
2288 d -= '0';
2289 } else if (d <= 'F') {
2290 d = d - 'A' + 10;
2291 } else {
2292 d = d - 'a' + 10;
2293 }
2294 val = (val << 4) + d;
2295 inp();
2296 }
2297 }
2298 } else {
2299 int val = ch;
2300 switch (ch) {
2301 case 'a':
2302 val = '\a';
2303 break;
2304 case 'b':
2305 val = '\b';
2306 break;
2307 case 'f':
2308 val = '\f';
2309 break;
2310 case 'n':
2311 val = '\n';
2312 break;
2313 case 'r':
2314 val = '\r';
2315 break;
2316 case 't':
2317 val = '\t';
2318 break;
2319 case 'v':
2320 val = '\v';
2321 break;
2322 case '\\':
2323 val = '\\';
2324 break;
2325 case '\'':
2326 val = '\'';
2327 break;
2328 case '"':
2329 val = '"';
2330 break;
2331 case '?':
2332 val = '?';
2333 break;
2334 default:
2335 error("Undefined character escape %c", ch);
2336 break;
2337 }
2338 inp();
2339 return val;
2340 }
2341 } else {
2342 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002343 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002344 return val;
2345 }
2346
2347 static bool isoctal(int ch) {
2348 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002349 }
2350
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002351 bool acceptCh(int c) {
2352 bool result = c == ch;
2353 if (result) {
2354 pdef(ch);
2355 inp();
2356 }
2357 return result;
2358 }
2359
2360 bool acceptDigitsCh() {
2361 bool result = false;
2362 while (isdigit(ch)) {
2363 result = true;
2364 pdef(ch);
2365 inp();
2366 }
2367 return result;
2368 }
2369
2370 void parseFloat() {
2371 tok = TOK_NUM_DOUBLE;
2372 // mTokenString already has the integral part of the number.
2373 acceptCh('.');
2374 acceptDigitsCh();
2375 bool doExp = true;
2376 if (acceptCh('e') || acceptCh('E')) {
2377 // Don't need to do any extra work
2378 } else if (ch == 'f' || ch == 'F') {
2379 pdef('e'); // So it can be parsed by strtof.
2380 inp();
2381 tok = TOK_NUM_FLOAT;
2382 } else {
2383 doExp = false;
2384 }
2385 if (doExp) {
2386 bool digitsRequired = acceptCh('-');
2387 bool digitsFound = acceptDigitsCh();
2388 if (digitsRequired && ! digitsFound) {
2389 error("malformed exponent");
2390 }
2391 }
2392 char* pText = mTokenString.getUnwrapped();
2393 if (tok == TOK_NUM_FLOAT) {
2394 tokd = strtof(pText, 0);
2395 } else {
2396 tokd = strtod(pText, 0);
2397 }
2398 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2399 }
2400
Jack Palevich21a15a22009-05-11 14:49:29 -07002401 void next() {
2402 int l, a;
2403
Jack Palevich546b2242009-05-13 15:10:04 -07002404 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002405 if (ch == '#') {
2406 inp();
2407 next();
2408 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002409 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002410 } else if (tok == TOK_PRAGMA) {
2411 doPragma();
2412 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002413 error("Unsupported preprocessor directive \"%s\"",
2414 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002415 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002416 }
2417 inp();
2418 }
2419 tokl = 0;
2420 tok = ch;
2421 /* encode identifiers & numbers */
2422 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002423 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002424 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002425 pdef(ch);
2426 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002427 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002428 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002429 // Start of a numeric constant. Could be integer, float, or
2430 // double, won't know until we look further.
2431 if (ch == '.' || ch == 'e' || ch == 'e'
2432 || ch == 'f' || ch == 'F') {
2433 parseFloat();
2434 } else {
2435 // It's an integer constant
2436 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2437 tok = TOK_NUM;
2438 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002439 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002440 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2441 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002442 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002443 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2444 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002445 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002446 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002447 dch = ch;
2448 inp();
2449 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002450 }
2451 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002452 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002453 inp();
2454 if (tok == '\'') {
2455 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002456 tokc = getq();
2457 if (ch != '\'') {
2458 error("Expected a ' character, got %c", ch);
2459 } else {
2460 inp();
2461 }
Jack Palevich546b2242009-05-13 15:10:04 -07002462 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002463 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002464 while (ch && ch != EOF) {
2465 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002466 inp();
2467 inp();
2468 if (ch == '/')
2469 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002470 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002471 if (ch == EOF) {
2472 error("End of file inside comment.");
2473 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002474 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002475 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002476 } else if ((tok == '/') & (ch == '/')) {
2477 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002478 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002479 inp();
2480 }
2481 inp();
2482 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002483 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002484 const char* t = operatorChars;
2485 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002486 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002487 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002488 tokl = operatorLevel[opIndex];
2489 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002490 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002491#if 0
2492 printf("%c%c -> tokl=%d tokc=0x%x\n",
2493 l, a, tokl, tokc);
2494#endif
2495 if (a == ch) {
2496 inp();
2497 tok = TOK_DUMMY; /* dummy token for double tokens */
2498 }
2499 break;
2500 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002501 opIndex++;
2502 }
2503 if (l == 0) {
2504 tokl = 0;
2505 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002506 }
2507 }
2508 }
2509#if 0
2510 {
Jack Palevich569f1352009-06-29 14:29:08 -07002511 String buf;
2512 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002513 fprintf(stderr, "%s\n", buf.getUnwrapped());
2514 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002515#endif
2516 }
2517
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002518 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002519 next();
2520 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002521 String* pName = new String();
2522 while (isspace(ch)) {
2523 inp();
2524 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002525 if (ch == '(') {
2526 delete pName;
2527 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002528 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002529 }
2530 while (isspace(ch)) {
2531 inp();
2532 }
Jack Palevich569f1352009-06-29 14:29:08 -07002533 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002534 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002535 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002536 inp();
2537 }
Jack Palevich569f1352009-06-29 14:29:08 -07002538 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2539 memcpy(pDefn, value.getUnwrapped(), value.len());
2540 pDefn[value.len()] = 0;
2541 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002542 }
2543
Jack Palevicheedf9d22009-06-04 16:23:40 -07002544 void doPragma() {
2545 // # pragma name(val)
2546 int state = 0;
2547 while(ch != EOF && ch != '\n' && state < 10) {
2548 switch(state) {
2549 case 0:
2550 if (isspace(ch)) {
2551 inp();
2552 } else {
2553 state++;
2554 }
2555 break;
2556 case 1:
2557 if (isalnum(ch)) {
2558 mPragmas.append(ch);
2559 inp();
2560 } else if (ch == '(') {
2561 mPragmas.append(0);
2562 inp();
2563 state++;
2564 } else {
2565 state = 11;
2566 }
2567 break;
2568 case 2:
2569 if (isalnum(ch)) {
2570 mPragmas.append(ch);
2571 inp();
2572 } else if (ch == ')') {
2573 mPragmas.append(0);
2574 inp();
2575 state = 10;
2576 } else {
2577 state = 11;
2578 }
2579 break;
2580 }
2581 }
2582 if(state != 10) {
2583 error("Unexpected pragma syntax");
2584 }
2585 mPragmaStringCount += 2;
2586 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002587
Jack Palevichac0e95e2009-05-29 13:53:44 -07002588 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002589 mErrorBuf.printf("%ld: ", file->getLine());
2590 mErrorBuf.vprintf(fmt, ap);
2591 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002592 }
2593
Jack Palevich8b0624c2009-05-20 12:12:06 -07002594 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002595 if (tok != c) {
2596 error("'%c' expected", c);
2597 }
2598 next();
2599 }
2600
Jack Palevich86351982009-06-30 18:09:56 -07002601 bool accept(intptr_t c) {
2602 if (tok == c) {
2603 next();
2604 return true;
2605 }
2606 return false;
2607 }
2608
Jack Palevich40600de2009-07-01 15:32:35 -07002609 bool acceptStringLiteral() {
2610 if (tok == '"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07002611 pGen->li((int) glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002612 // This while loop merges multiple adjacent string constants.
2613 while (tok == '"') {
2614 while (ch != '"' && ch != EOF) {
2615 *allocGlobalSpace(1) = getq();
2616 }
2617 if (ch != '"') {
2618 error("Unterminated string constant.");
2619 }
2620 inp();
2621 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002622 }
Jack Palevich40600de2009-07-01 15:32:35 -07002623 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002624 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002625 /* align heap */
2626 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002627
2628 return true;
2629 }
2630 return false;
2631 }
2632 /* Parse and evaluate a unary expression.
2633 * allowAssignment is true if '=' parsing wanted (quick hack)
2634 */
2635 void unary(bool allowAssignment) {
2636 intptr_t n, t, a;
2637 t = 0;
2638 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2639 if (acceptStringLiteral()) {
2640 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002641 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002642 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002643 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002644 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07002645 t = tok;
2646 next();
2647 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002648 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002649 } else if (t == TOK_NUM_FLOAT) {
2650 pGen->lif(ad);
2651 } else if (t == TOK_NUM_DOUBLE) {
2652 pGen->lid(ad);
Jack Palevich21a15a22009-05-11 14:49:29 -07002653 } else if (c == 2) {
2654 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002655 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002656 if (t == '!')
Jack Palevich9eed7a22009-07-06 17:24:34 -07002657 pGen->gUnaryCmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002658 else
Jack Palevich9eed7a22009-07-06 17:24:34 -07002659 pGen->genUnaryOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002660 } else if (t == '(') {
2661 expr();
2662 skip(')');
2663 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002664 /* This is a pointer dereference, but we currently only
2665 * support a pointer dereference if it's immediately
2666 * in front of a cast. So parse the cast right here.
2667 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002668 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002669 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2670 // We currently only handle 3 types of cast:
2671 // (int*), (char*) , (int (*)())
2672 if(typeEqual(pCast, mkpIntPtr)) {
2673 t = TOK_INT;
2674 } else if (typeEqual(pCast, mkpCharPtr)) {
2675 t = TOK_CHAR;
2676 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002677 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002678 } else {
2679 String buffer;
2680 decodeType(buffer, pCast);
2681 error("Unsupported cast type %s", buffer.getUnwrapped());
2682 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002683 }
2684 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002685 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002686 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002687 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002688 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002689 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002690 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002691 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002692 }
Jack Palevich3f226492009-07-02 14:46:19 -07002693 // Else we fall through to the function call below, with
2694 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002695 } else if (t == '&') {
Jack Palevich569f1352009-06-29 14:29:08 -07002696 pGen->leaR0((int) VI(tok)->pAddress);
Jack Palevich21a15a22009-05-11 14:49:29 -07002697 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002698 } else if (t == EOF ) {
2699 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002700 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002701 // Don't have to do anything special here, the error
2702 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002703 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002704 if (!isDefined(t)) {
2705 mGlobals.add(t);
2706 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002707 }
2708
Jack Palevich569f1352009-06-29 14:29:08 -07002709 n = (intptr_t) VI(t)->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002710 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002711 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002712 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002713 VI(t)->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002714 }
Jack Palevich40600de2009-07-01 15:32:35 -07002715 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002716 /* assignment */
2717 next();
2718 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002719 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002720 } else if (tok != '(') {
2721 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002722 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002723 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07002724 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002725 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002726 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002727 next();
2728 }
2729 }
2730 }
2731 }
2732
2733 /* function call */
2734 if (tok == '(') {
2735 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002736 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002737
2738 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002739 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07002740 next();
Jack Palevich40600de2009-07-01 15:32:35 -07002741 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002742 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002743 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002744 pGen->storeR0ToArg(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002745 l = l + 4;
Jack Palevich95727a02009-07-06 12:07:15 -07002746 if (accept(',')) {
2747 // fine
2748 } else if ( tok != ')') {
2749 error("Expected ',' or ')'");
2750 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002751 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002752 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002753 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002754 if (!n) {
2755 /* forward reference */
Jack Palevich569f1352009-06-29 14:29:08 -07002756 VariableInfo* pVI = VI(t);
2757 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward);
Jack Palevich21a15a22009-05-11 14:49:29 -07002758 } else if (n == 1) {
2759 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002760 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07002761 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07002762 }
-b master422972c2009-06-17 19:13:52 -07002763 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002764 }
2765 }
2766
Jack Palevich40600de2009-07-01 15:32:35 -07002767 /* Recursive descent parser for binary operations.
2768 */
2769 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002770 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002771 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002772 if (level-- == 1)
2773 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07002774 else {
Jack Palevich40600de2009-07-01 15:32:35 -07002775 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002776 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002777 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002778 n = tok;
2779 t = tokc;
2780 next();
2781
Jack Palevich40600de2009-07-01 15:32:35 -07002782 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002783 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002784 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002785 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002786 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07002787 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002788
Jack Palevich40600de2009-07-01 15:32:35 -07002789 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002790 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002791 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002792 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002793 }
2794 }
2795 }
2796 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002797 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002798 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2799 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002800 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002801 pGen->gsym(a);
2802 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002803 }
2804 }
2805 }
2806
2807 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07002808 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07002809 }
2810
2811 int test_expr() {
2812 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002813 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002814 }
2815
Jack Palevicha6baa232009-06-12 11:25:59 -07002816 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002817 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002818
Jack Palevich95727a02009-07-06 12:07:15 -07002819 Type* pBaseType;
2820 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002821 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07002822 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07002823 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002824 next();
2825 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002826 a = test_expr();
2827 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002828 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002829 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002830 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002831 n = pGen->gjmp(0); /* jmp */
2832 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002833 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002834 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002835 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002836 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002837 }
Jack Palevich546b2242009-05-13 15:10:04 -07002838 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002839 t = tok;
2840 next();
2841 skip('(');
2842 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002843 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002844 a = test_expr();
2845 } else {
2846 if (tok != ';')
2847 expr();
2848 skip(';');
2849 n = codeBuf.getPC();
2850 a = 0;
2851 if (tok != ';')
2852 a = test_expr();
2853 skip(';');
2854 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002855 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002856 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002857 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002858 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002859 n = t + 4;
2860 }
2861 }
2862 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002863 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002864 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002865 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002866 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002867 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002868 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002869 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002870 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002871 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002872 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002873 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002874 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002875 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002876 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002877 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07002878 if (accept(TOK_RETURN)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002879 if (tok != ';')
2880 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002881 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07002882 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002883 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002884 } else if (tok != ';')
2885 expr();
2886 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002887 }
2888 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002889
Jack Palevich86351982009-06-30 18:09:56 -07002890 enum TypeTag {
Jack Palevich95727a02009-07-06 12:07:15 -07002891 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
2892 TY_POINTER, TY_FUNC, TY_PARAM
Jack Palevich86351982009-06-30 18:09:56 -07002893 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002894
Jack Palevich86351982009-06-30 18:09:56 -07002895 struct Type {
2896 TypeTag tag;
2897 tokenid_t id; // For function arguments
2898 Type* pHead;
2899 Type* pTail;
2900 };
2901
Jack Palevich3f226492009-07-02 14:46:19 -07002902 bool typeEqual(Type* a, Type* b) {
2903 if (a == b) {
2904 return true;
2905 }
2906 if (a == NULL || b == NULL) {
2907 return false;
2908 }
2909 TypeTag at = a->tag;
2910 if (at != b->tag) {
2911 return false;
2912 }
2913 if (at == TY_POINTER) {
2914 return typeEqual(a->pHead, b->pHead);
2915 } else if (at == TY_FUNC || at == TY_PARAM) {
2916 return typeEqual(a->pHead, b->pHead)
2917 && typeEqual(a->pTail, b->pTail);
2918 }
2919 return true;
2920 }
2921
Jack Palevich86351982009-06-30 18:09:56 -07002922 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
2923 assert(tag >= TY_INT && tag <= TY_PARAM);
2924 Type* pType = (Type*) arena.alloc(sizeof(Type));
2925 memset(pType, 0, sizeof(*pType));
2926 pType->tag = tag;
2927 pType->pHead = pHead;
2928 pType->pTail = pTail;
2929 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002930 }
2931
Jack Palevich3f226492009-07-02 14:46:19 -07002932 Type* createPtrType(Type* pType, Arena& arena) {
2933 return createType(TY_POINTER, pType, NULL, arena);
2934 }
2935
2936 /**
2937 * Try to print a type in declaration order
2938 */
Jack Palevich86351982009-06-30 18:09:56 -07002939 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07002940 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07002941 if (pType == NULL) {
2942 buffer.appendCStr("null");
2943 return;
2944 }
Jack Palevich3f226492009-07-02 14:46:19 -07002945 decodeTypeImp(buffer, pType);
2946 }
2947
2948 void decodeTypeImp(String& buffer, Type* pType) {
2949 decodeTypeImpPrefix(buffer, pType);
2950
Jack Palevich86351982009-06-30 18:09:56 -07002951 String temp;
2952 if (pType->id != 0) {
2953 decodeToken(temp, pType->id);
2954 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07002955 }
2956
2957 decodeTypeImpPostfix(buffer, pType);
2958 }
2959
2960 void decodeTypeImpPrefix(String& buffer, Type* pType) {
2961 TypeTag tag = pType->tag;
2962
2963 if (tag >= TY_INT && tag <= TY_VOID) {
2964 switch (tag) {
2965 case TY_INT:
2966 buffer.appendCStr("int");
2967 break;
2968 case TY_CHAR:
2969 buffer.appendCStr("char");
2970 break;
2971 case TY_VOID:
2972 buffer.appendCStr("void");
2973 break;
Jack Palevich95727a02009-07-06 12:07:15 -07002974 case TY_FLOAT:
2975 buffer.appendCStr("float");
2976 break;
2977 case TY_DOUBLE:
2978 buffer.appendCStr("double");
2979 break;
Jack Palevich3f226492009-07-02 14:46:19 -07002980 default:
2981 break;
2982 }
Jack Palevich86351982009-06-30 18:09:56 -07002983 buffer.append(' ');
2984 }
Jack Palevich3f226492009-07-02 14:46:19 -07002985
2986 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07002987 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07002988 break;
2989 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07002990 break;
2991 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07002992 break;
Jack Palevich95727a02009-07-06 12:07:15 -07002993 case TY_FLOAT:
2994 break;
2995 case TY_DOUBLE:
2996 break;
Jack Palevich86351982009-06-30 18:09:56 -07002997 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07002998 decodeTypeImpPrefix(buffer, pType->pHead);
2999 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3000 buffer.append('(');
3001 }
3002 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003003 break;
3004 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003005 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003006 break;
3007 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003008 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003009 break;
3010 default:
3011 String temp;
3012 temp.printf("Unknown tag %d", pType->tag);
3013 buffer.append(temp);
3014 break;
3015 }
Jack Palevich3f226492009-07-02 14:46:19 -07003016 }
3017
3018 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3019 TypeTag tag = pType->tag;
3020
3021 switch(tag) {
3022 case TY_POINTER:
3023 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3024 buffer.append(')');
3025 }
3026 decodeTypeImpPostfix(buffer, pType->pHead);
3027 break;
3028 case TY_FUNC:
3029 buffer.append('(');
3030 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3031 decodeTypeImp(buffer, pArg);
3032 if (pArg->pTail) {
3033 buffer.appendCStr(", ");
3034 }
3035 }
3036 buffer.append(')');
3037 break;
3038 default:
3039 break;
Jack Palevich86351982009-06-30 18:09:56 -07003040 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003041 }
3042
Jack Palevich86351982009-06-30 18:09:56 -07003043 void printType(Type* pType) {
3044 String buffer;
3045 decodeType(buffer, pType);
3046 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003047 }
3048
Jack Palevich86351982009-06-30 18:09:56 -07003049 Type* acceptPrimitiveType(Arena& arena) {
3050 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003051 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003052 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003053 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003054 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003055 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003056 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003057 } else if (tok == TOK_FLOAT) {
3058 pType = mkpFloat;
3059 } else if (tok == TOK_DOUBLE) {
3060 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003061 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003062 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003063 }
3064 next();
Jack Palevich86351982009-06-30 18:09:56 -07003065 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003066 }
3067
Jack Palevich3f226492009-07-02 14:46:19 -07003068 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3069 Arena& arena) {
3070 tokenid_t declName = 0;
3071 pType = acceptDecl2(pType, declName, nameAllowed,
3072 nameRequired, arena);
3073 if (declName) {
3074 // Clone the parent type so we can set a unique ID
3075 pType = createType(pType->tag, pType->pHead,
3076 pType->pTail, arena);
3077
Jack Palevich86351982009-06-30 18:09:56 -07003078 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003079 }
Jack Palevich3f226492009-07-02 14:46:19 -07003080 // fprintf(stderr, "Parsed a declaration: ");
3081 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003082 return pType;
3083 }
3084
Jack Palevich3f226492009-07-02 14:46:19 -07003085 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3086 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003087 if (! pType) {
3088 error("Expected a declaration");
3089 }
3090 return pType;
3091 }
3092
Jack Palevich3f226492009-07-02 14:46:19 -07003093 /* Used for accepting types that appear in casts */
3094 Type* acceptCastTypeDeclaration(Arena& arena) {
3095 Type* pType = acceptPrimitiveType(arena);
3096 if (pType) {
3097 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003098 }
Jack Palevich86351982009-06-30 18:09:56 -07003099 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003100 }
3101
Jack Palevich3f226492009-07-02 14:46:19 -07003102 Type* expectCastTypeDeclaration(Arena& arena) {
3103 Type* pType = acceptCastTypeDeclaration(arena);
3104 if (! pType) {
3105 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003106 }
Jack Palevich3f226492009-07-02 14:46:19 -07003107 return pType;
3108 }
3109
3110 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3111 bool nameAllowed, bool nameRequired, Arena& arena) {
3112 int ptrCounter = 0;
3113 while (accept('*')) {
3114 ptrCounter++;
3115 }
3116 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3117 while (ptrCounter-- > 0) {
3118 pType = createType(TY_POINTER, pType, NULL, arena);
3119 }
3120 return pType;
3121 }
3122
3123 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3124 bool nameAllowed, bool nameRequired, Arena& arena) {
3125 // direct-dcl :
3126 // name
3127 // (dcl)
3128 // direct-dcl()
3129 // direct-dcl[]
3130 Type* pNewHead = NULL;
3131 if (accept('(')) {
3132 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3133 nameRequired, arena);
3134 skip(')');
3135 } else if ((declName = acceptSymbol()) != 0) {
3136 if (nameAllowed == false && declName) {
3137 error("Symbol %s not allowed here", nameof(declName));
3138 } else if (nameRequired && ! declName) {
3139 String temp;
3140 decodeToken(temp, tok);
3141 error("Expected symbol. Got %s", temp.getUnwrapped());
3142 }
3143 }
3144 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003145 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003146 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003147 pType = createType(TY_FUNC, pType, pTail, arena);
3148 skip(')');
3149 }
Jack Palevich3f226492009-07-02 14:46:19 -07003150
3151 if (pNewHead) {
3152 Type* pA = pNewHead;
3153 while (pA->pHead) {
3154 pA = pA->pHead;
3155 }
3156 pA->pHead = pType;
3157 pType = pNewHead;
3158 }
Jack Palevich86351982009-06-30 18:09:56 -07003159 return pType;
3160 }
3161
Jack Palevich3f226492009-07-02 14:46:19 -07003162 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003163 Type* pHead = NULL;
3164 Type* pTail = NULL;
3165 for(;;) {
3166 Type* pBaseArg = acceptPrimitiveType(arena);
3167 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003168 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3169 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003170 if (pArg) {
3171 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3172 if (!pHead) {
3173 pHead = pParam;
3174 pTail = pParam;
3175 } else {
3176 pTail->pTail = pParam;
3177 pTail = pParam;
3178 }
3179 }
3180 }
3181 if (! accept(',')) {
3182 break;
3183 }
3184 }
3185 return pHead;
3186 }
3187
3188 Type* expectPrimitiveType(Arena& arena) {
3189 Type* pType = acceptPrimitiveType(arena);
3190 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003191 String buf;
3192 decodeToken(buf, tok);
3193 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003194 }
Jack Palevich86351982009-06-30 18:09:56 -07003195 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003196 }
3197
Jack Palevich86351982009-06-30 18:09:56 -07003198 void addGlobalSymbol(Type* pDecl) {
3199 tokenid_t t = pDecl->id;
3200 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003201 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003202 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003203 }
Jack Palevich86351982009-06-30 18:09:56 -07003204 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003205 }
3206
Jack Palevich86351982009-06-30 18:09:56 -07003207 void reportDuplicate(tokenid_t t) {
3208 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003209 }
3210
Jack Palevich86351982009-06-30 18:09:56 -07003211 void addLocalSymbol(Type* pDecl) {
3212 tokenid_t t = pDecl->id;
3213 if (mLocals.isDefinedAtCurrentLevel(t)) {
3214 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003215 }
Jack Palevich86351982009-06-30 18:09:56 -07003216 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003217 }
3218
Jack Palevich95727a02009-07-06 12:07:15 -07003219 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003220 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003221
Jack Palevich95727a02009-07-06 12:07:15 -07003222 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003223 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003224 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3225 if (!pDecl) {
3226 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003227 }
Jack Palevich86351982009-06-30 18:09:56 -07003228 int variableAddress = 0;
3229 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003230 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003231 loc = loc + 4;
3232 variableAddress = -loc;
3233 VI(pDecl->id)->pAddress = (void*) variableAddress;
3234 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003235 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003236 expr();
3237 pGen->storeR0(variableAddress);
3238 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003239 if (tok == ',')
3240 next();
3241 }
3242 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003243 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003244 }
3245 }
3246
Jack Palevichf1728be2009-06-12 13:53:51 -07003247 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003248 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003249 }
3250
Jack Palevich569f1352009-06-29 14:29:08 -07003251 void decodeToken(String& buffer, tokenid_t token) {
3252 if (token == EOF ) {
3253 buffer.printf("EOF");
3254 } else if (token == TOK_NUM) {
3255 buffer.printf("numeric constant");
3256 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003257 if (token < 32) {
3258 buffer.printf("'\\x%02x'", token);
3259 } else {
3260 buffer.printf("'%c'", token);
3261 }
Jack Palevich569f1352009-06-29 14:29:08 -07003262 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3263 buffer.printf("keyword \"%s\"", nameof(token));
3264 } else {
3265 buffer.printf("symbol \"%s\"", nameof(token));
3266 }
3267 }
3268
Jack Palevich40600de2009-07-01 15:32:35 -07003269 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003270 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003271 if (!result) {
3272 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003273 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003274 error("Expected symbol. Got %s", temp.getUnwrapped());
3275 }
3276 return result;
3277 }
3278
Jack Palevich86351982009-06-30 18:09:56 -07003279 tokenid_t acceptSymbol() {
3280 tokenid_t result = 0;
3281 if (tok >= TOK_SYMBOL) {
3282 result = tok;
3283 next();
Jack Palevich86351982009-06-30 18:09:56 -07003284 }
3285 return result;
3286 }
3287
Jack Palevichb7c81e92009-06-04 19:56:13 -07003288 void globalDeclarations() {
3289 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003290 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3291 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003292 break;
3293 }
Jack Palevich86351982009-06-30 18:09:56 -07003294 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3295 if (!pDecl) {
3296 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003297 }
Jack Palevich86351982009-06-30 18:09:56 -07003298 if (! isDefined(pDecl->id)) {
3299 addGlobalSymbol(pDecl);
3300 }
3301 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003302 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003303 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003304 }
Jack Palevich86351982009-06-30 18:09:56 -07003305 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003306 // it's a variable declaration
3307 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003308 if (name && !name->pAddress) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003309 name->pAddress = (int*) allocGlobalSpace(4);
3310 }
Jack Palevich86351982009-06-30 18:09:56 -07003311 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003312 if (tok == TOK_NUM) {
3313 if (name) {
3314 * (int*) name->pAddress = tokc;
3315 }
3316 next();
3317 } else {
3318 error("Expected an integer constant");
3319 }
3320 }
Jack Palevich86351982009-06-30 18:09:56 -07003321 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003322 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003323 }
Jack Palevich86351982009-06-30 18:09:56 -07003324 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3325 if (!pDecl) {
3326 break;
3327 }
3328 if (! isDefined(pDecl->id)) {
3329 addGlobalSymbol(pDecl);
3330 }
3331 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003332 }
3333 skip(';');
3334 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003335 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003336 if (accept(';')) {
3337 // forward declaration.
3338 } else {
3339 if (name) {
3340 /* patch forward references (XXX: does not work for function
3341 pointers) */
3342 pGen->gsym((int) name->pForward);
3343 /* put function address */
3344 name->pAddress = (void*) codeBuf.getPC();
3345 }
3346 // Calculate stack offsets for parameters
3347 mLocals.pushLevel();
3348 intptr_t a = 8;
3349 int argCount = 0;
3350 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3351 Type* pArg = pP->pHead;
3352 addLocalSymbol(pArg);
3353 /* read param name and compute offset */
3354 VI(pArg->id)->pAddress = (void*) a;
3355 a = a + 4;
3356 argCount++;
3357 }
3358 rsym = loc = 0;
3359 a = pGen->functionEntry(argCount);
3360 block(0, true);
3361 pGen->gsym(rsym);
3362 pGen->functionExit(argCount, a, loc);
3363 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003364 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003365 }
3366 }
3367 }
3368
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003369 char* allocGlobalSpace(int bytes) {
3370 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
3371 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003372 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003373 }
3374 char* result = glo;
3375 glo += bytes;
3376 return result;
3377 }
3378
Jack Palevich21a15a22009-05-11 14:49:29 -07003379 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003380 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003381 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003382 pGlobalBase = 0;
3383 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003384 if (pGen) {
3385 delete pGen;
3386 pGen = 0;
3387 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003388 if (file) {
3389 delete file;
3390 file = 0;
3391 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003392 }
3393
3394 void clear() {
3395 tok = 0;
3396 tokc = 0;
3397 tokl = 0;
3398 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003399 rsym = 0;
3400 loc = 0;
3401 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003402 dptr = 0;
3403 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003404 file = 0;
3405 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003406 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003407 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003408 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003409
Jack Palevich22305132009-05-13 10:58:45 -07003410 void setArchitecture(const char* architecture) {
3411 delete pGen;
3412 pGen = 0;
3413
3414 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003415#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003416 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003417 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003418 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003419#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003420#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003421 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003422 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003423 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003424#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003425 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003426 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003427 }
3428 }
3429
3430 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003431#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003432 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003433#elif defined(DEFAULT_X86_CODEGEN)
3434 pGen = new X86CodeGenerator();
3435#endif
3436 }
3437 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003438 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003439 } else {
3440 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003441 }
3442 }
3443
Jack Palevich77ae76e2009-05-10 19:59:24 -07003444public:
Jack Palevich22305132009-05-13 10:58:45 -07003445 struct args {
3446 args() {
3447 architecture = 0;
3448 }
3449 const char* architecture;
3450 };
3451
Jack Paleviche7b59062009-05-19 17:12:17 -07003452 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003453 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003454 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003455
Jack Paleviche7b59062009-05-19 17:12:17 -07003456 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003457 cleanup();
3458 }
3459
Jack Palevich1cdef202009-05-22 12:06:27 -07003460 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003461 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003462
3463 cleanup();
3464 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003465 mTokenTable.setArena(&mGlobalArena);
3466 mGlobals.setArena(&mGlobalArena);
3467 mGlobals.setTokenTable(&mTokenTable);
3468 mLocals.setArena(&mLocalArena);
3469 mLocals.setTokenTable(&mTokenTable);
3470
3471 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003472 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003473 codeBuf.init(ALLOC_SIZE);
3474 setArchitecture(NULL);
3475 if (!pGen) {
3476 return -1;
3477 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003478#ifdef PROVIDE_TRACE_CODEGEN
3479 pGen = new TraceCodeGenerator(pGen);
3480#endif
3481 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003482 pGen->init(&codeBuf);
3483 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003484 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3485 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003486 inp();
3487 next();
3488 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003489 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003490 result = pGen->finishCompile();
3491 if (result == 0) {
3492 if (mErrorBuf.len()) {
3493 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003494 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003495 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003496 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003497 }
3498
Jack Palevich86351982009-06-30 18:09:56 -07003499 void createPrimitiveTypes() {
3500 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3501 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3502 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003503 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3504 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003505 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3506 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
3507 mkpPtrIntFn = createPtrType(
3508 createType(TY_FUNC, mkpInt, NULL, mGlobalArena),
3509 mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003510 }
3511
Jack Palevicha6baa232009-06-12 11:25:59 -07003512 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003513 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003514 }
3515
Jack Palevich569f1352009-06-29 14:29:08 -07003516 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003517 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003518 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003519 }
3520
Jack Palevich569f1352009-06-29 14:29:08 -07003521 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003522 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003523 error("Undefined forward reference: %s",
3524 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003525 }
3526 return true;
3527 }
3528
Jack Palevich21a15a22009-05-11 14:49:29 -07003529 int dump(FILE* out) {
3530 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3531 return 0;
3532 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003533
Jack Palevicha6535612009-05-13 16:24:17 -07003534 int disassemble(FILE* out) {
3535 return pGen->disassemble(out);
3536 }
3537
Jack Palevich1cdef202009-05-22 12:06:27 -07003538 /* Look through the symbol table to find a symbol.
3539 * If found, return its value.
3540 */
3541 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003542 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3543 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003544 if (pVariableInfo) {
3545 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003546 }
3547 return NULL;
3548 }
3549
Jack Palevicheedf9d22009-06-04 16:23:40 -07003550 void getPragmas(ACCsizei* actualStringCount,
3551 ACCsizei maxStringCount, ACCchar** strings) {
3552 int stringCount = mPragmaStringCount;
3553 if (actualStringCount) {
3554 *actualStringCount = stringCount;
3555 }
3556 if (stringCount > maxStringCount) {
3557 stringCount = maxStringCount;
3558 }
3559 if (strings) {
3560 char* pPragmas = mPragmas.getUnwrapped();
3561 while (stringCount-- > 0) {
3562 *strings++ = pPragmas;
3563 pPragmas += strlen(pPragmas) + 1;
3564 }
3565 }
3566 }
3567
Jack Palevichac0e95e2009-05-29 13:53:44 -07003568 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003569 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003570 }
3571
Jack Palevich77ae76e2009-05-10 19:59:24 -07003572};
3573
Jack Paleviche7b59062009-05-19 17:12:17 -07003574const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003575 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3576
Jack Paleviche7b59062009-05-19 17:12:17 -07003577const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003578 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3579 5, 5, /* ==, != */
3580 9, 10, /* &&, || */
3581 6, 7, 8, /* & ^ | */
3582 2, 2 /* ~ ! */
3583 };
3584
Jack Palevich8b0624c2009-05-20 12:12:06 -07003585#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003586FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003587#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003588
Jack Palevich8b0624c2009-05-20 12:12:06 -07003589#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003590const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003591 0x1, // ++
3592 0xff, // --
3593 0xc1af0f, // *
3594 0xf9f79991, // /
3595 0xf9f79991, // % (With manual assist to swap results)
3596 0xc801, // +
3597 0xd8f7c829, // -
3598 0xe0d391, // <<
3599 0xf8d391, // >>
3600 0xe, // <=
3601 0xd, // >=
3602 0xc, // <
3603 0xf, // >
3604 0x4, // ==
3605 0x5, // !=
3606 0x0, // &&
3607 0x1, // ||
3608 0xc821, // &
3609 0xc831, // ^
3610 0xc809, // |
3611 0xd0f7, // ~
3612 0x4 // !
3613};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003614#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003615
Jack Palevich1cdef202009-05-22 12:06:27 -07003616struct ACCscript {
3617 ACCscript() {
3618 text = 0;
3619 textLength = 0;
3620 accError = ACC_NO_ERROR;
3621 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003622
Jack Palevich1cdef202009-05-22 12:06:27 -07003623 ~ACCscript() {
3624 delete text;
3625 }
Jack Palevich546b2242009-05-13 15:10:04 -07003626
Jack Palevich1cdef202009-05-22 12:06:27 -07003627 void setError(ACCenum error) {
3628 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3629 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003630 }
3631 }
3632
Jack Palevich1cdef202009-05-22 12:06:27 -07003633 ACCenum getError() {
3634 ACCenum result = accError;
3635 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003636 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003637 }
3638
Jack Palevich1cdef202009-05-22 12:06:27 -07003639 Compiler compiler;
3640 char* text;
3641 int textLength;
3642 ACCenum accError;
3643};
3644
3645
3646extern "C"
3647ACCscript* accCreateScript() {
3648 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003649}
Jack Palevich1cdef202009-05-22 12:06:27 -07003650
3651extern "C"
3652ACCenum accGetError( ACCscript* script ) {
3653 return script->getError();
3654}
3655
3656extern "C"
3657void accDeleteScript(ACCscript* script) {
3658 delete script;
3659}
3660
3661extern "C"
3662void accScriptSource(ACCscript* script,
3663 ACCsizei count,
3664 const ACCchar ** string,
3665 const ACCint * length) {
3666 int totalLength = 0;
3667 for(int i = 0; i < count; i++) {
3668 int len = -1;
3669 const ACCchar* s = string[i];
3670 if (length) {
3671 len = length[i];
3672 }
3673 if (len < 0) {
3674 len = strlen(s);
3675 }
3676 totalLength += len;
3677 }
3678 delete script->text;
3679 char* text = new char[totalLength + 1];
3680 script->text = text;
3681 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003682 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003683 for(int i = 0; i < count; i++) {
3684 int len = -1;
3685 const ACCchar* s = string[i];
3686 if (length) {
3687 len = length[i];
3688 }
3689 if (len < 0) {
3690 len = strlen(s);
3691 }
Jack Palevich09555c72009-05-27 12:25:55 -07003692 memcpy(dest, s, len);
3693 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003694 }
3695 text[totalLength] = '\0';
3696}
3697
3698extern "C"
3699void accCompileScript(ACCscript* script) {
3700 int result = script->compiler.compile(script->text, script->textLength);
3701 if (result) {
3702 script->setError(ACC_INVALID_OPERATION);
3703 }
3704}
3705
3706extern "C"
3707void accGetScriptiv(ACCscript* script,
3708 ACCenum pname,
3709 ACCint * params) {
3710 switch (pname) {
3711 case ACC_INFO_LOG_LENGTH:
3712 *params = 0;
3713 break;
3714 }
3715}
3716
3717extern "C"
3718void accGetScriptInfoLog(ACCscript* script,
3719 ACCsizei maxLength,
3720 ACCsizei * length,
3721 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003722 char* message = script->compiler.getErrorMessage();
3723 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003724 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003725 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003726 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003727 if (infoLog && maxLength > 0) {
3728 int trimmedLength = maxLength < messageLength ?
3729 maxLength : messageLength;
3730 memcpy(infoLog, message, trimmedLength);
3731 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003732 }
3733}
3734
3735extern "C"
3736void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3737 ACCvoid ** address) {
3738 void* value = script->compiler.lookup(name);
3739 if (value) {
3740 *address = value;
3741 } else {
3742 script->setError(ACC_INVALID_VALUE);
3743 }
3744}
3745
Jack Palevicheedf9d22009-06-04 16:23:40 -07003746extern "C"
3747void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3748 ACCsizei maxStringCount, ACCchar** strings){
3749 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3750}
3751
-b master422972c2009-06-17 19:13:52 -07003752extern "C"
3753void accDisassemble(ACCscript* script) {
3754 script->compiler.disassemble(stderr);
3755}
3756
Jack Palevicheedf9d22009-06-04 16:23:40 -07003757
Jack Palevich1cdef202009-05-22 12:06:27 -07003758} // namespace acc
3759