blob: 7547fde79c53a3a2659f5086053c1a6895a4f027 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040
41#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070042#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070043#endif
Jack Palevicha6535612009-05-13 16:24:17 -070044
Jack Palevich1cdef202009-05-22 12:06:27 -070045#include <acc/acc.h>
46
Jack Palevich09555c72009-05-27 12:25:55 -070047#define LOG_API(...) do {} while(0)
48// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070049
-b master422972c2009-06-17 19:13:52 -070050#define LOG_STACK(...) do {} while(0)
51// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
52
53// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichbbf8ab52009-05-11 11:54:30 -070056namespace acc {
57
Jack Palevichac0e95e2009-05-29 13:53:44 -070058class ErrorSink {
59public:
60 void error(const char *fmt, ...) {
61 va_list ap;
62 va_start(ap, fmt);
63 verror(fmt, ap);
64 va_end(ap);
65 }
66
67 virtual void verror(const char* fmt, va_list ap) = 0;
68};
69
70class Compiler : public ErrorSink {
Jack Palevich9eed7a22009-07-06 17:24:34 -070071 struct Type;
72
Jack Palevich21a15a22009-05-11 14:49:29 -070073 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070074 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070075 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070076 ErrorSink* mErrorSink;
77 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -070078 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -070079
Jack Palevich21a15a22009-05-11 14:49:29 -070080 void release() {
81 if (pProgramBase != 0) {
82 free(pProgramBase);
83 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070084 }
Jack Palevich21a15a22009-05-11 14:49:29 -070085 }
86
Jack Palevich0a280a02009-06-11 10:53:51 -070087 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -070088 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -070089 bool overflow = newSize > mSize;
90 if (overflow && !mOverflowed) {
91 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -070092 if (mErrorSink) {
93 mErrorSink->error("Code too large: %d bytes", newSize);
94 }
95 }
Jack Palevich0a280a02009-06-11 10:53:51 -070096 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -070097 }
98
Jack Palevich21a15a22009-05-11 14:49:29 -070099 public:
100 CodeBuf() {
101 pProgramBase = 0;
102 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700103 mErrorSink = 0;
104 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700105 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700106 }
107
108 ~CodeBuf() {
109 release();
110 }
111
112 void init(int size) {
113 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700114 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700115 pProgramBase = (char*) calloc(1, size);
116 ind = pProgramBase;
117 }
118
Jack Palevichac0e95e2009-05-29 13:53:44 -0700119 void setErrorSink(ErrorSink* pErrorSink) {
120 mErrorSink = pErrorSink;
121 }
122
Jack Palevich546b2242009-05-13 15:10:04 -0700123 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700124 if(check(4)) {
125 return 0;
126 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700127 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700128 * (int*) ind = n;
129 ind += 4;
130 return result;
131 }
132
Jack Palevich21a15a22009-05-11 14:49:29 -0700133 /*
134 * Output a byte. Handles all values, 0..ff.
135 */
136 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700137 if(check(1)) {
138 return;
139 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700140 *ind++ = n;
141 }
142
Jack Palevich21a15a22009-05-11 14:49:29 -0700143 inline void* getBase() {
144 return (void*) pProgramBase;
145 }
146
Jack Palevich8b0624c2009-05-20 12:12:06 -0700147 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 return ind - pProgramBase;
149 }
150
Jack Palevich8b0624c2009-05-20 12:12:06 -0700151 intptr_t getPC() {
152 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700153 }
154 };
155
Jack Palevich1cdef202009-05-22 12:06:27 -0700156 /**
157 * A code generator creates an in-memory program, generating the code on
158 * the fly. There is one code generator implementation for each supported
159 * architecture.
160 *
161 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700162 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700163 * FP - a frame pointer for accessing function arguments and local
164 * variables.
165 * SP - a stack pointer for storing intermediate results while evaluating
166 * expressions. The stack pointer grows downwards.
167 *
168 * The function calling convention is that all arguments are placed on the
169 * stack such that the first argument has the lowest address.
170 * After the call, the result is in R0. The caller is responsible for
171 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700172 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700173 * FP and SP registers are saved.
174 */
175
Jack Palevich21a15a22009-05-11 14:49:29 -0700176 class CodeGenerator {
177 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700178 CodeGenerator() {
179 mErrorSink = 0;
180 pCodeBuf = 0;
181 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700182 virtual ~CodeGenerator() {}
183
Jack Palevich22305132009-05-13 10:58:45 -0700184 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700185 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700186 pCodeBuf->setErrorSink(mErrorSink);
187 }
188
Jack Palevichb67b18f2009-06-11 21:12:23 -0700189 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700190 mErrorSink = pErrorSink;
191 if (pCodeBuf) {
192 pCodeBuf->setErrorSink(mErrorSink);
193 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700194 }
195
Jack Palevich1cdef202009-05-22 12:06:27 -0700196 /* Emit a function prolog.
197 * argCount is the number of arguments.
198 * Save the old value of the FP.
199 * Set the new value of the FP.
200 * Convert from the native platform calling convention to
201 * our stack-based calling convention. This may require
202 * pushing arguments from registers to the stack.
203 * Allocate "N" bytes of stack space. N isn't known yet, so
204 * just emit the instructions for adjusting the stack, and return
205 * the address to patch up. The patching will be done in
206 * functionExit().
207 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700208 */
Jack Palevich546b2242009-05-13 15:10:04 -0700209 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700210
Jack Palevich1cdef202009-05-22 12:06:27 -0700211 /* Emit a function epilog.
212 * Restore the old SP and FP register values.
213 * Return to the calling function.
214 * argCount - the number of arguments to the function.
215 * localVariableAddress - returned from functionEntry()
216 * localVariableSize - the size in bytes of the local variables.
217 */
218 virtual void functionExit(int argCount, int localVariableAddress,
219 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700220
Jack Palevich1cdef202009-05-22 12:06:27 -0700221 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700222 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700223
Jack Palevich1cdef202009-05-22 12:06:27 -0700224 /* Jump to a target, and return the address of the word that
225 * holds the target data, in case it needs to be fixed up later.
226 */
Jack Palevich22305132009-05-13 10:58:45 -0700227 virtual int gjmp(int t) = 0;
228
Jack Palevich1cdef202009-05-22 12:06:27 -0700229 /* Test R0 and jump to a target if the test succeeds.
230 * l = 0: je, l == 1: jne
231 * Return the address of the word that holds the targed data, in
232 * case it needs to be fixed up later.
233 */
Jack Palevich22305132009-05-13 10:58:45 -0700234 virtual int gtst(bool l, int t) = 0;
235
Jack Palevich9eed7a22009-07-06 17:24:34 -0700236 /* Compare TOS against R0, and store the boolean result in R0.
237 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700238 * op specifies the comparison.
239 */
Jack Palevich22305132009-05-13 10:58:45 -0700240 virtual void gcmp(int op) = 0;
241
Jack Palevich9eed7a22009-07-06 17:24:34 -0700242 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700243 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700244 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700245 */
Jack Palevich546b2242009-05-13 15:10:04 -0700246 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700247
Jack Palevich9eed7a22009-07-06 17:24:34 -0700248 /* Compare 0 against R0, and store the boolean result in R0.
249 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700250 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700251 virtual void gUnaryCmp(int op) = 0;
252
253 /* Perform the arithmetic op specified by op. 0 is the
254 * left argument, R0 is the right argument.
255 */
256 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700257
Jack Palevich1cdef202009-05-22 12:06:27 -0700258 /* Push R0 onto the stack.
259 */
260 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700261
Jack Palevich9eed7a22009-07-06 17:24:34 -0700262 /* Store R0 to the address stored in TOS.
263 * The TOS is popped.
264 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700265 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700266 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700267
Jack Palevich1cdef202009-05-22 12:06:27 -0700268 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700269 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700270 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700271 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700272
Jack Palevich1cdef202009-05-22 12:06:27 -0700273 /* Load the absolute address of a variable to R0.
274 * If ea <= LOCAL, then this is a local variable, or an
275 * argument, addressed relative to FP.
276 * else it is an absolute global address.
277 */
278 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700279
Jack Palevich1cdef202009-05-22 12:06:27 -0700280 /* Store R0 to a variable.
281 * If ea <= LOCAL, then this is a local variable, or an
282 * argument, addressed relative to FP.
283 * else it is an absolute global address.
284 */
285 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700286
Jack Palevich1cdef202009-05-22 12:06:27 -0700287 /* load R0 from a variable.
288 * If ea <= LOCAL, then this is a local variable, or an
289 * argument, addressed relative to FP.
290 * else it is an absolute global address.
291 * If isIncDec is true, then the stored variable's value
292 * should be post-incremented or post-decremented, based
293 * on the value of op.
294 */
295 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700296
Jack Palevich1cdef202009-05-22 12:06:27 -0700297 /* Emit code to adjust the stack for a function call. Return the
298 * label for the address of the instruction that adjusts the
299 * stack size. This will be passed as argument "a" to
300 * endFunctionCallArguments.
301 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700302 virtual int beginFunctionCallArguments() = 0;
303
Jack Palevich1cdef202009-05-22 12:06:27 -0700304 /* Emit code to store R0 to the stack at byte offset l.
305 */
306 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700307
Jack Palevich1cdef202009-05-22 12:06:27 -0700308 /* Patch the function call preamble.
309 * a is the address returned from beginFunctionCallArguments
310 * l is the number of bytes the arguments took on the stack.
311 * Typically you would also emit code to convert the argument
312 * list into whatever the native function calling convention is.
313 * On ARM for example you would pop the first 5 arguments into
314 * R0..R4
315 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700316 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700317
Jack Palevich1cdef202009-05-22 12:06:27 -0700318 /* Emit a call to an unknown function. The argument "symbol" needs to
319 * be stored in the location where the address should go. It forms
320 * a chain. The address will be patched later.
321 * Return the address of the word that has to be patched.
322 */
Jack Palevich22305132009-05-13 10:58:45 -0700323 virtual int callForward(int symbol) = 0;
324
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 /* Call a function using PC-relative addressing. t is the PC-relative
326 * address of the function. It has already been adjusted for the
327 * architectural jump offset, so just store it as-is.
328 */
Jack Palevich22305132009-05-13 10:58:45 -0700329 virtual void callRelative(int t) = 0;
330
Jack Palevich1cdef202009-05-22 12:06:27 -0700331 /* Call a function pointer. L is the number of bytes the arguments
332 * take on the stack. The address of the function is stored at
333 * location SP + l.
334 */
Jack Palevich22305132009-05-13 10:58:45 -0700335 virtual void callIndirect(int l) = 0;
336
Jack Palevich1cdef202009-05-22 12:06:27 -0700337 /* Adjust SP after returning from a function call. l is the
338 * number of bytes of arguments stored on the stack. isIndirect
339 * is true if this was an indirect call. (In which case the
340 * address of the function is stored at location SP + l.)
341 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700342 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700343
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 /* Print a disassembly of the assembled code to out. Return
345 * non-zero if there is an error.
346 */
Jack Palevicha6535612009-05-13 16:24:17 -0700347 virtual int disassemble(FILE* out) = 0;
348
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 /* Generate a symbol at the current PC. t is the head of a
350 * linked list of addresses to patch.
351 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700352 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700353
Jack Palevich1cdef202009-05-22 12:06:27 -0700354 /*
355 * Do any cleanup work required at the end of a compile.
356 * For example, an instruction cache might need to be
357 * invalidated.
358 * Return non-zero if there is an error.
359 */
360 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700361
Jack Palevicha6535612009-05-13 16:24:17 -0700362 /**
363 * Adjust relative branches by this amount.
364 */
365 virtual int jumpOffset() = 0;
366
Jack Palevich9eed7a22009-07-06 17:24:34 -0700367 /**
368 * Stack alignment (in bytes) for this type of data
369 */
370 virtual size_t stackAlignment(Type* type) = 0;
371
372 /**
373 * Array element alignment (in bytes) for this type of data.
374 */
375 virtual size_t sizeOf(Type* type) = 0;
376
Jack Palevich21a15a22009-05-11 14:49:29 -0700377 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700378 /*
379 * Output a byte. Handles all values, 0..ff.
380 */
381 void ob(int n) {
382 pCodeBuf->ob(n);
383 }
384
Jack Palevich8b0624c2009-05-20 12:12:06 -0700385 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700386 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700387 }
388
Jack Palevich8b0624c2009-05-20 12:12:06 -0700389 intptr_t getBase() {
390 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700391 }
392
Jack Palevich8b0624c2009-05-20 12:12:06 -0700393 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700394 return pCodeBuf->getPC();
395 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700396
397 intptr_t getSize() {
398 return pCodeBuf->getSize();
399 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700400
401 void error(const char* fmt,...) {
402 va_list ap;
403 va_start(ap, fmt);
404 mErrorSink->verror(fmt, ap);
405 va_end(ap);
406 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700407
408 void assert(bool test) {
409 if (!test) {
410 error("code generator assertion failed.");
411 }
412 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700413 private:
414 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700415 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700416 };
417
Jack Paleviche7b59062009-05-19 17:12:17 -0700418#ifdef PROVIDE_ARM_CODEGEN
419
Jack Palevich22305132009-05-13 10:58:45 -0700420 class ARMCodeGenerator : public CodeGenerator {
421 public:
422 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700423
Jack Palevich22305132009-05-13 10:58:45 -0700424 virtual ~ARMCodeGenerator() {}
425
426 /* returns address to patch with local variable size
427 */
Jack Palevich546b2242009-05-13 15:10:04 -0700428 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700429 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700430 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700431 // sp -> arg4 arg5 ...
432 // Push our register-based arguments back on the stack
433 if (argCount > 0) {
434 int regArgCount = argCount <= 4 ? argCount : 4;
435 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700436 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700437 }
438 // sp -> arg0 arg1 ...
439 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700440 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700441 // sp, fp -> oldfp, retadr, arg0 arg1 ....
442 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700443 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700444 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700445 // We don't know how many local variables we are going to use,
446 // but we will round the allocation up to a multiple of
447 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700448 }
449
Jack Palevich546b2242009-05-13 15:10:04 -0700450 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700451 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700452 // Round local variable size up to a multiple of stack alignment
453 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
454 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700455 // Patch local variable allocation code:
456 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700457 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700458 }
Jack Palevich69796b62009-05-14 15:42:26 -0700459 *(char*) (localVariableAddress) = localVariableSize;
460
461 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
462 o4(0xE1A0E00B); // mov lr, fp
463 o4(0xE59BB000); // ldr fp, [fp]
464 o4(0xE28ED004); // add sp, lr, #4
465 // sp -> retadr, arg0, ...
466 o4(0xE8BD4000); // ldmfd sp!, {lr}
467 // sp -> arg0 ....
468 if (argCount > 0) {
469 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700470 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700471 // earlier. We don't need to actually store them anywhere,
472 // just adjust the stack.
473 int regArgCount = argCount <= 4 ? argCount : 4;
474 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
475 }
476 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700477 }
478
479 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700480 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700481 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700482 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700483 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700484 } else if (t >= -256 && t < 0) {
485 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700486 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700487 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700488 o4(0xE51F0000); // ldr r0, .L3
489 o4(0xEA000000); // b .L99
490 o4(t); // .L3: .word 0
491 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700492 }
Jack Palevich22305132009-05-13 10:58:45 -0700493 }
494
495 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700496 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700497 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700498 }
499
500 /* l = 0: je, l == 1: jne */
501 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700502 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700503 o4(0xE3500000); // cmp r0,#0
504 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
505 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700506 }
507
508 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700509 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700510 o4(0xE8BD0002); // ldmfd sp!,{r1}
511 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700512 o4(0xE1510000); // cmp r1, r1
513 switch(op) {
514 case OP_EQUALS:
515 o4(0x03A00001); // moveq r0,#1
516 o4(0x13A00000); // movne r0,#0
517 break;
518 case OP_NOT_EQUALS:
519 o4(0x03A00000); // moveq r0,#0
520 o4(0x13A00001); // movne r0,#1
521 break;
522 case OP_LESS_EQUAL:
523 o4(0xD3A00001); // movle r0,#1
524 o4(0xC3A00000); // movgt r0,#0
525 break;
526 case OP_GREATER:
527 o4(0xD3A00000); // movle r0,#0
528 o4(0xC3A00001); // movgt r0,#1
529 break;
530 case OP_GREATER_EQUAL:
531 o4(0xA3A00001); // movge r0,#1
532 o4(0xB3A00000); // movlt r0,#0
533 break;
534 case OP_LESS:
535 o4(0xA3A00000); // movge r0,#0
536 o4(0xB3A00001); // movlt r0,#1
537 break;
538 default:
539 error("Unknown comparison op %d", op);
540 break;
541 }
Jack Palevich22305132009-05-13 10:58:45 -0700542 }
543
Jack Palevich546b2242009-05-13 15:10:04 -0700544 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700545 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700546 o4(0xE8BD0002); // ldmfd sp!,{r1}
547 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700548 switch(op) {
549 case OP_MUL:
550 o4(0x0E0000091); // mul r0,r1,r0
551 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700552 case OP_DIV:
553 callRuntime(runtime_DIV);
554 break;
555 case OP_MOD:
556 callRuntime(runtime_MOD);
557 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700558 case OP_PLUS:
559 o4(0xE0810000); // add r0,r1,r0
560 break;
561 case OP_MINUS:
562 o4(0xE0410000); // sub r0,r1,r0
563 break;
564 case OP_SHIFT_LEFT:
565 o4(0xE1A00011); // lsl r0,r1,r0
566 break;
567 case OP_SHIFT_RIGHT:
568 o4(0xE1A00051); // asr r0,r1,r0
569 break;
570 case OP_BIT_AND:
571 o4(0xE0010000); // and r0,r1,r0
572 break;
573 case OP_BIT_XOR:
574 o4(0xE0210000); // eor r0,r1,r0
575 break;
576 case OP_BIT_OR:
577 o4(0xE1810000); // orr r0,r1,r0
578 break;
579 case OP_BIT_NOT:
580 o4(0xE1E00000); // mvn r0, r0
581 break;
582 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700583 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700584 break;
585 }
Jack Palevich22305132009-05-13 10:58:45 -0700586 }
587
Jack Palevich9eed7a22009-07-06 17:24:34 -0700588 virtual void gUnaryCmp(int op) {
589 LOG_API("gcmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700590 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700591 o4(0xE1510000); // cmp r1, r1
592 switch(op) {
593 case OP_NOT_EQUALS:
594 o4(0x03A00000); // moveq r0,#0
595 o4(0x13A00001); // movne r0,#1
596 break;
597 default:
598 error("Unknown unary comparison op %d", op);
599 break;
600 }
601 }
602
603 virtual void genUnaryOp(int op) {
604 LOG_API("genOp(%d);\n", op);
605 switch(op) {
606 case OP_PLUS:
607 // Do nothing
608 break;
609 case OP_MINUS:
610 o4(0xE3A01000); // mov r1, #0
611 o4(0xE0410000); // sub r0,r1,r0
612 break;
613 case OP_BIT_NOT:
614 o4(0xE1E00000); // mvn r0, r0
615 break;
616 default:
617 error("Unknown unary op %d\n", op);
618 break;
619 }
Jack Palevich22305132009-05-13 10:58:45 -0700620 }
621
Jack Palevich1cdef202009-05-22 12:06:27 -0700622 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700623 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700624 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700625 mStackUse += 4;
626 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700627 }
628
Jack Palevich9eed7a22009-07-06 17:24:34 -0700629 virtual void storeR0ToTOS(Type* pPointerType) {
630 LOG_API("storeR0ToTOS(%d);\n", isInt);
631 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700632 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700633 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700634 switch (pPointerType->pHead->tag) {
635 case TY_INT:
636 o4(0xE5810000); // str r0, [r1]
637 break;
638 case TY_CHAR:
639 o4(0xE5C10000); // strb r0, [r1]
640 break;
641 default:
642 assert(false);
643 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700644 }
Jack Palevich22305132009-05-13 10:58:45 -0700645 }
646
Jack Palevich9eed7a22009-07-06 17:24:34 -0700647 virtual void loadR0FromR0(Type* pPointerType) {
648 LOG_API("loadR0FromR0(%d);\n", pPointerType);
649 assert(pPointerType->tag == TY_POINTER);
650 switch (pPointerType->pHead->tag) {
651 case TY_INT:
652 o4(0xE5900000); // ldr r0, [r0]
653 break;
654 case TY_CHAR:
655 o4(0xE5D00000); // ldrb r0, [r0]
656 break;
657 default:
658 assert(false);
659 break;
660 }
Jack Palevich22305132009-05-13 10:58:45 -0700661 }
662
Jack Palevich1cdef202009-05-22 12:06:27 -0700663 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700664 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700665 if (ea < LOCAL) {
666 // Local, fp relative
667 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
668 error("Offset out of range: %08x", ea);
669 }
670 if (ea < 0) {
671 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
672 } else {
673 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
674 }
Jack Palevichbd894902009-05-14 19:35:31 -0700675 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700676 // Global, absolute.
677 o4(0xE59F0000); // ldr r0, .L1
678 o4(0xEA000000); // b .L99
679 o4(ea); // .L1: .word 0
680 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700681 }
Jack Palevich22305132009-05-13 10:58:45 -0700682 }
683
Jack Palevich1cdef202009-05-22 12:06:27 -0700684 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700685 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700686 if (ea < LOCAL) {
687 // Local, fp relative
688 if (ea < -4095 || ea > 4095) {
689 error("Offset out of range: %08x", ea);
690 }
691 if (ea < 0) {
692 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
693 } else {
694 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
695 }
696 } else{
697 // Global, absolute
698 o4(0xE59F1000); // ldr r1, .L1
699 o4(0xEA000000); // b .L99
700 o4(ea); // .L1: .word 0
701 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700702 }
Jack Palevich22305132009-05-13 10:58:45 -0700703 }
704
Jack Palevich1cdef202009-05-22 12:06:27 -0700705 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700706 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700707 if (ea < LOCAL) {
708 // Local, fp relative
709 if (ea < -4095 || ea > 4095) {
710 error("Offset out of range: %08x", ea);
711 }
712 if (ea < 0) {
713 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
714 } else {
715 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
716 }
Jack Palevich69796b62009-05-14 15:42:26 -0700717 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700718 // Global, absolute
719 o4(0xE59F2000); // ldr r2, .L1
720 o4(0xEA000000); // b .L99
721 o4(ea); // .L1: .word ea
722 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700723 }
Jack Palevich22305132009-05-13 10:58:45 -0700724
Jack Palevich4d93f302009-05-15 13:30:00 -0700725 if (isIncDec) {
726 switch (op) {
727 case OP_INCREMENT:
728 o4(0xE2801001); // add r1, r0, #1
729 break;
730 case OP_DECREMENT:
731 o4(0xE2401001); // sub r1, r0, #1
732 break;
733 default:
734 error("unknown opcode: %d", op);
735 }
736 if (ea < LOCAL) {
737 // Local, fp relative
738 // Don't need range check, was already checked above
739 if (ea < 0) {
740 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
741 } else {
742 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
743 }
744 } else{
745 // Global, absolute
746 // r2 is already set up from before.
747 o4(0xE5821000); // str r1, [r2]
748 }
Jack Palevichbd894902009-05-14 19:35:31 -0700749 }
Jack Palevich22305132009-05-13 10:58:45 -0700750 }
751
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700752 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700753 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700754 return o4(0xE24DDF00); // Placeholder
755 }
756
Jack Palevich1cdef202009-05-22 12:06:27 -0700757 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700758 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700759 if (l < 0 || l > 4096-4) {
760 error("l out of range for stack offset: 0x%08x", l);
761 }
762 o4(0xE58D0000 + l); // str r0, [sp, #4]
763 }
764
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700765 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700766 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700767 int argCount = l >> 2;
768 int argumentStackUse = l;
769 if (argCount > 0) {
770 int regArgCount = argCount > 4 ? 4 : argCount;
771 argumentStackUse -= regArgCount * 4;
772 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
773 }
774 mStackUse += argumentStackUse;
775
776 // Align stack.
777 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
778 * STACK_ALIGNMENT);
779 mStackAlignmentAdjustment = 0;
780 if (missalignment > 0) {
781 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
782 }
783 l += mStackAlignmentAdjustment;
784
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700785 if (l < 0 || l > 0x3FC) {
786 error("L out of range for stack adjustment: 0x%08x", l);
787 }
788 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700789 mStackUse += mStackAlignmentAdjustment;
790 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
791 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700792 }
793
Jack Palevich22305132009-05-13 10:58:45 -0700794 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700795 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700796 // Forward calls are always short (local)
797 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700798 }
799
800 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700801 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700802 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700803 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700804 if (t >= - (1 << 25) && t < (1 << 25)) {
805 o4(0xEB000000 | encodeAddress(t));
806 } else {
807 // Long call.
808 o4(0xE59FC000); // ldr r12, .L1
809 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700810 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700811 o4(0xE08CC00F); // .L99: add r12,pc
812 o4(0xE12FFF3C); // blx r12
813 }
Jack Palevich22305132009-05-13 10:58:45 -0700814 }
815
816 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700817 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700818 int argCount = l >> 2;
819 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700820 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700821 if (adjustedL < 0 || adjustedL > 4096-4) {
822 error("l out of range for stack offset: 0x%08x", l);
823 }
824 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
825 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700826 }
827
Jack Palevich7810bc92009-05-15 14:31:47 -0700828 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700829 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700830 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700831 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700832 int stackUse = stackArgs + (isIndirect ? 1 : 0)
833 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700834 if (stackUse) {
835 if (stackUse < 0 || stackUse > 255) {
836 error("L out of range for stack adjustment: 0x%08x", l);
837 }
838 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -0700839 mStackUse -= stackUse * 4;
840 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700841 }
Jack Palevich22305132009-05-13 10:58:45 -0700842 }
843
Jack Palevicha6535612009-05-13 16:24:17 -0700844 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700845 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700846 }
847
848 /* output a symbol and patch all calls to it */
849 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700850 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700851 int n;
852 int base = getBase();
853 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700854 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700855 while (t) {
856 int data = * (int*) t;
857 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
858 if (decodedOffset == 0) {
859 n = 0;
860 } else {
861 n = base + decodedOffset; /* next value */
862 }
863 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
864 | encodeRelAddress(pc - t - 8);
865 t = n;
866 }
867 }
868
Jack Palevich1cdef202009-05-22 12:06:27 -0700869 virtual int finishCompile() {
870#if defined(__arm__)
871 const long base = long(getBase());
872 const long curr = long(getPC());
873 int err = cacheflush(base, curr, 0);
874 return err;
875#else
876 return 0;
877#endif
878 }
879
Jack Palevicha6535612009-05-13 16:24:17 -0700880 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700881#ifdef ENABLE_ARM_DISASSEMBLY
882 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700883 disasm_interface_t di;
884 di.di_readword = disassemble_readword;
885 di.di_printaddr = disassemble_printaddr;
886 di.di_printf = disassemble_printf;
887
888 int base = getBase();
889 int pc = getPC();
890 for(int i = base; i < pc; i += 4) {
891 fprintf(out, "%08x: %08x ", i, *(int*) i);
892 ::disasm(&di, i, 0);
893 }
Jack Palevich09555c72009-05-27 12:25:55 -0700894#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700895 return 0;
896 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700897
Jack Palevich9eed7a22009-07-06 17:24:34 -0700898 /**
899 * Stack alignment (in bytes) for this type of data
900 */
901 virtual size_t stackAlignment(Type* pType){
902 switch(pType->tag) {
903 case TY_DOUBLE:
904 return 8;
905 default:
906 return 4;
907 }
908 }
909
910 /**
911 * Array element alignment (in bytes) for this type of data.
912 */
913 virtual size_t sizeOf(Type* pType){
914 switch(pType->tag) {
915 case TY_INT:
916 return 4;
917 case TY_CHAR:
918 return 1;
919 default:
920 return 0;
921 case TY_FLOAT:
922 return 4;
923 case TY_DOUBLE:
924 return 8;
925 case TY_POINTER:
926 return 4;
927 }
928 }
Jack Palevich22305132009-05-13 10:58:45 -0700929 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700930 static FILE* disasmOut;
931
932 static u_int
933 disassemble_readword(u_int address)
934 {
935 return(*((u_int *)address));
936 }
937
938 static void
939 disassemble_printaddr(u_int address)
940 {
941 fprintf(disasmOut, "0x%08x", address);
942 }
943
944 static void
945 disassemble_printf(const char *fmt, ...) {
946 va_list ap;
947 va_start(ap, fmt);
948 vfprintf(disasmOut, fmt, ap);
949 va_end(ap);
950 }
951
952 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
953
954 /** Encode a relative address that might also be
955 * a label.
956 */
957 int encodeAddress(int value) {
958 int base = getBase();
959 if (value >= base && value <= getPC() ) {
960 // This is a label, encode it relative to the base.
961 value = value - base;
962 }
963 return encodeRelAddress(value);
964 }
965
966 int encodeRelAddress(int value) {
967 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
968 }
Jack Palevich22305132009-05-13 10:58:45 -0700969
Jack Palevich3d474a72009-05-15 15:12:38 -0700970 typedef int (*int2FnPtr)(int a, int b);
971 void callRuntime(int2FnPtr fn) {
972 o4(0xE59F2000); // ldr r2, .L1
973 o4(0xEA000000); // b .L99
974 o4((int) fn); //.L1: .word fn
975 o4(0xE12FFF32); //.L99: blx r2
976 }
977
978 static int runtime_DIV(int a, int b) {
979 return b / a;
980 }
981
982 static int runtime_MOD(int a, int b) {
983 return b % a;
984 }
-b master422972c2009-06-17 19:13:52 -0700985
986 static const int STACK_ALIGNMENT = 8;
987 int mStackUse;
988 // This variable holds the amount we adjusted the stack in the most
989 // recent endFunctionCallArguments call. It's examined by the
990 // following adjustStackAfterCall call.
991 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -0700992 };
993
Jack Palevich09555c72009-05-27 12:25:55 -0700994#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700995
996#ifdef PROVIDE_X86_CODEGEN
997
Jack Palevich21a15a22009-05-11 14:49:29 -0700998 class X86CodeGenerator : public CodeGenerator {
999 public:
1000 X86CodeGenerator() {}
1001 virtual ~X86CodeGenerator() {}
1002
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001003 /* returns address to patch with local variable size
1004 */
Jack Palevich546b2242009-05-13 15:10:04 -07001005 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001006 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1007 return oad(0xec81, 0); /* sub $xxx, %esp */
1008 }
1009
Jack Palevich546b2242009-05-13 15:10:04 -07001010 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001011 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001012 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001013 }
1014
Jack Palevich21a15a22009-05-11 14:49:29 -07001015 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -07001016 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001017 oad(0xb8, t); /* mov $xx, %eax */
1018 }
1019
Jack Palevich22305132009-05-13 10:58:45 -07001020 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001021 return psym(0xe9, t);
1022 }
1023
1024 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001025 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001026 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1027 return psym(0x84 + l, t);
1028 }
1029
Jack Palevich22305132009-05-13 10:58:45 -07001030 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001031 int t = decodeOp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001032 o(0x59); /* pop %ecx */
Jack Palevich21a15a22009-05-11 14:49:29 -07001033 o(0xc139); /* cmp %eax,%ecx */
1034 li(0);
1035 o(0x0f); /* setxx %al */
1036 o(t + 0x90);
1037 o(0xc0);
1038 }
1039
Jack Palevich546b2242009-05-13 15:10:04 -07001040 virtual void genOp(int op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07001041 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001042 o(decodeOp(op));
1043 if (op == OP_MOD)
1044 o(0x92); /* xchg %edx, %eax */
1045 }
1046
Jack Palevich9eed7a22009-07-06 17:24:34 -07001047 virtual void gUnaryCmp(int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001048 oad(0xb9, 0); /* movl $0, %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001049 int t = decodeOp(op);
1050 o(0xc139); /* cmp %eax,%ecx */
1051 li(0);
1052 o(0x0f); /* setxx %al */
1053 o(t + 0x90);
1054 o(0xc0);
1055 }
1056
1057 virtual void genUnaryOp(int op) {
1058 oad(0xb9, 0); /* movl $0, %ecx */
1059 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -07001060 }
1061
Jack Palevich1cdef202009-05-22 12:06:27 -07001062 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001063 o(0x50); /* push %eax */
1064 }
1065
Jack Palevich9eed7a22009-07-06 17:24:34 -07001066 virtual void storeR0ToTOS(Type* pPointerType) {
1067 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001068 o(0x59); /* pop %ecx */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001069 switch (pPointerType->pHead->tag) {
1070 case TY_INT:
1071 o(0x0189); /* movl %eax/%al, (%ecx) */
1072 break;
1073 case TY_CHAR:
1074 o(0x0188); /* movl %eax/%al, (%ecx) */
1075 break;
1076 default:
1077 assert(false);
1078 break;
1079 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001080 }
1081
Jack Palevich9eed7a22009-07-06 17:24:34 -07001082 virtual void loadR0FromR0(Type* pPointerType) {
1083 assert(pPointerType->tag == TY_POINTER);
1084 switch (pPointerType->pHead->tag) {
1085 case TY_INT:
1086 o(0x8b); /* mov (%eax), %eax */
1087 break;
1088 case TY_CHAR:
1089 o(0xbe0f); /* movsbl (%eax), %eax */
1090 break;
1091 default:
1092 assert(false);
1093 break;
1094 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001095 ob(0); /* add zero in code */
1096 }
1097
Jack Palevich1cdef202009-05-22 12:06:27 -07001098 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001099 gmov(10, ea); /* leal EA, %eax */
1100 }
1101
Jack Palevich1cdef202009-05-22 12:06:27 -07001102 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001103 gmov(6, ea); /* mov %eax, EA */
1104 }
1105
Jack Palevich1cdef202009-05-22 12:06:27 -07001106 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001107 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -07001108 if (isIncDec) {
1109 /* Implement post-increment or post decrement.
1110 */
1111 gmov(0, ea); /* 83 ADD */
1112 o(decodeOp(op));
1113 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001114 }
1115
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001116 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001117 return oad(0xec81, 0); /* sub $xxx, %esp */
1118 }
1119
Jack Palevich1cdef202009-05-22 12:06:27 -07001120 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001121 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1122 }
1123
Jack Palevich7810bc92009-05-15 14:31:47 -07001124 virtual void endFunctionCallArguments(int a, int l) {
1125 * (int*) a = l;
1126 }
1127
Jack Palevich22305132009-05-13 10:58:45 -07001128 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001129 return psym(0xe8, symbol); /* call xxx */
1130 }
1131
Jack Palevich22305132009-05-13 10:58:45 -07001132 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001133 psym(0xe8, t); /* call xxx */
1134 }
1135
Jack Palevich22305132009-05-13 10:58:45 -07001136 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001137 oad(0x2494ff, l); /* call *xxx(%esp) */
1138 }
1139
Jack Palevich7810bc92009-05-15 14:31:47 -07001140 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1141 if (isIndirect) {
1142 l += 4;
1143 }
-b master422972c2009-06-17 19:13:52 -07001144 if (l > 0) {
1145 oad(0xc481, l); /* add $xxx, %esp */
1146 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001147 }
1148
Jack Palevicha6535612009-05-13 16:24:17 -07001149 virtual int jumpOffset() {
1150 return 5;
1151 }
1152
1153 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001154 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001155 }
1156
Jack Paleviche7b59062009-05-19 17:12:17 -07001157 /* output a symbol and patch all calls to it */
1158 virtual void gsym(int t) {
1159 int n;
1160 int pc = getPC();
1161 while (t) {
1162 n = *(int *) t; /* next value */
1163 *(int *) t = pc - t - 4;
1164 t = n;
1165 }
1166 }
1167
Jack Palevich1cdef202009-05-22 12:06:27 -07001168 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001169 size_t pagesize = 4096;
1170 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1171 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1172 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1173 if (err) {
1174 error("mprotect() failed: %d", errno);
1175 }
1176 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001177 }
1178
Jack Palevich9eed7a22009-07-06 17:24:34 -07001179 /**
1180 * Stack alignment (in bytes) for this type of data
1181 */
1182 virtual size_t stackAlignment(Type* pType){
1183 switch(pType->tag) {
1184 case TY_DOUBLE:
1185 return 8;
1186 default:
1187 return 4;
1188 }
1189 }
1190
1191 /**
1192 * Array element alignment (in bytes) for this type of data.
1193 */
1194 virtual size_t sizeOf(Type* pType){
1195 switch(pType->tag) {
1196 case TY_INT:
1197 return 4;
1198 case TY_CHAR:
1199 return 1;
1200 default:
1201 return 0;
1202 case TY_FLOAT:
1203 return 4;
1204 case TY_DOUBLE:
1205 return 8;
1206 case TY_POINTER:
1207 return 4;
1208 }
1209 }
1210
Jack Palevich21a15a22009-05-11 14:49:29 -07001211 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001212
1213 /** Output 1 to 4 bytes.
1214 *
1215 */
1216 void o(int n) {
1217 /* cannot use unsigned, so we must do a hack */
1218 while (n && n != -1) {
1219 ob(n & 0xff);
1220 n = n >> 8;
1221 }
1222 }
1223
1224 /* psym is used to put an instruction with a data field which is a
1225 reference to a symbol. It is in fact the same as oad ! */
1226 int psym(int n, int t) {
1227 return oad(n, t);
1228 }
1229
1230 /* instruction + address */
1231 int oad(int n, int t) {
1232 o(n);
1233 int result = getPC();
1234 o4(t);
1235 return result;
1236 }
1237
1238
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001239 static const int operatorHelper[];
1240
1241 int decodeOp(int op) {
1242 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001243 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001244 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001245 }
1246 return operatorHelper[op];
1247 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001248
Jack Palevich546b2242009-05-13 15:10:04 -07001249 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001250 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001251 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001252 }
1253 };
1254
Jack Paleviche7b59062009-05-19 17:12:17 -07001255#endif // PROVIDE_X86_CODEGEN
1256
Jack Palevichb67b18f2009-06-11 21:12:23 -07001257#ifdef PROVIDE_TRACE_CODEGEN
1258 class TraceCodeGenerator : public CodeGenerator {
1259 private:
1260 CodeGenerator* mpBase;
1261
1262 public:
1263 TraceCodeGenerator(CodeGenerator* pBase) {
1264 mpBase = pBase;
1265 }
1266
1267 virtual ~TraceCodeGenerator() {
1268 delete mpBase;
1269 }
1270
1271 virtual void init(CodeBuf* pCodeBuf) {
1272 mpBase->init(pCodeBuf);
1273 }
1274
1275 void setErrorSink(ErrorSink* pErrorSink) {
1276 mpBase->setErrorSink(pErrorSink);
1277 }
1278
1279 /* returns address to patch with local variable size
1280 */
1281 virtual int functionEntry(int argCount) {
1282 int result = mpBase->functionEntry(argCount);
1283 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1284 return result;
1285 }
1286
1287 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1288 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1289 argCount, localVariableAddress, localVariableSize);
1290 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1291 }
1292
1293 /* load immediate value */
1294 virtual void li(int t) {
1295 fprintf(stderr, "li(%d)\n", t);
1296 mpBase->li(t);
1297 }
1298
1299 virtual int gjmp(int t) {
1300 int result = mpBase->gjmp(t);
1301 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1302 return result;
1303 }
1304
1305 /* l = 0: je, l == 1: jne */
1306 virtual int gtst(bool l, int t) {
1307 int result = mpBase->gtst(l, t);
1308 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1309 return result;
1310 }
1311
1312 virtual void gcmp(int op) {
1313 fprintf(stderr, "gcmp(%d)\n", op);
1314 mpBase->gcmp(op);
1315 }
1316
1317 virtual void genOp(int op) {
1318 fprintf(stderr, "genOp(%d)\n", op);
1319 mpBase->genOp(op);
1320 }
1321
Jack Palevich9eed7a22009-07-06 17:24:34 -07001322
1323 virtual void gUnaryCmp(int op) {
1324 fprintf(stderr, "gUnaryCmp(%d)\n", op);
1325 mpBase->gUnaryCmp(op);
1326 }
1327
1328 virtual void genUnaryOp(int op) {
1329 fprintf(stderr, "genUnaryOp(%d)\n", op);
1330 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001331 }
1332
1333 virtual void pushR0() {
1334 fprintf(stderr, "pushR0()\n");
1335 mpBase->pushR0();
1336 }
1337
Jack Palevich9eed7a22009-07-06 17:24:34 -07001338 virtual void storeR0ToTOS(Type* pPointerType) {
1339 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType);
1340 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001341 }
1342
Jack Palevich9eed7a22009-07-06 17:24:34 -07001343 virtual void loadR0FromR0(Type* pPointerType) {
1344 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType);
1345 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001346 }
1347
1348 virtual void leaR0(int ea) {
1349 fprintf(stderr, "leaR0(%d)\n", ea);
1350 mpBase->leaR0(ea);
1351 }
1352
1353 virtual void storeR0(int ea) {
1354 fprintf(stderr, "storeR0(%d)\n", ea);
1355 mpBase->storeR0(ea);
1356 }
1357
1358 virtual void loadR0(int ea, bool isIncDec, int op) {
1359 fprintf(stderr, "loadR0(%d, %d, %d)\n", ea, isIncDec, op);
1360 mpBase->loadR0(ea, isIncDec, op);
1361 }
1362
1363 virtual int beginFunctionCallArguments() {
1364 int result = mpBase->beginFunctionCallArguments();
1365 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1366 return result;
1367 }
1368
1369 virtual void storeR0ToArg(int l) {
1370 fprintf(stderr, "storeR0ToArg(%d)\n", l);
1371 mpBase->storeR0ToArg(l);
1372 }
1373
1374 virtual void endFunctionCallArguments(int a, int l) {
1375 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1376 mpBase->endFunctionCallArguments(a, l);
1377 }
1378
1379 virtual int callForward(int symbol) {
1380 int result = mpBase->callForward(symbol);
1381 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1382 return result;
1383 }
1384
1385 virtual void callRelative(int t) {
1386 fprintf(stderr, "callRelative(%d)\n", t);
1387 mpBase->callRelative(t);
1388 }
1389
1390 virtual void callIndirect(int l) {
1391 fprintf(stderr, "callIndirect(%d)\n", l);
1392 mpBase->callIndirect(l);
1393 }
1394
1395 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1396 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1397 mpBase->adjustStackAfterCall(l, isIndirect);
1398 }
1399
1400 virtual int jumpOffset() {
1401 return mpBase->jumpOffset();
1402 }
1403
1404 virtual int disassemble(FILE* out) {
1405 return mpBase->disassemble(out);
1406 }
1407
1408 /* output a symbol and patch all calls to it */
1409 virtual void gsym(int t) {
1410 fprintf(stderr, "gsym(%d)\n", t);
1411 mpBase->gsym(t);
1412 }
1413
1414 virtual int finishCompile() {
1415 int result = mpBase->finishCompile();
1416 fprintf(stderr, "finishCompile() = %d\n", result);
1417 return result;
1418 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001419
1420 /**
1421 * Stack alignment (in bytes) for this type of data
1422 */
1423 virtual size_t stackAlignment(Type* pType){
1424 return mpBase->stackAlignment(pType);
1425 }
1426
1427 /**
1428 * Array element alignment (in bytes) for this type of data.
1429 */
1430 virtual size_t sizeOf(Type* pType){
1431 return mpBase->sizeOf(pType);
1432 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001433 };
1434
1435#endif // PROVIDE_TRACE_CODEGEN
1436
Jack Palevich569f1352009-06-29 14:29:08 -07001437
1438 // Subset of STL vector.
1439 template<class E> class Vector {
1440 public:
1441 Vector() {
1442 mpBase = 0;
1443 mUsed = 0;
1444 mSize = 0;
1445 }
1446
1447 ~Vector() {
1448 if (mpBase) {
1449 for(size_t i = 0; i < mUsed; i++) {
1450 mpBase[mUsed].~E();
1451 }
1452 free(mpBase);
1453 }
1454 }
1455
1456 inline E& operator[](size_t i) {
1457 return mpBase[i];
1458 }
1459
1460 inline E& front() {
1461 return mpBase[0];
1462 }
1463
1464 inline E& back() {
1465 return mpBase[mUsed - 1];
1466 }
1467
1468 void pop_back() {
1469 mUsed -= 1;
1470 mpBase[mUsed].~E();
1471 }
1472
1473 void push_back(const E& item) {
1474 * ensure(1) = item;
1475 }
1476
1477 size_t size() {
1478 return mUsed;
1479 }
1480
1481 private:
1482 E* ensure(int n) {
1483 size_t newUsed = mUsed + n;
1484 if (newUsed > mSize) {
1485 size_t newSize = mSize * 2 + 10;
1486 if (newSize < newUsed) {
1487 newSize = newUsed;
1488 }
1489 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1490 mSize = newSize;
1491 }
1492 E* result = mpBase + mUsed;
1493 mUsed = newUsed;
1494 return result;
1495 }
1496
1497 E* mpBase;
1498 size_t mUsed;
1499 size_t mSize;
1500 };
1501
1502 class Arena {
1503 public:
1504 // Used to record a given allocation amount.
1505 // Used:
1506 // Mark mark = arena.mark();
1507 // ... lots of arena.allocate()
1508 // arena.free(mark);
1509
1510 struct Mark {
1511 size_t chunk;
1512 size_t offset;
1513 };
1514
1515 Arena() {
1516 mCurrentChunk = 0;
1517 Chunk start(CHUNK_SIZE);
1518 mData.push_back(start);
1519 }
1520
1521 ~Arena() {
1522 for(size_t i = 0; i < mData.size(); i++) {
1523 mData[i].free();
1524 }
1525 }
1526
1527 // Alloc using the standard alignment size safe for any variable
1528 void* alloc(size_t size) {
1529 return alloc(size, 8);
1530 }
1531
1532 Mark mark(){
1533 Mark result;
1534 result.chunk = mCurrentChunk;
1535 result.offset = mData[mCurrentChunk].mOffset;
1536 return result;
1537 }
1538
1539 void freeToMark(const Mark& mark) {
1540 mCurrentChunk = mark.chunk;
1541 mData[mCurrentChunk].mOffset = mark.offset;
1542 }
1543
1544 private:
1545 // Allocate memory aligned to a given size
1546 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1547 // Memory is not zero filled.
1548
1549 void* alloc(size_t size, size_t alignment) {
1550 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1551 if (mCurrentChunk + 1 < mData.size()) {
1552 mCurrentChunk++;
1553 } else {
1554 size_t allocSize = CHUNK_SIZE;
1555 if (allocSize < size + alignment - 1) {
1556 allocSize = size + alignment - 1;
1557 }
1558 Chunk chunk(allocSize);
1559 mData.push_back(chunk);
1560 mCurrentChunk++;
1561 }
1562 }
1563 return mData[mCurrentChunk].allocate(size, alignment);
1564 }
1565
1566 static const size_t CHUNK_SIZE = 128*1024;
1567 // Note: this class does not deallocate its
1568 // memory when it's destroyed. It depends upon
1569 // its parent to deallocate the memory.
1570 struct Chunk {
1571 Chunk() {
1572 mpData = 0;
1573 mSize = 0;
1574 mOffset = 0;
1575 }
1576
1577 Chunk(size_t size) {
1578 mSize = size;
1579 mpData = (char*) malloc(size);
1580 mOffset = 0;
1581 }
1582
1583 ~Chunk() {
1584 // Doesn't deallocate memory.
1585 }
1586
1587 void* allocate(size_t size, size_t alignment) {
1588 size_t alignedOffset = aligned(mOffset, alignment);
1589 void* result = mpData + alignedOffset;
1590 mOffset = alignedOffset + size;
1591 return result;
1592 }
1593
1594 void free() {
1595 if (mpData) {
1596 ::free(mpData);
1597 mpData = 0;
1598 }
1599 }
1600
1601 size_t remainingCapacity(size_t alignment) {
1602 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1603 }
1604
1605 // Assume alignment is a power of two
1606 inline size_t aligned(size_t v, size_t alignment) {
1607 size_t mask = alignment-1;
1608 return (v + mask) & ~mask;
1609 }
1610
1611 char* mpData;
1612 size_t mSize;
1613 size_t mOffset;
1614 };
1615
1616 size_t mCurrentChunk;
1617
1618 Vector<Chunk> mData;
1619 };
1620
1621 typedef int tokenid_t;
1622 struct VariableInfo;
1623
1624 struct Token {
1625 int hash;
1626 size_t length;
1627 char* pText;
1628 tokenid_t id;
1629
1630 // Current values for the token
1631 char* mpMacroDefinition;
1632 VariableInfo* mpVariableInfo;
1633 };
1634
1635 class TokenTable {
1636 public:
1637 // Don't use 0..0xff, allows characters and operators to be tokens too.
1638
1639 static const int TOKEN_BASE = 0x100;
1640 TokenTable() {
1641 mpMap = hashmapCreate(128, hashFn, equalsFn);
1642 }
1643
1644 ~TokenTable() {
1645 hashmapFree(mpMap);
1646 }
1647
1648 void setArena(Arena* pArena) {
1649 mpArena = pArena;
1650 }
1651
1652 // Returns a token for a given string of characters.
1653 tokenid_t intern(const char* pText, size_t length) {
1654 Token probe;
1655 int hash = hashmapHash((void*) pText, length);
1656 {
1657 Token probe;
1658 probe.hash = hash;
1659 probe.length = length;
1660 probe.pText = (char*) pText;
1661 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1662 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07001663 return pValue->id;
1664 }
1665 }
1666
1667 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1668 memset(pToken, 0, sizeof(*pToken));
1669 pToken->hash = hash;
1670 pToken->length = length;
1671 pToken->pText = (char*) mpArena->alloc(length + 1);
1672 memcpy(pToken->pText, pText, length);
1673 pToken->pText[length] = 0;
1674 pToken->id = mTokens.size() + TOKEN_BASE;
1675 mTokens.push_back(pToken);
1676 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07001677 return pToken->id;
1678 }
1679
1680 // Return the Token for a given tokenid.
1681 Token& operator[](tokenid_t id) {
1682 return *mTokens[id - TOKEN_BASE];
1683 }
1684
1685 inline size_t size() {
1686 return mTokens.size();
1687 }
1688
1689 private:
1690
1691 static int hashFn(void* pKey) {
1692 Token* pToken = (Token*) pKey;
1693 return pToken->hash;
1694 }
1695
1696 static bool equalsFn(void* keyA, void* keyB) {
1697 Token* pTokenA = (Token*) keyA;
1698 Token* pTokenB = (Token*) keyB;
1699 // Don't need to compare hash values, they should always be equal
1700 return pTokenA->length == pTokenB->length
1701 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1702 }
1703
1704 Hashmap* mpMap;
1705 Vector<Token*> mTokens;
1706 Arena* mpArena;
1707 };
1708
Jack Palevich1cdef202009-05-22 12:06:27 -07001709 class InputStream {
1710 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001711 int getChar() {
1712 if (bumpLine) {
1713 line++;
1714 bumpLine = false;
1715 }
1716 int ch = get();
1717 if (ch == '\n') {
1718 bumpLine = true;
1719 }
1720 return ch;
1721 }
1722 int getLine() {
1723 return line;
1724 }
1725 protected:
1726 InputStream() :
1727 line(1), bumpLine(false) {
1728 }
1729 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001730 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001731 int line;
1732 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001733 };
1734
1735 class FileInputStream : public InputStream {
1736 public:
1737 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001738 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001739 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001740 FILE* f;
1741 };
1742
1743 class TextInputStream : public InputStream {
1744 public:
1745 TextInputStream(const char* text, size_t textLength)
1746 : pText(text), mTextLength(textLength), mPosition(0) {
1747 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001748
1749 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001750 virtual int get() {
1751 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1752 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001753
Jack Palevich1cdef202009-05-22 12:06:27 -07001754 const char* pText;
1755 size_t mTextLength;
1756 size_t mPosition;
1757 };
1758
Jack Palevicheedf9d22009-06-04 16:23:40 -07001759 class String {
1760 public:
1761 String() {
1762 mpBase = 0;
1763 mUsed = 0;
1764 mSize = 0;
1765 }
1766
Jack Palevich303d8ff2009-06-11 19:06:24 -07001767 String(const char* item, int len, bool adopt) {
1768 if (len < 0) {
1769 len = strlen(item);
1770 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001771 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001772 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001773 mUsed = len;
1774 mSize = len + 1;
1775 } else {
1776 mpBase = 0;
1777 mUsed = 0;
1778 mSize = 0;
1779 appendBytes(item, len);
1780 }
1781 }
1782
Jack Palevich303d8ff2009-06-11 19:06:24 -07001783 String(const String& other) {
1784 mpBase = 0;
1785 mUsed = 0;
1786 mSize = 0;
1787 appendBytes(other.getUnwrapped(), other.len());
1788 }
1789
Jack Palevicheedf9d22009-06-04 16:23:40 -07001790 ~String() {
1791 if (mpBase) {
1792 free(mpBase);
1793 }
1794 }
1795
Jack Palevicha6baa232009-06-12 11:25:59 -07001796 String& operator=(const String& other) {
1797 clear();
1798 appendBytes(other.getUnwrapped(), other.len());
1799 return *this;
1800 }
1801
Jack Palevich303d8ff2009-06-11 19:06:24 -07001802 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001803 return mpBase;
1804 }
1805
Jack Palevich303d8ff2009-06-11 19:06:24 -07001806 void clear() {
1807 mUsed = 0;
1808 if (mSize > 0) {
1809 mpBase[0] = 0;
1810 }
1811 }
1812
Jack Palevicheedf9d22009-06-04 16:23:40 -07001813 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001814 appendBytes(s, strlen(s));
1815 }
1816
1817 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001818 memcpy(ensure(n), s, n + 1);
1819 }
1820
1821 void append(char c) {
1822 * ensure(1) = c;
1823 }
1824
Jack Palevich86351982009-06-30 18:09:56 -07001825 void append(String& other) {
1826 appendBytes(other.getUnwrapped(), other.len());
1827 }
1828
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001829 char* orphan() {
1830 char* result = mpBase;
1831 mpBase = 0;
1832 mUsed = 0;
1833 mSize = 0;
1834 return result;
1835 }
1836
Jack Palevicheedf9d22009-06-04 16:23:40 -07001837 void printf(const char* fmt,...) {
1838 va_list ap;
1839 va_start(ap, fmt);
1840 vprintf(fmt, ap);
1841 va_end(ap);
1842 }
1843
1844 void vprintf(const char* fmt, va_list ap) {
1845 char* temp;
1846 int numChars = vasprintf(&temp, fmt, ap);
1847 memcpy(ensure(numChars), temp, numChars+1);
1848 free(temp);
1849 }
1850
Jack Palevich303d8ff2009-06-11 19:06:24 -07001851 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001852 return mUsed;
1853 }
1854
1855 private:
1856 char* ensure(int n) {
1857 size_t newUsed = mUsed + n;
1858 if (newUsed > mSize) {
1859 size_t newSize = mSize * 2 + 10;
1860 if (newSize < newUsed) {
1861 newSize = newUsed;
1862 }
1863 mpBase = (char*) realloc(mpBase, newSize + 1);
1864 mSize = newSize;
1865 }
1866 mpBase[newUsed] = '\0';
1867 char* result = mpBase + mUsed;
1868 mUsed = newUsed;
1869 return result;
1870 }
1871
1872 char* mpBase;
1873 size_t mUsed;
1874 size_t mSize;
1875 };
1876
Jack Palevich569f1352009-06-29 14:29:08 -07001877 void internKeywords() {
1878 // Note: order has to match TOK_ constants
1879 static const char* keywords[] = {
1880 "int",
1881 "char",
1882 "void",
1883 "if",
1884 "else",
1885 "while",
1886 "break",
1887 "return",
1888 "for",
1889 "pragma",
1890 "define",
1891 "auto",
1892 "case",
1893 "const",
1894 "continue",
1895 "default",
1896 "do",
1897 "double",
1898 "enum",
1899 "extern",
1900 "float",
1901 "goto",
1902 "long",
1903 "register",
1904 "short",
1905 "signed",
1906 "sizeof",
1907 "static",
1908 "struct",
1909 "switch",
1910 "typedef",
1911 "union",
1912 "unsigned",
1913 "volatile",
1914 "_Bool",
1915 "_Complex",
1916 "_Imaginary",
1917 "inline",
1918 "restrict",
1919 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001920
Jack Palevich569f1352009-06-29 14:29:08 -07001921 for(int i = 0; keywords[i]; i++) {
1922 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001923 }
Jack Palevich569f1352009-06-29 14:29:08 -07001924 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001925
Jack Palevich36d94142009-06-08 15:55:32 -07001926 struct InputState {
1927 InputStream* pStream;
1928 int oldCh;
1929 };
1930
Jack Palevich2db168f2009-06-11 14:29:47 -07001931 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001932 void* pAddress;
1933 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07001934 tokenid_t tok;
1935 size_t level;
1936 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07001937 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07001938 };
1939
Jack Palevich303d8ff2009-06-11 19:06:24 -07001940 class SymbolStack {
1941 public:
1942 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07001943 mpArena = 0;
1944 mpTokenTable = 0;
1945 }
1946
1947 void setArena(Arena* pArena) {
1948 mpArena = pArena;
1949 }
1950
1951 void setTokenTable(TokenTable* pTokenTable) {
1952 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001953 }
1954
1955 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07001956 Mark mark;
1957 mark.mArenaMark = mpArena->mark();
1958 mark.mSymbolHead = mStack.size();
1959 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07001960 }
1961
1962 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07001963 // Undo any shadowing that was done:
1964 Mark mark = mLevelStack.back();
1965 mLevelStack.pop_back();
1966 while (mStack.size() > mark.mSymbolHead) {
1967 VariableInfo* pV = mStack.back();
1968 mStack.pop_back();
1969 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001970 }
Jack Palevich569f1352009-06-29 14:29:08 -07001971 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07001972 }
1973
Jack Palevich569f1352009-06-29 14:29:08 -07001974 bool isDefinedAtCurrentLevel(tokenid_t tok) {
1975 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
1976 return pV && pV->level == level();
1977 }
1978
1979 VariableInfo* add(tokenid_t tok) {
1980 Token& token = (*mpTokenTable)[tok];
1981 VariableInfo* pOldV = token.mpVariableInfo;
1982 VariableInfo* pNewV =
1983 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
1984 memset(pNewV, 0, sizeof(VariableInfo));
1985 pNewV->tok = tok;
1986 pNewV->level = level();
1987 pNewV->pOldDefinition = pOldV;
1988 token.mpVariableInfo = pNewV;
1989 mStack.push_back(pNewV);
1990 return pNewV;
1991 }
1992
Jack Palevich86351982009-06-30 18:09:56 -07001993 VariableInfo* add(Type* pType) {
1994 VariableInfo* pVI = add(pType->id);
1995 pVI->pType = pType;
1996 return pVI;
1997 }
1998
Jack Palevich569f1352009-06-29 14:29:08 -07001999 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2000 for (size_t i = 0; i < mStack.size(); i++) {
2001 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002002 break;
2003 }
2004 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002005 }
2006
Jack Palevich303d8ff2009-06-11 19:06:24 -07002007 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002008 inline size_t level() {
2009 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002010 }
2011
Jack Palevich569f1352009-06-29 14:29:08 -07002012 struct Mark {
2013 Arena::Mark mArenaMark;
2014 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002015 };
2016
Jack Palevich569f1352009-06-29 14:29:08 -07002017 Arena* mpArena;
2018 TokenTable* mpTokenTable;
2019 Vector<VariableInfo*> mStack;
2020 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002021 };
Jack Palevich36d94142009-06-08 15:55:32 -07002022
2023 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002024 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002025 intptr_t tokc; // token extra info
2026 int tokl; // token operator level
2027 intptr_t rsym; // return symbol
2028 intptr_t loc; // local variable index
2029 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002030 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002031 char* dptr; // Macro state: Points to macro text during macro playback.
2032 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002033 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002034
2035 // Arena for the duration of the compile
2036 Arena mGlobalArena;
2037 // Arena for data that's only needed when compiling a single function
2038 Arena mLocalArena;
2039
2040 TokenTable mTokenTable;
2041 SymbolStack mGlobals;
2042 SymbolStack mLocals;
2043
Jack Palevich40600de2009-07-01 15:32:35 -07002044 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002045 Type* mkpInt; // int
2046 Type* mkpChar; // char
2047 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002048 Type* mkpFloat;
2049 Type* mkpDouble;
Jack Palevich3f226492009-07-02 14:46:19 -07002050 Type* mkpIntPtr;
2051 Type* mkpCharPtr;
2052 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002053
Jack Palevich36d94142009-06-08 15:55:32 -07002054 InputStream* file;
2055
2056 CodeBuf codeBuf;
2057 CodeGenerator* pGen;
2058
Jack Palevicheedf9d22009-06-04 16:23:40 -07002059 String mErrorBuf;
2060
Jack Palevicheedf9d22009-06-04 16:23:40 -07002061 String mPragmas;
2062 int mPragmaStringCount;
2063
Jack Palevich21a15a22009-05-11 14:49:29 -07002064 static const int ALLOC_SIZE = 99999;
2065
Jack Palevich303d8ff2009-06-11 19:06:24 -07002066 static const int TOK_DUMMY = 1;
2067 static const int TOK_NUM = 2;
2068
2069 // 3..255 are character and/or operators
2070
Jack Palevich2db168f2009-06-11 14:29:47 -07002071 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002072 // Order has to match string list in "internKeywords".
2073 enum {
2074 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2075 TOK_INT = TOK_KEYWORD,
2076 TOK_CHAR,
2077 TOK_VOID,
2078 TOK_IF,
2079 TOK_ELSE,
2080 TOK_WHILE,
2081 TOK_BREAK,
2082 TOK_RETURN,
2083 TOK_FOR,
2084 TOK_PRAGMA,
2085 TOK_DEFINE,
2086 TOK_AUTO,
2087 TOK_CASE,
2088 TOK_CONST,
2089 TOK_CONTINUE,
2090 TOK_DEFAULT,
2091 TOK_DO,
2092 TOK_DOUBLE,
2093 TOK_ENUM,
2094 TOK_EXTERN,
2095 TOK_FLOAT,
2096 TOK_GOTO,
2097 TOK_LONG,
2098 TOK_REGISTER,
2099 TOK_SHORT,
2100 TOK_SIGNED,
2101 TOK_SIZEOF,
2102 TOK_STATIC,
2103 TOK_STRUCT,
2104 TOK_SWITCH,
2105 TOK_TYPEDEF,
2106 TOK_UNION,
2107 TOK_UNSIGNED,
2108 TOK_VOLATILE,
2109 TOK__BOOL,
2110 TOK__COMPLEX,
2111 TOK__IMAGINARY,
2112 TOK_INLINE,
2113 TOK_RESTRICT,
2114 // Symbols start after tokens
2115 TOK_SYMBOL
2116 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002117
2118 static const int LOCAL = 0x200;
2119
2120 static const int SYM_FORWARD = 0;
2121 static const int SYM_DEFINE = 1;
2122
2123 /* tokens in string heap */
2124 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002125
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002126 static const int OP_INCREMENT = 0;
2127 static const int OP_DECREMENT = 1;
2128 static const int OP_MUL = 2;
2129 static const int OP_DIV = 3;
2130 static const int OP_MOD = 4;
2131 static const int OP_PLUS = 5;
2132 static const int OP_MINUS = 6;
2133 static const int OP_SHIFT_LEFT = 7;
2134 static const int OP_SHIFT_RIGHT = 8;
2135 static const int OP_LESS_EQUAL = 9;
2136 static const int OP_GREATER_EQUAL = 10;
2137 static const int OP_LESS = 11;
2138 static const int OP_GREATER = 12;
2139 static const int OP_EQUALS = 13;
2140 static const int OP_NOT_EQUALS = 14;
2141 static const int OP_LOGICAL_AND = 15;
2142 static const int OP_LOGICAL_OR = 16;
2143 static const int OP_BIT_AND = 17;
2144 static const int OP_BIT_XOR = 18;
2145 static const int OP_BIT_OR = 19;
2146 static const int OP_BIT_NOT = 20;
2147 static const int OP_LOGICAL_NOT = 21;
2148 static const int OP_COUNT = 22;
2149
2150 /* Operators are searched from front, the two-character operators appear
2151 * before the single-character operators with the same first character.
2152 * @ is used to pad out single-character operators.
2153 */
2154 static const char* operatorChars;
2155 static const char operatorLevel[];
2156
Jack Palevich569f1352009-06-29 14:29:08 -07002157 /* Called when we detect an internal problem. Does nothing in production.
2158 *
2159 */
2160 void internalError() {
2161 * (char*) 0 = 0;
2162 }
2163
Jack Palevich86351982009-06-30 18:09:56 -07002164 void assert(bool isTrue) {
2165 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002166 internalError();
2167 }
Jack Palevich86351982009-06-30 18:09:56 -07002168 }
2169
Jack Palevich40600de2009-07-01 15:32:35 -07002170 bool isSymbol(tokenid_t t) {
2171 return t >= TOK_SYMBOL &&
2172 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2173 }
2174
2175 bool isSymbolOrKeyword(tokenid_t t) {
2176 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002177 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002178 }
2179
Jack Palevich86351982009-06-30 18:09:56 -07002180 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002181 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002182 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2183 if (pV && pV->tok != t) {
2184 internalError();
2185 }
2186 return pV;
2187 }
2188
2189 inline bool isDefined(tokenid_t t) {
2190 return t >= TOK_SYMBOL && VI(t) != 0;
2191 }
2192
Jack Palevich40600de2009-07-01 15:32:35 -07002193 const char* nameof(tokenid_t t) {
2194 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002195 return mTokenTable[t].pText;
2196 }
2197
Jack Palevich21a15a22009-05-11 14:49:29 -07002198 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002199 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002200 }
2201
2202 void inp() {
2203 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002204 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002205 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002206 dptr = 0;
2207 ch = dch;
2208 }
2209 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002210 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002211#if 0
2212 printf("ch='%c' 0x%x\n", ch, ch);
2213#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002214 }
2215
2216 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002217 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002218 }
2219
Jack Palevichb4758ff2009-06-12 12:49:14 -07002220 /* read a character constant, advances ch to after end of constant */
2221 int getq() {
2222 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002223 if (ch == '\\') {
2224 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002225 if (isoctal(ch)) {
2226 // 1 to 3 octal characters.
2227 val = 0;
2228 for(int i = 0; i < 3; i++) {
2229 if (isoctal(ch)) {
2230 val = (val << 3) + ch - '0';
2231 inp();
2232 }
2233 }
2234 return val;
2235 } else if (ch == 'x' || ch == 'X') {
2236 // N hex chars
2237 inp();
2238 if (! isxdigit(ch)) {
2239 error("'x' character escape requires at least one digit.");
2240 } else {
2241 val = 0;
2242 while (isxdigit(ch)) {
2243 int d = ch;
2244 if (isdigit(d)) {
2245 d -= '0';
2246 } else if (d <= 'F') {
2247 d = d - 'A' + 10;
2248 } else {
2249 d = d - 'a' + 10;
2250 }
2251 val = (val << 4) + d;
2252 inp();
2253 }
2254 }
2255 } else {
2256 int val = ch;
2257 switch (ch) {
2258 case 'a':
2259 val = '\a';
2260 break;
2261 case 'b':
2262 val = '\b';
2263 break;
2264 case 'f':
2265 val = '\f';
2266 break;
2267 case 'n':
2268 val = '\n';
2269 break;
2270 case 'r':
2271 val = '\r';
2272 break;
2273 case 't':
2274 val = '\t';
2275 break;
2276 case 'v':
2277 val = '\v';
2278 break;
2279 case '\\':
2280 val = '\\';
2281 break;
2282 case '\'':
2283 val = '\'';
2284 break;
2285 case '"':
2286 val = '"';
2287 break;
2288 case '?':
2289 val = '?';
2290 break;
2291 default:
2292 error("Undefined character escape %c", ch);
2293 break;
2294 }
2295 inp();
2296 return val;
2297 }
2298 } else {
2299 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002300 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002301 return val;
2302 }
2303
2304 static bool isoctal(int ch) {
2305 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002306 }
2307
2308 void next() {
2309 int l, a;
2310
Jack Palevich546b2242009-05-13 15:10:04 -07002311 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002312 if (ch == '#') {
2313 inp();
2314 next();
2315 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002316 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002317 } else if (tok == TOK_PRAGMA) {
2318 doPragma();
2319 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002320 error("Unsupported preprocessor directive \"%s\"",
2321 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002322 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002323 }
2324 inp();
2325 }
2326 tokl = 0;
2327 tok = ch;
2328 /* encode identifiers & numbers */
2329 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002330 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002331 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002332 pdef(ch);
2333 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002334 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002335 if (isdigit(tok)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002336 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002337 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002338 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002339 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2340 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002341 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002342 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2343 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002344 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002345 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002346 dch = ch;
2347 inp();
2348 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002349 }
2350 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002351 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002352 inp();
2353 if (tok == '\'') {
2354 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002355 tokc = getq();
2356 if (ch != '\'') {
2357 error("Expected a ' character, got %c", ch);
2358 } else {
2359 inp();
2360 }
Jack Palevich546b2242009-05-13 15:10:04 -07002361 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002362 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002363 while (ch && ch != EOF) {
2364 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002365 inp();
2366 inp();
2367 if (ch == '/')
2368 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002369 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002370 if (ch == EOF) {
2371 error("End of file inside comment.");
2372 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002373 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002374 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002375 } else if ((tok == '/') & (ch == '/')) {
2376 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002377 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002378 inp();
2379 }
2380 inp();
2381 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002382 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002383 const char* t = operatorChars;
2384 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002385 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002386 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002387 tokl = operatorLevel[opIndex];
2388 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002389 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002390#if 0
2391 printf("%c%c -> tokl=%d tokc=0x%x\n",
2392 l, a, tokl, tokc);
2393#endif
2394 if (a == ch) {
2395 inp();
2396 tok = TOK_DUMMY; /* dummy token for double tokens */
2397 }
2398 break;
2399 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002400 opIndex++;
2401 }
2402 if (l == 0) {
2403 tokl = 0;
2404 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002405 }
2406 }
2407 }
2408#if 0
2409 {
Jack Palevich569f1352009-06-29 14:29:08 -07002410 String buf;
2411 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002412 fprintf(stderr, "%s\n", buf.getUnwrapped());
2413 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002414#endif
2415 }
2416
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002417 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002418 next();
2419 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002420 String* pName = new String();
2421 while (isspace(ch)) {
2422 inp();
2423 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002424 if (ch == '(') {
2425 delete pName;
2426 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002427 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002428 }
2429 while (isspace(ch)) {
2430 inp();
2431 }
Jack Palevich569f1352009-06-29 14:29:08 -07002432 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002433 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002434 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002435 inp();
2436 }
Jack Palevich569f1352009-06-29 14:29:08 -07002437 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2438 memcpy(pDefn, value.getUnwrapped(), value.len());
2439 pDefn[value.len()] = 0;
2440 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002441 }
2442
Jack Palevicheedf9d22009-06-04 16:23:40 -07002443 void doPragma() {
2444 // # pragma name(val)
2445 int state = 0;
2446 while(ch != EOF && ch != '\n' && state < 10) {
2447 switch(state) {
2448 case 0:
2449 if (isspace(ch)) {
2450 inp();
2451 } else {
2452 state++;
2453 }
2454 break;
2455 case 1:
2456 if (isalnum(ch)) {
2457 mPragmas.append(ch);
2458 inp();
2459 } else if (ch == '(') {
2460 mPragmas.append(0);
2461 inp();
2462 state++;
2463 } else {
2464 state = 11;
2465 }
2466 break;
2467 case 2:
2468 if (isalnum(ch)) {
2469 mPragmas.append(ch);
2470 inp();
2471 } else if (ch == ')') {
2472 mPragmas.append(0);
2473 inp();
2474 state = 10;
2475 } else {
2476 state = 11;
2477 }
2478 break;
2479 }
2480 }
2481 if(state != 10) {
2482 error("Unexpected pragma syntax");
2483 }
2484 mPragmaStringCount += 2;
2485 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002486
Jack Palevichac0e95e2009-05-29 13:53:44 -07002487 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002488 mErrorBuf.printf("%ld: ", file->getLine());
2489 mErrorBuf.vprintf(fmt, ap);
2490 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002491 }
2492
Jack Palevich8b0624c2009-05-20 12:12:06 -07002493 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002494 if (tok != c) {
2495 error("'%c' expected", c);
2496 }
2497 next();
2498 }
2499
Jack Palevich86351982009-06-30 18:09:56 -07002500 bool accept(intptr_t c) {
2501 if (tok == c) {
2502 next();
2503 return true;
2504 }
2505 return false;
2506 }
2507
Jack Palevich40600de2009-07-01 15:32:35 -07002508 bool acceptStringLiteral() {
2509 if (tok == '"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07002510 pGen->li((int) glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002511 // This while loop merges multiple adjacent string constants.
2512 while (tok == '"') {
2513 while (ch != '"' && ch != EOF) {
2514 *allocGlobalSpace(1) = getq();
2515 }
2516 if (ch != '"') {
2517 error("Unterminated string constant.");
2518 }
2519 inp();
2520 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002521 }
Jack Palevich40600de2009-07-01 15:32:35 -07002522 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07002523 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002524 /* align heap */
2525 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07002526
2527 return true;
2528 }
2529 return false;
2530 }
2531 /* Parse and evaluate a unary expression.
2532 * allowAssignment is true if '=' parsing wanted (quick hack)
2533 */
2534 void unary(bool allowAssignment) {
2535 intptr_t n, t, a;
2536 t = 0;
2537 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
2538 if (acceptStringLiteral()) {
2539 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07002540 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07002541 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07002542 a = tokc;
2543 t = tok;
2544 next();
2545 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002546 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002547 } else if (c == 2) {
2548 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07002549 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002550 if (t == '!')
Jack Palevich9eed7a22009-07-06 17:24:34 -07002551 pGen->gUnaryCmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002552 else
Jack Palevich9eed7a22009-07-06 17:24:34 -07002553 pGen->genUnaryOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002554 } else if (t == '(') {
2555 expr();
2556 skip(')');
2557 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07002558 /* This is a pointer dereference, but we currently only
2559 * support a pointer dereference if it's immediately
2560 * in front of a cast. So parse the cast right here.
2561 */
Jack Palevich21a15a22009-05-11 14:49:29 -07002562 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07002563 Type* pCast = expectCastTypeDeclaration(mLocalArena);
2564 // We currently only handle 3 types of cast:
2565 // (int*), (char*) , (int (*)())
2566 if(typeEqual(pCast, mkpIntPtr)) {
2567 t = TOK_INT;
2568 } else if (typeEqual(pCast, mkpCharPtr)) {
2569 t = TOK_CHAR;
2570 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07002571 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07002572 } else {
2573 String buffer;
2574 decodeType(buffer, pCast);
2575 error("Unsupported cast type %s", buffer.getUnwrapped());
2576 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07002577 }
2578 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07002579 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07002580 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002581 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002582 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002583 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002584 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002585 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07002586 }
Jack Palevich3f226492009-07-02 14:46:19 -07002587 // Else we fall through to the function call below, with
2588 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07002589 } else if (t == '&') {
Jack Palevich569f1352009-06-29 14:29:08 -07002590 pGen->leaR0((int) VI(tok)->pAddress);
Jack Palevich21a15a22009-05-11 14:49:29 -07002591 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002592 } else if (t == EOF ) {
2593 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07002594 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002595 // Don't have to do anything special here, the error
2596 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002597 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002598 if (!isDefined(t)) {
2599 mGlobals.add(t);
2600 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002601 }
2602
Jack Palevich569f1352009-06-29 14:29:08 -07002603 n = (intptr_t) VI(t)->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002604 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002605 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002606 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002607 VI(t)->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002608 }
Jack Palevich40600de2009-07-01 15:32:35 -07002609 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002610 /* assignment */
2611 next();
2612 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002613 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002614 } else if (tok != '(') {
2615 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002616 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07002617 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07002618 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002619 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002620 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002621 next();
2622 }
2623 }
2624 }
2625 }
2626
2627 /* function call */
2628 if (tok == '(') {
2629 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002630 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002631
2632 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002633 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07002634 next();
Jack Palevich40600de2009-07-01 15:32:35 -07002635 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002636 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002637 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002638 pGen->storeR0ToArg(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002639 l = l + 4;
Jack Palevich95727a02009-07-06 12:07:15 -07002640 if (accept(',')) {
2641 // fine
2642 } else if ( tok != ')') {
2643 error("Expected ',' or ')'");
2644 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002645 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002646 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002647 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002648 if (!n) {
2649 /* forward reference */
Jack Palevich569f1352009-06-29 14:29:08 -07002650 VariableInfo* pVI = VI(t);
2651 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward);
Jack Palevich21a15a22009-05-11 14:49:29 -07002652 } else if (n == 1) {
2653 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002654 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07002655 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07002656 }
-b master422972c2009-06-17 19:13:52 -07002657 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002658 }
2659 }
2660
Jack Palevich40600de2009-07-01 15:32:35 -07002661 /* Recursive descent parser for binary operations.
2662 */
2663 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002664 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002665 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002666 if (level-- == 1)
2667 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07002668 else {
Jack Palevich40600de2009-07-01 15:32:35 -07002669 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002670 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07002671 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002672 n = tok;
2673 t = tokc;
2674 next();
2675
Jack Palevich40600de2009-07-01 15:32:35 -07002676 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002677 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002678 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002679 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002680 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07002681 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07002682
Jack Palevich40600de2009-07-01 15:32:35 -07002683 if ((level == 4) | (level == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002684 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002685 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002686 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002687 }
2688 }
2689 }
2690 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07002691 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002692 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2693 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002694 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002695 pGen->gsym(a);
2696 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002697 }
2698 }
2699 }
2700
2701 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07002702 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07002703 }
2704
2705 int test_expr() {
2706 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002707 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002708 }
2709
Jack Palevicha6baa232009-06-12 11:25:59 -07002710 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002711 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002712
Jack Palevich95727a02009-07-06 12:07:15 -07002713 Type* pBaseType;
2714 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002715 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07002716 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07002717 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002718 next();
2719 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002720 a = test_expr();
2721 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002722 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002723 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002724 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002725 n = pGen->gjmp(0); /* jmp */
2726 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002727 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002728 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002729 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002730 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002731 }
Jack Palevich546b2242009-05-13 15:10:04 -07002732 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002733 t = tok;
2734 next();
2735 skip('(');
2736 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002737 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002738 a = test_expr();
2739 } else {
2740 if (tok != ';')
2741 expr();
2742 skip(';');
2743 n = codeBuf.getPC();
2744 a = 0;
2745 if (tok != ';')
2746 a = test_expr();
2747 skip(';');
2748 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002749 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002750 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002751 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002752 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002753 n = t + 4;
2754 }
2755 }
2756 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002757 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002758 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002759 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002760 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002761 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002762 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002763 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002764 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002765 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002766 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002767 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002768 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002769 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002770 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002771 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07002772 if (accept(TOK_RETURN)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002773 if (tok != ';')
2774 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002775 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07002776 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002777 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002778 } else if (tok != ';')
2779 expr();
2780 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002781 }
2782 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002783
Jack Palevich86351982009-06-30 18:09:56 -07002784 enum TypeTag {
Jack Palevich95727a02009-07-06 12:07:15 -07002785 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
2786 TY_POINTER, TY_FUNC, TY_PARAM
Jack Palevich86351982009-06-30 18:09:56 -07002787 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002788
Jack Palevich86351982009-06-30 18:09:56 -07002789 struct Type {
2790 TypeTag tag;
2791 tokenid_t id; // For function arguments
2792 Type* pHead;
2793 Type* pTail;
2794 };
2795
Jack Palevich3f226492009-07-02 14:46:19 -07002796 bool typeEqual(Type* a, Type* b) {
2797 if (a == b) {
2798 return true;
2799 }
2800 if (a == NULL || b == NULL) {
2801 return false;
2802 }
2803 TypeTag at = a->tag;
2804 if (at != b->tag) {
2805 return false;
2806 }
2807 if (at == TY_POINTER) {
2808 return typeEqual(a->pHead, b->pHead);
2809 } else if (at == TY_FUNC || at == TY_PARAM) {
2810 return typeEqual(a->pHead, b->pHead)
2811 && typeEqual(a->pTail, b->pTail);
2812 }
2813 return true;
2814 }
2815
Jack Palevich86351982009-06-30 18:09:56 -07002816 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
2817 assert(tag >= TY_INT && tag <= TY_PARAM);
2818 Type* pType = (Type*) arena.alloc(sizeof(Type));
2819 memset(pType, 0, sizeof(*pType));
2820 pType->tag = tag;
2821 pType->pHead = pHead;
2822 pType->pTail = pTail;
2823 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002824 }
2825
Jack Palevich3f226492009-07-02 14:46:19 -07002826 Type* createPtrType(Type* pType, Arena& arena) {
2827 return createType(TY_POINTER, pType, NULL, arena);
2828 }
2829
2830 /**
2831 * Try to print a type in declaration order
2832 */
Jack Palevich86351982009-06-30 18:09:56 -07002833 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07002834 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07002835 if (pType == NULL) {
2836 buffer.appendCStr("null");
2837 return;
2838 }
Jack Palevich3f226492009-07-02 14:46:19 -07002839 decodeTypeImp(buffer, pType);
2840 }
2841
2842 void decodeTypeImp(String& buffer, Type* pType) {
2843 decodeTypeImpPrefix(buffer, pType);
2844
Jack Palevich86351982009-06-30 18:09:56 -07002845 String temp;
2846 if (pType->id != 0) {
2847 decodeToken(temp, pType->id);
2848 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07002849 }
2850
2851 decodeTypeImpPostfix(buffer, pType);
2852 }
2853
2854 void decodeTypeImpPrefix(String& buffer, Type* pType) {
2855 TypeTag tag = pType->tag;
2856
2857 if (tag >= TY_INT && tag <= TY_VOID) {
2858 switch (tag) {
2859 case TY_INT:
2860 buffer.appendCStr("int");
2861 break;
2862 case TY_CHAR:
2863 buffer.appendCStr("char");
2864 break;
2865 case TY_VOID:
2866 buffer.appendCStr("void");
2867 break;
Jack Palevich95727a02009-07-06 12:07:15 -07002868 case TY_FLOAT:
2869 buffer.appendCStr("float");
2870 break;
2871 case TY_DOUBLE:
2872 buffer.appendCStr("double");
2873 break;
Jack Palevich3f226492009-07-02 14:46:19 -07002874 default:
2875 break;
2876 }
Jack Palevich86351982009-06-30 18:09:56 -07002877 buffer.append(' ');
2878 }
Jack Palevich3f226492009-07-02 14:46:19 -07002879
2880 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07002881 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07002882 break;
2883 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07002884 break;
2885 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07002886 break;
Jack Palevich95727a02009-07-06 12:07:15 -07002887 case TY_FLOAT:
2888 break;
2889 case TY_DOUBLE:
2890 break;
Jack Palevich86351982009-06-30 18:09:56 -07002891 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07002892 decodeTypeImpPrefix(buffer, pType->pHead);
2893 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
2894 buffer.append('(');
2895 }
2896 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07002897 break;
2898 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07002899 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07002900 break;
2901 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07002902 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07002903 break;
2904 default:
2905 String temp;
2906 temp.printf("Unknown tag %d", pType->tag);
2907 buffer.append(temp);
2908 break;
2909 }
Jack Palevich3f226492009-07-02 14:46:19 -07002910 }
2911
2912 void decodeTypeImpPostfix(String& buffer, Type* pType) {
2913 TypeTag tag = pType->tag;
2914
2915 switch(tag) {
2916 case TY_POINTER:
2917 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
2918 buffer.append(')');
2919 }
2920 decodeTypeImpPostfix(buffer, pType->pHead);
2921 break;
2922 case TY_FUNC:
2923 buffer.append('(');
2924 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
2925 decodeTypeImp(buffer, pArg);
2926 if (pArg->pTail) {
2927 buffer.appendCStr(", ");
2928 }
2929 }
2930 buffer.append(')');
2931 break;
2932 default:
2933 break;
Jack Palevich86351982009-06-30 18:09:56 -07002934 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002935 }
2936
Jack Palevich86351982009-06-30 18:09:56 -07002937 void printType(Type* pType) {
2938 String buffer;
2939 decodeType(buffer, pType);
2940 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07002941 }
2942
Jack Palevich86351982009-06-30 18:09:56 -07002943 Type* acceptPrimitiveType(Arena& arena) {
2944 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002945 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07002946 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002947 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07002948 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002949 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07002950 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07002951 } else if (tok == TOK_FLOAT) {
2952 pType = mkpFloat;
2953 } else if (tok == TOK_DOUBLE) {
2954 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002955 } else {
Jack Palevich86351982009-06-30 18:09:56 -07002956 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002957 }
2958 next();
Jack Palevich86351982009-06-30 18:09:56 -07002959 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002960 }
2961
Jack Palevich3f226492009-07-02 14:46:19 -07002962 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
2963 Arena& arena) {
2964 tokenid_t declName = 0;
2965 pType = acceptDecl2(pType, declName, nameAllowed,
2966 nameRequired, arena);
2967 if (declName) {
2968 // Clone the parent type so we can set a unique ID
2969 pType = createType(pType->tag, pType->pHead,
2970 pType->pTail, arena);
2971
Jack Palevich86351982009-06-30 18:09:56 -07002972 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07002973 }
Jack Palevich3f226492009-07-02 14:46:19 -07002974 // fprintf(stderr, "Parsed a declaration: ");
2975 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07002976 return pType;
2977 }
2978
Jack Palevich3f226492009-07-02 14:46:19 -07002979 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
2980 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07002981 if (! pType) {
2982 error("Expected a declaration");
2983 }
2984 return pType;
2985 }
2986
Jack Palevich3f226492009-07-02 14:46:19 -07002987 /* Used for accepting types that appear in casts */
2988 Type* acceptCastTypeDeclaration(Arena& arena) {
2989 Type* pType = acceptPrimitiveType(arena);
2990 if (pType) {
2991 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07002992 }
Jack Palevich86351982009-06-30 18:09:56 -07002993 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002994 }
2995
Jack Palevich3f226492009-07-02 14:46:19 -07002996 Type* expectCastTypeDeclaration(Arena& arena) {
2997 Type* pType = acceptCastTypeDeclaration(arena);
2998 if (! pType) {
2999 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003000 }
Jack Palevich3f226492009-07-02 14:46:19 -07003001 return pType;
3002 }
3003
3004 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3005 bool nameAllowed, bool nameRequired, Arena& arena) {
3006 int ptrCounter = 0;
3007 while (accept('*')) {
3008 ptrCounter++;
3009 }
3010 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3011 while (ptrCounter-- > 0) {
3012 pType = createType(TY_POINTER, pType, NULL, arena);
3013 }
3014 return pType;
3015 }
3016
3017 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3018 bool nameAllowed, bool nameRequired, Arena& arena) {
3019 // direct-dcl :
3020 // name
3021 // (dcl)
3022 // direct-dcl()
3023 // direct-dcl[]
3024 Type* pNewHead = NULL;
3025 if (accept('(')) {
3026 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3027 nameRequired, arena);
3028 skip(')');
3029 } else if ((declName = acceptSymbol()) != 0) {
3030 if (nameAllowed == false && declName) {
3031 error("Symbol %s not allowed here", nameof(declName));
3032 } else if (nameRequired && ! declName) {
3033 String temp;
3034 decodeToken(temp, tok);
3035 error("Expected symbol. Got %s", temp.getUnwrapped());
3036 }
3037 }
3038 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003039 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003040 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003041 pType = createType(TY_FUNC, pType, pTail, arena);
3042 skip(')');
3043 }
Jack Palevich3f226492009-07-02 14:46:19 -07003044
3045 if (pNewHead) {
3046 Type* pA = pNewHead;
3047 while (pA->pHead) {
3048 pA = pA->pHead;
3049 }
3050 pA->pHead = pType;
3051 pType = pNewHead;
3052 }
Jack Palevich86351982009-06-30 18:09:56 -07003053 return pType;
3054 }
3055
Jack Palevich3f226492009-07-02 14:46:19 -07003056 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003057 Type* pHead = NULL;
3058 Type* pTail = NULL;
3059 for(;;) {
3060 Type* pBaseArg = acceptPrimitiveType(arena);
3061 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003062 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3063 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003064 if (pArg) {
3065 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3066 if (!pHead) {
3067 pHead = pParam;
3068 pTail = pParam;
3069 } else {
3070 pTail->pTail = pParam;
3071 pTail = pParam;
3072 }
3073 }
3074 }
3075 if (! accept(',')) {
3076 break;
3077 }
3078 }
3079 return pHead;
3080 }
3081
3082 Type* expectPrimitiveType(Arena& arena) {
3083 Type* pType = acceptPrimitiveType(arena);
3084 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003085 String buf;
3086 decodeToken(buf, tok);
3087 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003088 }
Jack Palevich86351982009-06-30 18:09:56 -07003089 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003090 }
3091
Jack Palevich86351982009-06-30 18:09:56 -07003092 void addGlobalSymbol(Type* pDecl) {
3093 tokenid_t t = pDecl->id;
3094 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003095 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003096 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003097 }
Jack Palevich86351982009-06-30 18:09:56 -07003098 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003099 }
3100
Jack Palevich86351982009-06-30 18:09:56 -07003101 void reportDuplicate(tokenid_t t) {
3102 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003103 }
3104
Jack Palevich86351982009-06-30 18:09:56 -07003105 void addLocalSymbol(Type* pDecl) {
3106 tokenid_t t = pDecl->id;
3107 if (mLocals.isDefinedAtCurrentLevel(t)) {
3108 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003109 }
Jack Palevich86351982009-06-30 18:09:56 -07003110 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003111 }
3112
Jack Palevich95727a02009-07-06 12:07:15 -07003113 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003114 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003115
Jack Palevich95727a02009-07-06 12:07:15 -07003116 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003117 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003118 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3119 if (!pDecl) {
3120 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003121 }
Jack Palevich86351982009-06-30 18:09:56 -07003122 int variableAddress = 0;
3123 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003124 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003125 loc = loc + 4;
3126 variableAddress = -loc;
3127 VI(pDecl->id)->pAddress = (void*) variableAddress;
3128 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003129 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003130 expr();
3131 pGen->storeR0(variableAddress);
3132 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003133 if (tok == ',')
3134 next();
3135 }
3136 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003137 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003138 }
3139 }
3140
Jack Palevichf1728be2009-06-12 13:53:51 -07003141 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003142 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003143 }
3144
Jack Palevich569f1352009-06-29 14:29:08 -07003145 void decodeToken(String& buffer, tokenid_t token) {
3146 if (token == EOF ) {
3147 buffer.printf("EOF");
3148 } else if (token == TOK_NUM) {
3149 buffer.printf("numeric constant");
3150 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003151 if (token < 32) {
3152 buffer.printf("'\\x%02x'", token);
3153 } else {
3154 buffer.printf("'%c'", token);
3155 }
Jack Palevich569f1352009-06-29 14:29:08 -07003156 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3157 buffer.printf("keyword \"%s\"", nameof(token));
3158 } else {
3159 buffer.printf("symbol \"%s\"", nameof(token));
3160 }
3161 }
3162
Jack Palevich40600de2009-07-01 15:32:35 -07003163 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003164 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003165 if (!result) {
3166 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003167 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003168 error("Expected symbol. Got %s", temp.getUnwrapped());
3169 }
3170 return result;
3171 }
3172
Jack Palevich86351982009-06-30 18:09:56 -07003173 tokenid_t acceptSymbol() {
3174 tokenid_t result = 0;
3175 if (tok >= TOK_SYMBOL) {
3176 result = tok;
3177 next();
Jack Palevich86351982009-06-30 18:09:56 -07003178 }
3179 return result;
3180 }
3181
Jack Palevichb7c81e92009-06-04 19:56:13 -07003182 void globalDeclarations() {
3183 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003184 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3185 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003186 break;
3187 }
Jack Palevich86351982009-06-30 18:09:56 -07003188 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3189 if (!pDecl) {
3190 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003191 }
Jack Palevich86351982009-06-30 18:09:56 -07003192 if (! isDefined(pDecl->id)) {
3193 addGlobalSymbol(pDecl);
3194 }
3195 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003196 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003197 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003198 }
Jack Palevich86351982009-06-30 18:09:56 -07003199 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003200 // it's a variable declaration
3201 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003202 if (name && !name->pAddress) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003203 name->pAddress = (int*) allocGlobalSpace(4);
3204 }
Jack Palevich86351982009-06-30 18:09:56 -07003205 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003206 if (tok == TOK_NUM) {
3207 if (name) {
3208 * (int*) name->pAddress = tokc;
3209 }
3210 next();
3211 } else {
3212 error("Expected an integer constant");
3213 }
3214 }
Jack Palevich86351982009-06-30 18:09:56 -07003215 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003216 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003217 }
Jack Palevich86351982009-06-30 18:09:56 -07003218 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3219 if (!pDecl) {
3220 break;
3221 }
3222 if (! isDefined(pDecl->id)) {
3223 addGlobalSymbol(pDecl);
3224 }
3225 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003226 }
3227 skip(';');
3228 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003229 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003230 if (accept(';')) {
3231 // forward declaration.
3232 } else {
3233 if (name) {
3234 /* patch forward references (XXX: does not work for function
3235 pointers) */
3236 pGen->gsym((int) name->pForward);
3237 /* put function address */
3238 name->pAddress = (void*) codeBuf.getPC();
3239 }
3240 // Calculate stack offsets for parameters
3241 mLocals.pushLevel();
3242 intptr_t a = 8;
3243 int argCount = 0;
3244 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3245 Type* pArg = pP->pHead;
3246 addLocalSymbol(pArg);
3247 /* read param name and compute offset */
3248 VI(pArg->id)->pAddress = (void*) a;
3249 a = a + 4;
3250 argCount++;
3251 }
3252 rsym = loc = 0;
3253 a = pGen->functionEntry(argCount);
3254 block(0, true);
3255 pGen->gsym(rsym);
3256 pGen->functionExit(argCount, a, loc);
3257 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003258 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003259 }
3260 }
3261 }
3262
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003263 char* allocGlobalSpace(int bytes) {
3264 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
3265 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003266 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003267 }
3268 char* result = glo;
3269 glo += bytes;
3270 return result;
3271 }
3272
Jack Palevich21a15a22009-05-11 14:49:29 -07003273 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003274 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003275 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003276 pGlobalBase = 0;
3277 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003278 if (pGen) {
3279 delete pGen;
3280 pGen = 0;
3281 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003282 if (file) {
3283 delete file;
3284 file = 0;
3285 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003286 }
3287
3288 void clear() {
3289 tok = 0;
3290 tokc = 0;
3291 tokl = 0;
3292 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003293 rsym = 0;
3294 loc = 0;
3295 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003296 dptr = 0;
3297 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003298 file = 0;
3299 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003300 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003301 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003302 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003303
Jack Palevich22305132009-05-13 10:58:45 -07003304 void setArchitecture(const char* architecture) {
3305 delete pGen;
3306 pGen = 0;
3307
3308 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003309#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003310 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003311 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003312 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003313#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003314#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003315 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003316 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003317 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003318#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003319 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003320 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003321 }
3322 }
3323
3324 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003325#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003326 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003327#elif defined(DEFAULT_X86_CODEGEN)
3328 pGen = new X86CodeGenerator();
3329#endif
3330 }
3331 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003332 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003333 } else {
3334 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003335 }
3336 }
3337
Jack Palevich77ae76e2009-05-10 19:59:24 -07003338public:
Jack Palevich22305132009-05-13 10:58:45 -07003339 struct args {
3340 args() {
3341 architecture = 0;
3342 }
3343 const char* architecture;
3344 };
3345
Jack Paleviche7b59062009-05-19 17:12:17 -07003346 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003347 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003348 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003349
Jack Paleviche7b59062009-05-19 17:12:17 -07003350 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003351 cleanup();
3352 }
3353
Jack Palevich1cdef202009-05-22 12:06:27 -07003354 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003355 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003356
3357 cleanup();
3358 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003359 mTokenTable.setArena(&mGlobalArena);
3360 mGlobals.setArena(&mGlobalArena);
3361 mGlobals.setTokenTable(&mTokenTable);
3362 mLocals.setArena(&mLocalArena);
3363 mLocals.setTokenTable(&mTokenTable);
3364
3365 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003366 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003367 codeBuf.init(ALLOC_SIZE);
3368 setArchitecture(NULL);
3369 if (!pGen) {
3370 return -1;
3371 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003372#ifdef PROVIDE_TRACE_CODEGEN
3373 pGen = new TraceCodeGenerator(pGen);
3374#endif
3375 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003376 pGen->init(&codeBuf);
3377 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003378 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3379 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003380 inp();
3381 next();
3382 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003383 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003384 result = pGen->finishCompile();
3385 if (result == 0) {
3386 if (mErrorBuf.len()) {
3387 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003388 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003389 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003390 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003391 }
3392
Jack Palevich86351982009-06-30 18:09:56 -07003393 void createPrimitiveTypes() {
3394 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3395 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3396 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003397 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3398 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003399 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3400 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
3401 mkpPtrIntFn = createPtrType(
3402 createType(TY_FUNC, mkpInt, NULL, mGlobalArena),
3403 mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003404 }
3405
Jack Palevicha6baa232009-06-12 11:25:59 -07003406 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003407 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003408 }
3409
Jack Palevich569f1352009-06-29 14:29:08 -07003410 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003411 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003412 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003413 }
3414
Jack Palevich569f1352009-06-29 14:29:08 -07003415 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003416 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003417 error("Undefined forward reference: %s",
3418 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003419 }
3420 return true;
3421 }
3422
Jack Palevich21a15a22009-05-11 14:49:29 -07003423 int dump(FILE* out) {
3424 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
3425 return 0;
3426 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07003427
Jack Palevicha6535612009-05-13 16:24:17 -07003428 int disassemble(FILE* out) {
3429 return pGen->disassemble(out);
3430 }
3431
Jack Palevich1cdef202009-05-22 12:06:27 -07003432 /* Look through the symbol table to find a symbol.
3433 * If found, return its value.
3434 */
3435 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07003436 tokenid_t tok = mTokenTable.intern(name, strlen(name));
3437 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003438 if (pVariableInfo) {
3439 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07003440 }
3441 return NULL;
3442 }
3443
Jack Palevicheedf9d22009-06-04 16:23:40 -07003444 void getPragmas(ACCsizei* actualStringCount,
3445 ACCsizei maxStringCount, ACCchar** strings) {
3446 int stringCount = mPragmaStringCount;
3447 if (actualStringCount) {
3448 *actualStringCount = stringCount;
3449 }
3450 if (stringCount > maxStringCount) {
3451 stringCount = maxStringCount;
3452 }
3453 if (strings) {
3454 char* pPragmas = mPragmas.getUnwrapped();
3455 while (stringCount-- > 0) {
3456 *strings++ = pPragmas;
3457 pPragmas += strlen(pPragmas) + 1;
3458 }
3459 }
3460 }
3461
Jack Palevichac0e95e2009-05-29 13:53:44 -07003462 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003463 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07003464 }
3465
Jack Palevich77ae76e2009-05-10 19:59:24 -07003466};
3467
Jack Paleviche7b59062009-05-19 17:12:17 -07003468const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003469 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
3470
Jack Paleviche7b59062009-05-19 17:12:17 -07003471const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003472 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
3473 5, 5, /* ==, != */
3474 9, 10, /* &&, || */
3475 6, 7, 8, /* & ^ | */
3476 2, 2 /* ~ ! */
3477 };
3478
Jack Palevich8b0624c2009-05-20 12:12:06 -07003479#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003480FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07003481#endif
Jack Palevicha6535612009-05-13 16:24:17 -07003482
Jack Palevich8b0624c2009-05-20 12:12:06 -07003483#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07003484const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003485 0x1, // ++
3486 0xff, // --
3487 0xc1af0f, // *
3488 0xf9f79991, // /
3489 0xf9f79991, // % (With manual assist to swap results)
3490 0xc801, // +
3491 0xd8f7c829, // -
3492 0xe0d391, // <<
3493 0xf8d391, // >>
3494 0xe, // <=
3495 0xd, // >=
3496 0xc, // <
3497 0xf, // >
3498 0x4, // ==
3499 0x5, // !=
3500 0x0, // &&
3501 0x1, // ||
3502 0xc821, // &
3503 0xc831, // ^
3504 0xc809, // |
3505 0xd0f7, // ~
3506 0x4 // !
3507};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003508#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003509
Jack Palevich1cdef202009-05-22 12:06:27 -07003510struct ACCscript {
3511 ACCscript() {
3512 text = 0;
3513 textLength = 0;
3514 accError = ACC_NO_ERROR;
3515 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003516
Jack Palevich1cdef202009-05-22 12:06:27 -07003517 ~ACCscript() {
3518 delete text;
3519 }
Jack Palevich546b2242009-05-13 15:10:04 -07003520
Jack Palevich1cdef202009-05-22 12:06:27 -07003521 void setError(ACCenum error) {
3522 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3523 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003524 }
3525 }
3526
Jack Palevich1cdef202009-05-22 12:06:27 -07003527 ACCenum getError() {
3528 ACCenum result = accError;
3529 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003530 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003531 }
3532
Jack Palevich1cdef202009-05-22 12:06:27 -07003533 Compiler compiler;
3534 char* text;
3535 int textLength;
3536 ACCenum accError;
3537};
3538
3539
3540extern "C"
3541ACCscript* accCreateScript() {
3542 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003543}
Jack Palevich1cdef202009-05-22 12:06:27 -07003544
3545extern "C"
3546ACCenum accGetError( ACCscript* script ) {
3547 return script->getError();
3548}
3549
3550extern "C"
3551void accDeleteScript(ACCscript* script) {
3552 delete script;
3553}
3554
3555extern "C"
3556void accScriptSource(ACCscript* script,
3557 ACCsizei count,
3558 const ACCchar ** string,
3559 const ACCint * length) {
3560 int totalLength = 0;
3561 for(int i = 0; i < count; i++) {
3562 int len = -1;
3563 const ACCchar* s = string[i];
3564 if (length) {
3565 len = length[i];
3566 }
3567 if (len < 0) {
3568 len = strlen(s);
3569 }
3570 totalLength += len;
3571 }
3572 delete script->text;
3573 char* text = new char[totalLength + 1];
3574 script->text = text;
3575 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003576 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003577 for(int i = 0; i < count; i++) {
3578 int len = -1;
3579 const ACCchar* s = string[i];
3580 if (length) {
3581 len = length[i];
3582 }
3583 if (len < 0) {
3584 len = strlen(s);
3585 }
Jack Palevich09555c72009-05-27 12:25:55 -07003586 memcpy(dest, s, len);
3587 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003588 }
3589 text[totalLength] = '\0';
3590}
3591
3592extern "C"
3593void accCompileScript(ACCscript* script) {
3594 int result = script->compiler.compile(script->text, script->textLength);
3595 if (result) {
3596 script->setError(ACC_INVALID_OPERATION);
3597 }
3598}
3599
3600extern "C"
3601void accGetScriptiv(ACCscript* script,
3602 ACCenum pname,
3603 ACCint * params) {
3604 switch (pname) {
3605 case ACC_INFO_LOG_LENGTH:
3606 *params = 0;
3607 break;
3608 }
3609}
3610
3611extern "C"
3612void accGetScriptInfoLog(ACCscript* script,
3613 ACCsizei maxLength,
3614 ACCsizei * length,
3615 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003616 char* message = script->compiler.getErrorMessage();
3617 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003618 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003619 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003620 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003621 if (infoLog && maxLength > 0) {
3622 int trimmedLength = maxLength < messageLength ?
3623 maxLength : messageLength;
3624 memcpy(infoLog, message, trimmedLength);
3625 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003626 }
3627}
3628
3629extern "C"
3630void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3631 ACCvoid ** address) {
3632 void* value = script->compiler.lookup(name);
3633 if (value) {
3634 *address = value;
3635 } else {
3636 script->setError(ACC_INVALID_VALUE);
3637 }
3638}
3639
Jack Palevicheedf9d22009-06-04 16:23:40 -07003640extern "C"
3641void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3642 ACCsizei maxStringCount, ACCchar** strings){
3643 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3644}
3645
-b master422972c2009-06-17 19:13:52 -07003646extern "C"
3647void accDisassemble(ACCscript* script) {
3648 script->compiler.disassemble(stderr);
3649}
3650
Jack Palevicheedf9d22009-06-04 16:23:40 -07003651
Jack Palevich1cdef202009-05-22 12:06:27 -07003652} // namespace acc
3653