blob: 0209031541e61c43bc3b9f98ddbc3b5ea7ef110c [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 Palevich21a15a22009-05-11 14:49:29 -070071 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070072 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070073 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070074 ErrorSink* mErrorSink;
75 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -070076 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -070077
Jack Palevich21a15a22009-05-11 14:49:29 -070078 void release() {
79 if (pProgramBase != 0) {
80 free(pProgramBase);
81 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070082 }
Jack Palevich21a15a22009-05-11 14:49:29 -070083 }
84
Jack Palevich0a280a02009-06-11 10:53:51 -070085 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -070086 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -070087 bool overflow = newSize > mSize;
88 if (overflow && !mOverflowed) {
89 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -070090 if (mErrorSink) {
91 mErrorSink->error("Code too large: %d bytes", newSize);
92 }
93 }
Jack Palevich0a280a02009-06-11 10:53:51 -070094 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -070095 }
96
Jack Palevich21a15a22009-05-11 14:49:29 -070097 public:
98 CodeBuf() {
99 pProgramBase = 0;
100 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700101 mErrorSink = 0;
102 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700103 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700104 }
105
106 ~CodeBuf() {
107 release();
108 }
109
110 void init(int size) {
111 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700112 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700113 pProgramBase = (char*) calloc(1, size);
114 ind = pProgramBase;
115 }
116
Jack Palevichac0e95e2009-05-29 13:53:44 -0700117 void setErrorSink(ErrorSink* pErrorSink) {
118 mErrorSink = pErrorSink;
119 }
120
Jack Palevich546b2242009-05-13 15:10:04 -0700121 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700122 if(check(4)) {
123 return 0;
124 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700125 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700126 * (int*) ind = n;
127 ind += 4;
128 return result;
129 }
130
Jack Palevich21a15a22009-05-11 14:49:29 -0700131 /*
132 * Output a byte. Handles all values, 0..ff.
133 */
134 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700135 if(check(1)) {
136 return;
137 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700138 *ind++ = n;
139 }
140
Jack Palevich21a15a22009-05-11 14:49:29 -0700141 inline void* getBase() {
142 return (void*) pProgramBase;
143 }
144
Jack Palevich8b0624c2009-05-20 12:12:06 -0700145 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700146 return ind - pProgramBase;
147 }
148
Jack Palevich8b0624c2009-05-20 12:12:06 -0700149 intptr_t getPC() {
150 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700151 }
152 };
153
Jack Palevich1cdef202009-05-22 12:06:27 -0700154 /**
155 * A code generator creates an in-memory program, generating the code on
156 * the fly. There is one code generator implementation for each supported
157 * architecture.
158 *
159 * The code generator implements the following abstract machine:
160 * R0 - the main accumulator.
161 * R1 - the secondary accumulator.
162 * FP - a frame pointer for accessing function arguments and local
163 * variables.
164 * SP - a stack pointer for storing intermediate results while evaluating
165 * expressions. The stack pointer grows downwards.
166 *
167 * The function calling convention is that all arguments are placed on the
168 * stack such that the first argument has the lowest address.
169 * After the call, the result is in R0. The caller is responsible for
170 * removing the arguments from the stack.
171 * The R0 and R1 registers are not saved across function calls. The
172 * FP and SP registers are saved.
173 */
174
Jack Palevich21a15a22009-05-11 14:49:29 -0700175 class CodeGenerator {
176 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700177 CodeGenerator() {
178 mErrorSink = 0;
179 pCodeBuf = 0;
180 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 virtual ~CodeGenerator() {}
182
Jack Palevich22305132009-05-13 10:58:45 -0700183 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700184 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 pCodeBuf->setErrorSink(mErrorSink);
186 }
187
Jack Palevichb67b18f2009-06-11 21:12:23 -0700188 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 mErrorSink = pErrorSink;
190 if (pCodeBuf) {
191 pCodeBuf->setErrorSink(mErrorSink);
192 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700193 }
194
Jack Palevich1cdef202009-05-22 12:06:27 -0700195 /* Emit a function prolog.
196 * argCount is the number of arguments.
197 * Save the old value of the FP.
198 * Set the new value of the FP.
199 * Convert from the native platform calling convention to
200 * our stack-based calling convention. This may require
201 * pushing arguments from registers to the stack.
202 * Allocate "N" bytes of stack space. N isn't known yet, so
203 * just emit the instructions for adjusting the stack, and return
204 * the address to patch up. The patching will be done in
205 * functionExit().
206 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700207 */
Jack Palevich546b2242009-05-13 15:10:04 -0700208 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700209
Jack Palevich1cdef202009-05-22 12:06:27 -0700210 /* Emit a function epilog.
211 * Restore the old SP and FP register values.
212 * Return to the calling function.
213 * argCount - the number of arguments to the function.
214 * localVariableAddress - returned from functionEntry()
215 * localVariableSize - the size in bytes of the local variables.
216 */
217 virtual void functionExit(int argCount, int localVariableAddress,
218 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700219
Jack Palevich1cdef202009-05-22 12:06:27 -0700220 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700221 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700222
Jack Palevich1cdef202009-05-22 12:06:27 -0700223 /* Jump to a target, and return the address of the word that
224 * holds the target data, in case it needs to be fixed up later.
225 */
Jack Palevich22305132009-05-13 10:58:45 -0700226 virtual int gjmp(int t) = 0;
227
Jack Palevich1cdef202009-05-22 12:06:27 -0700228 /* Test R0 and jump to a target if the test succeeds.
229 * l = 0: je, l == 1: jne
230 * Return the address of the word that holds the targed data, in
231 * case it needs to be fixed up later.
232 */
Jack Palevich22305132009-05-13 10:58:45 -0700233 virtual int gtst(bool l, int t) = 0;
234
Jack Palevich1cdef202009-05-22 12:06:27 -0700235 /* Compare R1 against R0, and store the boolean result in R0.
236 * op specifies the comparison.
237 */
Jack Palevich22305132009-05-13 10:58:45 -0700238 virtual void gcmp(int op) = 0;
239
Jack Palevich1cdef202009-05-22 12:06:27 -0700240 /* Perform the arithmetic op specified by op. R1 is the
241 * left argument, R0 is the right argument.
242 */
Jack Palevich546b2242009-05-13 15:10:04 -0700243 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700244
Jack Palevich1cdef202009-05-22 12:06:27 -0700245 /* Set R1 to 0.
246 */
247 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700248
Jack Palevich1cdef202009-05-22 12:06:27 -0700249 /* Push R0 onto the stack.
250 */
251 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700252
Jack Palevich1cdef202009-05-22 12:06:27 -0700253 /* Pop R1 off of the stack.
254 */
255 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700256
Jack Palevich1cdef202009-05-22 12:06:27 -0700257 /* Store R0 to the address stored in R1.
258 * isInt is true if a whole 4-byte integer value
259 * should be stored, otherwise a 1-byte character
260 * value should be stored.
261 */
262 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700263
Jack Palevich1cdef202009-05-22 12:06:27 -0700264 /* Load R0 from the address stored in R0.
265 * isInt is true if a whole 4-byte integer value
266 * should be loaded, otherwise a 1-byte character
267 * value should be loaded.
268 */
269 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700270
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 /* Load the absolute address of a variable to R0.
272 * If ea <= LOCAL, then this is a local variable, or an
273 * argument, addressed relative to FP.
274 * else it is an absolute global address.
275 */
276 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700277
Jack Palevich1cdef202009-05-22 12:06:27 -0700278 /* Store R0 to a variable.
279 * If ea <= LOCAL, then this is a local variable, or an
280 * argument, addressed relative to FP.
281 * else it is an absolute global address.
282 */
283 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700284
Jack Palevich1cdef202009-05-22 12:06:27 -0700285 /* load R0 from a variable.
286 * If ea <= LOCAL, then this is a local variable, or an
287 * argument, addressed relative to FP.
288 * else it is an absolute global address.
289 * If isIncDec is true, then the stored variable's value
290 * should be post-incremented or post-decremented, based
291 * on the value of op.
292 */
293 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700294
Jack Palevich1cdef202009-05-22 12:06:27 -0700295 /* Emit code to adjust the stack for a function call. Return the
296 * label for the address of the instruction that adjusts the
297 * stack size. This will be passed as argument "a" to
298 * endFunctionCallArguments.
299 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700300 virtual int beginFunctionCallArguments() = 0;
301
Jack Palevich1cdef202009-05-22 12:06:27 -0700302 /* Emit code to store R0 to the stack at byte offset l.
303 */
304 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700305
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 /* Patch the function call preamble.
307 * a is the address returned from beginFunctionCallArguments
308 * l is the number of bytes the arguments took on the stack.
309 * Typically you would also emit code to convert the argument
310 * list into whatever the native function calling convention is.
311 * On ARM for example you would pop the first 5 arguments into
312 * R0..R4
313 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700314 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700315
Jack Palevich1cdef202009-05-22 12:06:27 -0700316 /* Emit a call to an unknown function. The argument "symbol" needs to
317 * be stored in the location where the address should go. It forms
318 * a chain. The address will be patched later.
319 * Return the address of the word that has to be patched.
320 */
Jack Palevich22305132009-05-13 10:58:45 -0700321 virtual int callForward(int symbol) = 0;
322
Jack Palevich1cdef202009-05-22 12:06:27 -0700323 /* Call a function using PC-relative addressing. t is the PC-relative
324 * address of the function. It has already been adjusted for the
325 * architectural jump offset, so just store it as-is.
326 */
Jack Palevich22305132009-05-13 10:58:45 -0700327 virtual void callRelative(int t) = 0;
328
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 /* Call a function pointer. L is the number of bytes the arguments
330 * take on the stack. The address of the function is stored at
331 * location SP + l.
332 */
Jack Palevich22305132009-05-13 10:58:45 -0700333 virtual void callIndirect(int l) = 0;
334
Jack Palevich1cdef202009-05-22 12:06:27 -0700335 /* Adjust SP after returning from a function call. l is the
336 * number of bytes of arguments stored on the stack. isIndirect
337 * is true if this was an indirect call. (In which case the
338 * address of the function is stored at location SP + l.)
339 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700340 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700341
Jack Palevich1cdef202009-05-22 12:06:27 -0700342 /* Print a disassembly of the assembled code to out. Return
343 * non-zero if there is an error.
344 */
Jack Palevicha6535612009-05-13 16:24:17 -0700345 virtual int disassemble(FILE* out) = 0;
346
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 /* Generate a symbol at the current PC. t is the head of a
348 * linked list of addresses to patch.
349 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700350 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700351
Jack Palevich1cdef202009-05-22 12:06:27 -0700352 /*
353 * Do any cleanup work required at the end of a compile.
354 * For example, an instruction cache might need to be
355 * invalidated.
356 * Return non-zero if there is an error.
357 */
358 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700359
Jack Palevicha6535612009-05-13 16:24:17 -0700360 /**
361 * Adjust relative branches by this amount.
362 */
363 virtual int jumpOffset() = 0;
364
Jack Palevich21a15a22009-05-11 14:49:29 -0700365 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700366 /*
367 * Output a byte. Handles all values, 0..ff.
368 */
369 void ob(int n) {
370 pCodeBuf->ob(n);
371 }
372
Jack Palevich8b0624c2009-05-20 12:12:06 -0700373 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700374 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700375 }
376
Jack Palevich8b0624c2009-05-20 12:12:06 -0700377 intptr_t getBase() {
378 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700379 }
380
Jack Palevich8b0624c2009-05-20 12:12:06 -0700381 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700382 return pCodeBuf->getPC();
383 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700384
385 intptr_t getSize() {
386 return pCodeBuf->getSize();
387 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700388
389 void error(const char* fmt,...) {
390 va_list ap;
391 va_start(ap, fmt);
392 mErrorSink->verror(fmt, ap);
393 va_end(ap);
394 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700395 private:
396 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700397 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700398 };
399
Jack Paleviche7b59062009-05-19 17:12:17 -0700400#ifdef PROVIDE_ARM_CODEGEN
401
Jack Palevich22305132009-05-13 10:58:45 -0700402 class ARMCodeGenerator : public CodeGenerator {
403 public:
404 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700405
Jack Palevich22305132009-05-13 10:58:45 -0700406 virtual ~ARMCodeGenerator() {}
407
408 /* returns address to patch with local variable size
409 */
Jack Palevich546b2242009-05-13 15:10:04 -0700410 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700411 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700412 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700413 // sp -> arg4 arg5 ...
414 // Push our register-based arguments back on the stack
415 if (argCount > 0) {
416 int regArgCount = argCount <= 4 ? argCount : 4;
417 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700418 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700419 }
420 // sp -> arg0 arg1 ...
421 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700422 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700423 // sp, fp -> oldfp, retadr, arg0 arg1 ....
424 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700425 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700426 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700427 // We don't know how many local variables we are going to use,
428 // but we will round the allocation up to a multiple of
429 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700430 }
431
Jack Palevich546b2242009-05-13 15:10:04 -0700432 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700433 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700434 // Round local variable size up to a multiple of stack alignment
435 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
436 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700437 // Patch local variable allocation code:
438 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700439 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700440 }
Jack Palevich69796b62009-05-14 15:42:26 -0700441 *(char*) (localVariableAddress) = localVariableSize;
442
443 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
444 o4(0xE1A0E00B); // mov lr, fp
445 o4(0xE59BB000); // ldr fp, [fp]
446 o4(0xE28ED004); // add sp, lr, #4
447 // sp -> retadr, arg0, ...
448 o4(0xE8BD4000); // ldmfd sp!, {lr}
449 // sp -> arg0 ....
450 if (argCount > 0) {
451 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700452 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700453 // earlier. We don't need to actually store them anywhere,
454 // just adjust the stack.
455 int regArgCount = argCount <= 4 ? argCount : 4;
456 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
457 }
458 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700459 }
460
461 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700462 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700463 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700464 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700465 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700466 } else if (t >= -256 && t < 0) {
467 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700468 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700469 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700470 o4(0xE51F0000); // ldr r0, .L3
471 o4(0xEA000000); // b .L99
472 o4(t); // .L3: .word 0
473 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700474 }
Jack Palevich22305132009-05-13 10:58:45 -0700475 }
476
477 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700478 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700479 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700480 }
481
482 /* l = 0: je, l == 1: jne */
483 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700484 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700485 o4(0xE3500000); // cmp r0,#0
486 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
487 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700488 }
489
490 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700491 LOG_API("gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700492 o4(0xE1510000); // cmp r1, r1
493 switch(op) {
494 case OP_EQUALS:
495 o4(0x03A00001); // moveq r0,#1
496 o4(0x13A00000); // movne r0,#0
497 break;
498 case OP_NOT_EQUALS:
499 o4(0x03A00000); // moveq r0,#0
500 o4(0x13A00001); // movne r0,#1
501 break;
502 case OP_LESS_EQUAL:
503 o4(0xD3A00001); // movle r0,#1
504 o4(0xC3A00000); // movgt r0,#0
505 break;
506 case OP_GREATER:
507 o4(0xD3A00000); // movle r0,#0
508 o4(0xC3A00001); // movgt r0,#1
509 break;
510 case OP_GREATER_EQUAL:
511 o4(0xA3A00001); // movge r0,#1
512 o4(0xB3A00000); // movlt r0,#0
513 break;
514 case OP_LESS:
515 o4(0xA3A00000); // movge r0,#0
516 o4(0xB3A00001); // movlt r0,#1
517 break;
518 default:
519 error("Unknown comparison op %d", op);
520 break;
521 }
Jack Palevich22305132009-05-13 10:58:45 -0700522 }
523
Jack Palevich546b2242009-05-13 15:10:04 -0700524 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700525 LOG_API("genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700526 switch(op) {
527 case OP_MUL:
528 o4(0x0E0000091); // mul r0,r1,r0
529 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700530 case OP_DIV:
531 callRuntime(runtime_DIV);
532 break;
533 case OP_MOD:
534 callRuntime(runtime_MOD);
535 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700536 case OP_PLUS:
537 o4(0xE0810000); // add r0,r1,r0
538 break;
539 case OP_MINUS:
540 o4(0xE0410000); // sub r0,r1,r0
541 break;
542 case OP_SHIFT_LEFT:
543 o4(0xE1A00011); // lsl r0,r1,r0
544 break;
545 case OP_SHIFT_RIGHT:
546 o4(0xE1A00051); // asr r0,r1,r0
547 break;
548 case OP_BIT_AND:
549 o4(0xE0010000); // and r0,r1,r0
550 break;
551 case OP_BIT_XOR:
552 o4(0xE0210000); // eor r0,r1,r0
553 break;
554 case OP_BIT_OR:
555 o4(0xE1810000); // orr r0,r1,r0
556 break;
557 case OP_BIT_NOT:
558 o4(0xE1E00000); // mvn r0, r0
559 break;
560 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700561 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700562 break;
563 }
Jack Palevich22305132009-05-13 10:58:45 -0700564 }
565
Jack Palevich1cdef202009-05-22 12:06:27 -0700566 virtual void clearR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700567 LOG_API("clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700568 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700569 }
570
Jack Palevich1cdef202009-05-22 12:06:27 -0700571 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700572 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700573 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700574 mStackUse += 4;
575 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700576 }
577
Jack Palevich1cdef202009-05-22 12:06:27 -0700578 virtual void popR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700579 LOG_API("popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700580 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700581 mStackUse -= 4;
582 LOG_STACK("popR1: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700583 }
584
Jack Palevich1cdef202009-05-22 12:06:27 -0700585 virtual void storeR0ToR1(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700586 LOG_API("storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700587 if (isInt) {
588 o4(0xE5810000); // str r0, [r1]
589 } else {
590 o4(0xE5C10000); // strb r0, [r1]
591 }
Jack Palevich22305132009-05-13 10:58:45 -0700592 }
593
Jack Palevich1cdef202009-05-22 12:06:27 -0700594 virtual void loadR0FromR0(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700595 LOG_API("loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700596 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700597 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700598 else
Jack Palevich69796b62009-05-14 15:42:26 -0700599 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700600 }
601
Jack Palevich1cdef202009-05-22 12:06:27 -0700602 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700603 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700604 if (ea < LOCAL) {
605 // Local, fp relative
606 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
607 error("Offset out of range: %08x", ea);
608 }
609 if (ea < 0) {
610 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
611 } else {
612 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
613 }
Jack Palevichbd894902009-05-14 19:35:31 -0700614 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700615 // Global, absolute.
616 o4(0xE59F0000); // ldr r0, .L1
617 o4(0xEA000000); // b .L99
618 o4(ea); // .L1: .word 0
619 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700620 }
Jack Palevich22305132009-05-13 10:58:45 -0700621 }
622
Jack Palevich1cdef202009-05-22 12:06:27 -0700623 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700624 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700625 if (ea < LOCAL) {
626 // Local, fp relative
627 if (ea < -4095 || ea > 4095) {
628 error("Offset out of range: %08x", ea);
629 }
630 if (ea < 0) {
631 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
632 } else {
633 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
634 }
635 } else{
636 // Global, absolute
637 o4(0xE59F1000); // ldr r1, .L1
638 o4(0xEA000000); // b .L99
639 o4(ea); // .L1: .word 0
640 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700641 }
Jack Palevich22305132009-05-13 10:58:45 -0700642 }
643
Jack Palevich1cdef202009-05-22 12:06:27 -0700644 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700645 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700646 if (ea < LOCAL) {
647 // Local, fp relative
648 if (ea < -4095 || ea > 4095) {
649 error("Offset out of range: %08x", ea);
650 }
651 if (ea < 0) {
652 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
653 } else {
654 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
655 }
Jack Palevich69796b62009-05-14 15:42:26 -0700656 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700657 // Global, absolute
658 o4(0xE59F2000); // ldr r2, .L1
659 o4(0xEA000000); // b .L99
660 o4(ea); // .L1: .word ea
661 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700662 }
Jack Palevich22305132009-05-13 10:58:45 -0700663
Jack Palevich4d93f302009-05-15 13:30:00 -0700664 if (isIncDec) {
665 switch (op) {
666 case OP_INCREMENT:
667 o4(0xE2801001); // add r1, r0, #1
668 break;
669 case OP_DECREMENT:
670 o4(0xE2401001); // sub r1, r0, #1
671 break;
672 default:
673 error("unknown opcode: %d", op);
674 }
675 if (ea < LOCAL) {
676 // Local, fp relative
677 // Don't need range check, was already checked above
678 if (ea < 0) {
679 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
680 } else {
681 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
682 }
683 } else{
684 // Global, absolute
685 // r2 is already set up from before.
686 o4(0xE5821000); // str r1, [r2]
687 }
Jack Palevichbd894902009-05-14 19:35:31 -0700688 }
Jack Palevich22305132009-05-13 10:58:45 -0700689 }
690
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700691 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700692 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700693 return o4(0xE24DDF00); // Placeholder
694 }
695
Jack Palevich1cdef202009-05-22 12:06:27 -0700696 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700697 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700698 if (l < 0 || l > 4096-4) {
699 error("l out of range for stack offset: 0x%08x", l);
700 }
701 o4(0xE58D0000 + l); // str r0, [sp, #4]
702 }
703
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700704 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700705 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700706 int argCount = l >> 2;
707 int argumentStackUse = l;
708 if (argCount > 0) {
709 int regArgCount = argCount > 4 ? 4 : argCount;
710 argumentStackUse -= regArgCount * 4;
711 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
712 }
713 mStackUse += argumentStackUse;
714
715 // Align stack.
716 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
717 * STACK_ALIGNMENT);
718 mStackAlignmentAdjustment = 0;
719 if (missalignment > 0) {
720 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
721 }
722 l += mStackAlignmentAdjustment;
723
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700724 if (l < 0 || l > 0x3FC) {
725 error("L out of range for stack adjustment: 0x%08x", l);
726 }
727 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700728 mStackUse += mStackAlignmentAdjustment;
729 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
730 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700731 }
732
Jack Palevich22305132009-05-13 10:58:45 -0700733 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700734 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700735 // Forward calls are always short (local)
736 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700737 }
738
739 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700740 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700741 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700742 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700743 if (t >= - (1 << 25) && t < (1 << 25)) {
744 o4(0xEB000000 | encodeAddress(t));
745 } else {
746 // Long call.
747 o4(0xE59FC000); // ldr r12, .L1
748 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700749 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700750 o4(0xE08CC00F); // .L99: add r12,pc
751 o4(0xE12FFF3C); // blx r12
752 }
Jack Palevich22305132009-05-13 10:58:45 -0700753 }
754
755 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700756 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700757 int argCount = l >> 2;
758 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700759 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700760 if (adjustedL < 0 || adjustedL > 4096-4) {
761 error("l out of range for stack offset: 0x%08x", l);
762 }
763 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
764 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700765 }
766
Jack Palevich7810bc92009-05-15 14:31:47 -0700767 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700768 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700769 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700770 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700771 int stackUse = stackArgs + (isIndirect ? 1 : 0)
772 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700773 if (stackUse) {
774 if (stackUse < 0 || stackUse > 255) {
775 error("L out of range for stack adjustment: 0x%08x", l);
776 }
777 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -0700778 mStackUse -= stackUse * 4;
779 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700780 }
Jack Palevich22305132009-05-13 10:58:45 -0700781 }
782
Jack Palevicha6535612009-05-13 16:24:17 -0700783 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700784 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700785 }
786
787 /* output a symbol and patch all calls to it */
788 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700789 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700790 int n;
791 int base = getBase();
792 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700793 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700794 while (t) {
795 int data = * (int*) t;
796 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
797 if (decodedOffset == 0) {
798 n = 0;
799 } else {
800 n = base + decodedOffset; /* next value */
801 }
802 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
803 | encodeRelAddress(pc - t - 8);
804 t = n;
805 }
806 }
807
Jack Palevich1cdef202009-05-22 12:06:27 -0700808 virtual int finishCompile() {
809#if defined(__arm__)
810 const long base = long(getBase());
811 const long curr = long(getPC());
812 int err = cacheflush(base, curr, 0);
813 return err;
814#else
815 return 0;
816#endif
817 }
818
Jack Palevicha6535612009-05-13 16:24:17 -0700819 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700820#ifdef ENABLE_ARM_DISASSEMBLY
821 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700822 disasm_interface_t di;
823 di.di_readword = disassemble_readword;
824 di.di_printaddr = disassemble_printaddr;
825 di.di_printf = disassemble_printf;
826
827 int base = getBase();
828 int pc = getPC();
829 for(int i = base; i < pc; i += 4) {
830 fprintf(out, "%08x: %08x ", i, *(int*) i);
831 ::disasm(&di, i, 0);
832 }
Jack Palevich09555c72009-05-27 12:25:55 -0700833#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700834 return 0;
835 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700836
Jack Palevich22305132009-05-13 10:58:45 -0700837 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700838 static FILE* disasmOut;
839
840 static u_int
841 disassemble_readword(u_int address)
842 {
843 return(*((u_int *)address));
844 }
845
846 static void
847 disassemble_printaddr(u_int address)
848 {
849 fprintf(disasmOut, "0x%08x", address);
850 }
851
852 static void
853 disassemble_printf(const char *fmt, ...) {
854 va_list ap;
855 va_start(ap, fmt);
856 vfprintf(disasmOut, fmt, ap);
857 va_end(ap);
858 }
859
860 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
861
862 /** Encode a relative address that might also be
863 * a label.
864 */
865 int encodeAddress(int value) {
866 int base = getBase();
867 if (value >= base && value <= getPC() ) {
868 // This is a label, encode it relative to the base.
869 value = value - base;
870 }
871 return encodeRelAddress(value);
872 }
873
874 int encodeRelAddress(int value) {
875 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
876 }
Jack Palevich22305132009-05-13 10:58:45 -0700877
Jack Palevich3d474a72009-05-15 15:12:38 -0700878 typedef int (*int2FnPtr)(int a, int b);
879 void callRuntime(int2FnPtr fn) {
880 o4(0xE59F2000); // ldr r2, .L1
881 o4(0xEA000000); // b .L99
882 o4((int) fn); //.L1: .word fn
883 o4(0xE12FFF32); //.L99: blx r2
884 }
885
886 static int runtime_DIV(int a, int b) {
887 return b / a;
888 }
889
890 static int runtime_MOD(int a, int b) {
891 return b % a;
892 }
-b master422972c2009-06-17 19:13:52 -0700893
894 static const int STACK_ALIGNMENT = 8;
895 int mStackUse;
896 // This variable holds the amount we adjusted the stack in the most
897 // recent endFunctionCallArguments call. It's examined by the
898 // following adjustStackAfterCall call.
899 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -0700900 };
901
Jack Palevich09555c72009-05-27 12:25:55 -0700902#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700903
904#ifdef PROVIDE_X86_CODEGEN
905
Jack Palevich21a15a22009-05-11 14:49:29 -0700906 class X86CodeGenerator : public CodeGenerator {
907 public:
908 X86CodeGenerator() {}
909 virtual ~X86CodeGenerator() {}
910
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700911 /* returns address to patch with local variable size
912 */
Jack Palevich546b2242009-05-13 15:10:04 -0700913 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700914 o(0xe58955); /* push %ebp, mov %esp, %ebp */
915 return oad(0xec81, 0); /* sub $xxx, %esp */
916 }
917
Jack Palevich546b2242009-05-13 15:10:04 -0700918 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700919 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700920 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700921 }
922
Jack Palevich21a15a22009-05-11 14:49:29 -0700923 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700924 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700925 oad(0xb8, t); /* mov $xx, %eax */
926 }
927
Jack Palevich22305132009-05-13 10:58:45 -0700928 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700929 return psym(0xe9, t);
930 }
931
932 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700933 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700934 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
935 return psym(0x84 + l, t);
936 }
937
Jack Palevich22305132009-05-13 10:58:45 -0700938 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700939 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700940 o(0xc139); /* cmp %eax,%ecx */
941 li(0);
942 o(0x0f); /* setxx %al */
943 o(t + 0x90);
944 o(0xc0);
945 }
946
Jack Palevich546b2242009-05-13 15:10:04 -0700947 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700948 o(decodeOp(op));
949 if (op == OP_MOD)
950 o(0x92); /* xchg %edx, %eax */
951 }
952
Jack Palevich1cdef202009-05-22 12:06:27 -0700953 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700954 oad(0xb9, 0); /* movl $0, %ecx */
955 }
956
Jack Palevich1cdef202009-05-22 12:06:27 -0700957 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700958 o(0x50); /* push %eax */
959 }
960
Jack Palevich1cdef202009-05-22 12:06:27 -0700961 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700962 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700963 }
964
Jack Palevich1cdef202009-05-22 12:06:27 -0700965 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700966 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
967 }
968
Jack Palevich1cdef202009-05-22 12:06:27 -0700969 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700970 if (isInt)
971 o(0x8b); /* mov (%eax), %eax */
972 else
973 o(0xbe0f); /* movsbl (%eax), %eax */
974 ob(0); /* add zero in code */
975 }
976
Jack Palevich1cdef202009-05-22 12:06:27 -0700977 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700978 gmov(10, ea); /* leal EA, %eax */
979 }
980
Jack Palevich1cdef202009-05-22 12:06:27 -0700981 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700982 gmov(6, ea); /* mov %eax, EA */
983 }
984
Jack Palevich1cdef202009-05-22 12:06:27 -0700985 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700986 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700987 if (isIncDec) {
988 /* Implement post-increment or post decrement.
989 */
990 gmov(0, ea); /* 83 ADD */
991 o(decodeOp(op));
992 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700993 }
994
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700995 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700996 return oad(0xec81, 0); /* sub $xxx, %esp */
997 }
998
Jack Palevich1cdef202009-05-22 12:06:27 -0700999 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001000 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1001 }
1002
Jack Palevich7810bc92009-05-15 14:31:47 -07001003 virtual void endFunctionCallArguments(int a, int l) {
1004 * (int*) a = l;
1005 }
1006
Jack Palevich22305132009-05-13 10:58:45 -07001007 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001008 return psym(0xe8, symbol); /* call xxx */
1009 }
1010
Jack Palevich22305132009-05-13 10:58:45 -07001011 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001012 psym(0xe8, t); /* call xxx */
1013 }
1014
Jack Palevich22305132009-05-13 10:58:45 -07001015 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001016 oad(0x2494ff, l); /* call *xxx(%esp) */
1017 }
1018
Jack Palevich7810bc92009-05-15 14:31:47 -07001019 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1020 if (isIndirect) {
1021 l += 4;
1022 }
-b master422972c2009-06-17 19:13:52 -07001023 if (l > 0) {
1024 oad(0xc481, l); /* add $xxx, %esp */
1025 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001026 }
1027
Jack Palevicha6535612009-05-13 16:24:17 -07001028 virtual int jumpOffset() {
1029 return 5;
1030 }
1031
1032 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001033 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001034 }
1035
Jack Paleviche7b59062009-05-19 17:12:17 -07001036 /* output a symbol and patch all calls to it */
1037 virtual void gsym(int t) {
1038 int n;
1039 int pc = getPC();
1040 while (t) {
1041 n = *(int *) t; /* next value */
1042 *(int *) t = pc - t - 4;
1043 t = n;
1044 }
1045 }
1046
Jack Palevich1cdef202009-05-22 12:06:27 -07001047 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001048 size_t pagesize = 4096;
1049 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1050 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1051 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1052 if (err) {
1053 error("mprotect() failed: %d", errno);
1054 }
1055 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001056 }
1057
Jack Palevich21a15a22009-05-11 14:49:29 -07001058 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001059
1060 /** Output 1 to 4 bytes.
1061 *
1062 */
1063 void o(int n) {
1064 /* cannot use unsigned, so we must do a hack */
1065 while (n && n != -1) {
1066 ob(n & 0xff);
1067 n = n >> 8;
1068 }
1069 }
1070
1071 /* psym is used to put an instruction with a data field which is a
1072 reference to a symbol. It is in fact the same as oad ! */
1073 int psym(int n, int t) {
1074 return oad(n, t);
1075 }
1076
1077 /* instruction + address */
1078 int oad(int n, int t) {
1079 o(n);
1080 int result = getPC();
1081 o4(t);
1082 return result;
1083 }
1084
1085
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001086 static const int operatorHelper[];
1087
1088 int decodeOp(int op) {
1089 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001090 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001091 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001092 }
1093 return operatorHelper[op];
1094 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001095
Jack Palevich546b2242009-05-13 15:10:04 -07001096 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001097 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001098 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001099 }
1100 };
1101
Jack Paleviche7b59062009-05-19 17:12:17 -07001102#endif // PROVIDE_X86_CODEGEN
1103
Jack Palevichb67b18f2009-06-11 21:12:23 -07001104#ifdef PROVIDE_TRACE_CODEGEN
1105 class TraceCodeGenerator : public CodeGenerator {
1106 private:
1107 CodeGenerator* mpBase;
1108
1109 public:
1110 TraceCodeGenerator(CodeGenerator* pBase) {
1111 mpBase = pBase;
1112 }
1113
1114 virtual ~TraceCodeGenerator() {
1115 delete mpBase;
1116 }
1117
1118 virtual void init(CodeBuf* pCodeBuf) {
1119 mpBase->init(pCodeBuf);
1120 }
1121
1122 void setErrorSink(ErrorSink* pErrorSink) {
1123 mpBase->setErrorSink(pErrorSink);
1124 }
1125
1126 /* returns address to patch with local variable size
1127 */
1128 virtual int functionEntry(int argCount) {
1129 int result = mpBase->functionEntry(argCount);
1130 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1131 return result;
1132 }
1133
1134 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1135 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1136 argCount, localVariableAddress, localVariableSize);
1137 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1138 }
1139
1140 /* load immediate value */
1141 virtual void li(int t) {
1142 fprintf(stderr, "li(%d)\n", t);
1143 mpBase->li(t);
1144 }
1145
1146 virtual int gjmp(int t) {
1147 int result = mpBase->gjmp(t);
1148 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1149 return result;
1150 }
1151
1152 /* l = 0: je, l == 1: jne */
1153 virtual int gtst(bool l, int t) {
1154 int result = mpBase->gtst(l, t);
1155 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1156 return result;
1157 }
1158
1159 virtual void gcmp(int op) {
1160 fprintf(stderr, "gcmp(%d)\n", op);
1161 mpBase->gcmp(op);
1162 }
1163
1164 virtual void genOp(int op) {
1165 fprintf(stderr, "genOp(%d)\n", op);
1166 mpBase->genOp(op);
1167 }
1168
1169 virtual void clearR1() {
1170 fprintf(stderr, "clearR1()\n");
1171 mpBase->clearR1();
1172 }
1173
1174 virtual void pushR0() {
1175 fprintf(stderr, "pushR0()\n");
1176 mpBase->pushR0();
1177 }
1178
1179 virtual void popR1() {
1180 fprintf(stderr, "popR1()\n");
1181 mpBase->popR1();
1182 }
1183
1184 virtual void storeR0ToR1(bool isInt) {
1185 fprintf(stderr, "storeR0ToR1(%d)\n", isInt);
1186 mpBase->storeR0ToR1(isInt);
1187 }
1188
1189 virtual void loadR0FromR0(bool isInt) {
1190 fprintf(stderr, "loadR0FromR0(%d)\n", isInt);
1191 mpBase->loadR0FromR0(isInt);
1192 }
1193
1194 virtual void leaR0(int ea) {
1195 fprintf(stderr, "leaR0(%d)\n", ea);
1196 mpBase->leaR0(ea);
1197 }
1198
1199 virtual void storeR0(int ea) {
1200 fprintf(stderr, "storeR0(%d)\n", ea);
1201 mpBase->storeR0(ea);
1202 }
1203
1204 virtual void loadR0(int ea, bool isIncDec, int op) {
1205 fprintf(stderr, "loadR0(%d, %d, %d)\n", ea, isIncDec, op);
1206 mpBase->loadR0(ea, isIncDec, op);
1207 }
1208
1209 virtual int beginFunctionCallArguments() {
1210 int result = mpBase->beginFunctionCallArguments();
1211 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1212 return result;
1213 }
1214
1215 virtual void storeR0ToArg(int l) {
1216 fprintf(stderr, "storeR0ToArg(%d)\n", l);
1217 mpBase->storeR0ToArg(l);
1218 }
1219
1220 virtual void endFunctionCallArguments(int a, int l) {
1221 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1222 mpBase->endFunctionCallArguments(a, l);
1223 }
1224
1225 virtual int callForward(int symbol) {
1226 int result = mpBase->callForward(symbol);
1227 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1228 return result;
1229 }
1230
1231 virtual void callRelative(int t) {
1232 fprintf(stderr, "callRelative(%d)\n", t);
1233 mpBase->callRelative(t);
1234 }
1235
1236 virtual void callIndirect(int l) {
1237 fprintf(stderr, "callIndirect(%d)\n", l);
1238 mpBase->callIndirect(l);
1239 }
1240
1241 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1242 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1243 mpBase->adjustStackAfterCall(l, isIndirect);
1244 }
1245
1246 virtual int jumpOffset() {
1247 return mpBase->jumpOffset();
1248 }
1249
1250 virtual int disassemble(FILE* out) {
1251 return mpBase->disassemble(out);
1252 }
1253
1254 /* output a symbol and patch all calls to it */
1255 virtual void gsym(int t) {
1256 fprintf(stderr, "gsym(%d)\n", t);
1257 mpBase->gsym(t);
1258 }
1259
1260 virtual int finishCompile() {
1261 int result = mpBase->finishCompile();
1262 fprintf(stderr, "finishCompile() = %d\n", result);
1263 return result;
1264 }
1265 };
1266
1267#endif // PROVIDE_TRACE_CODEGEN
1268
Jack Palevich569f1352009-06-29 14:29:08 -07001269
1270 // Subset of STL vector.
1271 template<class E> class Vector {
1272 public:
1273 Vector() {
1274 mpBase = 0;
1275 mUsed = 0;
1276 mSize = 0;
1277 }
1278
1279 ~Vector() {
1280 if (mpBase) {
1281 for(size_t i = 0; i < mUsed; i++) {
1282 mpBase[mUsed].~E();
1283 }
1284 free(mpBase);
1285 }
1286 }
1287
1288 inline E& operator[](size_t i) {
1289 return mpBase[i];
1290 }
1291
1292 inline E& front() {
1293 return mpBase[0];
1294 }
1295
1296 inline E& back() {
1297 return mpBase[mUsed - 1];
1298 }
1299
1300 void pop_back() {
1301 mUsed -= 1;
1302 mpBase[mUsed].~E();
1303 }
1304
1305 void push_back(const E& item) {
1306 * ensure(1) = item;
1307 }
1308
1309 size_t size() {
1310 return mUsed;
1311 }
1312
1313 private:
1314 E* ensure(int n) {
1315 size_t newUsed = mUsed + n;
1316 if (newUsed > mSize) {
1317 size_t newSize = mSize * 2 + 10;
1318 if (newSize < newUsed) {
1319 newSize = newUsed;
1320 }
1321 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1322 mSize = newSize;
1323 }
1324 E* result = mpBase + mUsed;
1325 mUsed = newUsed;
1326 return result;
1327 }
1328
1329 E* mpBase;
1330 size_t mUsed;
1331 size_t mSize;
1332 };
1333
1334 class Arena {
1335 public:
1336 // Used to record a given allocation amount.
1337 // Used:
1338 // Mark mark = arena.mark();
1339 // ... lots of arena.allocate()
1340 // arena.free(mark);
1341
1342 struct Mark {
1343 size_t chunk;
1344 size_t offset;
1345 };
1346
1347 Arena() {
1348 mCurrentChunk = 0;
1349 Chunk start(CHUNK_SIZE);
1350 mData.push_back(start);
1351 }
1352
1353 ~Arena() {
1354 for(size_t i = 0; i < mData.size(); i++) {
1355 mData[i].free();
1356 }
1357 }
1358
1359 // Alloc using the standard alignment size safe for any variable
1360 void* alloc(size_t size) {
1361 return alloc(size, 8);
1362 }
1363
1364 Mark mark(){
1365 Mark result;
1366 result.chunk = mCurrentChunk;
1367 result.offset = mData[mCurrentChunk].mOffset;
1368 return result;
1369 }
1370
1371 void freeToMark(const Mark& mark) {
1372 mCurrentChunk = mark.chunk;
1373 mData[mCurrentChunk].mOffset = mark.offset;
1374 }
1375
1376 private:
1377 // Allocate memory aligned to a given size
1378 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1379 // Memory is not zero filled.
1380
1381 void* alloc(size_t size, size_t alignment) {
1382 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1383 if (mCurrentChunk + 1 < mData.size()) {
1384 mCurrentChunk++;
1385 } else {
1386 size_t allocSize = CHUNK_SIZE;
1387 if (allocSize < size + alignment - 1) {
1388 allocSize = size + alignment - 1;
1389 }
1390 Chunk chunk(allocSize);
1391 mData.push_back(chunk);
1392 mCurrentChunk++;
1393 }
1394 }
1395 return mData[mCurrentChunk].allocate(size, alignment);
1396 }
1397
1398 static const size_t CHUNK_SIZE = 128*1024;
1399 // Note: this class does not deallocate its
1400 // memory when it's destroyed. It depends upon
1401 // its parent to deallocate the memory.
1402 struct Chunk {
1403 Chunk() {
1404 mpData = 0;
1405 mSize = 0;
1406 mOffset = 0;
1407 }
1408
1409 Chunk(size_t size) {
1410 mSize = size;
1411 mpData = (char*) malloc(size);
1412 mOffset = 0;
1413 }
1414
1415 ~Chunk() {
1416 // Doesn't deallocate memory.
1417 }
1418
1419 void* allocate(size_t size, size_t alignment) {
1420 size_t alignedOffset = aligned(mOffset, alignment);
1421 void* result = mpData + alignedOffset;
1422 mOffset = alignedOffset + size;
1423 return result;
1424 }
1425
1426 void free() {
1427 if (mpData) {
1428 ::free(mpData);
1429 mpData = 0;
1430 }
1431 }
1432
1433 size_t remainingCapacity(size_t alignment) {
1434 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1435 }
1436
1437 // Assume alignment is a power of two
1438 inline size_t aligned(size_t v, size_t alignment) {
1439 size_t mask = alignment-1;
1440 return (v + mask) & ~mask;
1441 }
1442
1443 char* mpData;
1444 size_t mSize;
1445 size_t mOffset;
1446 };
1447
1448 size_t mCurrentChunk;
1449
1450 Vector<Chunk> mData;
1451 };
1452
1453 typedef int tokenid_t;
1454 struct VariableInfo;
1455
1456 struct Token {
1457 int hash;
1458 size_t length;
1459 char* pText;
1460 tokenid_t id;
1461
1462 // Current values for the token
1463 char* mpMacroDefinition;
1464 VariableInfo* mpVariableInfo;
1465 };
1466
1467 class TokenTable {
1468 public:
1469 // Don't use 0..0xff, allows characters and operators to be tokens too.
1470
1471 static const int TOKEN_BASE = 0x100;
1472 TokenTable() {
1473 mpMap = hashmapCreate(128, hashFn, equalsFn);
1474 }
1475
1476 ~TokenTable() {
1477 hashmapFree(mpMap);
1478 }
1479
1480 void setArena(Arena* pArena) {
1481 mpArena = pArena;
1482 }
1483
1484 // Returns a token for a given string of characters.
1485 tokenid_t intern(const char* pText, size_t length) {
1486 Token probe;
1487 int hash = hashmapHash((void*) pText, length);
1488 {
1489 Token probe;
1490 probe.hash = hash;
1491 probe.length = length;
1492 probe.pText = (char*) pText;
1493 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1494 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001495 return pValue->id;
1496 }
1497 }
1498
1499 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1500 memset(pToken, 0, sizeof(*pToken));
1501 pToken->hash = hash;
1502 pToken->length = length;
1503 pToken->pText = (char*) mpArena->alloc(length + 1);
1504 memcpy(pToken->pText, pText, length);
1505 pToken->pText[length] = 0;
1506 pToken->id = mTokens.size() + TOKEN_BASE;
1507 mTokens.push_back(pToken);
1508 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001509 return pToken->id;
1510 }
1511
1512 // Return the Token for a given tokenid.
1513 Token& operator[](tokenid_t id) {
1514 return *mTokens[id - TOKEN_BASE];
1515 }
1516
1517 inline size_t size() {
1518 return mTokens.size();
1519 }
1520
1521 private:
1522
1523 static int hashFn(void* pKey) {
1524 Token* pToken = (Token*) pKey;
1525 return pToken->hash;
1526 }
1527
1528 static bool equalsFn(void* keyA, void* keyB) {
1529 Token* pTokenA = (Token*) keyA;
1530 Token* pTokenB = (Token*) keyB;
1531 // Don't need to compare hash values, they should always be equal
1532 return pTokenA->length == pTokenB->length
1533 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1534 }
1535
1536 Hashmap* mpMap;
1537 Vector<Token*> mTokens;
1538 Arena* mpArena;
1539 };
1540
Jack Palevich1cdef202009-05-22 12:06:27 -07001541 class InputStream {
1542 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001543 int getChar() {
1544 if (bumpLine) {
1545 line++;
1546 bumpLine = false;
1547 }
1548 int ch = get();
1549 if (ch == '\n') {
1550 bumpLine = true;
1551 }
1552 return ch;
1553 }
1554 int getLine() {
1555 return line;
1556 }
1557 protected:
1558 InputStream() :
1559 line(1), bumpLine(false) {
1560 }
1561 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001562 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001563 int line;
1564 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001565 };
1566
1567 class FileInputStream : public InputStream {
1568 public:
1569 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001570 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001571 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001572 FILE* f;
1573 };
1574
1575 class TextInputStream : public InputStream {
1576 public:
1577 TextInputStream(const char* text, size_t textLength)
1578 : pText(text), mTextLength(textLength), mPosition(0) {
1579 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001580
1581 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001582 virtual int get() {
1583 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1584 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001585
Jack Palevich1cdef202009-05-22 12:06:27 -07001586 const char* pText;
1587 size_t mTextLength;
1588 size_t mPosition;
1589 };
1590
Jack Palevicheedf9d22009-06-04 16:23:40 -07001591 class String {
1592 public:
1593 String() {
1594 mpBase = 0;
1595 mUsed = 0;
1596 mSize = 0;
1597 }
1598
Jack Palevich303d8ff2009-06-11 19:06:24 -07001599 String(const char* item, int len, bool adopt) {
1600 if (len < 0) {
1601 len = strlen(item);
1602 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001603 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001604 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001605 mUsed = len;
1606 mSize = len + 1;
1607 } else {
1608 mpBase = 0;
1609 mUsed = 0;
1610 mSize = 0;
1611 appendBytes(item, len);
1612 }
1613 }
1614
Jack Palevich303d8ff2009-06-11 19:06:24 -07001615 String(const String& other) {
1616 mpBase = 0;
1617 mUsed = 0;
1618 mSize = 0;
1619 appendBytes(other.getUnwrapped(), other.len());
1620 }
1621
Jack Palevicheedf9d22009-06-04 16:23:40 -07001622 ~String() {
1623 if (mpBase) {
1624 free(mpBase);
1625 }
1626 }
1627
Jack Palevicha6baa232009-06-12 11:25:59 -07001628 String& operator=(const String& other) {
1629 clear();
1630 appendBytes(other.getUnwrapped(), other.len());
1631 return *this;
1632 }
1633
Jack Palevich303d8ff2009-06-11 19:06:24 -07001634 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001635 return mpBase;
1636 }
1637
Jack Palevich303d8ff2009-06-11 19:06:24 -07001638 void clear() {
1639 mUsed = 0;
1640 if (mSize > 0) {
1641 mpBase[0] = 0;
1642 }
1643 }
1644
Jack Palevicheedf9d22009-06-04 16:23:40 -07001645 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001646 appendBytes(s, strlen(s));
1647 }
1648
1649 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001650 memcpy(ensure(n), s, n + 1);
1651 }
1652
1653 void append(char c) {
1654 * ensure(1) = c;
1655 }
1656
Jack Palevich86351982009-06-30 18:09:56 -07001657 void append(String& other) {
1658 appendBytes(other.getUnwrapped(), other.len());
1659 }
1660
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001661 char* orphan() {
1662 char* result = mpBase;
1663 mpBase = 0;
1664 mUsed = 0;
1665 mSize = 0;
1666 return result;
1667 }
1668
Jack Palevicheedf9d22009-06-04 16:23:40 -07001669 void printf(const char* fmt,...) {
1670 va_list ap;
1671 va_start(ap, fmt);
1672 vprintf(fmt, ap);
1673 va_end(ap);
1674 }
1675
1676 void vprintf(const char* fmt, va_list ap) {
1677 char* temp;
1678 int numChars = vasprintf(&temp, fmt, ap);
1679 memcpy(ensure(numChars), temp, numChars+1);
1680 free(temp);
1681 }
1682
Jack Palevich303d8ff2009-06-11 19:06:24 -07001683 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001684 return mUsed;
1685 }
1686
1687 private:
1688 char* ensure(int n) {
1689 size_t newUsed = mUsed + n;
1690 if (newUsed > mSize) {
1691 size_t newSize = mSize * 2 + 10;
1692 if (newSize < newUsed) {
1693 newSize = newUsed;
1694 }
1695 mpBase = (char*) realloc(mpBase, newSize + 1);
1696 mSize = newSize;
1697 }
1698 mpBase[newUsed] = '\0';
1699 char* result = mpBase + mUsed;
1700 mUsed = newUsed;
1701 return result;
1702 }
1703
1704 char* mpBase;
1705 size_t mUsed;
1706 size_t mSize;
1707 };
1708
Jack Palevich569f1352009-06-29 14:29:08 -07001709 void internKeywords() {
1710 // Note: order has to match TOK_ constants
1711 static const char* keywords[] = {
1712 "int",
1713 "char",
1714 "void",
1715 "if",
1716 "else",
1717 "while",
1718 "break",
1719 "return",
1720 "for",
1721 "pragma",
1722 "define",
1723 "auto",
1724 "case",
1725 "const",
1726 "continue",
1727 "default",
1728 "do",
1729 "double",
1730 "enum",
1731 "extern",
1732 "float",
1733 "goto",
1734 "long",
1735 "register",
1736 "short",
1737 "signed",
1738 "sizeof",
1739 "static",
1740 "struct",
1741 "switch",
1742 "typedef",
1743 "union",
1744 "unsigned",
1745 "volatile",
1746 "_Bool",
1747 "_Complex",
1748 "_Imaginary",
1749 "inline",
1750 "restrict",
1751 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001752
Jack Palevich569f1352009-06-29 14:29:08 -07001753 for(int i = 0; keywords[i]; i++) {
1754 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001755 }
Jack Palevich569f1352009-06-29 14:29:08 -07001756 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001757
Jack Palevich36d94142009-06-08 15:55:32 -07001758 struct InputState {
1759 InputStream* pStream;
1760 int oldCh;
1761 };
1762
Jack Palevich86351982009-06-30 18:09:56 -07001763 struct Type;
1764
Jack Palevich2db168f2009-06-11 14:29:47 -07001765 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001766 void* pAddress;
1767 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07001768 tokenid_t tok;
1769 size_t level;
1770 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07001771 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07001772 };
1773
Jack Palevich303d8ff2009-06-11 19:06:24 -07001774 class SymbolStack {
1775 public:
1776 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07001777 mpArena = 0;
1778 mpTokenTable = 0;
1779 }
1780
1781 void setArena(Arena* pArena) {
1782 mpArena = pArena;
1783 }
1784
1785 void setTokenTable(TokenTable* pTokenTable) {
1786 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001787 }
1788
1789 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07001790 Mark mark;
1791 mark.mArenaMark = mpArena->mark();
1792 mark.mSymbolHead = mStack.size();
1793 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07001794 }
1795
1796 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07001797 // Undo any shadowing that was done:
1798 Mark mark = mLevelStack.back();
1799 mLevelStack.pop_back();
1800 while (mStack.size() > mark.mSymbolHead) {
1801 VariableInfo* pV = mStack.back();
1802 mStack.pop_back();
1803 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001804 }
Jack Palevich569f1352009-06-29 14:29:08 -07001805 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07001806 }
1807
Jack Palevich569f1352009-06-29 14:29:08 -07001808 bool isDefinedAtCurrentLevel(tokenid_t tok) {
1809 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
1810 return pV && pV->level == level();
1811 }
1812
1813 VariableInfo* add(tokenid_t tok) {
1814 Token& token = (*mpTokenTable)[tok];
1815 VariableInfo* pOldV = token.mpVariableInfo;
1816 VariableInfo* pNewV =
1817 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
1818 memset(pNewV, 0, sizeof(VariableInfo));
1819 pNewV->tok = tok;
1820 pNewV->level = level();
1821 pNewV->pOldDefinition = pOldV;
1822 token.mpVariableInfo = pNewV;
1823 mStack.push_back(pNewV);
1824 return pNewV;
1825 }
1826
Jack Palevich86351982009-06-30 18:09:56 -07001827 VariableInfo* add(Type* pType) {
1828 VariableInfo* pVI = add(pType->id);
1829 pVI->pType = pType;
1830 return pVI;
1831 }
1832
Jack Palevich569f1352009-06-29 14:29:08 -07001833 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
1834 for (size_t i = 0; i < mStack.size(); i++) {
1835 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001836 break;
1837 }
1838 }
Jack Palevicha6baa232009-06-12 11:25:59 -07001839 }
1840
Jack Palevich303d8ff2009-06-11 19:06:24 -07001841 private:
Jack Palevich569f1352009-06-29 14:29:08 -07001842 inline size_t level() {
1843 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07001844 }
1845
Jack Palevich569f1352009-06-29 14:29:08 -07001846 struct Mark {
1847 Arena::Mark mArenaMark;
1848 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001849 };
1850
Jack Palevich569f1352009-06-29 14:29:08 -07001851 Arena* mpArena;
1852 TokenTable* mpTokenTable;
1853 Vector<VariableInfo*> mStack;
1854 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001855 };
Jack Palevich36d94142009-06-08 15:55:32 -07001856
1857 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07001858 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07001859 intptr_t tokc; // token extra info
1860 int tokl; // token operator level
1861 intptr_t rsym; // return symbol
1862 intptr_t loc; // local variable index
1863 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07001864 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07001865 char* dptr; // Macro state: Points to macro text during macro playback.
1866 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07001867 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07001868
1869 // Arena for the duration of the compile
1870 Arena mGlobalArena;
1871 // Arena for data that's only needed when compiling a single function
1872 Arena mLocalArena;
1873
1874 TokenTable mTokenTable;
1875 SymbolStack mGlobals;
1876 SymbolStack mLocals;
1877
Jack Palevich40600de2009-07-01 15:32:35 -07001878 // Prebuilt types, makes things slightly faster.
Jack Palevich86351982009-06-30 18:09:56 -07001879 Type* mkpInt;
1880 Type* mkpChar;
1881 Type* mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07001882 Type* mkpFloat;
1883 Type* mkpDouble;
Jack Palevich3f226492009-07-02 14:46:19 -07001884 Type* mkpIntPtr;
1885 Type* mkpCharPtr;
1886 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07001887
Jack Palevich36d94142009-06-08 15:55:32 -07001888 InputStream* file;
1889
1890 CodeBuf codeBuf;
1891 CodeGenerator* pGen;
1892
Jack Palevicheedf9d22009-06-04 16:23:40 -07001893 String mErrorBuf;
1894
Jack Palevicheedf9d22009-06-04 16:23:40 -07001895 String mPragmas;
1896 int mPragmaStringCount;
1897
Jack Palevich21a15a22009-05-11 14:49:29 -07001898 static const int ALLOC_SIZE = 99999;
1899
Jack Palevich303d8ff2009-06-11 19:06:24 -07001900 static const int TOK_DUMMY = 1;
1901 static const int TOK_NUM = 2;
1902
1903 // 3..255 are character and/or operators
1904
Jack Palevich2db168f2009-06-11 14:29:47 -07001905 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07001906 // Order has to match string list in "internKeywords".
1907 enum {
1908 TOK_KEYWORD = TokenTable::TOKEN_BASE,
1909 TOK_INT = TOK_KEYWORD,
1910 TOK_CHAR,
1911 TOK_VOID,
1912 TOK_IF,
1913 TOK_ELSE,
1914 TOK_WHILE,
1915 TOK_BREAK,
1916 TOK_RETURN,
1917 TOK_FOR,
1918 TOK_PRAGMA,
1919 TOK_DEFINE,
1920 TOK_AUTO,
1921 TOK_CASE,
1922 TOK_CONST,
1923 TOK_CONTINUE,
1924 TOK_DEFAULT,
1925 TOK_DO,
1926 TOK_DOUBLE,
1927 TOK_ENUM,
1928 TOK_EXTERN,
1929 TOK_FLOAT,
1930 TOK_GOTO,
1931 TOK_LONG,
1932 TOK_REGISTER,
1933 TOK_SHORT,
1934 TOK_SIGNED,
1935 TOK_SIZEOF,
1936 TOK_STATIC,
1937 TOK_STRUCT,
1938 TOK_SWITCH,
1939 TOK_TYPEDEF,
1940 TOK_UNION,
1941 TOK_UNSIGNED,
1942 TOK_VOLATILE,
1943 TOK__BOOL,
1944 TOK__COMPLEX,
1945 TOK__IMAGINARY,
1946 TOK_INLINE,
1947 TOK_RESTRICT,
1948 // Symbols start after tokens
1949 TOK_SYMBOL
1950 };
Jack Palevich21a15a22009-05-11 14:49:29 -07001951
1952 static const int LOCAL = 0x200;
1953
1954 static const int SYM_FORWARD = 0;
1955 static const int SYM_DEFINE = 1;
1956
1957 /* tokens in string heap */
1958 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07001959
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001960 static const int OP_INCREMENT = 0;
1961 static const int OP_DECREMENT = 1;
1962 static const int OP_MUL = 2;
1963 static const int OP_DIV = 3;
1964 static const int OP_MOD = 4;
1965 static const int OP_PLUS = 5;
1966 static const int OP_MINUS = 6;
1967 static const int OP_SHIFT_LEFT = 7;
1968 static const int OP_SHIFT_RIGHT = 8;
1969 static const int OP_LESS_EQUAL = 9;
1970 static const int OP_GREATER_EQUAL = 10;
1971 static const int OP_LESS = 11;
1972 static const int OP_GREATER = 12;
1973 static const int OP_EQUALS = 13;
1974 static const int OP_NOT_EQUALS = 14;
1975 static const int OP_LOGICAL_AND = 15;
1976 static const int OP_LOGICAL_OR = 16;
1977 static const int OP_BIT_AND = 17;
1978 static const int OP_BIT_XOR = 18;
1979 static const int OP_BIT_OR = 19;
1980 static const int OP_BIT_NOT = 20;
1981 static const int OP_LOGICAL_NOT = 21;
1982 static const int OP_COUNT = 22;
1983
1984 /* Operators are searched from front, the two-character operators appear
1985 * before the single-character operators with the same first character.
1986 * @ is used to pad out single-character operators.
1987 */
1988 static const char* operatorChars;
1989 static const char operatorLevel[];
1990
Jack Palevich569f1352009-06-29 14:29:08 -07001991 /* Called when we detect an internal problem. Does nothing in production.
1992 *
1993 */
1994 void internalError() {
1995 * (char*) 0 = 0;
1996 }
1997
Jack Palevich86351982009-06-30 18:09:56 -07001998 void assert(bool isTrue) {
1999 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002000 internalError();
2001 }
Jack Palevich86351982009-06-30 18:09:56 -07002002 }
2003
Jack Palevich40600de2009-07-01 15:32:35 -07002004 bool isSymbol(tokenid_t t) {
2005 return t >= TOK_SYMBOL &&
2006 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2007 }
2008
2009 bool isSymbolOrKeyword(tokenid_t t) {
2010 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002011 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002012 }
2013
Jack Palevich86351982009-06-30 18:09:56 -07002014 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002015 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002016 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2017 if (pV && pV->tok != t) {
2018 internalError();
2019 }
2020 return pV;
2021 }
2022
2023 inline bool isDefined(tokenid_t t) {
2024 return t >= TOK_SYMBOL && VI(t) != 0;
2025 }
2026
Jack Palevich40600de2009-07-01 15:32:35 -07002027 const char* nameof(tokenid_t t) {
2028 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002029 return mTokenTable[t].pText;
2030 }
2031
Jack Palevich21a15a22009-05-11 14:49:29 -07002032 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002033 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002034 }
2035
2036 void inp() {
2037 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002038 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002039 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002040 dptr = 0;
2041 ch = dch;
2042 }
2043 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002044 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002045#if 0
2046 printf("ch='%c' 0x%x\n", ch, ch);
2047#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002048 }
2049
2050 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002051 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002052 }
2053
Jack Palevichb4758ff2009-06-12 12:49:14 -07002054 /* read a character constant, advances ch to after end of constant */
2055 int getq() {
2056 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002057 if (ch == '\\') {
2058 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002059 if (isoctal(ch)) {
2060 // 1 to 3 octal characters.
2061 val = 0;
2062 for(int i = 0; i < 3; i++) {
2063 if (isoctal(ch)) {
2064 val = (val << 3) + ch - '0';
2065 inp();
2066 }
2067 }
2068 return val;
2069 } else if (ch == 'x' || ch == 'X') {
2070 // N hex chars
2071 inp();
2072 if (! isxdigit(ch)) {
2073 error("'x' character escape requires at least one digit.");
2074 } else {
2075 val = 0;
2076 while (isxdigit(ch)) {
2077 int d = ch;
2078 if (isdigit(d)) {
2079 d -= '0';
2080 } else if (d <= 'F') {
2081 d = d - 'A' + 10;
2082 } else {
2083 d = d - 'a' + 10;
2084 }
2085 val = (val << 4) + d;
2086 inp();
2087 }
2088 }
2089 } else {
2090 int val = ch;
2091 switch (ch) {
2092 case 'a':
2093 val = '\a';
2094 break;
2095 case 'b':
2096 val = '\b';
2097 break;
2098 case 'f':
2099 val = '\f';
2100 break;
2101 case 'n':
2102 val = '\n';
2103 break;
2104 case 'r':
2105 val = '\r';
2106 break;
2107 case 't':
2108 val = '\t';
2109 break;
2110 case 'v':
2111 val = '\v';
2112 break;
2113 case '\\':
2114 val = '\\';
2115 break;
2116 case '\'':
2117 val = '\'';
2118 break;
2119 case '"':
2120 val = '"';
2121 break;
2122 case '?':
2123 val = '?';
2124 break;
2125 default:
2126 error("Undefined character escape %c", ch);
2127 break;
2128 }
2129 inp();
2130 return val;
2131 }
2132 } else {
2133 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002134 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002135 return val;
2136 }
2137
2138 static bool isoctal(int ch) {
2139 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002140 }
2141
2142 void next() {
2143 int l, a;
2144
Jack Palevich546b2242009-05-13 15:10:04 -07002145 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002146 if (ch == '#') {
2147 inp();
2148 next();
2149 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002150 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002151 } else if (tok == TOK_PRAGMA) {
2152 doPragma();
2153 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002154 error("Unsupported preprocessor directive \"%s\"",
2155 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002156 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002157 }
2158 inp();
2159 }
2160 tokl = 0;
2161 tok = ch;
2162 /* encode identifiers & numbers */
2163 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002164 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002165 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002166 pdef(ch);
2167 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002168 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002169 if (isdigit(tok)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002170 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002171 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002172 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002173 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2174 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002175 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002176 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2177 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002178 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002179 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002180 dch = ch;
2181 inp();
2182 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002183 }
2184 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002185 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002186 inp();
2187 if (tok == '\'') {
2188 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002189 tokc = getq();
2190 if (ch != '\'') {
2191 error("Expected a ' character, got %c", ch);
2192 } else {
2193 inp();
2194 }
Jack Palevich546b2242009-05-13 15:10:04 -07002195 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002196 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002197 while (ch && ch != EOF) {
2198 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002199 inp();
2200 inp();
2201 if (ch == '/')
2202 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002203 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002204 if (ch == EOF) {
2205 error("End of file inside comment.");
2206 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002207 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002208 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002209 } else if ((tok == '/') & (ch == '/')) {
2210 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002211 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002212 inp();
2213 }
2214 inp();
2215 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002216 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002217 const char* t = operatorChars;
2218 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002219 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002220 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002221 tokl = operatorLevel[opIndex];
2222 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002223 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002224#if 0
2225 printf("%c%c -> tokl=%d tokc=0x%x\n",
2226 l, a, tokl, tokc);
2227#endif
2228 if (a == ch) {
2229 inp();
2230 tok = TOK_DUMMY; /* dummy token for double tokens */
2231 }
2232 break;
2233 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002234 opIndex++;
2235 }
2236 if (l == 0) {
2237 tokl = 0;
2238 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002239 }
2240 }
2241 }
2242#if 0
2243 {
Jack Palevich569f1352009-06-29 14:29:08 -07002244 String buf;
2245 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002246 fprintf(stderr, "%s\n", buf.getUnwrapped());
2247 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002248#endif
2249 }
2250
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002251 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002252 next();
2253 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002254 String* pName = new String();
2255 while (isspace(ch)) {
2256 inp();
2257 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002258 if (ch == '(') {
2259 delete pName;
2260 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002261 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002262 }
2263 while (isspace(ch)) {
2264 inp();
2265 }
Jack Palevich569f1352009-06-29 14:29:08 -07002266 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002267 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002268 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002269 inp();
2270 }
Jack Palevich569f1352009-06-29 14:29:08 -07002271 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2272 memcpy(pDefn, value.getUnwrapped(), value.len());
2273 pDefn[value.len()] = 0;
2274 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002275 }
2276
Jack Palevicheedf9d22009-06-04 16:23:40 -07002277 void doPragma() {
2278 // # pragma name(val)
2279 int state = 0;
2280 while(ch != EOF && ch != '\n' && state < 10) {
2281 switch(state) {
2282 case 0:
2283 if (isspace(ch)) {
2284 inp();
2285 } else {
2286 state++;
2287 }
2288 break;
2289 case 1:
2290 if (isalnum(ch)) {
2291 mPragmas.append(ch);
2292 inp();
2293 } else if (ch == '(') {
2294 mPragmas.append(0);
2295 inp();
2296 state++;
2297 } else {
2298 state = 11;
2299 }
2300 break;
2301 case 2:
2302 if (isalnum(ch)) {
2303 mPragmas.append(ch);
2304 inp();
2305 } else if (ch == ')') {
2306 mPragmas.append(0);
2307 inp();
2308 state = 10;
2309 } else {
2310 state = 11;
2311 }
2312 break;
2313 }
2314 }
2315 if(state != 10) {
2316 error("Unexpected pragma syntax");
2317 }
2318 mPragmaStringCount += 2;
2319 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002320
Jack Palevichac0e95e2009-05-29 13:53:44 -07002321 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002322 mErrorBuf.printf("%ld: ", file->getLine());
2323 mErrorBuf.vprintf(fmt, ap);
2324 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002325 }
2326
Jack Palevich8b0624c2009-05-20 12:12:06 -07002327 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002328 if (tok != c) {
2329 error("'%c' expected", c);
2330 }
2331 next();
2332 }
2333
Jack Palevich86351982009-06-30 18:09:56 -07002334 bool accept(intptr_t c) {
2335 if (tok == c) {
2336 next();
2337 return true;
2338 }
2339 return false;
2340 }
2341
Jack Palevich40600de2009-07-01 15:32:35 -07002342 bool acceptStringLiteral() {
2343 if (tok == '"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07002344 pGen->li((int) glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002345 // This while loop merges multiple adjacent string constants.
2346 while (tok == '"') {
2347 while (ch != '"' && ch != EOF) {
2348 *allocGlobalSpace(1) = getq();
2349 }
2350 if (ch != '"') {
2351 error("Unterminated string constant.");
2352 }
2353 inp();
2354 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002355 }
Jack Palevich40600de2009-07-01 15:32:35 -07002356 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002357 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002358 /* align heap */
2359 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002360
2361 return true;
2362 }
2363 return false;
2364 }
2365 /* Parse and evaluate a unary expression.
2366 * allowAssignment is true if '=' parsing wanted (quick hack)
2367 */
2368 void unary(bool allowAssignment) {
2369 intptr_t n, t, a;
2370 t = 0;
2371 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2372 if (acceptStringLiteral()) {
2373 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002374 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002375 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002376 a = tokc;
2377 t = tok;
2378 next();
2379 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002380 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002381 } else if (c == 2) {
2382 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002383 unary(false);
Jack Palevich1cdef202009-05-22 12:06:27 -07002384 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002385 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002386 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002387 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002388 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002389 } else if (t == '(') {
2390 expr();
2391 skip(')');
2392 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002393 /* This is a pointer dereference, but we currently only
2394 * support a pointer dereference if it's immediately
2395 * in front of a cast. So parse the cast right here.
2396 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002397 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002398 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2399 // We currently only handle 3 types of cast:
2400 // (int*), (char*) , (int (*)())
2401 if(typeEqual(pCast, mkpIntPtr)) {
2402 t = TOK_INT;
2403 } else if (typeEqual(pCast, mkpCharPtr)) {
2404 t = TOK_CHAR;
2405 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002406 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002407 } else {
2408 String buffer;
2409 decodeType(buffer, pCast);
2410 error("Unsupported cast type %s", buffer.getUnwrapped());
2411 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002412 }
2413 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002414 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002415 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002416 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002417 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002418 pGen->popR1();
2419 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002421 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002422 }
Jack Palevich3f226492009-07-02 14:46:19 -07002423 // Else we fall through to the function call below, with
2424 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002425 } else if (t == '&') {
Jack Palevich569f1352009-06-29 14:29:08 -07002426 pGen->leaR0((int) VI(tok)->pAddress);
Jack Palevich21a15a22009-05-11 14:49:29 -07002427 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002428 } else if (t == EOF ) {
2429 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002430 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002431 // Don't have to do anything special here, the error
2432 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002433 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002434 if (!isDefined(t)) {
2435 mGlobals.add(t);
2436 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002437 }
2438
Jack Palevich569f1352009-06-29 14:29:08 -07002439 n = (intptr_t) VI(t)->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002440 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002441 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002442 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002443 VI(t)->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002444 }
Jack Palevich40600de2009-07-01 15:32:35 -07002445 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002446 /* assignment */
2447 next();
2448 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002449 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002450 } else if (tok != '(') {
2451 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002452 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002453 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07002454 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002455 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002456 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002457 next();
2458 }
2459 }
2460 }
2461 }
2462
2463 /* function call */
2464 if (tok == '(') {
2465 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002466 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002467
2468 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002469 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07002470 next();
Jack Palevich40600de2009-07-01 15:32:35 -07002471 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002472 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002473 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002474 pGen->storeR0ToArg(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002475 l = l + 4;
Jack Palevich95727a02009-07-06 12:07:15 -07002476 if (accept(',')) {
2477 // fine
2478 } else if ( tok != ')') {
2479 error("Expected ',' or ')'");
2480 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002481 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002482 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002483 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002484 if (!n) {
2485 /* forward reference */
Jack Palevich569f1352009-06-29 14:29:08 -07002486 VariableInfo* pVI = VI(t);
2487 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward);
Jack Palevich21a15a22009-05-11 14:49:29 -07002488 } else if (n == 1) {
2489 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002490 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07002491 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07002492 }
-b master422972c2009-06-17 19:13:52 -07002493 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002494 }
2495 }
2496
Jack Palevich40600de2009-07-01 15:32:35 -07002497 /* Recursive descent parser for binary operations.
2498 */
2499 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002500 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002501 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002502 if (level-- == 1)
2503 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07002504 else {
Jack Palevich40600de2009-07-01 15:32:35 -07002505 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002506 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002507 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002508 n = tok;
2509 t = tokc;
2510 next();
2511
Jack Palevich40600de2009-07-01 15:32:35 -07002512 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002513 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002514 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002515 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002516 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07002517 binaryOp(level);
Jack Palevich1cdef202009-05-22 12:06:27 -07002518 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002519
Jack Palevich40600de2009-07-01 15:32:35 -07002520 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002521 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002522 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002523 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002524 }
2525 }
2526 }
2527 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002528 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002529 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2530 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002531 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002532 pGen->gsym(a);
2533 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002534 }
2535 }
2536 }
2537
2538 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07002539 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07002540 }
2541
2542 int test_expr() {
2543 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002544 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002545 }
2546
Jack Palevicha6baa232009-06-12 11:25:59 -07002547 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002548 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002549
Jack Palevich95727a02009-07-06 12:07:15 -07002550 Type* pBaseType;
2551 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002552 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07002553 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07002554 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002555 next();
2556 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002557 a = test_expr();
2558 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002559 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002560 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002561 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002562 n = pGen->gjmp(0); /* jmp */
2563 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002564 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002565 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002566 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002567 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002568 }
Jack Palevich546b2242009-05-13 15:10:04 -07002569 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002570 t = tok;
2571 next();
2572 skip('(');
2573 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002574 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002575 a = test_expr();
2576 } else {
2577 if (tok != ';')
2578 expr();
2579 skip(';');
2580 n = codeBuf.getPC();
2581 a = 0;
2582 if (tok != ';')
2583 a = test_expr();
2584 skip(';');
2585 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002586 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002587 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002588 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002589 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002590 n = t + 4;
2591 }
2592 }
2593 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002594 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002595 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002596 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002597 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002598 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002599 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002600 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002601 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002602 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002603 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002604 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002605 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002606 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002607 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002608 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07002609 if (accept(TOK_RETURN)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002610 if (tok != ';')
2611 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002612 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07002613 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002614 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002615 } else if (tok != ';')
2616 expr();
2617 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002618 }
2619 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002620
Jack Palevich86351982009-06-30 18:09:56 -07002621 enum TypeTag {
Jack Palevich95727a02009-07-06 12:07:15 -07002622 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
2623 TY_POINTER, TY_FUNC, TY_PARAM
Jack Palevich86351982009-06-30 18:09:56 -07002624 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002625
Jack Palevich86351982009-06-30 18:09:56 -07002626 struct Type {
2627 TypeTag tag;
2628 tokenid_t id; // For function arguments
2629 Type* pHead;
2630 Type* pTail;
2631 };
2632
Jack Palevich3f226492009-07-02 14:46:19 -07002633 bool typeEqual(Type* a, Type* b) {
2634 if (a == b) {
2635 return true;
2636 }
2637 if (a == NULL || b == NULL) {
2638 return false;
2639 }
2640 TypeTag at = a->tag;
2641 if (at != b->tag) {
2642 return false;
2643 }
2644 if (at == TY_POINTER) {
2645 return typeEqual(a->pHead, b->pHead);
2646 } else if (at == TY_FUNC || at == TY_PARAM) {
2647 return typeEqual(a->pHead, b->pHead)
2648 && typeEqual(a->pTail, b->pTail);
2649 }
2650 return true;
2651 }
2652
Jack Palevich86351982009-06-30 18:09:56 -07002653 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
2654 assert(tag >= TY_INT && tag <= TY_PARAM);
2655 Type* pType = (Type*) arena.alloc(sizeof(Type));
2656 memset(pType, 0, sizeof(*pType));
2657 pType->tag = tag;
2658 pType->pHead = pHead;
2659 pType->pTail = pTail;
2660 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002661 }
2662
Jack Palevich3f226492009-07-02 14:46:19 -07002663 Type* createPtrType(Type* pType, Arena& arena) {
2664 return createType(TY_POINTER, pType, NULL, arena);
2665 }
2666
2667 /**
2668 * Try to print a type in declaration order
2669 */
Jack Palevich86351982009-06-30 18:09:56 -07002670 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07002671 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07002672 if (pType == NULL) {
2673 buffer.appendCStr("null");
2674 return;
2675 }
Jack Palevich3f226492009-07-02 14:46:19 -07002676 decodeTypeImp(buffer, pType);
2677 }
2678
2679 void decodeTypeImp(String& buffer, Type* pType) {
2680 decodeTypeImpPrefix(buffer, pType);
2681
Jack Palevich86351982009-06-30 18:09:56 -07002682 String temp;
2683 if (pType->id != 0) {
2684 decodeToken(temp, pType->id);
2685 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07002686 }
2687
2688 decodeTypeImpPostfix(buffer, pType);
2689 }
2690
2691 void decodeTypeImpPrefix(String& buffer, Type* pType) {
2692 TypeTag tag = pType->tag;
2693
2694 if (tag >= TY_INT && tag <= TY_VOID) {
2695 switch (tag) {
2696 case TY_INT:
2697 buffer.appendCStr("int");
2698 break;
2699 case TY_CHAR:
2700 buffer.appendCStr("char");
2701 break;
2702 case TY_VOID:
2703 buffer.appendCStr("void");
2704 break;
Jack Palevich95727a02009-07-06 12:07:15 -07002705 case TY_FLOAT:
2706 buffer.appendCStr("float");
2707 break;
2708 case TY_DOUBLE:
2709 buffer.appendCStr("double");
2710 break;
Jack Palevich3f226492009-07-02 14:46:19 -07002711 default:
2712 break;
2713 }
Jack Palevich86351982009-06-30 18:09:56 -07002714 buffer.append(' ');
2715 }
Jack Palevich3f226492009-07-02 14:46:19 -07002716
2717 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07002718 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07002719 break;
2720 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07002721 break;
2722 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07002723 break;
Jack Palevich95727a02009-07-06 12:07:15 -07002724 case TY_FLOAT:
2725 break;
2726 case TY_DOUBLE:
2727 break;
Jack Palevich86351982009-06-30 18:09:56 -07002728 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07002729 decodeTypeImpPrefix(buffer, pType->pHead);
2730 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
2731 buffer.append('(');
2732 }
2733 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07002734 break;
2735 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07002736 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07002737 break;
2738 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07002739 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07002740 break;
2741 default:
2742 String temp;
2743 temp.printf("Unknown tag %d", pType->tag);
2744 buffer.append(temp);
2745 break;
2746 }
Jack Palevich3f226492009-07-02 14:46:19 -07002747 }
2748
2749 void decodeTypeImpPostfix(String& buffer, Type* pType) {
2750 TypeTag tag = pType->tag;
2751
2752 switch(tag) {
2753 case TY_POINTER:
2754 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
2755 buffer.append(')');
2756 }
2757 decodeTypeImpPostfix(buffer, pType->pHead);
2758 break;
2759 case TY_FUNC:
2760 buffer.append('(');
2761 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
2762 decodeTypeImp(buffer, pArg);
2763 if (pArg->pTail) {
2764 buffer.appendCStr(", ");
2765 }
2766 }
2767 buffer.append(')');
2768 break;
2769 default:
2770 break;
Jack Palevich86351982009-06-30 18:09:56 -07002771 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002772 }
2773
Jack Palevich86351982009-06-30 18:09:56 -07002774 void printType(Type* pType) {
2775 String buffer;
2776 decodeType(buffer, pType);
2777 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07002778 }
2779
Jack Palevich86351982009-06-30 18:09:56 -07002780 Type* acceptPrimitiveType(Arena& arena) {
2781 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002782 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07002783 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002784 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07002785 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002786 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07002787 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07002788 } else if (tok == TOK_FLOAT) {
2789 pType = mkpFloat;
2790 } else if (tok == TOK_DOUBLE) {
2791 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002792 } else {
Jack Palevich86351982009-06-30 18:09:56 -07002793 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002794 }
2795 next();
Jack Palevich86351982009-06-30 18:09:56 -07002796 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002797 }
2798
Jack Palevich3f226492009-07-02 14:46:19 -07002799 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
2800 Arena& arena) {
2801 tokenid_t declName = 0;
2802 pType = acceptDecl2(pType, declName, nameAllowed,
2803 nameRequired, arena);
2804 if (declName) {
2805 // Clone the parent type so we can set a unique ID
2806 pType = createType(pType->tag, pType->pHead,
2807 pType->pTail, arena);
2808
Jack Palevich86351982009-06-30 18:09:56 -07002809 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07002810 }
Jack Palevich3f226492009-07-02 14:46:19 -07002811 // fprintf(stderr, "Parsed a declaration: ");
2812 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07002813 return pType;
2814 }
2815
Jack Palevich3f226492009-07-02 14:46:19 -07002816 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
2817 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07002818 if (! pType) {
2819 error("Expected a declaration");
2820 }
2821 return pType;
2822 }
2823
Jack Palevich3f226492009-07-02 14:46:19 -07002824 /* Used for accepting types that appear in casts */
2825 Type* acceptCastTypeDeclaration(Arena& arena) {
2826 Type* pType = acceptPrimitiveType(arena);
2827 if (pType) {
2828 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07002829 }
Jack Palevich86351982009-06-30 18:09:56 -07002830 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002831 }
2832
Jack Palevich3f226492009-07-02 14:46:19 -07002833 Type* expectCastTypeDeclaration(Arena& arena) {
2834 Type* pType = acceptCastTypeDeclaration(arena);
2835 if (! pType) {
2836 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07002837 }
Jack Palevich3f226492009-07-02 14:46:19 -07002838 return pType;
2839 }
2840
2841 Type* acceptDecl2(Type* pType, tokenid_t& declName,
2842 bool nameAllowed, bool nameRequired, Arena& arena) {
2843 int ptrCounter = 0;
2844 while (accept('*')) {
2845 ptrCounter++;
2846 }
2847 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
2848 while (ptrCounter-- > 0) {
2849 pType = createType(TY_POINTER, pType, NULL, arena);
2850 }
2851 return pType;
2852 }
2853
2854 Type* acceptDecl3(Type* pType, tokenid_t& declName,
2855 bool nameAllowed, bool nameRequired, Arena& arena) {
2856 // direct-dcl :
2857 // name
2858 // (dcl)
2859 // direct-dcl()
2860 // direct-dcl[]
2861 Type* pNewHead = NULL;
2862 if (accept('(')) {
2863 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
2864 nameRequired, arena);
2865 skip(')');
2866 } else if ((declName = acceptSymbol()) != 0) {
2867 if (nameAllowed == false && declName) {
2868 error("Symbol %s not allowed here", nameof(declName));
2869 } else if (nameRequired && ! declName) {
2870 String temp;
2871 decodeToken(temp, tok);
2872 error("Expected symbol. Got %s", temp.getUnwrapped());
2873 }
2874 }
2875 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07002876 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07002877 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07002878 pType = createType(TY_FUNC, pType, pTail, arena);
2879 skip(')');
2880 }
Jack Palevich3f226492009-07-02 14:46:19 -07002881
2882 if (pNewHead) {
2883 Type* pA = pNewHead;
2884 while (pA->pHead) {
2885 pA = pA->pHead;
2886 }
2887 pA->pHead = pType;
2888 pType = pNewHead;
2889 }
Jack Palevich86351982009-06-30 18:09:56 -07002890 return pType;
2891 }
2892
Jack Palevich3f226492009-07-02 14:46:19 -07002893 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07002894 Type* pHead = NULL;
2895 Type* pTail = NULL;
2896 for(;;) {
2897 Type* pBaseArg = acceptPrimitiveType(arena);
2898 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07002899 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
2900 arena);
Jack Palevich86351982009-06-30 18:09:56 -07002901 if (pArg) {
2902 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
2903 if (!pHead) {
2904 pHead = pParam;
2905 pTail = pParam;
2906 } else {
2907 pTail->pTail = pParam;
2908 pTail = pParam;
2909 }
2910 }
2911 }
2912 if (! accept(',')) {
2913 break;
2914 }
2915 }
2916 return pHead;
2917 }
2918
2919 Type* expectPrimitiveType(Arena& arena) {
2920 Type* pType = acceptPrimitiveType(arena);
2921 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07002922 String buf;
2923 decodeToken(buf, tok);
2924 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07002925 }
Jack Palevich86351982009-06-30 18:09:56 -07002926 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002927 }
2928
Jack Palevich86351982009-06-30 18:09:56 -07002929 void addGlobalSymbol(Type* pDecl) {
2930 tokenid_t t = pDecl->id;
2931 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07002932 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07002933 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07002934 }
Jack Palevich86351982009-06-30 18:09:56 -07002935 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07002936 }
2937
Jack Palevich86351982009-06-30 18:09:56 -07002938 void reportDuplicate(tokenid_t t) {
2939 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002940 }
2941
Jack Palevich86351982009-06-30 18:09:56 -07002942 void addLocalSymbol(Type* pDecl) {
2943 tokenid_t t = pDecl->id;
2944 if (mLocals.isDefinedAtCurrentLevel(t)) {
2945 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07002946 }
Jack Palevich86351982009-06-30 18:09:56 -07002947 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002948 }
2949
Jack Palevich95727a02009-07-06 12:07:15 -07002950 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002951 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002952
Jack Palevich95727a02009-07-06 12:07:15 -07002953 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002954 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07002955 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
2956 if (!pDecl) {
2957 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07002958 }
Jack Palevich86351982009-06-30 18:09:56 -07002959 int variableAddress = 0;
2960 addLocalSymbol(pDecl);
2961 loc = loc + 4;
2962 variableAddress = -loc;
2963 VI(pDecl->id)->pAddress = (void*) variableAddress;
2964 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07002965 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07002966 expr();
2967 pGen->storeR0(variableAddress);
2968 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002969 if (tok == ',')
2970 next();
2971 }
2972 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07002973 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07002974 }
2975 }
2976
Jack Palevichf1728be2009-06-12 13:53:51 -07002977 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07002978 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07002979 }
2980
Jack Palevich569f1352009-06-29 14:29:08 -07002981 void decodeToken(String& buffer, tokenid_t token) {
2982 if (token == EOF ) {
2983 buffer.printf("EOF");
2984 } else if (token == TOK_NUM) {
2985 buffer.printf("numeric constant");
2986 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07002987 if (token < 32) {
2988 buffer.printf("'\\x%02x'", token);
2989 } else {
2990 buffer.printf("'%c'", token);
2991 }
Jack Palevich569f1352009-06-29 14:29:08 -07002992 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
2993 buffer.printf("keyword \"%s\"", nameof(token));
2994 } else {
2995 buffer.printf("symbol \"%s\"", nameof(token));
2996 }
2997 }
2998
Jack Palevich40600de2009-07-01 15:32:35 -07002999 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003000 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003001 if (!result) {
3002 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003003 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003004 error("Expected symbol. Got %s", temp.getUnwrapped());
3005 }
3006 return result;
3007 }
3008
Jack Palevich86351982009-06-30 18:09:56 -07003009 tokenid_t acceptSymbol() {
3010 tokenid_t result = 0;
3011 if (tok >= TOK_SYMBOL) {
3012 result = tok;
3013 next();
Jack Palevich86351982009-06-30 18:09:56 -07003014 }
3015 return result;
3016 }
3017
Jack Palevichb7c81e92009-06-04 19:56:13 -07003018 void globalDeclarations() {
3019 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003020 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3021 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003022 break;
3023 }
Jack Palevich86351982009-06-30 18:09:56 -07003024 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3025 if (!pDecl) {
3026 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003027 }
Jack Palevich86351982009-06-30 18:09:56 -07003028 if (! isDefined(pDecl->id)) {
3029 addGlobalSymbol(pDecl);
3030 }
3031 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003032 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003033 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003034 }
Jack Palevich86351982009-06-30 18:09:56 -07003035 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003036 // it's a variable declaration
3037 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003038 if (name && !name->pAddress) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003039 name->pAddress = (int*) allocGlobalSpace(4);
3040 }
Jack Palevich86351982009-06-30 18:09:56 -07003041 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003042 if (tok == TOK_NUM) {
3043 if (name) {
3044 * (int*) name->pAddress = tokc;
3045 }
3046 next();
3047 } else {
3048 error("Expected an integer constant");
3049 }
3050 }
Jack Palevich86351982009-06-30 18:09:56 -07003051 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003052 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003053 }
Jack Palevich86351982009-06-30 18:09:56 -07003054 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3055 if (!pDecl) {
3056 break;
3057 }
3058 if (! isDefined(pDecl->id)) {
3059 addGlobalSymbol(pDecl);
3060 }
3061 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003062 }
3063 skip(';');
3064 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003065 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003066 if (accept(';')) {
3067 // forward declaration.
3068 } else {
3069 if (name) {
3070 /* patch forward references (XXX: does not work for function
3071 pointers) */
3072 pGen->gsym((int) name->pForward);
3073 /* put function address */
3074 name->pAddress = (void*) codeBuf.getPC();
3075 }
3076 // Calculate stack offsets for parameters
3077 mLocals.pushLevel();
3078 intptr_t a = 8;
3079 int argCount = 0;
3080 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3081 Type* pArg = pP->pHead;
3082 addLocalSymbol(pArg);
3083 /* read param name and compute offset */
3084 VI(pArg->id)->pAddress = (void*) a;
3085 a = a + 4;
3086 argCount++;
3087 }
3088 rsym = loc = 0;
3089 a = pGen->functionEntry(argCount);
3090 block(0, true);
3091 pGen->gsym(rsym);
3092 pGen->functionExit(argCount, a, loc);
3093 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003094 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003095 }
3096 }
3097 }
3098
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003099 char* allocGlobalSpace(int bytes) {
3100 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
3101 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003102 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003103 }
3104 char* result = glo;
3105 glo += bytes;
3106 return result;
3107 }
3108
Jack Palevich21a15a22009-05-11 14:49:29 -07003109 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003110 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003111 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003112 pGlobalBase = 0;
3113 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003114 if (pGen) {
3115 delete pGen;
3116 pGen = 0;
3117 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003118 if (file) {
3119 delete file;
3120 file = 0;
3121 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003122 }
3123
3124 void clear() {
3125 tok = 0;
3126 tokc = 0;
3127 tokl = 0;
3128 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003129 rsym = 0;
3130 loc = 0;
3131 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003132 dptr = 0;
3133 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003134 file = 0;
3135 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003136 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003137 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003138 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003139
Jack Palevich22305132009-05-13 10:58:45 -07003140 void setArchitecture(const char* architecture) {
3141 delete pGen;
3142 pGen = 0;
3143
3144 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003145#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003146 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003147 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003148 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003149#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003150#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003151 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003152 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003153 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003154#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003155 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003156 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003157 }
3158 }
3159
3160 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003161#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003162 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003163#elif defined(DEFAULT_X86_CODEGEN)
3164 pGen = new X86CodeGenerator();
3165#endif
3166 }
3167 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003168 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003169 } else {
3170 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003171 }
3172 }
3173
Jack Palevich77ae76e2009-05-10 19:59:24 -07003174public:
Jack Palevich22305132009-05-13 10:58:45 -07003175 struct args {
3176 args() {
3177 architecture = 0;
3178 }
3179 const char* architecture;
3180 };
3181
Jack Paleviche7b59062009-05-19 17:12:17 -07003182 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003183 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003184 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003185
Jack Paleviche7b59062009-05-19 17:12:17 -07003186 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003187 cleanup();
3188 }
3189
Jack Palevich1cdef202009-05-22 12:06:27 -07003190 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003191 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003192
3193 cleanup();
3194 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003195 mTokenTable.setArena(&mGlobalArena);
3196 mGlobals.setArena(&mGlobalArena);
3197 mGlobals.setTokenTable(&mTokenTable);
3198 mLocals.setArena(&mLocalArena);
3199 mLocals.setTokenTable(&mTokenTable);
3200
3201 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003202 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003203 codeBuf.init(ALLOC_SIZE);
3204 setArchitecture(NULL);
3205 if (!pGen) {
3206 return -1;
3207 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003208#ifdef PROVIDE_TRACE_CODEGEN
3209 pGen = new TraceCodeGenerator(pGen);
3210#endif
3211 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003212 pGen->init(&codeBuf);
3213 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003214 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3215 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003216 inp();
3217 next();
3218 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003219 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003220 result = pGen->finishCompile();
3221 if (result == 0) {
3222 if (mErrorBuf.len()) {
3223 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003224 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003225 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003226 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003227 }
3228
Jack Palevich86351982009-06-30 18:09:56 -07003229 void createPrimitiveTypes() {
3230 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3231 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3232 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003233 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3234 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003235 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3236 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
3237 mkpPtrIntFn = createPtrType(
3238 createType(TY_FUNC, mkpInt, NULL, mGlobalArena),
3239 mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003240 }
3241
Jack Palevicha6baa232009-06-12 11:25:59 -07003242 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003243 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003244 }
3245
Jack Palevich569f1352009-06-29 14:29:08 -07003246 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003247 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003248 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003249 }
3250
Jack Palevich569f1352009-06-29 14:29:08 -07003251 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003252 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003253 error("Undefined forward reference: %s",
3254 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003255 }
3256 return true;
3257 }
3258
Jack Palevich21a15a22009-05-11 14:49:29 -07003259 int dump(FILE* out) {
3260 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3261 return 0;
3262 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003263
Jack Palevicha6535612009-05-13 16:24:17 -07003264 int disassemble(FILE* out) {
3265 return pGen->disassemble(out);
3266 }
3267
Jack Palevich1cdef202009-05-22 12:06:27 -07003268 /* Look through the symbol table to find a symbol.
3269 * If found, return its value.
3270 */
3271 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003272 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3273 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003274 if (pVariableInfo) {
3275 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003276 }
3277 return NULL;
3278 }
3279
Jack Palevicheedf9d22009-06-04 16:23:40 -07003280 void getPragmas(ACCsizei* actualStringCount,
3281 ACCsizei maxStringCount, ACCchar** strings) {
3282 int stringCount = mPragmaStringCount;
3283 if (actualStringCount) {
3284 *actualStringCount = stringCount;
3285 }
3286 if (stringCount > maxStringCount) {
3287 stringCount = maxStringCount;
3288 }
3289 if (strings) {
3290 char* pPragmas = mPragmas.getUnwrapped();
3291 while (stringCount-- > 0) {
3292 *strings++ = pPragmas;
3293 pPragmas += strlen(pPragmas) + 1;
3294 }
3295 }
3296 }
3297
Jack Palevichac0e95e2009-05-29 13:53:44 -07003298 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003299 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003300 }
3301
Jack Palevich77ae76e2009-05-10 19:59:24 -07003302};
3303
Jack Paleviche7b59062009-05-19 17:12:17 -07003304const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003305 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3306
Jack Paleviche7b59062009-05-19 17:12:17 -07003307const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003308 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3309 5, 5, /* ==, != */
3310 9, 10, /* &&, || */
3311 6, 7, 8, /* & ^ | */
3312 2, 2 /* ~ ! */
3313 };
3314
Jack Palevich8b0624c2009-05-20 12:12:06 -07003315#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003316FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003317#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003318
Jack Palevich8b0624c2009-05-20 12:12:06 -07003319#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003320const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003321 0x1, // ++
3322 0xff, // --
3323 0xc1af0f, // *
3324 0xf9f79991, // /
3325 0xf9f79991, // % (With manual assist to swap results)
3326 0xc801, // +
3327 0xd8f7c829, // -
3328 0xe0d391, // <<
3329 0xf8d391, // >>
3330 0xe, // <=
3331 0xd, // >=
3332 0xc, // <
3333 0xf, // >
3334 0x4, // ==
3335 0x5, // !=
3336 0x0, // &&
3337 0x1, // ||
3338 0xc821, // &
3339 0xc831, // ^
3340 0xc809, // |
3341 0xd0f7, // ~
3342 0x4 // !
3343};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003344#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003345
Jack Palevich1cdef202009-05-22 12:06:27 -07003346struct ACCscript {
3347 ACCscript() {
3348 text = 0;
3349 textLength = 0;
3350 accError = ACC_NO_ERROR;
3351 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003352
Jack Palevich1cdef202009-05-22 12:06:27 -07003353 ~ACCscript() {
3354 delete text;
3355 }
Jack Palevich546b2242009-05-13 15:10:04 -07003356
Jack Palevich1cdef202009-05-22 12:06:27 -07003357 void setError(ACCenum error) {
3358 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3359 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003360 }
3361 }
3362
Jack Palevich1cdef202009-05-22 12:06:27 -07003363 ACCenum getError() {
3364 ACCenum result = accError;
3365 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003366 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003367 }
3368
Jack Palevich1cdef202009-05-22 12:06:27 -07003369 Compiler compiler;
3370 char* text;
3371 int textLength;
3372 ACCenum accError;
3373};
3374
3375
3376extern "C"
3377ACCscript* accCreateScript() {
3378 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003379}
Jack Palevich1cdef202009-05-22 12:06:27 -07003380
3381extern "C"
3382ACCenum accGetError( ACCscript* script ) {
3383 return script->getError();
3384}
3385
3386extern "C"
3387void accDeleteScript(ACCscript* script) {
3388 delete script;
3389}
3390
3391extern "C"
3392void accScriptSource(ACCscript* script,
3393 ACCsizei count,
3394 const ACCchar ** string,
3395 const ACCint * length) {
3396 int totalLength = 0;
3397 for(int i = 0; i < count; i++) {
3398 int len = -1;
3399 const ACCchar* s = string[i];
3400 if (length) {
3401 len = length[i];
3402 }
3403 if (len < 0) {
3404 len = strlen(s);
3405 }
3406 totalLength += len;
3407 }
3408 delete script->text;
3409 char* text = new char[totalLength + 1];
3410 script->text = text;
3411 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003412 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003413 for(int i = 0; i < count; i++) {
3414 int len = -1;
3415 const ACCchar* s = string[i];
3416 if (length) {
3417 len = length[i];
3418 }
3419 if (len < 0) {
3420 len = strlen(s);
3421 }
Jack Palevich09555c72009-05-27 12:25:55 -07003422 memcpy(dest, s, len);
3423 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003424 }
3425 text[totalLength] = '\0';
3426}
3427
3428extern "C"
3429void accCompileScript(ACCscript* script) {
3430 int result = script->compiler.compile(script->text, script->textLength);
3431 if (result) {
3432 script->setError(ACC_INVALID_OPERATION);
3433 }
3434}
3435
3436extern "C"
3437void accGetScriptiv(ACCscript* script,
3438 ACCenum pname,
3439 ACCint * params) {
3440 switch (pname) {
3441 case ACC_INFO_LOG_LENGTH:
3442 *params = 0;
3443 break;
3444 }
3445}
3446
3447extern "C"
3448void accGetScriptInfoLog(ACCscript* script,
3449 ACCsizei maxLength,
3450 ACCsizei * length,
3451 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003452 char* message = script->compiler.getErrorMessage();
3453 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003454 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003455 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003456 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003457 if (infoLog && maxLength > 0) {
3458 int trimmedLength = maxLength < messageLength ?
3459 maxLength : messageLength;
3460 memcpy(infoLog, message, trimmedLength);
3461 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003462 }
3463}
3464
3465extern "C"
3466void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3467 ACCvoid ** address) {
3468 void* value = script->compiler.lookup(name);
3469 if (value) {
3470 *address = value;
3471 } else {
3472 script->setError(ACC_INVALID_VALUE);
3473 }
3474}
3475
Jack Palevicheedf9d22009-06-04 16:23:40 -07003476extern "C"
3477void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3478 ACCsizei maxStringCount, ACCchar** strings){
3479 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3480}
3481
-b master422972c2009-06-17 19:13:52 -07003482extern "C"
3483void accDisassemble(ACCscript* script) {
3484 script->compiler.disassemble(stderr);
3485}
3486
Jack Palevicheedf9d22009-06-04 16:23:40 -07003487
Jack Palevich1cdef202009-05-22 12:06:27 -07003488} // namespace acc
3489