blob: 83fc2fe58596916c3a7b50f585524745afcc90d5 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040
41#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070042#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070043#endif
Jack Palevicha6535612009-05-13 16:24:17 -070044
Jack Palevich1cdef202009-05-22 12:06:27 -070045#include <acc/acc.h>
46
Jack Palevich09555c72009-05-27 12:25:55 -070047#define LOG_API(...) do {} while(0)
48// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070049
-b master422972c2009-06-17 19:13:52 -070050#define LOG_STACK(...) do {} while(0)
51// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
52
53// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichbbf8ab52009-05-11 11:54:30 -070056namespace acc {
57
Jack Palevichac0e95e2009-05-29 13:53:44 -070058class ErrorSink {
59public:
60 void error(const char *fmt, ...) {
61 va_list ap;
62 va_start(ap, fmt);
63 verror(fmt, ap);
64 va_end(ap);
65 }
66
67 virtual void verror(const char* fmt, va_list ap) = 0;
68};
69
70class Compiler : public ErrorSink {
Jack Palevich21a15a22009-05-11 14:49:29 -070071 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070072 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070073 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070074 ErrorSink* mErrorSink;
75 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -070076 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -070077
Jack Palevich21a15a22009-05-11 14:49:29 -070078 void release() {
79 if (pProgramBase != 0) {
80 free(pProgramBase);
81 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070082 }
Jack Palevich21a15a22009-05-11 14:49:29 -070083 }
84
Jack Palevich0a280a02009-06-11 10:53:51 -070085 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -070086 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -070087 bool overflow = newSize > mSize;
88 if (overflow && !mOverflowed) {
89 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -070090 if (mErrorSink) {
91 mErrorSink->error("Code too large: %d bytes", newSize);
92 }
93 }
Jack Palevich0a280a02009-06-11 10:53:51 -070094 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -070095 }
96
Jack Palevich21a15a22009-05-11 14:49:29 -070097 public:
98 CodeBuf() {
99 pProgramBase = 0;
100 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700101 mErrorSink = 0;
102 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700103 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700104 }
105
106 ~CodeBuf() {
107 release();
108 }
109
110 void init(int size) {
111 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700112 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700113 pProgramBase = (char*) calloc(1, size);
114 ind = pProgramBase;
115 }
116
Jack Palevichac0e95e2009-05-29 13:53:44 -0700117 void setErrorSink(ErrorSink* pErrorSink) {
118 mErrorSink = pErrorSink;
119 }
120
Jack Palevich546b2242009-05-13 15:10:04 -0700121 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700122 if(check(4)) {
123 return 0;
124 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700125 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700126 * (int*) ind = n;
127 ind += 4;
128 return result;
129 }
130
Jack Palevich21a15a22009-05-11 14:49:29 -0700131 /*
132 * Output a byte. Handles all values, 0..ff.
133 */
134 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700135 if(check(1)) {
136 return;
137 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700138 *ind++ = n;
139 }
140
Jack Palevich21a15a22009-05-11 14:49:29 -0700141 inline void* getBase() {
142 return (void*) pProgramBase;
143 }
144
Jack Palevich8b0624c2009-05-20 12:12:06 -0700145 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700146 return ind - pProgramBase;
147 }
148
Jack Palevich8b0624c2009-05-20 12:12:06 -0700149 intptr_t getPC() {
150 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700151 }
152 };
153
Jack Palevich1cdef202009-05-22 12:06:27 -0700154 /**
155 * A code generator creates an in-memory program, generating the code on
156 * the fly. There is one code generator implementation for each supported
157 * architecture.
158 *
159 * The code generator implements the following abstract machine:
160 * R0 - the main accumulator.
161 * R1 - the secondary accumulator.
162 * FP - a frame pointer for accessing function arguments and local
163 * variables.
164 * SP - a stack pointer for storing intermediate results while evaluating
165 * expressions. The stack pointer grows downwards.
166 *
167 * The function calling convention is that all arguments are placed on the
168 * stack such that the first argument has the lowest address.
169 * After the call, the result is in R0. The caller is responsible for
170 * removing the arguments from the stack.
171 * The R0 and R1 registers are not saved across function calls. The
172 * FP and SP registers are saved.
173 */
174
Jack Palevich21a15a22009-05-11 14:49:29 -0700175 class CodeGenerator {
176 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700177 CodeGenerator() {
178 mErrorSink = 0;
179 pCodeBuf = 0;
180 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 virtual ~CodeGenerator() {}
182
Jack Palevich22305132009-05-13 10:58:45 -0700183 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700184 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 pCodeBuf->setErrorSink(mErrorSink);
186 }
187
Jack Palevichb67b18f2009-06-11 21:12:23 -0700188 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 mErrorSink = pErrorSink;
190 if (pCodeBuf) {
191 pCodeBuf->setErrorSink(mErrorSink);
192 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700193 }
194
Jack Palevich1cdef202009-05-22 12:06:27 -0700195 /* Emit a function prolog.
196 * argCount is the number of arguments.
197 * Save the old value of the FP.
198 * Set the new value of the FP.
199 * Convert from the native platform calling convention to
200 * our stack-based calling convention. This may require
201 * pushing arguments from registers to the stack.
202 * Allocate "N" bytes of stack space. N isn't known yet, so
203 * just emit the instructions for adjusting the stack, and return
204 * the address to patch up. The patching will be done in
205 * functionExit().
206 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700207 */
Jack Palevich546b2242009-05-13 15:10:04 -0700208 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700209
Jack Palevich1cdef202009-05-22 12:06:27 -0700210 /* Emit a function epilog.
211 * Restore the old SP and FP register values.
212 * Return to the calling function.
213 * argCount - the number of arguments to the function.
214 * localVariableAddress - returned from functionEntry()
215 * localVariableSize - the size in bytes of the local variables.
216 */
217 virtual void functionExit(int argCount, int localVariableAddress,
218 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700219
Jack Palevich1cdef202009-05-22 12:06:27 -0700220 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700221 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700222
Jack Palevich1cdef202009-05-22 12:06:27 -0700223 /* Jump to a target, and return the address of the word that
224 * holds the target data, in case it needs to be fixed up later.
225 */
Jack Palevich22305132009-05-13 10:58:45 -0700226 virtual int gjmp(int t) = 0;
227
Jack Palevich1cdef202009-05-22 12:06:27 -0700228 /* Test R0 and jump to a target if the test succeeds.
229 * l = 0: je, l == 1: jne
230 * Return the address of the word that holds the targed data, in
231 * case it needs to be fixed up later.
232 */
Jack Palevich22305132009-05-13 10:58:45 -0700233 virtual int gtst(bool l, int t) = 0;
234
Jack Palevich1cdef202009-05-22 12:06:27 -0700235 /* Compare R1 against R0, and store the boolean result in R0.
236 * op specifies the comparison.
237 */
Jack Palevich22305132009-05-13 10:58:45 -0700238 virtual void gcmp(int op) = 0;
239
Jack Palevich1cdef202009-05-22 12:06:27 -0700240 /* Perform the arithmetic op specified by op. R1 is the
241 * left argument, R0 is the right argument.
242 */
Jack Palevich546b2242009-05-13 15:10:04 -0700243 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700244
Jack Palevich1cdef202009-05-22 12:06:27 -0700245 /* Set R1 to 0.
246 */
247 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700248
Jack Palevich1cdef202009-05-22 12:06:27 -0700249 /* Push R0 onto the stack.
250 */
251 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700252
Jack Palevich1cdef202009-05-22 12:06:27 -0700253 /* Pop R1 off of the stack.
254 */
255 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700256
Jack Palevich1cdef202009-05-22 12:06:27 -0700257 /* Store R0 to the address stored in R1.
258 * isInt is true if a whole 4-byte integer value
259 * should be stored, otherwise a 1-byte character
260 * value should be stored.
261 */
262 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700263
Jack Palevich1cdef202009-05-22 12:06:27 -0700264 /* Load R0 from the address stored in R0.
265 * isInt is true if a whole 4-byte integer value
266 * should be loaded, otherwise a 1-byte character
267 * value should be loaded.
268 */
269 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700270
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 /* Load the absolute address of a variable to R0.
272 * If ea <= LOCAL, then this is a local variable, or an
273 * argument, addressed relative to FP.
274 * else it is an absolute global address.
275 */
276 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700277
Jack Palevich1cdef202009-05-22 12:06:27 -0700278 /* Store R0 to a variable.
279 * If ea <= LOCAL, then this is a local variable, or an
280 * argument, addressed relative to FP.
281 * else it is an absolute global address.
282 */
283 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700284
Jack Palevich1cdef202009-05-22 12:06:27 -0700285 /* load R0 from a variable.
286 * If ea <= LOCAL, then this is a local variable, or an
287 * argument, addressed relative to FP.
288 * else it is an absolute global address.
289 * If isIncDec is true, then the stored variable's value
290 * should be post-incremented or post-decremented, based
291 * on the value of op.
292 */
293 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700294
Jack Palevich1cdef202009-05-22 12:06:27 -0700295 /* Emit code to adjust the stack for a function call. Return the
296 * label for the address of the instruction that adjusts the
297 * stack size. This will be passed as argument "a" to
298 * endFunctionCallArguments.
299 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700300 virtual int beginFunctionCallArguments() = 0;
301
Jack Palevich1cdef202009-05-22 12:06:27 -0700302 /* Emit code to store R0 to the stack at byte offset l.
303 */
304 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700305
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 /* Patch the function call preamble.
307 * a is the address returned from beginFunctionCallArguments
308 * l is the number of bytes the arguments took on the stack.
309 * Typically you would also emit code to convert the argument
310 * list into whatever the native function calling convention is.
311 * On ARM for example you would pop the first 5 arguments into
312 * R0..R4
313 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700314 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700315
Jack Palevich1cdef202009-05-22 12:06:27 -0700316 /* Emit a call to an unknown function. The argument "symbol" needs to
317 * be stored in the location where the address should go. It forms
318 * a chain. The address will be patched later.
319 * Return the address of the word that has to be patched.
320 */
Jack Palevich22305132009-05-13 10:58:45 -0700321 virtual int callForward(int symbol) = 0;
322
Jack Palevich1cdef202009-05-22 12:06:27 -0700323 /* Call a function using PC-relative addressing. t is the PC-relative
324 * address of the function. It has already been adjusted for the
325 * architectural jump offset, so just store it as-is.
326 */
Jack Palevich22305132009-05-13 10:58:45 -0700327 virtual void callRelative(int t) = 0;
328
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 /* Call a function pointer. L is the number of bytes the arguments
330 * take on the stack. The address of the function is stored at
331 * location SP + l.
332 */
Jack Palevich22305132009-05-13 10:58:45 -0700333 virtual void callIndirect(int l) = 0;
334
Jack Palevich1cdef202009-05-22 12:06:27 -0700335 /* Adjust SP after returning from a function call. l is the
336 * number of bytes of arguments stored on the stack. isIndirect
337 * is true if this was an indirect call. (In which case the
338 * address of the function is stored at location SP + l.)
339 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700340 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700341
Jack Palevich1cdef202009-05-22 12:06:27 -0700342 /* Print a disassembly of the assembled code to out. Return
343 * non-zero if there is an error.
344 */
Jack Palevicha6535612009-05-13 16:24:17 -0700345 virtual int disassemble(FILE* out) = 0;
346
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 /* Generate a symbol at the current PC. t is the head of a
348 * linked list of addresses to patch.
349 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700350 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700351
Jack Palevich1cdef202009-05-22 12:06:27 -0700352 /*
353 * Do any cleanup work required at the end of a compile.
354 * For example, an instruction cache might need to be
355 * invalidated.
356 * Return non-zero if there is an error.
357 */
358 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700359
Jack Palevicha6535612009-05-13 16:24:17 -0700360 /**
361 * Adjust relative branches by this amount.
362 */
363 virtual int jumpOffset() = 0;
364
Jack Palevich21a15a22009-05-11 14:49:29 -0700365 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700366 /*
367 * Output a byte. Handles all values, 0..ff.
368 */
369 void ob(int n) {
370 pCodeBuf->ob(n);
371 }
372
Jack Palevich8b0624c2009-05-20 12:12:06 -0700373 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700374 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700375 }
376
Jack Palevich8b0624c2009-05-20 12:12:06 -0700377 intptr_t getBase() {
378 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700379 }
380
Jack Palevich8b0624c2009-05-20 12:12:06 -0700381 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700382 return pCodeBuf->getPC();
383 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700384
385 intptr_t getSize() {
386 return pCodeBuf->getSize();
387 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700388
389 void error(const char* fmt,...) {
390 va_list ap;
391 va_start(ap, fmt);
392 mErrorSink->verror(fmt, ap);
393 va_end(ap);
394 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700395 private:
396 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700397 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700398 };
399
Jack Paleviche7b59062009-05-19 17:12:17 -0700400#ifdef PROVIDE_ARM_CODEGEN
401
Jack Palevich22305132009-05-13 10:58:45 -0700402 class ARMCodeGenerator : public CodeGenerator {
403 public:
404 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700405
Jack Palevich22305132009-05-13 10:58:45 -0700406 virtual ~ARMCodeGenerator() {}
407
408 /* returns address to patch with local variable size
409 */
Jack Palevich546b2242009-05-13 15:10:04 -0700410 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700411 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700412 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700413 // sp -> arg4 arg5 ...
414 // Push our register-based arguments back on the stack
415 if (argCount > 0) {
416 int regArgCount = argCount <= 4 ? argCount : 4;
417 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700418 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700419 }
420 // sp -> arg0 arg1 ...
421 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700422 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700423 // sp, fp -> oldfp, retadr, arg0 arg1 ....
424 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700425 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700426 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700427 // We don't know how many local variables we are going to use,
428 // but we will round the allocation up to a multiple of
429 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700430 }
431
Jack Palevich546b2242009-05-13 15:10:04 -0700432 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700433 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700434 // Round local variable size up to a multiple of stack alignment
435 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
436 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700437 // Patch local variable allocation code:
438 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700439 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700440 }
Jack Palevich69796b62009-05-14 15:42:26 -0700441 *(char*) (localVariableAddress) = localVariableSize;
442
443 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
444 o4(0xE1A0E00B); // mov lr, fp
445 o4(0xE59BB000); // ldr fp, [fp]
446 o4(0xE28ED004); // add sp, lr, #4
447 // sp -> retadr, arg0, ...
448 o4(0xE8BD4000); // ldmfd sp!, {lr}
449 // sp -> arg0 ....
450 if (argCount > 0) {
451 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700452 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700453 // earlier. We don't need to actually store them anywhere,
454 // just adjust the stack.
455 int regArgCount = argCount <= 4 ? argCount : 4;
456 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
457 }
458 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700459 }
460
461 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700462 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700463 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700464 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700465 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700466 } else if (t >= -256 && t < 0) {
467 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700468 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700469 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700470 o4(0xE51F0000); // ldr r0, .L3
471 o4(0xEA000000); // b .L99
472 o4(t); // .L3: .word 0
473 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700474 }
Jack Palevich22305132009-05-13 10:58:45 -0700475 }
476
477 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700478 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700479 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700480 }
481
482 /* l = 0: je, l == 1: jne */
483 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700484 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700485 o4(0xE3500000); // cmp r0,#0
486 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
487 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700488 }
489
490 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700491 LOG_API("gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700492 o4(0xE1510000); // cmp r1, r1
493 switch(op) {
494 case OP_EQUALS:
495 o4(0x03A00001); // moveq r0,#1
496 o4(0x13A00000); // movne r0,#0
497 break;
498 case OP_NOT_EQUALS:
499 o4(0x03A00000); // moveq r0,#0
500 o4(0x13A00001); // movne r0,#1
501 break;
502 case OP_LESS_EQUAL:
503 o4(0xD3A00001); // movle r0,#1
504 o4(0xC3A00000); // movgt r0,#0
505 break;
506 case OP_GREATER:
507 o4(0xD3A00000); // movle r0,#0
508 o4(0xC3A00001); // movgt r0,#1
509 break;
510 case OP_GREATER_EQUAL:
511 o4(0xA3A00001); // movge r0,#1
512 o4(0xB3A00000); // movlt r0,#0
513 break;
514 case OP_LESS:
515 o4(0xA3A00000); // movge r0,#0
516 o4(0xB3A00001); // movlt r0,#1
517 break;
518 default:
519 error("Unknown comparison op %d", op);
520 break;
521 }
Jack Palevich22305132009-05-13 10:58:45 -0700522 }
523
Jack Palevich546b2242009-05-13 15:10:04 -0700524 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700525 LOG_API("genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700526 switch(op) {
527 case OP_MUL:
528 o4(0x0E0000091); // mul r0,r1,r0
529 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700530 case OP_DIV:
531 callRuntime(runtime_DIV);
532 break;
533 case OP_MOD:
534 callRuntime(runtime_MOD);
535 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700536 case OP_PLUS:
537 o4(0xE0810000); // add r0,r1,r0
538 break;
539 case OP_MINUS:
540 o4(0xE0410000); // sub r0,r1,r0
541 break;
542 case OP_SHIFT_LEFT:
543 o4(0xE1A00011); // lsl r0,r1,r0
544 break;
545 case OP_SHIFT_RIGHT:
546 o4(0xE1A00051); // asr r0,r1,r0
547 break;
548 case OP_BIT_AND:
549 o4(0xE0010000); // and r0,r1,r0
550 break;
551 case OP_BIT_XOR:
552 o4(0xE0210000); // eor r0,r1,r0
553 break;
554 case OP_BIT_OR:
555 o4(0xE1810000); // orr r0,r1,r0
556 break;
557 case OP_BIT_NOT:
558 o4(0xE1E00000); // mvn r0, r0
559 break;
560 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700561 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700562 break;
563 }
Jack Palevich22305132009-05-13 10:58:45 -0700564 }
565
Jack Palevich1cdef202009-05-22 12:06:27 -0700566 virtual void clearR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700567 LOG_API("clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700568 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700569 }
570
Jack Palevich1cdef202009-05-22 12:06:27 -0700571 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700572 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700573 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700574 mStackUse += 4;
575 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700576 }
577
Jack Palevich1cdef202009-05-22 12:06:27 -0700578 virtual void popR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700579 LOG_API("popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700580 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700581 mStackUse -= 4;
582 LOG_STACK("popR1: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700583 }
584
Jack Palevich1cdef202009-05-22 12:06:27 -0700585 virtual void storeR0ToR1(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700586 LOG_API("storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700587 if (isInt) {
588 o4(0xE5810000); // str r0, [r1]
589 } else {
590 o4(0xE5C10000); // strb r0, [r1]
591 }
Jack Palevich22305132009-05-13 10:58:45 -0700592 }
593
Jack Palevich1cdef202009-05-22 12:06:27 -0700594 virtual void loadR0FromR0(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700595 LOG_API("loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700596 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700597 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700598 else
Jack Palevich69796b62009-05-14 15:42:26 -0700599 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700600 }
601
Jack Palevich1cdef202009-05-22 12:06:27 -0700602 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700603 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700604 if (ea < LOCAL) {
605 // Local, fp relative
606 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
607 error("Offset out of range: %08x", ea);
608 }
609 if (ea < 0) {
610 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
611 } else {
612 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
613 }
Jack Palevichbd894902009-05-14 19:35:31 -0700614 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700615 // Global, absolute.
616 o4(0xE59F0000); // ldr r0, .L1
617 o4(0xEA000000); // b .L99
618 o4(ea); // .L1: .word 0
619 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700620 }
Jack Palevich22305132009-05-13 10:58:45 -0700621 }
622
Jack Palevich1cdef202009-05-22 12:06:27 -0700623 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700624 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700625 if (ea < LOCAL) {
626 // Local, fp relative
627 if (ea < -4095 || ea > 4095) {
628 error("Offset out of range: %08x", ea);
629 }
630 if (ea < 0) {
631 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
632 } else {
633 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
634 }
635 } else{
636 // Global, absolute
637 o4(0xE59F1000); // ldr r1, .L1
638 o4(0xEA000000); // b .L99
639 o4(ea); // .L1: .word 0
640 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700641 }
Jack Palevich22305132009-05-13 10:58:45 -0700642 }
643
Jack Palevich1cdef202009-05-22 12:06:27 -0700644 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700645 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700646 if (ea < LOCAL) {
647 // Local, fp relative
648 if (ea < -4095 || ea > 4095) {
649 error("Offset out of range: %08x", ea);
650 }
651 if (ea < 0) {
652 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
653 } else {
654 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
655 }
Jack Palevich69796b62009-05-14 15:42:26 -0700656 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700657 // Global, absolute
658 o4(0xE59F2000); // ldr r2, .L1
659 o4(0xEA000000); // b .L99
660 o4(ea); // .L1: .word ea
661 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700662 }
Jack Palevich22305132009-05-13 10:58:45 -0700663
Jack Palevich4d93f302009-05-15 13:30:00 -0700664 if (isIncDec) {
665 switch (op) {
666 case OP_INCREMENT:
667 o4(0xE2801001); // add r1, r0, #1
668 break;
669 case OP_DECREMENT:
670 o4(0xE2401001); // sub r1, r0, #1
671 break;
672 default:
673 error("unknown opcode: %d", op);
674 }
675 if (ea < LOCAL) {
676 // Local, fp relative
677 // Don't need range check, was already checked above
678 if (ea < 0) {
679 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
680 } else {
681 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
682 }
683 } else{
684 // Global, absolute
685 // r2 is already set up from before.
686 o4(0xE5821000); // str r1, [r2]
687 }
Jack Palevichbd894902009-05-14 19:35:31 -0700688 }
Jack Palevich22305132009-05-13 10:58:45 -0700689 }
690
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700691 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700692 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700693 return o4(0xE24DDF00); // Placeholder
694 }
695
Jack Palevich1cdef202009-05-22 12:06:27 -0700696 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700697 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700698 if (l < 0 || l > 4096-4) {
699 error("l out of range for stack offset: 0x%08x", l);
700 }
701 o4(0xE58D0000 + l); // str r0, [sp, #4]
702 }
703
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700704 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700705 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700706 int argCount = l >> 2;
707 int argumentStackUse = l;
708 if (argCount > 0) {
709 int regArgCount = argCount > 4 ? 4 : argCount;
710 argumentStackUse -= regArgCount * 4;
711 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
712 }
713 mStackUse += argumentStackUse;
714
715 // Align stack.
716 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
717 * STACK_ALIGNMENT);
718 mStackAlignmentAdjustment = 0;
719 if (missalignment > 0) {
720 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
721 }
722 l += mStackAlignmentAdjustment;
723
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700724 if (l < 0 || l > 0x3FC) {
725 error("L out of range for stack adjustment: 0x%08x", l);
726 }
727 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700728 mStackUse += mStackAlignmentAdjustment;
729 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
730 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700731 }
732
Jack Palevich22305132009-05-13 10:58:45 -0700733 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700734 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700735 // Forward calls are always short (local)
736 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700737 }
738
739 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700740 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700741 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700742 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700743 if (t >= - (1 << 25) && t < (1 << 25)) {
744 o4(0xEB000000 | encodeAddress(t));
745 } else {
746 // Long call.
747 o4(0xE59FC000); // ldr r12, .L1
748 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700749 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700750 o4(0xE08CC00F); // .L99: add r12,pc
751 o4(0xE12FFF3C); // blx r12
752 }
Jack Palevich22305132009-05-13 10:58:45 -0700753 }
754
755 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700756 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700757 int argCount = l >> 2;
758 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700759 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700760 if (adjustedL < 0 || adjustedL > 4096-4) {
761 error("l out of range for stack offset: 0x%08x", l);
762 }
763 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
764 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700765 }
766
Jack Palevich7810bc92009-05-15 14:31:47 -0700767 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700768 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700769 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700770 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700771 int stackUse = stackArgs + (isIndirect ? 1 : 0)
772 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700773 if (stackUse) {
774 if (stackUse < 0 || stackUse > 255) {
775 error("L out of range for stack adjustment: 0x%08x", l);
776 }
777 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -0700778 mStackUse -= stackUse * 4;
779 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700780 }
Jack Palevich22305132009-05-13 10:58:45 -0700781 }
782
Jack Palevicha6535612009-05-13 16:24:17 -0700783 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700784 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700785 }
786
787 /* output a symbol and patch all calls to it */
788 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700789 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700790 int n;
791 int base = getBase();
792 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700793 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700794 while (t) {
795 int data = * (int*) t;
796 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
797 if (decodedOffset == 0) {
798 n = 0;
799 } else {
800 n = base + decodedOffset; /* next value */
801 }
802 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
803 | encodeRelAddress(pc - t - 8);
804 t = n;
805 }
806 }
807
Jack Palevich1cdef202009-05-22 12:06:27 -0700808 virtual int finishCompile() {
809#if defined(__arm__)
810 const long base = long(getBase());
811 const long curr = long(getPC());
812 int err = cacheflush(base, curr, 0);
813 return err;
814#else
815 return 0;
816#endif
817 }
818
Jack Palevicha6535612009-05-13 16:24:17 -0700819 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700820#ifdef ENABLE_ARM_DISASSEMBLY
821 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700822 disasm_interface_t di;
823 di.di_readword = disassemble_readword;
824 di.di_printaddr = disassemble_printaddr;
825 di.di_printf = disassemble_printf;
826
827 int base = getBase();
828 int pc = getPC();
829 for(int i = base; i < pc; i += 4) {
830 fprintf(out, "%08x: %08x ", i, *(int*) i);
831 ::disasm(&di, i, 0);
832 }
Jack Palevich09555c72009-05-27 12:25:55 -0700833#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700834 return 0;
835 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700836
Jack Palevich22305132009-05-13 10:58:45 -0700837 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700838 static FILE* disasmOut;
839
840 static u_int
841 disassemble_readword(u_int address)
842 {
843 return(*((u_int *)address));
844 }
845
846 static void
847 disassemble_printaddr(u_int address)
848 {
849 fprintf(disasmOut, "0x%08x", address);
850 }
851
852 static void
853 disassemble_printf(const char *fmt, ...) {
854 va_list ap;
855 va_start(ap, fmt);
856 vfprintf(disasmOut, fmt, ap);
857 va_end(ap);
858 }
859
860 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
861
862 /** Encode a relative address that might also be
863 * a label.
864 */
865 int encodeAddress(int value) {
866 int base = getBase();
867 if (value >= base && value <= getPC() ) {
868 // This is a label, encode it relative to the base.
869 value = value - base;
870 }
871 return encodeRelAddress(value);
872 }
873
874 int encodeRelAddress(int value) {
875 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
876 }
Jack Palevich22305132009-05-13 10:58:45 -0700877
Jack Palevich3d474a72009-05-15 15:12:38 -0700878 typedef int (*int2FnPtr)(int a, int b);
879 void callRuntime(int2FnPtr fn) {
880 o4(0xE59F2000); // ldr r2, .L1
881 o4(0xEA000000); // b .L99
882 o4((int) fn); //.L1: .word fn
883 o4(0xE12FFF32); //.L99: blx r2
884 }
885
886 static int runtime_DIV(int a, int b) {
887 return b / a;
888 }
889
890 static int runtime_MOD(int a, int b) {
891 return b % a;
892 }
-b master422972c2009-06-17 19:13:52 -0700893
894 static const int STACK_ALIGNMENT = 8;
895 int mStackUse;
896 // This variable holds the amount we adjusted the stack in the most
897 // recent endFunctionCallArguments call. It's examined by the
898 // following adjustStackAfterCall call.
899 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -0700900 };
901
Jack Palevich09555c72009-05-27 12:25:55 -0700902#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700903
904#ifdef PROVIDE_X86_CODEGEN
905
Jack Palevich21a15a22009-05-11 14:49:29 -0700906 class X86CodeGenerator : public CodeGenerator {
907 public:
908 X86CodeGenerator() {}
909 virtual ~X86CodeGenerator() {}
910
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700911 /* returns address to patch with local variable size
912 */
Jack Palevich546b2242009-05-13 15:10:04 -0700913 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700914 o(0xe58955); /* push %ebp, mov %esp, %ebp */
915 return oad(0xec81, 0); /* sub $xxx, %esp */
916 }
917
Jack Palevich546b2242009-05-13 15:10:04 -0700918 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700919 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700920 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700921 }
922
Jack Palevich21a15a22009-05-11 14:49:29 -0700923 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700924 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700925 oad(0xb8, t); /* mov $xx, %eax */
926 }
927
Jack Palevich22305132009-05-13 10:58:45 -0700928 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700929 return psym(0xe9, t);
930 }
931
932 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700933 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700934 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
935 return psym(0x84 + l, t);
936 }
937
Jack Palevich22305132009-05-13 10:58:45 -0700938 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700939 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700940 o(0xc139); /* cmp %eax,%ecx */
941 li(0);
942 o(0x0f); /* setxx %al */
943 o(t + 0x90);
944 o(0xc0);
945 }
946
Jack Palevich546b2242009-05-13 15:10:04 -0700947 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700948 o(decodeOp(op));
949 if (op == OP_MOD)
950 o(0x92); /* xchg %edx, %eax */
951 }
952
Jack Palevich1cdef202009-05-22 12:06:27 -0700953 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700954 oad(0xb9, 0); /* movl $0, %ecx */
955 }
956
Jack Palevich1cdef202009-05-22 12:06:27 -0700957 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700958 o(0x50); /* push %eax */
959 }
960
Jack Palevich1cdef202009-05-22 12:06:27 -0700961 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700962 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700963 }
964
Jack Palevich1cdef202009-05-22 12:06:27 -0700965 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700966 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
967 }
968
Jack Palevich1cdef202009-05-22 12:06:27 -0700969 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700970 if (isInt)
971 o(0x8b); /* mov (%eax), %eax */
972 else
973 o(0xbe0f); /* movsbl (%eax), %eax */
974 ob(0); /* add zero in code */
975 }
976
Jack Palevich1cdef202009-05-22 12:06:27 -0700977 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700978 gmov(10, ea); /* leal EA, %eax */
979 }
980
Jack Palevich1cdef202009-05-22 12:06:27 -0700981 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700982 gmov(6, ea); /* mov %eax, EA */
983 }
984
Jack Palevich1cdef202009-05-22 12:06:27 -0700985 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700986 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700987 if (isIncDec) {
988 /* Implement post-increment or post decrement.
989 */
990 gmov(0, ea); /* 83 ADD */
991 o(decodeOp(op));
992 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700993 }
994
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700995 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700996 return oad(0xec81, 0); /* sub $xxx, %esp */
997 }
998
Jack Palevich1cdef202009-05-22 12:06:27 -0700999 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001000 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1001 }
1002
Jack Palevich7810bc92009-05-15 14:31:47 -07001003 virtual void endFunctionCallArguments(int a, int l) {
1004 * (int*) a = l;
1005 }
1006
Jack Palevich22305132009-05-13 10:58:45 -07001007 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001008 return psym(0xe8, symbol); /* call xxx */
1009 }
1010
Jack Palevich22305132009-05-13 10:58:45 -07001011 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001012 psym(0xe8, t); /* call xxx */
1013 }
1014
Jack Palevich22305132009-05-13 10:58:45 -07001015 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001016 oad(0x2494ff, l); /* call *xxx(%esp) */
1017 }
1018
Jack Palevich7810bc92009-05-15 14:31:47 -07001019 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1020 if (isIndirect) {
1021 l += 4;
1022 }
-b master422972c2009-06-17 19:13:52 -07001023 if (l > 0) {
1024 oad(0xc481, l); /* add $xxx, %esp */
1025 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001026 }
1027
Jack Palevicha6535612009-05-13 16:24:17 -07001028 virtual int jumpOffset() {
1029 return 5;
1030 }
1031
1032 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001033 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001034 }
1035
Jack Paleviche7b59062009-05-19 17:12:17 -07001036 /* output a symbol and patch all calls to it */
1037 virtual void gsym(int t) {
1038 int n;
1039 int pc = getPC();
1040 while (t) {
1041 n = *(int *) t; /* next value */
1042 *(int *) t = pc - t - 4;
1043 t = n;
1044 }
1045 }
1046
Jack Palevich1cdef202009-05-22 12:06:27 -07001047 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001048 size_t pagesize = 4096;
1049 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1050 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1051 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1052 if (err) {
1053 error("mprotect() failed: %d", errno);
1054 }
1055 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001056 }
1057
Jack Palevich21a15a22009-05-11 14:49:29 -07001058 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001059
1060 /** Output 1 to 4 bytes.
1061 *
1062 */
1063 void o(int n) {
1064 /* cannot use unsigned, so we must do a hack */
1065 while (n && n != -1) {
1066 ob(n & 0xff);
1067 n = n >> 8;
1068 }
1069 }
1070
1071 /* psym is used to put an instruction with a data field which is a
1072 reference to a symbol. It is in fact the same as oad ! */
1073 int psym(int n, int t) {
1074 return oad(n, t);
1075 }
1076
1077 /* instruction + address */
1078 int oad(int n, int t) {
1079 o(n);
1080 int result = getPC();
1081 o4(t);
1082 return result;
1083 }
1084
1085
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001086 static const int operatorHelper[];
1087
1088 int decodeOp(int op) {
1089 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001090 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001091 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001092 }
1093 return operatorHelper[op];
1094 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001095
Jack Palevich546b2242009-05-13 15:10:04 -07001096 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001097 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001098 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001099 }
1100 };
1101
Jack Paleviche7b59062009-05-19 17:12:17 -07001102#endif // PROVIDE_X86_CODEGEN
1103
Jack Palevichb67b18f2009-06-11 21:12:23 -07001104#ifdef PROVIDE_TRACE_CODEGEN
1105 class TraceCodeGenerator : public CodeGenerator {
1106 private:
1107 CodeGenerator* mpBase;
1108
1109 public:
1110 TraceCodeGenerator(CodeGenerator* pBase) {
1111 mpBase = pBase;
1112 }
1113
1114 virtual ~TraceCodeGenerator() {
1115 delete mpBase;
1116 }
1117
1118 virtual void init(CodeBuf* pCodeBuf) {
1119 mpBase->init(pCodeBuf);
1120 }
1121
1122 void setErrorSink(ErrorSink* pErrorSink) {
1123 mpBase->setErrorSink(pErrorSink);
1124 }
1125
1126 /* returns address to patch with local variable size
1127 */
1128 virtual int functionEntry(int argCount) {
1129 int result = mpBase->functionEntry(argCount);
1130 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1131 return result;
1132 }
1133
1134 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1135 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1136 argCount, localVariableAddress, localVariableSize);
1137 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1138 }
1139
1140 /* load immediate value */
1141 virtual void li(int t) {
1142 fprintf(stderr, "li(%d)\n", t);
1143 mpBase->li(t);
1144 }
1145
1146 virtual int gjmp(int t) {
1147 int result = mpBase->gjmp(t);
1148 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1149 return result;
1150 }
1151
1152 /* l = 0: je, l == 1: jne */
1153 virtual int gtst(bool l, int t) {
1154 int result = mpBase->gtst(l, t);
1155 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1156 return result;
1157 }
1158
1159 virtual void gcmp(int op) {
1160 fprintf(stderr, "gcmp(%d)\n", op);
1161 mpBase->gcmp(op);
1162 }
1163
1164 virtual void genOp(int op) {
1165 fprintf(stderr, "genOp(%d)\n", op);
1166 mpBase->genOp(op);
1167 }
1168
1169 virtual void clearR1() {
1170 fprintf(stderr, "clearR1()\n");
1171 mpBase->clearR1();
1172 }
1173
1174 virtual void pushR0() {
1175 fprintf(stderr, "pushR0()\n");
1176 mpBase->pushR0();
1177 }
1178
1179 virtual void popR1() {
1180 fprintf(stderr, "popR1()\n");
1181 mpBase->popR1();
1182 }
1183
1184 virtual void storeR0ToR1(bool isInt) {
1185 fprintf(stderr, "storeR0ToR1(%d)\n", isInt);
1186 mpBase->storeR0ToR1(isInt);
1187 }
1188
1189 virtual void loadR0FromR0(bool isInt) {
1190 fprintf(stderr, "loadR0FromR0(%d)\n", isInt);
1191 mpBase->loadR0FromR0(isInt);
1192 }
1193
1194 virtual void leaR0(int ea) {
1195 fprintf(stderr, "leaR0(%d)\n", ea);
1196 mpBase->leaR0(ea);
1197 }
1198
1199 virtual void storeR0(int ea) {
1200 fprintf(stderr, "storeR0(%d)\n", ea);
1201 mpBase->storeR0(ea);
1202 }
1203
1204 virtual void loadR0(int ea, bool isIncDec, int op) {
1205 fprintf(stderr, "loadR0(%d, %d, %d)\n", ea, isIncDec, op);
1206 mpBase->loadR0(ea, isIncDec, op);
1207 }
1208
1209 virtual int beginFunctionCallArguments() {
1210 int result = mpBase->beginFunctionCallArguments();
1211 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1212 return result;
1213 }
1214
1215 virtual void storeR0ToArg(int l) {
1216 fprintf(stderr, "storeR0ToArg(%d)\n", l);
1217 mpBase->storeR0ToArg(l);
1218 }
1219
1220 virtual void endFunctionCallArguments(int a, int l) {
1221 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1222 mpBase->endFunctionCallArguments(a, l);
1223 }
1224
1225 virtual int callForward(int symbol) {
1226 int result = mpBase->callForward(symbol);
1227 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1228 return result;
1229 }
1230
1231 virtual void callRelative(int t) {
1232 fprintf(stderr, "callRelative(%d)\n", t);
1233 mpBase->callRelative(t);
1234 }
1235
1236 virtual void callIndirect(int l) {
1237 fprintf(stderr, "callIndirect(%d)\n", l);
1238 mpBase->callIndirect(l);
1239 }
1240
1241 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1242 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1243 mpBase->adjustStackAfterCall(l, isIndirect);
1244 }
1245
1246 virtual int jumpOffset() {
1247 return mpBase->jumpOffset();
1248 }
1249
1250 virtual int disassemble(FILE* out) {
1251 return mpBase->disassemble(out);
1252 }
1253
1254 /* output a symbol and patch all calls to it */
1255 virtual void gsym(int t) {
1256 fprintf(stderr, "gsym(%d)\n", t);
1257 mpBase->gsym(t);
1258 }
1259
1260 virtual int finishCompile() {
1261 int result = mpBase->finishCompile();
1262 fprintf(stderr, "finishCompile() = %d\n", result);
1263 return result;
1264 }
1265 };
1266
1267#endif // PROVIDE_TRACE_CODEGEN
1268
Jack Palevich569f1352009-06-29 14:29:08 -07001269
1270 // Subset of STL vector.
1271 template<class E> class Vector {
1272 public:
1273 Vector() {
1274 mpBase = 0;
1275 mUsed = 0;
1276 mSize = 0;
1277 }
1278
1279 ~Vector() {
1280 if (mpBase) {
1281 for(size_t i = 0; i < mUsed; i++) {
1282 mpBase[mUsed].~E();
1283 }
1284 free(mpBase);
1285 }
1286 }
1287
1288 inline E& operator[](size_t i) {
1289 return mpBase[i];
1290 }
1291
1292 inline E& front() {
1293 return mpBase[0];
1294 }
1295
1296 inline E& back() {
1297 return mpBase[mUsed - 1];
1298 }
1299
1300 void pop_back() {
1301 mUsed -= 1;
1302 mpBase[mUsed].~E();
1303 }
1304
1305 void push_back(const E& item) {
1306 * ensure(1) = item;
1307 }
1308
1309 size_t size() {
1310 return mUsed;
1311 }
1312
1313 private:
1314 E* ensure(int n) {
1315 size_t newUsed = mUsed + n;
1316 if (newUsed > mSize) {
1317 size_t newSize = mSize * 2 + 10;
1318 if (newSize < newUsed) {
1319 newSize = newUsed;
1320 }
1321 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1322 mSize = newSize;
1323 }
1324 E* result = mpBase + mUsed;
1325 mUsed = newUsed;
1326 return result;
1327 }
1328
1329 E* mpBase;
1330 size_t mUsed;
1331 size_t mSize;
1332 };
1333
1334 class Arena {
1335 public:
1336 // Used to record a given allocation amount.
1337 // Used:
1338 // Mark mark = arena.mark();
1339 // ... lots of arena.allocate()
1340 // arena.free(mark);
1341
1342 struct Mark {
1343 size_t chunk;
1344 size_t offset;
1345 };
1346
1347 Arena() {
1348 mCurrentChunk = 0;
1349 Chunk start(CHUNK_SIZE);
1350 mData.push_back(start);
1351 }
1352
1353 ~Arena() {
1354 for(size_t i = 0; i < mData.size(); i++) {
1355 mData[i].free();
1356 }
1357 }
1358
1359 // Alloc using the standard alignment size safe for any variable
1360 void* alloc(size_t size) {
1361 return alloc(size, 8);
1362 }
1363
1364 Mark mark(){
1365 Mark result;
1366 result.chunk = mCurrentChunk;
1367 result.offset = mData[mCurrentChunk].mOffset;
1368 return result;
1369 }
1370
1371 void freeToMark(const Mark& mark) {
1372 mCurrentChunk = mark.chunk;
1373 mData[mCurrentChunk].mOffset = mark.offset;
1374 }
1375
1376 private:
1377 // Allocate memory aligned to a given size
1378 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
1379 // Memory is not zero filled.
1380
1381 void* alloc(size_t size, size_t alignment) {
1382 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
1383 if (mCurrentChunk + 1 < mData.size()) {
1384 mCurrentChunk++;
1385 } else {
1386 size_t allocSize = CHUNK_SIZE;
1387 if (allocSize < size + alignment - 1) {
1388 allocSize = size + alignment - 1;
1389 }
1390 Chunk chunk(allocSize);
1391 mData.push_back(chunk);
1392 mCurrentChunk++;
1393 }
1394 }
1395 return mData[mCurrentChunk].allocate(size, alignment);
1396 }
1397
1398 static const size_t CHUNK_SIZE = 128*1024;
1399 // Note: this class does not deallocate its
1400 // memory when it's destroyed. It depends upon
1401 // its parent to deallocate the memory.
1402 struct Chunk {
1403 Chunk() {
1404 mpData = 0;
1405 mSize = 0;
1406 mOffset = 0;
1407 }
1408
1409 Chunk(size_t size) {
1410 mSize = size;
1411 mpData = (char*) malloc(size);
1412 mOffset = 0;
1413 }
1414
1415 ~Chunk() {
1416 // Doesn't deallocate memory.
1417 }
1418
1419 void* allocate(size_t size, size_t alignment) {
1420 size_t alignedOffset = aligned(mOffset, alignment);
1421 void* result = mpData + alignedOffset;
1422 mOffset = alignedOffset + size;
1423 return result;
1424 }
1425
1426 void free() {
1427 if (mpData) {
1428 ::free(mpData);
1429 mpData = 0;
1430 }
1431 }
1432
1433 size_t remainingCapacity(size_t alignment) {
1434 return aligned(mSize, alignment) - aligned(mOffset, alignment);
1435 }
1436
1437 // Assume alignment is a power of two
1438 inline size_t aligned(size_t v, size_t alignment) {
1439 size_t mask = alignment-1;
1440 return (v + mask) & ~mask;
1441 }
1442
1443 char* mpData;
1444 size_t mSize;
1445 size_t mOffset;
1446 };
1447
1448 size_t mCurrentChunk;
1449
1450 Vector<Chunk> mData;
1451 };
1452
1453 typedef int tokenid_t;
1454 struct VariableInfo;
1455
1456 struct Token {
1457 int hash;
1458 size_t length;
1459 char* pText;
1460 tokenid_t id;
1461
1462 // Current values for the token
1463 char* mpMacroDefinition;
1464 VariableInfo* mpVariableInfo;
1465 };
1466
1467 class TokenTable {
1468 public:
1469 // Don't use 0..0xff, allows characters and operators to be tokens too.
1470
1471 static const int TOKEN_BASE = 0x100;
1472 TokenTable() {
1473 mpMap = hashmapCreate(128, hashFn, equalsFn);
1474 }
1475
1476 ~TokenTable() {
1477 hashmapFree(mpMap);
1478 }
1479
1480 void setArena(Arena* pArena) {
1481 mpArena = pArena;
1482 }
1483
1484 // Returns a token for a given string of characters.
1485 tokenid_t intern(const char* pText, size_t length) {
1486 Token probe;
1487 int hash = hashmapHash((void*) pText, length);
1488 {
1489 Token probe;
1490 probe.hash = hash;
1491 probe.length = length;
1492 probe.pText = (char*) pText;
1493 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
1494 if (pValue) {
1495 // printf("intern - found existing %s for %d\n",
1496 // pValue->pText, pValue->id);
1497 return pValue->id;
1498 }
1499 }
1500
1501 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
1502 memset(pToken, 0, sizeof(*pToken));
1503 pToken->hash = hash;
1504 pToken->length = length;
1505 pToken->pText = (char*) mpArena->alloc(length + 1);
1506 memcpy(pToken->pText, pText, length);
1507 pToken->pText[length] = 0;
1508 pToken->id = mTokens.size() + TOKEN_BASE;
1509 mTokens.push_back(pToken);
1510 hashmapPut(mpMap, pToken, pToken);
1511 // printf("intern - new token %s %d\n", pToken->pText, pToken->id);
1512 return pToken->id;
1513 }
1514
1515 // Return the Token for a given tokenid.
1516 Token& operator[](tokenid_t id) {
1517 return *mTokens[id - TOKEN_BASE];
1518 }
1519
1520 inline size_t size() {
1521 return mTokens.size();
1522 }
1523
1524 private:
1525
1526 static int hashFn(void* pKey) {
1527 Token* pToken = (Token*) pKey;
1528 return pToken->hash;
1529 }
1530
1531 static bool equalsFn(void* keyA, void* keyB) {
1532 Token* pTokenA = (Token*) keyA;
1533 Token* pTokenB = (Token*) keyB;
1534 // Don't need to compare hash values, they should always be equal
1535 return pTokenA->length == pTokenB->length
1536 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
1537 }
1538
1539 Hashmap* mpMap;
1540 Vector<Token*> mTokens;
1541 Arena* mpArena;
1542 };
1543
Jack Palevich1cdef202009-05-22 12:06:27 -07001544 class InputStream {
1545 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001546 int getChar() {
1547 if (bumpLine) {
1548 line++;
1549 bumpLine = false;
1550 }
1551 int ch = get();
1552 if (ch == '\n') {
1553 bumpLine = true;
1554 }
1555 return ch;
1556 }
1557 int getLine() {
1558 return line;
1559 }
1560 protected:
1561 InputStream() :
1562 line(1), bumpLine(false) {
1563 }
1564 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001565 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001566 int line;
1567 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001568 };
1569
1570 class FileInputStream : public InputStream {
1571 public:
1572 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001573 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001574 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001575 FILE* f;
1576 };
1577
1578 class TextInputStream : public InputStream {
1579 public:
1580 TextInputStream(const char* text, size_t textLength)
1581 : pText(text), mTextLength(textLength), mPosition(0) {
1582 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001583
1584 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001585 virtual int get() {
1586 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1587 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001588
Jack Palevich1cdef202009-05-22 12:06:27 -07001589 const char* pText;
1590 size_t mTextLength;
1591 size_t mPosition;
1592 };
1593
Jack Palevicheedf9d22009-06-04 16:23:40 -07001594 class String {
1595 public:
1596 String() {
1597 mpBase = 0;
1598 mUsed = 0;
1599 mSize = 0;
1600 }
1601
Jack Palevich303d8ff2009-06-11 19:06:24 -07001602 String(const char* item, int len, bool adopt) {
1603 if (len < 0) {
1604 len = strlen(item);
1605 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001606 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001607 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001608 mUsed = len;
1609 mSize = len + 1;
1610 } else {
1611 mpBase = 0;
1612 mUsed = 0;
1613 mSize = 0;
1614 appendBytes(item, len);
1615 }
1616 }
1617
Jack Palevich303d8ff2009-06-11 19:06:24 -07001618 String(const String& other) {
1619 mpBase = 0;
1620 mUsed = 0;
1621 mSize = 0;
1622 appendBytes(other.getUnwrapped(), other.len());
1623 }
1624
Jack Palevicheedf9d22009-06-04 16:23:40 -07001625 ~String() {
1626 if (mpBase) {
1627 free(mpBase);
1628 }
1629 }
1630
Jack Palevicha6baa232009-06-12 11:25:59 -07001631 String& operator=(const String& other) {
1632 clear();
1633 appendBytes(other.getUnwrapped(), other.len());
1634 return *this;
1635 }
1636
Jack Palevich303d8ff2009-06-11 19:06:24 -07001637 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001638 return mpBase;
1639 }
1640
Jack Palevich303d8ff2009-06-11 19:06:24 -07001641 void clear() {
1642 mUsed = 0;
1643 if (mSize > 0) {
1644 mpBase[0] = 0;
1645 }
1646 }
1647
Jack Palevicheedf9d22009-06-04 16:23:40 -07001648 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001649 appendBytes(s, strlen(s));
1650 }
1651
1652 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001653 memcpy(ensure(n), s, n + 1);
1654 }
1655
1656 void append(char c) {
1657 * ensure(1) = c;
1658 }
1659
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001660 char* orphan() {
1661 char* result = mpBase;
1662 mpBase = 0;
1663 mUsed = 0;
1664 mSize = 0;
1665 return result;
1666 }
1667
Jack Palevicheedf9d22009-06-04 16:23:40 -07001668 void printf(const char* fmt,...) {
1669 va_list ap;
1670 va_start(ap, fmt);
1671 vprintf(fmt, ap);
1672 va_end(ap);
1673 }
1674
1675 void vprintf(const char* fmt, va_list ap) {
1676 char* temp;
1677 int numChars = vasprintf(&temp, fmt, ap);
1678 memcpy(ensure(numChars), temp, numChars+1);
1679 free(temp);
1680 }
1681
Jack Palevich303d8ff2009-06-11 19:06:24 -07001682 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001683 return mUsed;
1684 }
1685
1686 private:
1687 char* ensure(int n) {
1688 size_t newUsed = mUsed + n;
1689 if (newUsed > mSize) {
1690 size_t newSize = mSize * 2 + 10;
1691 if (newSize < newUsed) {
1692 newSize = newUsed;
1693 }
1694 mpBase = (char*) realloc(mpBase, newSize + 1);
1695 mSize = newSize;
1696 }
1697 mpBase[newUsed] = '\0';
1698 char* result = mpBase + mUsed;
1699 mUsed = newUsed;
1700 return result;
1701 }
1702
1703 char* mpBase;
1704 size_t mUsed;
1705 size_t mSize;
1706 };
1707
Jack Palevich569f1352009-06-29 14:29:08 -07001708 void internKeywords() {
1709 // Note: order has to match TOK_ constants
1710 static const char* keywords[] = {
1711 "int",
1712 "char",
1713 "void",
1714 "if",
1715 "else",
1716 "while",
1717 "break",
1718 "return",
1719 "for",
1720 "pragma",
1721 "define",
1722 "auto",
1723 "case",
1724 "const",
1725 "continue",
1726 "default",
1727 "do",
1728 "double",
1729 "enum",
1730 "extern",
1731 "float",
1732 "goto",
1733 "long",
1734 "register",
1735 "short",
1736 "signed",
1737 "sizeof",
1738 "static",
1739 "struct",
1740 "switch",
1741 "typedef",
1742 "union",
1743 "unsigned",
1744 "volatile",
1745 "_Bool",
1746 "_Complex",
1747 "_Imaginary",
1748 "inline",
1749 "restrict",
1750 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001751
Jack Palevich569f1352009-06-29 14:29:08 -07001752 for(int i = 0; keywords[i]; i++) {
1753 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001754 }
Jack Palevich569f1352009-06-29 14:29:08 -07001755 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001756
Jack Palevich36d94142009-06-08 15:55:32 -07001757 struct InputState {
1758 InputStream* pStream;
1759 int oldCh;
1760 };
1761
Jack Palevich2db168f2009-06-11 14:29:47 -07001762 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001763 void* pAddress;
1764 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07001765 tokenid_t tok;
1766 size_t level;
1767 VariableInfo* pOldDefinition;
Jack Palevich2db168f2009-06-11 14:29:47 -07001768 };
1769
Jack Palevich303d8ff2009-06-11 19:06:24 -07001770 class SymbolStack {
1771 public:
1772 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07001773 mpArena = 0;
1774 mpTokenTable = 0;
1775 }
1776
1777 void setArena(Arena* pArena) {
1778 mpArena = pArena;
1779 }
1780
1781 void setTokenTable(TokenTable* pTokenTable) {
1782 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001783 }
1784
1785 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07001786 Mark mark;
1787 mark.mArenaMark = mpArena->mark();
1788 mark.mSymbolHead = mStack.size();
1789 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07001790 }
1791
1792 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07001793 // Undo any shadowing that was done:
1794 Mark mark = mLevelStack.back();
1795 mLevelStack.pop_back();
1796 while (mStack.size() > mark.mSymbolHead) {
1797 VariableInfo* pV = mStack.back();
1798 mStack.pop_back();
1799 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001800 }
Jack Palevich569f1352009-06-29 14:29:08 -07001801 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07001802 }
1803
Jack Palevich569f1352009-06-29 14:29:08 -07001804 bool isDefinedAtCurrentLevel(tokenid_t tok) {
1805 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
1806 return pV && pV->level == level();
1807 }
1808
1809 VariableInfo* add(tokenid_t tok) {
1810 Token& token = (*mpTokenTable)[tok];
1811 VariableInfo* pOldV = token.mpVariableInfo;
1812 VariableInfo* pNewV =
1813 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
1814 memset(pNewV, 0, sizeof(VariableInfo));
1815 pNewV->tok = tok;
1816 pNewV->level = level();
1817 pNewV->pOldDefinition = pOldV;
1818 token.mpVariableInfo = pNewV;
1819 mStack.push_back(pNewV);
1820 return pNewV;
1821 }
1822
1823 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
1824 for (size_t i = 0; i < mStack.size(); i++) {
1825 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001826 break;
1827 }
1828 }
Jack Palevicha6baa232009-06-12 11:25:59 -07001829 }
1830
Jack Palevich303d8ff2009-06-11 19:06:24 -07001831 private:
Jack Palevich569f1352009-06-29 14:29:08 -07001832 inline size_t level() {
1833 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07001834 }
1835
Jack Palevich569f1352009-06-29 14:29:08 -07001836 struct Mark {
1837 Arena::Mark mArenaMark;
1838 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001839 };
1840
Jack Palevich569f1352009-06-29 14:29:08 -07001841 Arena* mpArena;
1842 TokenTable* mpTokenTable;
1843 Vector<VariableInfo*> mStack;
1844 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001845 };
Jack Palevich36d94142009-06-08 15:55:32 -07001846
1847 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07001848 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07001849 intptr_t tokc; // token extra info
1850 int tokl; // token operator level
1851 intptr_t rsym; // return symbol
1852 intptr_t loc; // local variable index
1853 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07001854 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07001855 char* dptr; // Macro state: Points to macro text during macro playback.
1856 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07001857 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07001858
1859 // Arena for the duration of the compile
1860 Arena mGlobalArena;
1861 // Arena for data that's only needed when compiling a single function
1862 Arena mLocalArena;
1863
1864 TokenTable mTokenTable;
1865 SymbolStack mGlobals;
1866 SymbolStack mLocals;
1867
Jack Palevich36d94142009-06-08 15:55:32 -07001868 InputStream* file;
1869
1870 CodeBuf codeBuf;
1871 CodeGenerator* pGen;
1872
Jack Palevicheedf9d22009-06-04 16:23:40 -07001873 String mErrorBuf;
1874
Jack Palevicheedf9d22009-06-04 16:23:40 -07001875 String mPragmas;
1876 int mPragmaStringCount;
1877
Jack Palevich21a15a22009-05-11 14:49:29 -07001878 static const int ALLOC_SIZE = 99999;
1879
Jack Palevich303d8ff2009-06-11 19:06:24 -07001880 static const int TOK_DUMMY = 1;
1881 static const int TOK_NUM = 2;
1882
1883 // 3..255 are character and/or operators
1884
Jack Palevich2db168f2009-06-11 14:29:47 -07001885 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07001886 // Order has to match string list in "internKeywords".
1887 enum {
1888 TOK_KEYWORD = TokenTable::TOKEN_BASE,
1889 TOK_INT = TOK_KEYWORD,
1890 TOK_CHAR,
1891 TOK_VOID,
1892 TOK_IF,
1893 TOK_ELSE,
1894 TOK_WHILE,
1895 TOK_BREAK,
1896 TOK_RETURN,
1897 TOK_FOR,
1898 TOK_PRAGMA,
1899 TOK_DEFINE,
1900 TOK_AUTO,
1901 TOK_CASE,
1902 TOK_CONST,
1903 TOK_CONTINUE,
1904 TOK_DEFAULT,
1905 TOK_DO,
1906 TOK_DOUBLE,
1907 TOK_ENUM,
1908 TOK_EXTERN,
1909 TOK_FLOAT,
1910 TOK_GOTO,
1911 TOK_LONG,
1912 TOK_REGISTER,
1913 TOK_SHORT,
1914 TOK_SIGNED,
1915 TOK_SIZEOF,
1916 TOK_STATIC,
1917 TOK_STRUCT,
1918 TOK_SWITCH,
1919 TOK_TYPEDEF,
1920 TOK_UNION,
1921 TOK_UNSIGNED,
1922 TOK_VOLATILE,
1923 TOK__BOOL,
1924 TOK__COMPLEX,
1925 TOK__IMAGINARY,
1926 TOK_INLINE,
1927 TOK_RESTRICT,
1928 // Symbols start after tokens
1929 TOK_SYMBOL
1930 };
Jack Palevich21a15a22009-05-11 14:49:29 -07001931
1932 static const int LOCAL = 0x200;
1933
1934 static const int SYM_FORWARD = 0;
1935 static const int SYM_DEFINE = 1;
1936
1937 /* tokens in string heap */
1938 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07001939
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001940 static const int OP_INCREMENT = 0;
1941 static const int OP_DECREMENT = 1;
1942 static const int OP_MUL = 2;
1943 static const int OP_DIV = 3;
1944 static const int OP_MOD = 4;
1945 static const int OP_PLUS = 5;
1946 static const int OP_MINUS = 6;
1947 static const int OP_SHIFT_LEFT = 7;
1948 static const int OP_SHIFT_RIGHT = 8;
1949 static const int OP_LESS_EQUAL = 9;
1950 static const int OP_GREATER_EQUAL = 10;
1951 static const int OP_LESS = 11;
1952 static const int OP_GREATER = 12;
1953 static const int OP_EQUALS = 13;
1954 static const int OP_NOT_EQUALS = 14;
1955 static const int OP_LOGICAL_AND = 15;
1956 static const int OP_LOGICAL_OR = 16;
1957 static const int OP_BIT_AND = 17;
1958 static const int OP_BIT_XOR = 18;
1959 static const int OP_BIT_OR = 19;
1960 static const int OP_BIT_NOT = 20;
1961 static const int OP_LOGICAL_NOT = 21;
1962 static const int OP_COUNT = 22;
1963
1964 /* Operators are searched from front, the two-character operators appear
1965 * before the single-character operators with the same first character.
1966 * @ is used to pad out single-character operators.
1967 */
1968 static const char* operatorChars;
1969 static const char operatorLevel[];
1970
Jack Palevich569f1352009-06-29 14:29:08 -07001971 /* Called when we detect an internal problem. Does nothing in production.
1972 *
1973 */
1974 void internalError() {
1975 * (char*) 0 = 0;
1976 }
1977
1978 VariableInfo* VI(tokenid_t t) {
1979 if ( t < TOK_SYMBOL || t-TOK_SYMBOL >= mTokenTable.size()) {
1980 internalError();
1981 }
1982 // printf("Looking up %s %d\n", nameof(t), t);
1983 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
1984 if (pV && pV->tok != t) {
1985 internalError();
1986 }
1987 return pV;
1988 }
1989
1990 inline bool isDefined(tokenid_t t) {
1991 return t >= TOK_SYMBOL && VI(t) != 0;
1992 }
1993
1994 inline const char* nameof(tokenid_t t) {
1995 return mTokenTable[t].pText;
1996 }
1997
Jack Palevich21a15a22009-05-11 14:49:29 -07001998 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001999 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002000 }
2001
2002 void inp() {
2003 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002004 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002005 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002006 dptr = 0;
2007 ch = dch;
2008 }
2009 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002010 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002011#if 0
2012 printf("ch='%c' 0x%x\n", ch, ch);
2013#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002014 }
2015
2016 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002017 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002018 }
2019
Jack Palevichb4758ff2009-06-12 12:49:14 -07002020 /* read a character constant, advances ch to after end of constant */
2021 int getq() {
2022 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002023 if (ch == '\\') {
2024 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002025 if (isoctal(ch)) {
2026 // 1 to 3 octal characters.
2027 val = 0;
2028 for(int i = 0; i < 3; i++) {
2029 if (isoctal(ch)) {
2030 val = (val << 3) + ch - '0';
2031 inp();
2032 }
2033 }
2034 return val;
2035 } else if (ch == 'x' || ch == 'X') {
2036 // N hex chars
2037 inp();
2038 if (! isxdigit(ch)) {
2039 error("'x' character escape requires at least one digit.");
2040 } else {
2041 val = 0;
2042 while (isxdigit(ch)) {
2043 int d = ch;
2044 if (isdigit(d)) {
2045 d -= '0';
2046 } else if (d <= 'F') {
2047 d = d - 'A' + 10;
2048 } else {
2049 d = d - 'a' + 10;
2050 }
2051 val = (val << 4) + d;
2052 inp();
2053 }
2054 }
2055 } else {
2056 int val = ch;
2057 switch (ch) {
2058 case 'a':
2059 val = '\a';
2060 break;
2061 case 'b':
2062 val = '\b';
2063 break;
2064 case 'f':
2065 val = '\f';
2066 break;
2067 case 'n':
2068 val = '\n';
2069 break;
2070 case 'r':
2071 val = '\r';
2072 break;
2073 case 't':
2074 val = '\t';
2075 break;
2076 case 'v':
2077 val = '\v';
2078 break;
2079 case '\\':
2080 val = '\\';
2081 break;
2082 case '\'':
2083 val = '\'';
2084 break;
2085 case '"':
2086 val = '"';
2087 break;
2088 case '?':
2089 val = '?';
2090 break;
2091 default:
2092 error("Undefined character escape %c", ch);
2093 break;
2094 }
2095 inp();
2096 return val;
2097 }
2098 } else {
2099 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002100 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002101 return val;
2102 }
2103
2104 static bool isoctal(int ch) {
2105 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002106 }
2107
2108 void next() {
2109 int l, a;
2110
Jack Palevich546b2242009-05-13 15:10:04 -07002111 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002112 if (ch == '#') {
2113 inp();
2114 next();
2115 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002116 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002117 } else if (tok == TOK_PRAGMA) {
2118 doPragma();
2119 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002120 error("Unsupported preprocessor directive \"%s\"",
2121 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002122 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002123 }
2124 inp();
2125 }
2126 tokl = 0;
2127 tok = ch;
2128 /* encode identifiers & numbers */
2129 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002130 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002131 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002132 pdef(ch);
2133 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002134 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002135 if (isdigit(tok)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002136 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002137 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002138 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002139 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2140 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002141 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002142 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2143 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002144 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002145 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002146 dch = ch;
2147 inp();
2148 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002149 }
2150 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002151 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002152 inp();
2153 if (tok == '\'') {
2154 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002155 tokc = getq();
2156 if (ch != '\'') {
2157 error("Expected a ' character, got %c", ch);
2158 } else {
2159 inp();
2160 }
Jack Palevich546b2242009-05-13 15:10:04 -07002161 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002162 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002163 while (ch && ch != EOF) {
2164 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002165 inp();
2166 inp();
2167 if (ch == '/')
2168 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002169 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002170 if (ch == EOF) {
2171 error("End of file inside comment.");
2172 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002173 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002174 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002175 } else if ((tok == '/') & (ch == '/')) {
2176 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002177 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002178 inp();
2179 }
2180 inp();
2181 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002182 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002183 const char* t = operatorChars;
2184 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002185 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002186 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002187 tokl = operatorLevel[opIndex];
2188 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002189 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002190#if 0
2191 printf("%c%c -> tokl=%d tokc=0x%x\n",
2192 l, a, tokl, tokc);
2193#endif
2194 if (a == ch) {
2195 inp();
2196 tok = TOK_DUMMY; /* dummy token for double tokens */
2197 }
2198 break;
2199 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002200 opIndex++;
2201 }
2202 if (l == 0) {
2203 tokl = 0;
2204 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002205 }
2206 }
2207 }
2208#if 0
2209 {
Jack Palevich569f1352009-06-29 14:29:08 -07002210 String buf;
2211 decodeToken(buf, tok);
2212 printf("%s\n", buf.getUnwrapped()); }
Jack Palevich21a15a22009-05-11 14:49:29 -07002213#endif
2214 }
2215
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002216 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002217 next();
2218 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002219 String* pName = new String();
2220 while (isspace(ch)) {
2221 inp();
2222 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002223 if (ch == '(') {
2224 delete pName;
2225 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002226 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002227 }
2228 while (isspace(ch)) {
2229 inp();
2230 }
Jack Palevich569f1352009-06-29 14:29:08 -07002231 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002232 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002233 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002234 inp();
2235 }
Jack Palevich569f1352009-06-29 14:29:08 -07002236 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2237 memcpy(pDefn, value.getUnwrapped(), value.len());
2238 pDefn[value.len()] = 0;
2239 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002240 }
2241
Jack Palevicheedf9d22009-06-04 16:23:40 -07002242 void doPragma() {
2243 // # pragma name(val)
2244 int state = 0;
2245 while(ch != EOF && ch != '\n' && state < 10) {
2246 switch(state) {
2247 case 0:
2248 if (isspace(ch)) {
2249 inp();
2250 } else {
2251 state++;
2252 }
2253 break;
2254 case 1:
2255 if (isalnum(ch)) {
2256 mPragmas.append(ch);
2257 inp();
2258 } else if (ch == '(') {
2259 mPragmas.append(0);
2260 inp();
2261 state++;
2262 } else {
2263 state = 11;
2264 }
2265 break;
2266 case 2:
2267 if (isalnum(ch)) {
2268 mPragmas.append(ch);
2269 inp();
2270 } else if (ch == ')') {
2271 mPragmas.append(0);
2272 inp();
2273 state = 10;
2274 } else {
2275 state = 11;
2276 }
2277 break;
2278 }
2279 }
2280 if(state != 10) {
2281 error("Unexpected pragma syntax");
2282 }
2283 mPragmaStringCount += 2;
2284 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002285
Jack Palevichac0e95e2009-05-29 13:53:44 -07002286 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002287 mErrorBuf.printf("%ld: ", file->getLine());
2288 mErrorBuf.vprintf(fmt, ap);
2289 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002290 }
2291
Jack Palevich8b0624c2009-05-20 12:12:06 -07002292 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002293 if (tok != c) {
2294 error("'%c' expected", c);
2295 }
2296 next();
2297 }
2298
Jack Palevich21a15a22009-05-11 14:49:29 -07002299 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07002300 void unary(intptr_t l) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002301 intptr_t n, t, a;
2302 int c;
Jack Palevicha6baa232009-06-12 11:25:59 -07002303 String tString;
Jack Palevich546b2242009-05-13 15:10:04 -07002304 t = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002305 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
Jack Palevich21a15a22009-05-11 14:49:29 -07002306 if (tok == '\"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07002307 pGen->li((int) glo);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002308 while (ch != '\"' && ch != EOF) {
2309 *allocGlobalSpace(1) = getq();
2310 }
2311 if (ch != '\"') {
2312 error("Unterminated string constant.");
Jack Palevich21a15a22009-05-11 14:49:29 -07002313 }
Jack Palevich653f42d2009-05-28 17:15:32 -07002314 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002315 /* align heap */
2316 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07002317 inp();
2318 next();
2319 } else {
2320 c = tokl;
2321 a = tokc;
2322 t = tok;
Jack Palevicha6baa232009-06-12 11:25:59 -07002323 tString = mTokenString;
Jack Palevich21a15a22009-05-11 14:49:29 -07002324 next();
2325 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002326 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002327 } else if (c == 2) {
2328 /* -, +, !, ~ */
2329 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07002330 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002331 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002332 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002333 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002334 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002335 } else if (t == '(') {
2336 expr();
2337 skip(')');
2338 } else if (t == '*') {
2339 /* parse cast */
2340 skip('(');
2341 t = tok; /* get type */
2342 next(); /* skip int/char/void */
2343 next(); /* skip '*' or '(' */
2344 if (tok == '*') {
2345 /* function type */
2346 skip('*');
2347 skip(')');
2348 skip('(');
2349 skip(')');
2350 t = 0;
2351 }
2352 skip(')');
2353 unary(0);
2354 if (tok == '=') {
2355 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07002356 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002357 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002358 pGen->popR1();
2359 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002360 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002361 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002362 }
2363 } else if (t == '&') {
Jack Palevich569f1352009-06-29 14:29:08 -07002364 pGen->leaR0((int) VI(tok)->pAddress);
Jack Palevich21a15a22009-05-11 14:49:29 -07002365 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002366 } else if (t == EOF ) {
2367 error("Unexpected EOF.");
Jack Palevicha1804dd2009-06-12 14:40:04 -07002368 } else if (!checkSymbol(t, &tString)) {
2369 // Don't have to do anything special here, the error
2370 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002371 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002372 if (!isDefined(t)) {
2373 mGlobals.add(t);
2374 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002375 }
2376
Jack Palevich569f1352009-06-29 14:29:08 -07002377 n = (intptr_t) VI(t)->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002378 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002379 if (!n) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002380 n = (intptr_t) dlsym(RTLD_DEFAULT,
Jack Palevicha6baa232009-06-12 11:25:59 -07002381 tString.getUnwrapped());
Jack Palevich569f1352009-06-29 14:29:08 -07002382 VI(t)->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002383 }
Jack Palevich546b2242009-05-13 15:10:04 -07002384 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002385 /* assignment */
2386 next();
2387 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002388 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002389 } else if (tok != '(') {
2390 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002391 if (!n) {
2392 error("Undefined variable %s", tString.getUnwrapped());
2393 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002394 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002395 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002396 next();
2397 }
2398 }
2399 }
2400 }
2401
2402 /* function call */
2403 if (tok == '(') {
2404 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002405 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002406
2407 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002408 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07002409 next();
2410 l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002411 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002412 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002413 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002414 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002415 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002416 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002417 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002418 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002419 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 if (!n) {
2421 /* forward reference */
Jack Palevich569f1352009-06-29 14:29:08 -07002422 VariableInfo* pVI = VI(t);
2423 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward);
Jack Palevich21a15a22009-05-11 14:49:29 -07002424 } else if (n == 1) {
2425 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002426 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07002427 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07002428 }
-b master422972c2009-06-17 19:13:52 -07002429 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002430 }
2431 }
2432
Jack Palevich653f42d2009-05-28 17:15:32 -07002433 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002434 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002435 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002436 if (l-- == 1)
2437 unary(1);
2438 else {
2439 sum(l);
2440 a = 0;
2441 while (l == tokl) {
2442 n = tok;
2443 t = tokc;
2444 next();
2445
2446 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002447 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07002448 sum(l);
2449 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002450 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002451 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07002452 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002453
Jack Palevich546b2242009-05-13 15:10:04 -07002454 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002455 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002456 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002457 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002458 }
2459 }
2460 }
2461 /* && and || output code generation */
2462 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002463 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2464 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002465 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002466 pGen->gsym(a);
2467 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002468 }
2469 }
2470 }
2471
2472 void expr() {
2473 sum(11);
2474 }
2475
2476 int test_expr() {
2477 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002478 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002479 }
2480
Jack Palevicha6baa232009-06-12 11:25:59 -07002481 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002482 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002483
Jack Palevicha1804dd2009-06-12 14:40:04 -07002484 if (tok == TOK_INT || tok == TOK_CHAR) {
2485 /* declarations */
2486 localDeclarations();
2487 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002488 next();
2489 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002490 a = test_expr();
2491 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002492 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002493 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002494 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002495 n = pGen->gjmp(0); /* jmp */
2496 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002497 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002498 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002499 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002500 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002501 }
Jack Palevich546b2242009-05-13 15:10:04 -07002502 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002503 t = tok;
2504 next();
2505 skip('(');
2506 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002507 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002508 a = test_expr();
2509 } else {
2510 if (tok != ';')
2511 expr();
2512 skip(';');
2513 n = codeBuf.getPC();
2514 a = 0;
2515 if (tok != ';')
2516 a = test_expr();
2517 skip(';');
2518 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002519 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002520 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002521 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002522 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002523 n = t + 4;
2524 }
2525 }
2526 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002527 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002528 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002529 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002530 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002531 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002532 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002533 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002534 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002535 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002536 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002537 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002538 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07002539 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07002540 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002541 } else {
2542 if (tok == TOK_RETURN) {
2543 next();
2544 if (tok != ';')
2545 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002546 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002547 } else if (tok == TOK_BREAK) {
2548 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002549 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002550 } else if (tok != ';')
2551 expr();
2552 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002553 }
2554 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002555
Jack Palevichb7c81e92009-06-04 19:56:13 -07002556 typedef int Type;
2557 static const Type TY_UNKNOWN = 0;
2558 static const Type TY_INT = 1;
2559 static const Type TY_CHAR = 2;
2560 static const Type TY_VOID = 3;
2561 static const int TY_BASE_TYPE_MASK = 0xf;
2562 static const int TY_INDIRECTION_MASK = 0xf0;
2563 static const int TY_INDIRECTION_SHIFT = 4;
2564 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07002565
Jack Palevichb7c81e92009-06-04 19:56:13 -07002566 Type getBaseType(Type t) {
2567 return t & TY_BASE_TYPE_MASK;
2568 }
2569
2570 int getIndirectionCount(Type t) {
2571 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
2572 }
2573
2574 void setIndirectionCount(Type& t, int count) {
2575 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
2576 | (t & ~TY_INDIRECTION_MASK));
2577 }
2578
2579 bool acceptType(Type& t) {
2580 t = TY_UNKNOWN;
2581 if (tok == TOK_INT) {
2582 t = TY_INT;
2583 } else if (tok == TOK_CHAR) {
2584 t = TY_CHAR;
2585 } else if (tok == TOK_VOID) {
2586 t = TY_VOID;
2587 } else {
2588 return false;
2589 }
2590 next();
2591 return true;
2592 }
2593
2594 Type acceptPointerDeclaration(Type& base) {
2595 Type t = base;
2596 int indirectionCount = 0;
2597 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
2598 next();
2599 indirectionCount++;
2600 }
2601 if (indirectionCount > MAX_INDIRECTION_COUNT) {
2602 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
2603 }
2604 setIndirectionCount(t, indirectionCount);
2605 return t;
2606 }
2607
2608 void expectType(Type& t) {
2609 if (!acceptType(t)) {
Jack Palevich569f1352009-06-29 14:29:08 -07002610 String buf;
2611 decodeToken(buf, tok);
2612 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07002613 }
2614 }
2615
Jack Palevicha6baa232009-06-12 11:25:59 -07002616 void addGlobalSymbol() {
Jack Palevich569f1352009-06-29 14:29:08 -07002617 VariableInfo* pVI = VI(tok);
2618 if(pVI && pVI->pAddress) {
2619 reportDuplicate();
2620 }
2621 mGlobals.add(tok);
Jack Palevicha6baa232009-06-12 11:25:59 -07002622 }
2623
Jack Palevich569f1352009-06-29 14:29:08 -07002624 void reportDuplicate() {
2625 error("Duplicate definition of %s", nameof(tok));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002626 }
2627
Jack Palevicha6baa232009-06-12 11:25:59 -07002628 void addLocalSymbol() {
Jack Palevich569f1352009-06-29 14:29:08 -07002629 if (mLocals.isDefinedAtCurrentLevel(tok)) {
2630 reportDuplicate();
2631 }
2632 mLocals.add(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002633 }
2634
Jack Palevichb7c81e92009-06-04 19:56:13 -07002635 void localDeclarations() {
2636 intptr_t a;
2637 Type base;
2638
2639 while (acceptType(base)) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002640 while (tok != ';' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002641 Type t = acceptPointerDeclaration(t);
Jack Palevichd7461a72009-06-12 14:26:58 -07002642 int variableAddress = 0;
Jack Palevichf1728be2009-06-12 13:53:51 -07002643 if (checkSymbol()) {
2644 addLocalSymbol();
2645 if (tok) {
2646 loc = loc + 4;
Jack Palevichd7461a72009-06-12 14:26:58 -07002647 variableAddress = -loc;
Jack Palevich569f1352009-06-29 14:29:08 -07002648 VI(tok)->pAddress = (void*) variableAddress;
Jack Palevichf1728be2009-06-12 13:53:51 -07002649 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002650 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002651 next();
Jack Palevichd7461a72009-06-12 14:26:58 -07002652 if (tok == '=') {
2653 /* assignment */
2654 next();
2655 expr();
2656 pGen->storeR0(variableAddress);
2657 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002658 if (tok == ',')
2659 next();
2660 }
2661 skip(';');
2662 }
2663 }
2664
Jack Palevichf1728be2009-06-12 13:53:51 -07002665 bool checkSymbol() {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002666 return checkSymbol(tok, &mTokenString);
2667 }
2668
Jack Palevich569f1352009-06-29 14:29:08 -07002669 void decodeToken(String& buffer, tokenid_t token) {
2670 if (token == EOF ) {
2671 buffer.printf("EOF");
2672 } else if (token == TOK_NUM) {
2673 buffer.printf("numeric constant");
2674 } else if (token >= 0 && token < 256) {
2675 buffer.printf("char \'%c\'", token);
2676 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
2677 buffer.printf("keyword \"%s\"", nameof(token));
2678 } else {
2679 buffer.printf("symbol \"%s\"", nameof(token));
2680 }
2681 }
2682
2683 bool checkSymbol(tokenid_t token, String* pText) {
2684 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07002685 if (!result) {
2686 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07002687 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07002688 error("Expected symbol. Got %s", temp.getUnwrapped());
2689 }
2690 return result;
2691 }
2692
Jack Palevichb7c81e92009-06-04 19:56:13 -07002693 void globalDeclarations() {
2694 while (tok != EOF) {
2695 Type base;
2696 expectType(base);
2697 Type t = acceptPointerDeclaration(t);
Jack Palevich569f1352009-06-29 14:29:08 -07002698 if (tok < TOK_SYMBOL) {
Jack Palevichf1728be2009-06-12 13:53:51 -07002699 error("Unexpected token %d", tok);
2700 break;
2701 }
Jack Palevich569f1352009-06-29 14:29:08 -07002702 if (! isDefined(tok)) {
Jack Palevicha6baa232009-06-12 11:25:59 -07002703 addGlobalSymbol();
2704 }
Jack Palevich569f1352009-06-29 14:29:08 -07002705 VariableInfo* name = VI(tok);
Jack Palevicha6baa232009-06-12 11:25:59 -07002706 if (name && name->pAddress) {
2707 error("Already defined global %s",
2708 mTokenString.getUnwrapped());
2709 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002710 next();
Jack Palevichd7461a72009-06-12 14:26:58 -07002711 if (tok == ',' || tok == ';' || tok == '=') {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002712 // it's a variable declaration
2713 for(;;) {
Jack Palevicha6baa232009-06-12 11:25:59 -07002714 if (name) {
2715 name->pAddress = (int*) allocGlobalSpace(4);
2716 }
Jack Palevichd7461a72009-06-12 14:26:58 -07002717 if (tok == '=') {
2718 next();
2719 if (tok == TOK_NUM) {
2720 if (name) {
2721 * (int*) name->pAddress = tokc;
2722 }
2723 next();
2724 } else {
2725 error("Expected an integer constant");
2726 }
2727 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002728 if (tok != ',') {
2729 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07002730 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002731 skip(',');
Jack Palevichb7c81e92009-06-04 19:56:13 -07002732 t = acceptPointerDeclaration(t);
Jack Palevicha6baa232009-06-12 11:25:59 -07002733 addGlobalSymbol();
Jack Palevich569f1352009-06-29 14:29:08 -07002734 name = VI(tok);
Jack Palevichb7c81e92009-06-04 19:56:13 -07002735 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002736 }
2737 skip(';');
2738 } else {
Jack Palevicha6baa232009-06-12 11:25:59 -07002739 if (name) {
2740 /* patch forward references (XXX: does not work for function
2741 pointers) */
2742 pGen->gsym((int) name->pForward);
2743 /* put function address */
2744 name->pAddress = (void*) codeBuf.getPC();
2745 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002746 skip('(');
Jack Palevich569f1352009-06-29 14:29:08 -07002747 mLocals.pushLevel();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002748 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07002749 int argCount = 0;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002750 while (tok != ')' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002751 Type aType;
2752 expectType(aType);
2753 aType = acceptPointerDeclaration(aType);
Jack Palevichf1728be2009-06-12 13:53:51 -07002754 if (checkSymbol()) {
2755 addLocalSymbol();
2756 if (tok) {
2757 /* read param name and compute offset */
Jack Palevich569f1352009-06-29 14:29:08 -07002758 VI(tok)->pAddress = (void*) a;
Jack Palevichf1728be2009-06-12 13:53:51 -07002759 a = a + 4;
2760 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002761 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002762 next();
2763 if (tok == ',')
2764 next();
Jack Palevich546b2242009-05-13 15:10:04 -07002765 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07002766 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002767 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002768 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002769 a = pGen->functionEntry(argCount);
Jack Palevicha6baa232009-06-12 11:25:59 -07002770 block(0, true);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002771 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07002772 pGen->functionExit(argCount, a, loc);
Jack Palevich569f1352009-06-29 14:29:08 -07002773 mLocals.popLevel();
Jack Palevich21a15a22009-05-11 14:49:29 -07002774 }
2775 }
2776 }
2777
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002778 char* allocGlobalSpace(int bytes) {
2779 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
2780 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07002781 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002782 }
2783 char* result = glo;
2784 glo += bytes;
2785 return result;
2786 }
2787
Jack Palevich21a15a22009-05-11 14:49:29 -07002788 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002789 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002790 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07002791 pGlobalBase = 0;
2792 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002793 if (pGen) {
2794 delete pGen;
2795 pGen = 0;
2796 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002797 if (file) {
2798 delete file;
2799 file = 0;
2800 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002801 }
2802
2803 void clear() {
2804 tok = 0;
2805 tokc = 0;
2806 tokl = 0;
2807 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002808 rsym = 0;
2809 loc = 0;
2810 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002811 dptr = 0;
2812 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002813 file = 0;
2814 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002815 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002816 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002817 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002818
Jack Palevich22305132009-05-13 10:58:45 -07002819 void setArchitecture(const char* architecture) {
2820 delete pGen;
2821 pGen = 0;
2822
2823 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002824#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002825 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002826 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002827 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002828#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07002829#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002830 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002831 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002832 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002833#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07002834 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002835 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07002836 }
2837 }
2838
2839 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002840#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07002841 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07002842#elif defined(DEFAULT_X86_CODEGEN)
2843 pGen = new X86CodeGenerator();
2844#endif
2845 }
2846 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002847 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07002848 } else {
2849 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07002850 }
2851 }
2852
Jack Palevich77ae76e2009-05-10 19:59:24 -07002853public:
Jack Palevich22305132009-05-13 10:58:45 -07002854 struct args {
2855 args() {
2856 architecture = 0;
2857 }
2858 const char* architecture;
2859 };
2860
Jack Paleviche7b59062009-05-19 17:12:17 -07002861 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002862 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002863 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002864
Jack Paleviche7b59062009-05-19 17:12:17 -07002865 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002866 cleanup();
2867 }
2868
Jack Palevich1cdef202009-05-22 12:06:27 -07002869 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002870 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07002871
2872 cleanup();
2873 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07002874 mTokenTable.setArena(&mGlobalArena);
2875 mGlobals.setArena(&mGlobalArena);
2876 mGlobals.setTokenTable(&mTokenTable);
2877 mLocals.setArena(&mLocalArena);
2878 mLocals.setTokenTable(&mTokenTable);
2879
2880 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07002881 codeBuf.init(ALLOC_SIZE);
2882 setArchitecture(NULL);
2883 if (!pGen) {
2884 return -1;
2885 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002886#ifdef PROVIDE_TRACE_CODEGEN
2887 pGen = new TraceCodeGenerator(pGen);
2888#endif
2889 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07002890 pGen->init(&codeBuf);
2891 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07002892 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
2893 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07002894 inp();
2895 next();
2896 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07002897 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07002898 result = pGen->finishCompile();
2899 if (result == 0) {
2900 if (mErrorBuf.len()) {
2901 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07002902 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07002903 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002904 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07002905 }
2906
Jack Palevicha6baa232009-06-12 11:25:59 -07002907 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07002908 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07002909 }
2910
Jack Palevich569f1352009-06-29 14:29:08 -07002911 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07002912 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07002913 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07002914 }
2915
Jack Palevich569f1352009-06-29 14:29:08 -07002916 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07002917 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07002918 error("Undefined forward reference: %s",
2919 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07002920 }
2921 return true;
2922 }
2923
Jack Palevich21a15a22009-05-11 14:49:29 -07002924 int dump(FILE* out) {
2925 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
2926 return 0;
2927 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07002928
Jack Palevicha6535612009-05-13 16:24:17 -07002929 int disassemble(FILE* out) {
2930 return pGen->disassemble(out);
2931 }
2932
Jack Palevich1cdef202009-05-22 12:06:27 -07002933 /* Look through the symbol table to find a symbol.
2934 * If found, return its value.
2935 */
2936 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07002937 tokenid_t tok = mTokenTable.intern(name, strlen(name));
2938 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002939 if (pVariableInfo) {
2940 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07002941 }
2942 return NULL;
2943 }
2944
Jack Palevicheedf9d22009-06-04 16:23:40 -07002945 void getPragmas(ACCsizei* actualStringCount,
2946 ACCsizei maxStringCount, ACCchar** strings) {
2947 int stringCount = mPragmaStringCount;
2948 if (actualStringCount) {
2949 *actualStringCount = stringCount;
2950 }
2951 if (stringCount > maxStringCount) {
2952 stringCount = maxStringCount;
2953 }
2954 if (strings) {
2955 char* pPragmas = mPragmas.getUnwrapped();
2956 while (stringCount-- > 0) {
2957 *strings++ = pPragmas;
2958 pPragmas += strlen(pPragmas) + 1;
2959 }
2960 }
2961 }
2962
Jack Palevichac0e95e2009-05-29 13:53:44 -07002963 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002964 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002965 }
2966
Jack Palevich77ae76e2009-05-10 19:59:24 -07002967};
2968
Jack Paleviche7b59062009-05-19 17:12:17 -07002969const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002970 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2971
Jack Paleviche7b59062009-05-19 17:12:17 -07002972const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002973 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2974 5, 5, /* ==, != */
2975 9, 10, /* &&, || */
2976 6, 7, 8, /* & ^ | */
2977 2, 2 /* ~ ! */
2978 };
2979
Jack Palevich8b0624c2009-05-20 12:12:06 -07002980#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002981FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002982#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002983
Jack Palevich8b0624c2009-05-20 12:12:06 -07002984#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002985const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002986 0x1, // ++
2987 0xff, // --
2988 0xc1af0f, // *
2989 0xf9f79991, // /
2990 0xf9f79991, // % (With manual assist to swap results)
2991 0xc801, // +
2992 0xd8f7c829, // -
2993 0xe0d391, // <<
2994 0xf8d391, // >>
2995 0xe, // <=
2996 0xd, // >=
2997 0xc, // <
2998 0xf, // >
2999 0x4, // ==
3000 0x5, // !=
3001 0x0, // &&
3002 0x1, // ||
3003 0xc821, // &
3004 0xc831, // ^
3005 0xc809, // |
3006 0xd0f7, // ~
3007 0x4 // !
3008};
Jack Palevich8b0624c2009-05-20 12:12:06 -07003009#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003010
Jack Palevich1cdef202009-05-22 12:06:27 -07003011struct ACCscript {
3012 ACCscript() {
3013 text = 0;
3014 textLength = 0;
3015 accError = ACC_NO_ERROR;
3016 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003017
Jack Palevich1cdef202009-05-22 12:06:27 -07003018 ~ACCscript() {
3019 delete text;
3020 }
Jack Palevich546b2242009-05-13 15:10:04 -07003021
Jack Palevich1cdef202009-05-22 12:06:27 -07003022 void setError(ACCenum error) {
3023 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
3024 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003025 }
3026 }
3027
Jack Palevich1cdef202009-05-22 12:06:27 -07003028 ACCenum getError() {
3029 ACCenum result = accError;
3030 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07003031 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003032 }
3033
Jack Palevich1cdef202009-05-22 12:06:27 -07003034 Compiler compiler;
3035 char* text;
3036 int textLength;
3037 ACCenum accError;
3038};
3039
3040
3041extern "C"
3042ACCscript* accCreateScript() {
3043 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003044}
Jack Palevich1cdef202009-05-22 12:06:27 -07003045
3046extern "C"
3047ACCenum accGetError( ACCscript* script ) {
3048 return script->getError();
3049}
3050
3051extern "C"
3052void accDeleteScript(ACCscript* script) {
3053 delete script;
3054}
3055
3056extern "C"
3057void accScriptSource(ACCscript* script,
3058 ACCsizei count,
3059 const ACCchar ** string,
3060 const ACCint * length) {
3061 int totalLength = 0;
3062 for(int i = 0; i < count; i++) {
3063 int len = -1;
3064 const ACCchar* s = string[i];
3065 if (length) {
3066 len = length[i];
3067 }
3068 if (len < 0) {
3069 len = strlen(s);
3070 }
3071 totalLength += len;
3072 }
3073 delete script->text;
3074 char* text = new char[totalLength + 1];
3075 script->text = text;
3076 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07003077 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07003078 for(int i = 0; i < count; i++) {
3079 int len = -1;
3080 const ACCchar* s = string[i];
3081 if (length) {
3082 len = length[i];
3083 }
3084 if (len < 0) {
3085 len = strlen(s);
3086 }
Jack Palevich09555c72009-05-27 12:25:55 -07003087 memcpy(dest, s, len);
3088 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003089 }
3090 text[totalLength] = '\0';
3091}
3092
3093extern "C"
3094void accCompileScript(ACCscript* script) {
3095 int result = script->compiler.compile(script->text, script->textLength);
3096 if (result) {
3097 script->setError(ACC_INVALID_OPERATION);
3098 }
3099}
3100
3101extern "C"
3102void accGetScriptiv(ACCscript* script,
3103 ACCenum pname,
3104 ACCint * params) {
3105 switch (pname) {
3106 case ACC_INFO_LOG_LENGTH:
3107 *params = 0;
3108 break;
3109 }
3110}
3111
3112extern "C"
3113void accGetScriptInfoLog(ACCscript* script,
3114 ACCsizei maxLength,
3115 ACCsizei * length,
3116 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003117 char* message = script->compiler.getErrorMessage();
3118 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003119 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003120 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003121 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003122 if (infoLog && maxLength > 0) {
3123 int trimmedLength = maxLength < messageLength ?
3124 maxLength : messageLength;
3125 memcpy(infoLog, message, trimmedLength);
3126 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003127 }
3128}
3129
3130extern "C"
3131void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3132 ACCvoid ** address) {
3133 void* value = script->compiler.lookup(name);
3134 if (value) {
3135 *address = value;
3136 } else {
3137 script->setError(ACC_INVALID_VALUE);
3138 }
3139}
3140
Jack Palevicheedf9d22009-06-04 16:23:40 -07003141extern "C"
3142void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3143 ACCsizei maxStringCount, ACCchar** strings){
3144 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3145}
3146
-b master422972c2009-06-17 19:13:52 -07003147extern "C"
3148void accDisassemble(ACCscript* script) {
3149 script->compiler.disassemble(stderr);
3150}
3151
Jack Palevicheedf9d22009-06-04 16:23:40 -07003152
Jack Palevich1cdef202009-05-22 12:06:27 -07003153} // namespace acc
3154