blob: fdddf22053f9fd9e2a8299088d1cc301780336d8 [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 Palevich1cdef202009-05-22 12:06:27 -07001269 class InputStream {
1270 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001271 int getChar() {
1272 if (bumpLine) {
1273 line++;
1274 bumpLine = false;
1275 }
1276 int ch = get();
1277 if (ch == '\n') {
1278 bumpLine = true;
1279 }
1280 return ch;
1281 }
1282 int getLine() {
1283 return line;
1284 }
1285 protected:
1286 InputStream() :
1287 line(1), bumpLine(false) {
1288 }
1289 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001290 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001291 int line;
1292 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001293 };
1294
1295 class FileInputStream : public InputStream {
1296 public:
1297 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001298 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001299 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001300 FILE* f;
1301 };
1302
1303 class TextInputStream : public InputStream {
1304 public:
1305 TextInputStream(const char* text, size_t textLength)
1306 : pText(text), mTextLength(textLength), mPosition(0) {
1307 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001308
1309 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001310 virtual int get() {
1311 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1312 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001313
Jack Palevich1cdef202009-05-22 12:06:27 -07001314 const char* pText;
1315 size_t mTextLength;
1316 size_t mPosition;
1317 };
1318
Jack Palevicheedf9d22009-06-04 16:23:40 -07001319 class String {
1320 public:
1321 String() {
1322 mpBase = 0;
1323 mUsed = 0;
1324 mSize = 0;
1325 }
1326
Jack Palevich303d8ff2009-06-11 19:06:24 -07001327 String(const char* item, int len, bool adopt) {
1328 if (len < 0) {
1329 len = strlen(item);
1330 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001331 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001332 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001333 mUsed = len;
1334 mSize = len + 1;
1335 } else {
1336 mpBase = 0;
1337 mUsed = 0;
1338 mSize = 0;
1339 appendBytes(item, len);
1340 }
1341 }
1342
Jack Palevich303d8ff2009-06-11 19:06:24 -07001343 String(const String& other) {
1344 mpBase = 0;
1345 mUsed = 0;
1346 mSize = 0;
1347 appendBytes(other.getUnwrapped(), other.len());
1348 }
1349
Jack Palevicheedf9d22009-06-04 16:23:40 -07001350 ~String() {
1351 if (mpBase) {
1352 free(mpBase);
1353 }
1354 }
1355
Jack Palevicha6baa232009-06-12 11:25:59 -07001356 String& operator=(const String& other) {
1357 clear();
1358 appendBytes(other.getUnwrapped(), other.len());
1359 return *this;
1360 }
1361
Jack Palevich303d8ff2009-06-11 19:06:24 -07001362 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001363 return mpBase;
1364 }
1365
Jack Palevich303d8ff2009-06-11 19:06:24 -07001366 void clear() {
1367 mUsed = 0;
1368 if (mSize > 0) {
1369 mpBase[0] = 0;
1370 }
1371 }
1372
Jack Palevicheedf9d22009-06-04 16:23:40 -07001373 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001374 appendBytes(s, strlen(s));
1375 }
1376
1377 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001378 memcpy(ensure(n), s, n + 1);
1379 }
1380
1381 void append(char c) {
1382 * ensure(1) = c;
1383 }
1384
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001385 char* orphan() {
1386 char* result = mpBase;
1387 mpBase = 0;
1388 mUsed = 0;
1389 mSize = 0;
1390 return result;
1391 }
1392
Jack Palevicheedf9d22009-06-04 16:23:40 -07001393 void printf(const char* fmt,...) {
1394 va_list ap;
1395 va_start(ap, fmt);
1396 vprintf(fmt, ap);
1397 va_end(ap);
1398 }
1399
1400 void vprintf(const char* fmt, va_list ap) {
1401 char* temp;
1402 int numChars = vasprintf(&temp, fmt, ap);
1403 memcpy(ensure(numChars), temp, numChars+1);
1404 free(temp);
1405 }
1406
Jack Palevich303d8ff2009-06-11 19:06:24 -07001407 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001408 return mUsed;
1409 }
1410
1411 private:
1412 char* ensure(int n) {
1413 size_t newUsed = mUsed + n;
1414 if (newUsed > mSize) {
1415 size_t newSize = mSize * 2 + 10;
1416 if (newSize < newUsed) {
1417 newSize = newUsed;
1418 }
1419 mpBase = (char*) realloc(mpBase, newSize + 1);
1420 mSize = newSize;
1421 }
1422 mpBase[newUsed] = '\0';
1423 char* result = mpBase + mUsed;
1424 mUsed = newUsed;
1425 return result;
1426 }
1427
1428 char* mpBase;
1429 size_t mUsed;
1430 size_t mSize;
1431 };
1432
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001433 /**
1434 * Wrap an externally allocated string for use as a hash key.
1435 */
1436 class FakeString : public String {
1437 public:
Jack Palevich2db168f2009-06-11 14:29:47 -07001438 FakeString(const char* string, size_t length) :
1439 String((char*) string, length, true) {}
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001440
1441 ~FakeString() {
1442 orphan();
1443 }
1444 };
1445
1446 template<class V> class StringTable {
1447 public:
Jack Palevich303d8ff2009-06-11 19:06:24 -07001448 StringTable() {
1449 init(10);
1450 }
1451
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001452 StringTable(size_t initialCapacity) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001453 init(initialCapacity);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001454 }
1455
1456 ~StringTable() {
1457 clear();
Jack Palevich2db168f2009-06-11 14:29:47 -07001458 hashmapFree(mpMap);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001459 }
1460
1461 void clear() {
1462 hashmapForEach(mpMap, freeKeyValue, this);
1463 }
1464
1465 bool contains(String* pKey) {
1466 bool result = hashmapContainsKey(mpMap, pKey);
1467 return result;
1468 }
1469
1470 V* get(String* pKey) {
1471 V* result = (V*) hashmapGet(mpMap, pKey);
1472 return result;
1473 }
1474
1475 V* remove(String* pKey) {
1476 V* result = (V*) hashmapRemove(mpMap, pKey);
1477 return result;
1478 }
1479
1480 V* put(String* pKey, V* value) {
1481 V* result = (V*) hashmapPut(mpMap, pKey, value);
1482 if (result) {
1483 // The key was not adopted by the map, so delete it here.
1484 delete pKey;
1485 }
1486 return result;
1487 }
1488
Jack Palevicha6baa232009-06-12 11:25:59 -07001489 void forEach(bool (*callback)(String* key, V* value, void* context),
1490 void* context) {
1491 hashmapForEach(mpMap, (bool (*)(void*, void*, void*)) callback,
1492 context);
1493 }
1494
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001495 protected:
Jack Palevich303d8ff2009-06-11 19:06:24 -07001496
1497 void init(size_t initialCapacity) {
1498 mpMap = hashmapCreate(initialCapacity, hashFn, equalsFn);
1499 }
1500
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001501 static int hashFn(void* pKey) {
1502 String* pString = (String*) pKey;
1503 return hashmapHash(pString->getUnwrapped(), pString->len());
1504 }
1505
1506 static bool equalsFn(void* keyA, void* keyB) {
1507 String* pStringA = (String*) keyA;
1508 String* pStringB = (String*) keyB;
1509 return pStringA->len() == pStringB->len()
1510 && strcmp(pStringA->getUnwrapped(), pStringB->getUnwrapped())
1511 == 0;
1512 }
1513
1514 static bool freeKeyValue(void* key, void* value, void* context) {
1515 delete (String*) key;
1516 delete (V*) value;
1517 return true;
1518 }
1519
1520 Hashmap* mpMap;
1521 };
1522
1523 class MacroTable : public StringTable<String> {
1524 public:
1525 MacroTable() : StringTable<String>(10) {}
1526 };
1527
Jack Palevich2db168f2009-06-11 14:29:47 -07001528 class KeywordTable {
1529 public:
1530
1531 KeywordTable(){
1532 mpMap = hashmapCreate(40, hashFn, equalsFn);
1533 put("int", TOK_INT);
1534 put("char", TOK_CHAR);
1535 put("void", TOK_VOID);
1536 put("if", TOK_IF);
1537 put("else", TOK_ELSE);
1538 put("while", TOK_WHILE);
1539 put("break", TOK_BREAK);
1540 put("return", TOK_RETURN);
1541 put("for", TOK_FOR);
Jack Palevich2ccc40d2009-06-12 11:53:07 -07001542 // TODO: remove these preprocessor-specific keywords. You should
1543 // be able to have symbols named pragma or define.
Jack Palevich2db168f2009-06-11 14:29:47 -07001544 put("pragma", TOK_PRAGMA);
Jack Palevich2ccc40d2009-06-12 11:53:07 -07001545 put("define", TOK_DEFINE);
Jack Palevichf1728be2009-06-12 13:53:51 -07001546
1547 const char* unsupported[] = {
1548 "auto",
1549 "case",
1550 "const",
1551 "continue",
1552 "default",
1553 "do",
1554 "double",
1555 "enum",
1556 "extern",
1557 "float",
1558 "goto",
1559 "long",
1560 "register",
1561 "short",
1562 "signed",
1563 "sizeof",
1564 "static",
1565 "struct",
1566 "switch",
1567 "typedef",
1568 "union",
1569 "unsigned",
1570 "volatile",
1571 "_Bool",
1572 "_Complex",
1573 "_Imaginary",
1574 "inline",
1575 "restrict",
1576 0};
1577
1578 for(int i = 0; unsupported[i]; i++) {
1579 put(unsupported[i], TOK_UNSUPPORTED_KEYWORD);
1580 }
Jack Palevich2db168f2009-06-11 14:29:47 -07001581 }
1582
1583 ~KeywordTable() {
1584 hashmapFree(mpMap);
1585 }
1586
Jack Palevich303d8ff2009-06-11 19:06:24 -07001587 int get(String* key) {
1588 return (int) hashmapGet(mpMap, key->getUnwrapped());
Jack Palevich2db168f2009-06-11 14:29:47 -07001589 }
1590
1591 const char* lookupKeyFor(int value) {
1592 FindValContext context;
1593 context.key = 0;
1594 hashmapForEach(mpMap, findKeyFn, &context);
1595 return context.key;
1596 }
1597
1598 private:
1599 void put(const char* kw, int val) {
1600 hashmapPut(mpMap, (void*) kw, (void*) val);
1601 }
1602
1603 static int hashFn(void* pKey) {
1604 char* pString = (char*) pKey;
1605 return hashmapHash(pString, strlen(pString));
1606 }
1607
1608 static bool equalsFn(void* keyA, void* keyB) {
1609 const char* pStringA = (const char*) keyA;
1610 const char* pStringB = (const char*) keyB;
1611 return strcmp(pStringA, pStringB) == 0;
1612 }
1613
1614 struct FindValContext {
1615 char* key;
1616 int value;
1617 };
1618
1619 static bool findKeyFn(void* key, void* value, void* context) {
1620 FindValContext* pContext = (FindValContext*) context;
1621 if ((int) value == pContext->value) {
1622 pContext->key = (char*) key;
1623 return false;
1624 }
1625 return true;
1626 }
1627
1628 Hashmap* mpMap;
1629 };
1630
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001631 template<class E> class Array {
1632 public:
1633 Array() {
1634 mpBase = 0;
1635 mUsed = 0;
1636 mSize = 0;
1637 }
1638
1639 ~Array() {
1640 if (mpBase) {
1641 free(mpBase);
1642 }
1643 }
1644
1645 E get(int i) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001646 if (i < 0 || i > (int) mUsed) {
1647 // error("internal error: Index out of range");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001648 return E();
1649 }
1650 return mpBase[i];
1651 }
1652
1653 void set(int i, E val) {
1654 mpBase[i] = val;
1655 }
1656
1657 void pop() {
1658 if (mUsed > 0) {
1659 mUsed -= 1;
Jack Palevich36d94142009-06-08 15:55:32 -07001660 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001661 // error("internal error: Popped empty stack.");
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001662 }
1663 }
1664
1665 void push(E item) {
1666 * ensure(1) = item;
1667 }
1668
1669 size_t len() {
1670 return mUsed;
1671 }
1672
1673 private:
1674 E* ensure(int n) {
1675 size_t newUsed = mUsed + n;
1676 if (newUsed > mSize) {
1677 size_t newSize = mSize * 2 + 10;
1678 if (newSize < newUsed) {
1679 newSize = newUsed;
1680 }
1681 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
1682 mSize = newSize;
1683 }
1684 E* result = mpBase + mUsed;
1685 mUsed = newUsed;
1686 return result;
1687 }
1688
1689 E* mpBase;
1690 size_t mUsed;
1691 size_t mSize;
1692 };
1693
Jack Palevich36d94142009-06-08 15:55:32 -07001694 struct InputState {
1695 InputStream* pStream;
1696 int oldCh;
1697 };
1698
Jack Palevich2db168f2009-06-11 14:29:47 -07001699 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001700 VariableInfo() {
1701 pAddress = 0;
1702 pForward = 0;
1703 }
1704 void* pAddress;
1705 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich2db168f2009-06-11 14:29:47 -07001706 };
1707
Jack Palevich303d8ff2009-06-11 19:06:24 -07001708 typedef StringTable<VariableInfo> SymbolTable;
1709
1710 class SymbolStack {
1711 public:
1712 SymbolStack() {
1713 mLevel = 0;
1714 addEntry();
1715 }
1716
1717 void pushLevel() {
1718 mLevel++;
1719 }
1720
1721 void popLevel() {
1722 mLevel--;
1723 Entry e = mStack.get(mStack.len()-1);
1724 if (mLevel < e.level) {
1725 mStack.pop();
1726 delete e.pTable;
1727 }
1728 }
1729
1730 VariableInfo* get(String* pName) {
1731 int len = mStack.len();
1732 VariableInfo* v = NULL;
1733 int level = -1;
1734 for (int i = len - 1; i >= 0; i--) {
1735 Entry e = mStack.get(i);
1736 v = e.pTable->get(pName);
1737 if (v) {
1738 level = e.level;
1739 break;
1740 }
1741 }
1742#if 0
1743 fprintf(stderr, "Lookup %s %08x level %d\n", pName->getUnwrapped(), v, level);
1744 if (v) {
1745 fprintf(stderr, " %08x %08x\n", v->pAddress, v->pForward);
1746 }
1747#endif
1748 return v;
1749 }
1750
1751 VariableInfo* addLocal(String* pName) {
1752 int len = mStack.len();
1753 if (mStack.get(len-1).level != mLevel) {
1754 addEntry();
1755 len++;
1756 }
1757 return addImp(len-1, pName);
1758 }
1759
1760 VariableInfo* addGlobal(String* pName) {
1761 return addImp(0, pName);
1762 }
1763
Jack Palevicha6baa232009-06-12 11:25:59 -07001764 void forEachGlobal(
1765 bool (*callback)(String* key, VariableInfo* value, void* context),
1766 void* context) {
1767 mStack.get(0).pTable->forEach(callback, context);
1768 }
1769
Jack Palevich303d8ff2009-06-11 19:06:24 -07001770 private:
1771 VariableInfo* addImp(int entryIndex, String* pName) {
1772 Entry e = mStack.get(entryIndex);
1773 SymbolTable* pTable = e.pTable;
Jack Palevicha6baa232009-06-12 11:25:59 -07001774 if (pTable->contains(pName)) {
1775 return NULL;
1776 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07001777 VariableInfo* v = new VariableInfo();
Jack Palevicha6baa232009-06-12 11:25:59 -07001778
Jack Palevich303d8ff2009-06-11 19:06:24 -07001779 delete pTable->put(pName, v);
1780#if 0
1781 fprintf(stderr, "Add \"%s\" %08x level %d\n", pName->getUnwrapped(), v, e.level);
1782#endif
1783 return v;
1784 }
1785
1786 void addEntry() {
1787 Entry e;
1788 e.level = mLevel;
1789 e.pTable = new SymbolTable();
1790 mStack.push(e);
1791 }
1792
1793 struct Entry {
1794 Entry() {
1795 level = 0;
1796 pTable = NULL;
1797 }
1798 int level;
1799 SymbolTable* pTable;
1800 };
1801
1802 int mLevel;
1803 Array<Entry> mStack;
1804 };
Jack Palevich36d94142009-06-08 15:55:32 -07001805
1806 int ch; // Current input character, or EOF
1807 intptr_t tok; // token
1808 intptr_t tokc; // token extra info
1809 int tokl; // token operator level
1810 intptr_t rsym; // return symbol
1811 intptr_t loc; // local variable index
1812 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07001813 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07001814 char* dptr; // Macro state: Points to macro text during macro playback.
1815 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07001816 char* pGlobalBase;
Jack Palevich2db168f2009-06-11 14:29:47 -07001817 KeywordTable mKeywords;
Jack Palevich303d8ff2009-06-11 19:06:24 -07001818 SymbolStack mSymbolTable;
Jack Palevich36d94142009-06-08 15:55:32 -07001819 InputStream* file;
1820
1821 CodeBuf codeBuf;
1822 CodeGenerator* pGen;
1823
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001824 MacroTable mMacros;
Jack Palevich36d94142009-06-08 15:55:32 -07001825 Array<InputState> mInputStateStack;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001826
Jack Palevicheedf9d22009-06-04 16:23:40 -07001827 String mErrorBuf;
1828
Jack Palevicheedf9d22009-06-04 16:23:40 -07001829 String mPragmas;
1830 int mPragmaStringCount;
1831
Jack Palevich21a15a22009-05-11 14:49:29 -07001832 static const int ALLOC_SIZE = 99999;
1833
Jack Palevich303d8ff2009-06-11 19:06:24 -07001834 static const int TOK_DUMMY = 1;
1835 static const int TOK_NUM = 2;
1836
1837 // 3..255 are character and/or operators
1838
Jack Palevich2db168f2009-06-11 14:29:47 -07001839 // Keywords start at 0x100 and increase by 1
1840 static const int TOK_KEYWORD = 0x100;
1841 static const int TOK_INT = TOK_KEYWORD + 0;
1842 static const int TOK_CHAR = TOK_KEYWORD + 1;
1843 static const int TOK_VOID = TOK_KEYWORD + 2;
1844 static const int TOK_IF = TOK_KEYWORD + 3;
1845 static const int TOK_ELSE = TOK_KEYWORD + 4;
1846 static const int TOK_WHILE = TOK_KEYWORD + 5;
1847 static const int TOK_BREAK = TOK_KEYWORD + 6;
1848 static const int TOK_RETURN = TOK_KEYWORD + 7;
1849 static const int TOK_FOR = TOK_KEYWORD + 8;
1850 static const int TOK_PRAGMA = TOK_KEYWORD + 9;
1851 static const int TOK_DEFINE = TOK_KEYWORD + 10;
Jack Palevichf1728be2009-06-12 13:53:51 -07001852 static const int TOK_UNSUPPORTED_KEYWORD = TOK_KEYWORD + 0xff;
Jack Palevich2db168f2009-06-11 14:29:47 -07001853
Jack Palevich303d8ff2009-06-11 19:06:24 -07001854 static const int TOK_UNDEFINED_SYMBOL = 0x200;
Jack Palevich21a15a22009-05-11 14:49:29 -07001855
Jack Palevich303d8ff2009-06-11 19:06:24 -07001856 // Symbols start at 0x300, but are really pointers to VariableInfo structs.
1857 static const int TOK_SYMBOL = 0x300;
1858
Jack Palevich21a15a22009-05-11 14:49:29 -07001859
1860 static const int LOCAL = 0x200;
1861
1862 static const int SYM_FORWARD = 0;
1863 static const int SYM_DEFINE = 1;
1864
1865 /* tokens in string heap */
1866 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07001867
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001868 static const int OP_INCREMENT = 0;
1869 static const int OP_DECREMENT = 1;
1870 static const int OP_MUL = 2;
1871 static const int OP_DIV = 3;
1872 static const int OP_MOD = 4;
1873 static const int OP_PLUS = 5;
1874 static const int OP_MINUS = 6;
1875 static const int OP_SHIFT_LEFT = 7;
1876 static const int OP_SHIFT_RIGHT = 8;
1877 static const int OP_LESS_EQUAL = 9;
1878 static const int OP_GREATER_EQUAL = 10;
1879 static const int OP_LESS = 11;
1880 static const int OP_GREATER = 12;
1881 static const int OP_EQUALS = 13;
1882 static const int OP_NOT_EQUALS = 14;
1883 static const int OP_LOGICAL_AND = 15;
1884 static const int OP_LOGICAL_OR = 16;
1885 static const int OP_BIT_AND = 17;
1886 static const int OP_BIT_XOR = 18;
1887 static const int OP_BIT_OR = 19;
1888 static const int OP_BIT_NOT = 20;
1889 static const int OP_LOGICAL_NOT = 21;
1890 static const int OP_COUNT = 22;
1891
1892 /* Operators are searched from front, the two-character operators appear
1893 * before the single-character operators with the same first character.
1894 * @ is used to pad out single-character operators.
1895 */
1896 static const char* operatorChars;
1897 static const char operatorLevel[];
1898
Jack Palevich21a15a22009-05-11 14:49:29 -07001899 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07001900 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001901 }
1902
1903 void inp() {
1904 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001905 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07001906 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001907 dptr = 0;
1908 ch = dch;
1909 }
1910 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07001911 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001912#if 0
1913 printf("ch='%c' 0x%x\n", ch, ch);
1914#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07001915 }
1916
1917 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07001918 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07001919 }
1920
Jack Palevichb4758ff2009-06-12 12:49:14 -07001921 /* read a character constant, advances ch to after end of constant */
1922 int getq() {
1923 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07001924 if (ch == '\\') {
1925 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07001926 if (isoctal(ch)) {
1927 // 1 to 3 octal characters.
1928 val = 0;
1929 for(int i = 0; i < 3; i++) {
1930 if (isoctal(ch)) {
1931 val = (val << 3) + ch - '0';
1932 inp();
1933 }
1934 }
1935 return val;
1936 } else if (ch == 'x' || ch == 'X') {
1937 // N hex chars
1938 inp();
1939 if (! isxdigit(ch)) {
1940 error("'x' character escape requires at least one digit.");
1941 } else {
1942 val = 0;
1943 while (isxdigit(ch)) {
1944 int d = ch;
1945 if (isdigit(d)) {
1946 d -= '0';
1947 } else if (d <= 'F') {
1948 d = d - 'A' + 10;
1949 } else {
1950 d = d - 'a' + 10;
1951 }
1952 val = (val << 4) + d;
1953 inp();
1954 }
1955 }
1956 } else {
1957 int val = ch;
1958 switch (ch) {
1959 case 'a':
1960 val = '\a';
1961 break;
1962 case 'b':
1963 val = '\b';
1964 break;
1965 case 'f':
1966 val = '\f';
1967 break;
1968 case 'n':
1969 val = '\n';
1970 break;
1971 case 'r':
1972 val = '\r';
1973 break;
1974 case 't':
1975 val = '\t';
1976 break;
1977 case 'v':
1978 val = '\v';
1979 break;
1980 case '\\':
1981 val = '\\';
1982 break;
1983 case '\'':
1984 val = '\'';
1985 break;
1986 case '"':
1987 val = '"';
1988 break;
1989 case '?':
1990 val = '?';
1991 break;
1992 default:
1993 error("Undefined character escape %c", ch);
1994 break;
1995 }
1996 inp();
1997 return val;
1998 }
1999 } else {
2000 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002001 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002002 return val;
2003 }
2004
2005 static bool isoctal(int ch) {
2006 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002007 }
2008
2009 void next() {
2010 int l, a;
2011
Jack Palevich546b2242009-05-13 15:10:04 -07002012 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002013 if (ch == '#') {
2014 inp();
2015 next();
2016 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002017 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002018 } else if (tok == TOK_PRAGMA) {
2019 doPragma();
2020 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002021 error("Unsupported preprocessor directive \"%s\"",
2022 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002023 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002024 }
2025 inp();
2026 }
2027 tokl = 0;
2028 tok = ch;
2029 /* encode identifiers & numbers */
2030 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002031 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002032 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002033 pdef(ch);
2034 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002035 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002036 if (isdigit(tok)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002037 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002038 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002039 } else {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002040 // Is this a macro?
Jack Palevich303d8ff2009-06-11 19:06:24 -07002041 String* pValue = mMacros.get(&mTokenString);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002042 if (pValue) {
2043 // Yes, it is a macro
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002044 dptr = pValue->getUnwrapped();
2045 dch = ch;
2046 inp();
2047 next();
2048 } else {
Jack Palevich2db168f2009-06-11 14:29:47 -07002049 // Is this a keyword?
Jack Palevich303d8ff2009-06-11 19:06:24 -07002050 int kwtok = mKeywords.get(&mTokenString);
Jack Palevich2db168f2009-06-11 14:29:47 -07002051 if (kwtok) {
2052 tok = kwtok;
2053 // fprintf(stderr, "tok= keyword %s %x\n", last_id, tok);
2054 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002055 tok = (intptr_t) mSymbolTable.get(&mTokenString);
2056 if (!tok) {
2057 tok = TOK_UNDEFINED_SYMBOL;
2058 }
Jack Palevich2db168f2009-06-11 14:29:47 -07002059 // fprintf(stderr, "tok= symbol %s %x\n", last_id, tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07002060 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002061 }
2062 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002063 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002064 inp();
2065 if (tok == '\'') {
2066 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002067 tokc = getq();
2068 if (ch != '\'') {
2069 error("Expected a ' character, got %c", ch);
2070 } else {
2071 inp();
2072 }
Jack Palevich546b2242009-05-13 15:10:04 -07002073 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002074 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002075 while (ch && ch != EOF) {
2076 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002077 inp();
2078 inp();
2079 if (ch == '/')
2080 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002081 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002082 if (ch == EOF) {
2083 error("End of file inside comment.");
2084 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002085 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002086 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002087 } else if ((tok == '/') & (ch == '/')) {
2088 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002089 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002090 inp();
2091 }
2092 inp();
2093 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002094 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002095 const char* t = operatorChars;
2096 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002097 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002098 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002099 tokl = operatorLevel[opIndex];
2100 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002101 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002102#if 0
2103 printf("%c%c -> tokl=%d tokc=0x%x\n",
2104 l, a, tokl, tokc);
2105#endif
2106 if (a == ch) {
2107 inp();
2108 tok = TOK_DUMMY; /* dummy token for double tokens */
2109 }
2110 break;
2111 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002112 opIndex++;
2113 }
2114 if (l == 0) {
2115 tokl = 0;
2116 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002117 }
2118 }
2119 }
2120#if 0
2121 {
Jack Palevich2db168f2009-06-11 14:29:47 -07002122 const char* p;
Jack Palevich21a15a22009-05-11 14:49:29 -07002123
2124 printf("tok=0x%x ", tok);
Jack Palevich2db168f2009-06-11 14:29:47 -07002125 if (tok >= TOK_KEYWORD) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002126 printf("'");
Jack Palevich2db168f2009-06-11 14:29:47 -07002127 if (tok>= TOK_SYMBOL)
2128 p = sym_stk + 1 + ((char*) tok - (char*) pVarsBase) / 8;
2129 else {
2130 p = mKeywords.lookupKeyFor(tok);
2131 if (!p) {
2132 p = "unknown keyword";
2133 }
2134 }
Jack Palevich653f42d2009-05-28 17:15:32 -07002135 while (*p != TAG_TOK && *p)
2136 printf("%c", *p++);
Jack Palevich21a15a22009-05-11 14:49:29 -07002137 printf("'\n");
2138 } else if (tok == TOK_NUM) {
2139 printf("%d\n", tokc);
2140 } else {
2141 printf("'%c'\n", tok);
2142 }
2143 }
2144#endif
2145 }
2146
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002147 void doDefine() {
2148 String* pName = new String();
2149 while (isspace(ch)) {
2150 inp();
2151 }
2152 while (isid()) {
2153 pName->append(ch);
2154 inp();
2155 }
2156 if (ch == '(') {
2157 delete pName;
2158 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002159 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002160 }
2161 while (isspace(ch)) {
2162 inp();
2163 }
2164 String* pValue = new String();
2165 while (ch != '\n' && ch != EOF) {
2166 pValue->append(ch);
2167 inp();
2168 }
2169 delete mMacros.put(pName, pValue);
2170 }
2171
Jack Palevicheedf9d22009-06-04 16:23:40 -07002172 void doPragma() {
2173 // # pragma name(val)
2174 int state = 0;
2175 while(ch != EOF && ch != '\n' && state < 10) {
2176 switch(state) {
2177 case 0:
2178 if (isspace(ch)) {
2179 inp();
2180 } else {
2181 state++;
2182 }
2183 break;
2184 case 1:
2185 if (isalnum(ch)) {
2186 mPragmas.append(ch);
2187 inp();
2188 } else if (ch == '(') {
2189 mPragmas.append(0);
2190 inp();
2191 state++;
2192 } else {
2193 state = 11;
2194 }
2195 break;
2196 case 2:
2197 if (isalnum(ch)) {
2198 mPragmas.append(ch);
2199 inp();
2200 } else if (ch == ')') {
2201 mPragmas.append(0);
2202 inp();
2203 state = 10;
2204 } else {
2205 state = 11;
2206 }
2207 break;
2208 }
2209 }
2210 if(state != 10) {
2211 error("Unexpected pragma syntax");
2212 }
2213 mPragmaStringCount += 2;
2214 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002215
Jack Palevichac0e95e2009-05-29 13:53:44 -07002216 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002217 mErrorBuf.printf("%ld: ", file->getLine());
2218 mErrorBuf.vprintf(fmt, ap);
2219 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07002220 }
2221
Jack Palevich8b0624c2009-05-20 12:12:06 -07002222 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002223 if (tok != c) {
2224 error("'%c' expected", c);
2225 }
2226 next();
2227 }
2228
Jack Palevich21a15a22009-05-11 14:49:29 -07002229 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07002230 void unary(intptr_t l) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002231 intptr_t n, t, a;
2232 int c;
Jack Palevicha6baa232009-06-12 11:25:59 -07002233 String tString;
Jack Palevich546b2242009-05-13 15:10:04 -07002234 t = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002235 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
Jack Palevich21a15a22009-05-11 14:49:29 -07002236 if (tok == '\"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07002237 pGen->li((int) glo);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002238 while (ch != '\"' && ch != EOF) {
2239 *allocGlobalSpace(1) = getq();
2240 }
2241 if (ch != '\"') {
2242 error("Unterminated string constant.");
Jack Palevich21a15a22009-05-11 14:49:29 -07002243 }
Jack Palevich653f42d2009-05-28 17:15:32 -07002244 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002245 /* align heap */
2246 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07002247 inp();
2248 next();
2249 } else {
2250 c = tokl;
2251 a = tokc;
2252 t = tok;
Jack Palevicha6baa232009-06-12 11:25:59 -07002253 tString = mTokenString;
Jack Palevich21a15a22009-05-11 14:49:29 -07002254 next();
2255 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002256 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002257 } else if (c == 2) {
2258 /* -, +, !, ~ */
2259 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07002260 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002261 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002262 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002263 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002264 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002265 } else if (t == '(') {
2266 expr();
2267 skip(')');
2268 } else if (t == '*') {
2269 /* parse cast */
2270 skip('(');
2271 t = tok; /* get type */
2272 next(); /* skip int/char/void */
2273 next(); /* skip '*' or '(' */
2274 if (tok == '*') {
2275 /* function type */
2276 skip('*');
2277 skip(')');
2278 skip('(');
2279 skip(')');
2280 t = 0;
2281 }
2282 skip(')');
2283 unary(0);
2284 if (tok == '=') {
2285 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07002286 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002287 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002288 pGen->popR1();
2289 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002290 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002291 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07002292 }
2293 } else if (t == '&') {
Jack Palevich1cdef202009-05-22 12:06:27 -07002294 pGen->leaR0(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07002295 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002296 } else if (t == EOF ) {
2297 error("Unexpected EOF.");
Jack Palevicha1804dd2009-06-12 14:40:04 -07002298 } else if (!checkSymbol(t, &tString)) {
2299 // Don't have to do anything special here, the error
2300 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07002301 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002302 if (t == TOK_UNDEFINED_SYMBOL) {
2303 t = (intptr_t) mSymbolTable.addGlobal(
Jack Palevicha6baa232009-06-12 11:25:59 -07002304 new String(tString));
Jack Palevich303d8ff2009-06-11 19:06:24 -07002305 }
2306
Jack Palevicha6baa232009-06-12 11:25:59 -07002307 n = (intptr_t) ((VariableInfo*) t)->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07002308 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002309 if (!n) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002310 n = (intptr_t) dlsym(RTLD_DEFAULT,
Jack Palevicha6baa232009-06-12 11:25:59 -07002311 tString.getUnwrapped());
2312 ((VariableInfo*) t)->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002313 }
Jack Palevich546b2242009-05-13 15:10:04 -07002314 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002315 /* assignment */
2316 next();
2317 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002318 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07002319 } else if (tok != '(') {
2320 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07002321 if (!n) {
2322 error("Undefined variable %s", tString.getUnwrapped());
2323 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002324 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07002325 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002326 next();
2327 }
2328 }
2329 }
2330 }
2331
2332 /* function call */
2333 if (tok == '(') {
2334 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07002335 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002336
2337 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002338 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07002339 next();
2340 l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002341 while (tok != ')' && tok != EOF) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002342 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07002343 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002344 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002345 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002346 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002347 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002348 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07002349 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002350 if (!n) {
2351 /* forward reference */
2352 t = t + 4;
2353 *(int *) t = pGen->callForward(*(int *) t);
2354 } else if (n == 1) {
2355 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002356 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07002357 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07002358 }
-b master422972c2009-06-17 19:13:52 -07002359 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07002360 }
2361 }
2362
Jack Palevich653f42d2009-05-28 17:15:32 -07002363 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002364 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07002365 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002366 if (l-- == 1)
2367 unary(1);
2368 else {
2369 sum(l);
2370 a = 0;
2371 while (l == tokl) {
2372 n = tok;
2373 t = tokc;
2374 next();
2375
2376 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002377 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07002378 sum(l);
2379 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07002380 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07002381 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07002382 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07002383
Jack Palevich546b2242009-05-13 15:10:04 -07002384 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002385 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002386 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002387 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002388 }
2389 }
2390 }
2391 /* && and || output code generation */
2392 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002393 a = pGen->gtst(t == OP_LOGICAL_OR, a);
2394 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07002395 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002396 pGen->gsym(a);
2397 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07002398 }
2399 }
2400 }
2401
2402 void expr() {
2403 sum(11);
2404 }
2405
2406 int test_expr() {
2407 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002408 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002409 }
2410
Jack Palevicha6baa232009-06-12 11:25:59 -07002411 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07002412 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07002413
Jack Palevicha1804dd2009-06-12 14:40:04 -07002414 if (tok == TOK_INT || tok == TOK_CHAR) {
2415 /* declarations */
2416 localDeclarations();
2417 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002418 next();
2419 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 a = test_expr();
2421 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002422 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07002423 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002424 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002425 n = pGen->gjmp(0); /* jmp */
2426 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07002427 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002428 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002429 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002430 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002431 }
Jack Palevich546b2242009-05-13 15:10:04 -07002432 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002433 t = tok;
2434 next();
2435 skip('(');
2436 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07002437 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07002438 a = test_expr();
2439 } else {
2440 if (tok != ';')
2441 expr();
2442 skip(';');
2443 n = codeBuf.getPC();
2444 a = 0;
2445 if (tok != ';')
2446 a = test_expr();
2447 skip(';');
2448 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002449 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07002450 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07002451 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002452 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002453 n = t + 4;
2454 }
2455 }
2456 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07002457 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07002458 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002459 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07002460 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07002461 if (! outermostFunctionBlock) {
2462 mSymbolTable.pushLevel();
2463 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002464 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002465 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07002466 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002467 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07002468 if (! outermostFunctionBlock) {
2469 mSymbolTable.popLevel();
2470 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002471 } else {
2472 if (tok == TOK_RETURN) {
2473 next();
2474 if (tok != ';')
2475 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002476 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07002477 } else if (tok == TOK_BREAK) {
2478 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002479 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07002480 } else if (tok != ';')
2481 expr();
2482 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002483 }
2484 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002485
Jack Palevichb7c81e92009-06-04 19:56:13 -07002486 typedef int Type;
2487 static const Type TY_UNKNOWN = 0;
2488 static const Type TY_INT = 1;
2489 static const Type TY_CHAR = 2;
2490 static const Type TY_VOID = 3;
2491 static const int TY_BASE_TYPE_MASK = 0xf;
2492 static const int TY_INDIRECTION_MASK = 0xf0;
2493 static const int TY_INDIRECTION_SHIFT = 4;
2494 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07002495
Jack Palevichb7c81e92009-06-04 19:56:13 -07002496 Type getBaseType(Type t) {
2497 return t & TY_BASE_TYPE_MASK;
2498 }
2499
2500 int getIndirectionCount(Type t) {
2501 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
2502 }
2503
2504 void setIndirectionCount(Type& t, int count) {
2505 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
2506 | (t & ~TY_INDIRECTION_MASK));
2507 }
2508
2509 bool acceptType(Type& t) {
2510 t = TY_UNKNOWN;
2511 if (tok == TOK_INT) {
2512 t = TY_INT;
2513 } else if (tok == TOK_CHAR) {
2514 t = TY_CHAR;
2515 } else if (tok == TOK_VOID) {
2516 t = TY_VOID;
2517 } else {
2518 return false;
2519 }
2520 next();
2521 return true;
2522 }
2523
2524 Type acceptPointerDeclaration(Type& base) {
2525 Type t = base;
2526 int indirectionCount = 0;
2527 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
2528 next();
2529 indirectionCount++;
2530 }
2531 if (indirectionCount > MAX_INDIRECTION_COUNT) {
2532 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
2533 }
2534 setIndirectionCount(t, indirectionCount);
2535 return t;
2536 }
2537
2538 void expectType(Type& t) {
2539 if (!acceptType(t)) {
2540 error("Expected a type.");
2541 }
2542 }
2543
Jack Palevicha6baa232009-06-12 11:25:59 -07002544 void addGlobalSymbol() {
2545 tok = (intptr_t) mSymbolTable.addGlobal(
2546 new String(mTokenString));
2547 reportIfDuplicate();
2548 }
2549
2550 void reportIfDuplicate() {
2551 if (!tok) {
2552 error("Duplicate definition of %s", mTokenString.getUnwrapped());
Jack Palevich303d8ff2009-06-11 19:06:24 -07002553 }
2554 }
2555
Jack Palevicha6baa232009-06-12 11:25:59 -07002556 void addLocalSymbol() {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002557 tok = (intptr_t) mSymbolTable.addLocal(
2558 new String(mTokenString));
Jack Palevicha6baa232009-06-12 11:25:59 -07002559 reportIfDuplicate();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002560 }
2561
Jack Palevichb7c81e92009-06-04 19:56:13 -07002562 void localDeclarations() {
2563 intptr_t a;
2564 Type base;
2565
2566 while (acceptType(base)) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002567 while (tok != ';' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002568 Type t = acceptPointerDeclaration(t);
Jack Palevichd7461a72009-06-12 14:26:58 -07002569 int variableAddress = 0;
Jack Palevichf1728be2009-06-12 13:53:51 -07002570 if (checkSymbol()) {
2571 addLocalSymbol();
2572 if (tok) {
2573 loc = loc + 4;
Jack Palevichd7461a72009-06-12 14:26:58 -07002574 variableAddress = -loc;
2575 ((VariableInfo*) tok)->pAddress = (void*) variableAddress;
Jack Palevichf1728be2009-06-12 13:53:51 -07002576 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002577 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002578 next();
Jack Palevichd7461a72009-06-12 14:26:58 -07002579 if (tok == '=') {
2580 /* assignment */
2581 next();
2582 expr();
2583 pGen->storeR0(variableAddress);
2584 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002585 if (tok == ',')
2586 next();
2587 }
2588 skip(';');
2589 }
2590 }
2591
Jack Palevichf1728be2009-06-12 13:53:51 -07002592 bool checkSymbol() {
Jack Palevicha1804dd2009-06-12 14:40:04 -07002593 return checkSymbol(tok, &mTokenString);
2594 }
2595
2596 bool checkSymbol(int token, String* pText) {
2597 bool result = token < EOF || token >= TOK_UNDEFINED_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07002598 if (!result) {
2599 String temp;
Jack Palevicha1804dd2009-06-12 14:40:04 -07002600 if (token == EOF ) {
Jack Palevichd7461a72009-06-12 14:26:58 -07002601 temp.printf("EOF");
Jack Palevicha1804dd2009-06-12 14:40:04 -07002602 } else if (token == TOK_NUM) {
Jack Palevichd7461a72009-06-12 14:26:58 -07002603 temp.printf("numeric constant");
Jack Palevicha1804dd2009-06-12 14:40:04 -07002604 } else if (token >= 0 && token < 256) {
2605 temp.printf("char \'%c\'", token);
2606 } else if (token >= TOK_KEYWORD && token < TOK_UNSUPPORTED_KEYWORD) {
2607 temp.printf("keyword \"%s\"", pText->getUnwrapped());
Jack Palevichf1728be2009-06-12 13:53:51 -07002608 } else {
2609 temp.printf("reserved keyword \"%s\"",
Jack Palevicha1804dd2009-06-12 14:40:04 -07002610 pText->getUnwrapped());
Jack Palevichf1728be2009-06-12 13:53:51 -07002611 }
2612 error("Expected symbol. Got %s", temp.getUnwrapped());
2613 }
2614 return result;
2615 }
2616
Jack Palevichb7c81e92009-06-04 19:56:13 -07002617 void globalDeclarations() {
2618 while (tok != EOF) {
2619 Type base;
2620 expectType(base);
2621 Type t = acceptPointerDeclaration(t);
Jack Palevichf1728be2009-06-12 13:53:51 -07002622 if (tok >= 0 && tok < TOK_UNDEFINED_SYMBOL) {
2623 error("Unexpected token %d", tok);
2624 break;
2625 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002626 if (tok == TOK_UNDEFINED_SYMBOL) {
2627 addGlobalSymbol();
2628 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002629 VariableInfo* name = (VariableInfo*) tok;
Jack Palevicha6baa232009-06-12 11:25:59 -07002630 if (name && name->pAddress) {
2631 error("Already defined global %s",
2632 mTokenString.getUnwrapped());
2633 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002634 next();
Jack Palevichd7461a72009-06-12 14:26:58 -07002635 if (tok == ',' || tok == ';' || tok == '=') {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002636 // it's a variable declaration
2637 for(;;) {
Jack Palevicha6baa232009-06-12 11:25:59 -07002638 if (name) {
2639 name->pAddress = (int*) allocGlobalSpace(4);
2640 }
Jack Palevichd7461a72009-06-12 14:26:58 -07002641 if (tok == '=') {
2642 next();
2643 if (tok == TOK_NUM) {
2644 if (name) {
2645 * (int*) name->pAddress = tokc;
2646 }
2647 next();
2648 } else {
2649 error("Expected an integer constant");
2650 }
2651 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07002652 if (tok != ',') {
2653 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07002654 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002655 skip(',');
Jack Palevichb7c81e92009-06-04 19:56:13 -07002656 t = acceptPointerDeclaration(t);
Jack Palevicha6baa232009-06-12 11:25:59 -07002657 addGlobalSymbol();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002658 name = (VariableInfo*) tok;
Jack Palevichb7c81e92009-06-04 19:56:13 -07002659 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002660 }
2661 skip(';');
2662 } else {
Jack Palevicha6baa232009-06-12 11:25:59 -07002663 if (name) {
2664 /* patch forward references (XXX: does not work for function
2665 pointers) */
2666 pGen->gsym((int) name->pForward);
2667 /* put function address */
2668 name->pAddress = (void*) codeBuf.getPC();
2669 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002670 skip('(');
Jack Palevich303d8ff2009-06-11 19:06:24 -07002671 mSymbolTable.pushLevel();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002672 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07002673 int argCount = 0;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002674 while (tok != ')' && tok != EOF) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07002675 Type aType;
2676 expectType(aType);
2677 aType = acceptPointerDeclaration(aType);
Jack Palevichf1728be2009-06-12 13:53:51 -07002678 if (checkSymbol()) {
2679 addLocalSymbol();
2680 if (tok) {
2681 /* read param name and compute offset */
2682 *(int *) tok = a;
2683 a = a + 4;
2684 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002685 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002686 next();
2687 if (tok == ',')
2688 next();
Jack Palevich546b2242009-05-13 15:10:04 -07002689 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07002690 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07002691 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07002692 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002693 a = pGen->functionEntry(argCount);
Jack Palevicha6baa232009-06-12 11:25:59 -07002694 block(0, true);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002695 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07002696 pGen->functionExit(argCount, a, loc);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002697 mSymbolTable.popLevel();
Jack Palevich21a15a22009-05-11 14:49:29 -07002698 }
2699 }
2700 }
2701
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002702 char* allocGlobalSpace(int bytes) {
2703 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
2704 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07002705 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002706 }
2707 char* result = glo;
2708 glo += bytes;
2709 return result;
2710 }
2711
Jack Palevich21a15a22009-05-11 14:49:29 -07002712 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002713 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07002714 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07002715 pGlobalBase = 0;
2716 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002717 if (pGen) {
2718 delete pGen;
2719 pGen = 0;
2720 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002721 if (file) {
2722 delete file;
2723 file = 0;
2724 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002725 }
2726
2727 void clear() {
2728 tok = 0;
2729 tokc = 0;
2730 tokl = 0;
2731 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002732 rsym = 0;
2733 loc = 0;
2734 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002735 dptr = 0;
2736 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002737 file = 0;
2738 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002739 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002740 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002741 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002742
Jack Palevich22305132009-05-13 10:58:45 -07002743 void setArchitecture(const char* architecture) {
2744 delete pGen;
2745 pGen = 0;
2746
2747 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002748#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002749 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002750 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002751 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002752#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07002753#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07002754 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07002755 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07002756 }
Jack Paleviche7b59062009-05-19 17:12:17 -07002757#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07002758 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002759 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07002760 }
2761 }
2762
2763 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07002764#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07002765 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07002766#elif defined(DEFAULT_X86_CODEGEN)
2767 pGen = new X86CodeGenerator();
2768#endif
2769 }
2770 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002771 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07002772 } else {
2773 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07002774 }
2775 }
2776
Jack Palevich77ae76e2009-05-10 19:59:24 -07002777public:
Jack Palevich22305132009-05-13 10:58:45 -07002778 struct args {
2779 args() {
2780 architecture = 0;
2781 }
2782 const char* architecture;
2783 };
2784
Jack Paleviche7b59062009-05-19 17:12:17 -07002785 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002786 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002787 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002788
Jack Paleviche7b59062009-05-19 17:12:17 -07002789 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002790 cleanup();
2791 }
2792
Jack Palevich1cdef202009-05-22 12:06:27 -07002793 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002794 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07002795
2796 cleanup();
2797 clear();
2798 codeBuf.init(ALLOC_SIZE);
2799 setArchitecture(NULL);
2800 if (!pGen) {
2801 return -1;
2802 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002803#ifdef PROVIDE_TRACE_CODEGEN
2804 pGen = new TraceCodeGenerator(pGen);
2805#endif
2806 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07002807 pGen->init(&codeBuf);
2808 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07002809 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
2810 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07002811 inp();
2812 next();
2813 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07002814 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07002815 result = pGen->finishCompile();
2816 if (result == 0) {
2817 if (mErrorBuf.len()) {
2818 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07002819 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07002820 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002821 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07002822 }
2823
Jack Palevicha6baa232009-06-12 11:25:59 -07002824 void checkForUndefinedForwardReferences() {
2825 mSymbolTable.forEachGlobal(static_ufrcFn, this);
2826 }
2827
2828 static bool static_ufrcFn(String* key, VariableInfo* value,
2829 void* context) {
2830 Compiler* pCompiler = (Compiler*) context;
2831 return pCompiler->undefinedForwardReferenceCheck(key, value);
2832 }
2833
2834 bool undefinedForwardReferenceCheck(String* key, VariableInfo* value) {
2835#if 0
2836 fprintf(stderr, "%s 0x%8x 0x%08x\n", key->getUnwrapped(),
2837 value->pAddress, value->pForward);
2838#endif
2839 if (!value->pAddress && value->pForward) {
2840 error("Undefined forward reference: %s", key->getUnwrapped());
2841 }
2842 return true;
2843 }
2844
Jack Palevich21a15a22009-05-11 14:49:29 -07002845 int dump(FILE* out) {
2846 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
2847 return 0;
2848 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07002849
Jack Palevicha6535612009-05-13 16:24:17 -07002850 int disassemble(FILE* out) {
2851 return pGen->disassemble(out);
2852 }
2853
Jack Palevich1cdef202009-05-22 12:06:27 -07002854 /* Look through the symbol table to find a symbol.
2855 * If found, return its value.
2856 */
2857 void* lookup(const char* name) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002858 String string(name, -1, false);
2859 VariableInfo* pVariableInfo = mSymbolTable.get(&string);
2860 if (pVariableInfo) {
2861 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07002862 }
2863 return NULL;
2864 }
2865
Jack Palevicheedf9d22009-06-04 16:23:40 -07002866 void getPragmas(ACCsizei* actualStringCount,
2867 ACCsizei maxStringCount, ACCchar** strings) {
2868 int stringCount = mPragmaStringCount;
2869 if (actualStringCount) {
2870 *actualStringCount = stringCount;
2871 }
2872 if (stringCount > maxStringCount) {
2873 stringCount = maxStringCount;
2874 }
2875 if (strings) {
2876 char* pPragmas = mPragmas.getUnwrapped();
2877 while (stringCount-- > 0) {
2878 *strings++ = pPragmas;
2879 pPragmas += strlen(pPragmas) + 1;
2880 }
2881 }
2882 }
2883
Jack Palevichac0e95e2009-05-29 13:53:44 -07002884 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002885 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002886 }
2887
Jack Palevich77ae76e2009-05-10 19:59:24 -07002888};
2889
Jack Paleviche7b59062009-05-19 17:12:17 -07002890const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002891 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2892
Jack Paleviche7b59062009-05-19 17:12:17 -07002893const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002894 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2895 5, 5, /* ==, != */
2896 9, 10, /* &&, || */
2897 6, 7, 8, /* & ^ | */
2898 2, 2 /* ~ ! */
2899 };
2900
Jack Palevich8b0624c2009-05-20 12:12:06 -07002901#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002902FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002903#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002904
Jack Palevich8b0624c2009-05-20 12:12:06 -07002905#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002906const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002907 0x1, // ++
2908 0xff, // --
2909 0xc1af0f, // *
2910 0xf9f79991, // /
2911 0xf9f79991, // % (With manual assist to swap results)
2912 0xc801, // +
2913 0xd8f7c829, // -
2914 0xe0d391, // <<
2915 0xf8d391, // >>
2916 0xe, // <=
2917 0xd, // >=
2918 0xc, // <
2919 0xf, // >
2920 0x4, // ==
2921 0x5, // !=
2922 0x0, // &&
2923 0x1, // ||
2924 0xc821, // &
2925 0xc831, // ^
2926 0xc809, // |
2927 0xd0f7, // ~
2928 0x4 // !
2929};
Jack Palevich8b0624c2009-05-20 12:12:06 -07002930#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002931
Jack Palevich1cdef202009-05-22 12:06:27 -07002932struct ACCscript {
2933 ACCscript() {
2934 text = 0;
2935 textLength = 0;
2936 accError = ACC_NO_ERROR;
2937 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002938
Jack Palevich1cdef202009-05-22 12:06:27 -07002939 ~ACCscript() {
2940 delete text;
2941 }
Jack Palevich546b2242009-05-13 15:10:04 -07002942
Jack Palevich1cdef202009-05-22 12:06:27 -07002943 void setError(ACCenum error) {
2944 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
2945 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002946 }
2947 }
2948
Jack Palevich1cdef202009-05-22 12:06:27 -07002949 ACCenum getError() {
2950 ACCenum result = accError;
2951 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07002952 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002953 }
2954
Jack Palevich1cdef202009-05-22 12:06:27 -07002955 Compiler compiler;
2956 char* text;
2957 int textLength;
2958 ACCenum accError;
2959};
2960
2961
2962extern "C"
2963ACCscript* accCreateScript() {
2964 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002965}
Jack Palevich1cdef202009-05-22 12:06:27 -07002966
2967extern "C"
2968ACCenum accGetError( ACCscript* script ) {
2969 return script->getError();
2970}
2971
2972extern "C"
2973void accDeleteScript(ACCscript* script) {
2974 delete script;
2975}
2976
2977extern "C"
2978void accScriptSource(ACCscript* script,
2979 ACCsizei count,
2980 const ACCchar ** string,
2981 const ACCint * length) {
2982 int totalLength = 0;
2983 for(int i = 0; i < count; i++) {
2984 int len = -1;
2985 const ACCchar* s = string[i];
2986 if (length) {
2987 len = length[i];
2988 }
2989 if (len < 0) {
2990 len = strlen(s);
2991 }
2992 totalLength += len;
2993 }
2994 delete script->text;
2995 char* text = new char[totalLength + 1];
2996 script->text = text;
2997 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07002998 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07002999 for(int i = 0; i < count; i++) {
3000 int len = -1;
3001 const ACCchar* s = string[i];
3002 if (length) {
3003 len = length[i];
3004 }
3005 if (len < 0) {
3006 len = strlen(s);
3007 }
Jack Palevich09555c72009-05-27 12:25:55 -07003008 memcpy(dest, s, len);
3009 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07003010 }
3011 text[totalLength] = '\0';
3012}
3013
3014extern "C"
3015void accCompileScript(ACCscript* script) {
3016 int result = script->compiler.compile(script->text, script->textLength);
3017 if (result) {
3018 script->setError(ACC_INVALID_OPERATION);
3019 }
3020}
3021
3022extern "C"
3023void accGetScriptiv(ACCscript* script,
3024 ACCenum pname,
3025 ACCint * params) {
3026 switch (pname) {
3027 case ACC_INFO_LOG_LENGTH:
3028 *params = 0;
3029 break;
3030 }
3031}
3032
3033extern "C"
3034void accGetScriptInfoLog(ACCscript* script,
3035 ACCsizei maxLength,
3036 ACCsizei * length,
3037 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003038 char* message = script->compiler.getErrorMessage();
3039 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07003040 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003041 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07003042 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003043 if (infoLog && maxLength > 0) {
3044 int trimmedLength = maxLength < messageLength ?
3045 maxLength : messageLength;
3046 memcpy(infoLog, message, trimmedLength);
3047 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003048 }
3049}
3050
3051extern "C"
3052void accGetScriptLabel(ACCscript* script, const ACCchar * name,
3053 ACCvoid ** address) {
3054 void* value = script->compiler.lookup(name);
3055 if (value) {
3056 *address = value;
3057 } else {
3058 script->setError(ACC_INVALID_VALUE);
3059 }
3060}
3061
Jack Palevicheedf9d22009-06-04 16:23:40 -07003062extern "C"
3063void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
3064 ACCsizei maxStringCount, ACCchar** strings){
3065 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
3066}
3067
-b master422972c2009-06-17 19:13:52 -07003068extern "C"
3069void accDisassemble(ACCscript* script) {
3070 script->compiler.disassemble(stderr);
3071}
3072
Jack Palevicheedf9d22009-06-04 16:23:40 -07003073
Jack Palevich1cdef202009-05-22 12:06:27 -07003074} // namespace acc
3075