blob: 04d45d524fe546191b4057d648b5f98ea33b5ba3 [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
7 * Obfuscated Tiny C compiler, and retains the
8 * original copyright notice and license from that compiler, see below.
9 *
10 */
11
12/*
Jack Palevich21a15a22009-05-11 14:49:29 -070013 Obfuscated Tiny C Compiler
Jack Palevich88311482009-05-08 13:57:37 -070014
Jack Palevich21a15a22009-05-11 14:49:29 -070015 Copyright (C) 2001-2003 Fabrice Bellard
Jack Palevichae54f1f2009-05-08 14:54:15 -070016
Jack Palevich21a15a22009-05-11 14:49:29 -070017 This software is provided 'as-is', without any express or implied
18 warranty. In no event will the authors be held liable for any damages
19 arising from the use of this software.
Jack Paleviche27bf3e2009-05-10 14:09:03 -070020
Jack Palevich21a15a22009-05-11 14:49:29 -070021 Permission is granted to anyone to use this software for any purpose,
22 including commercial applications, and to alter it and redistribute it
23 freely, subject to the following restrictions:
Jack Paleviche27bf3e2009-05-10 14:09:03 -070024
Jack Palevich21a15a22009-05-11 14:49:29 -070025 1. The origin of this software must not be misrepresented; you must not
26 claim that you wrote the original software. If you use this software
27 in a product, an acknowledgment in the product and its documentation
28 *is* required.
29 2. Altered source versions must be plainly marked as such, and must not be
30 misrepresented as being the original software.
31 3. This notice may not be removed or altered from any source distribution.
32 */
Jack Paleviche27bf3e2009-05-10 14:09:03 -070033
Jack Palevich77ae76e2009-05-10 19:59:24 -070034#include <ctype.h>
35#include <dlfcn.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070036#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070038#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070039#include <stdlib.h>
40#include <string.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070041
Jack Palevich546b2242009-05-13 15:10:04 -070042#if defined(__arm__)
43#include <unistd.h>
44#endif
45
Jack Paleviche7b59062009-05-19 17:12:17 -070046#if defined(__arm__)
47#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070048#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070049#elif defined(__i386__)
50#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070051#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070052#elif defined(__x86_64__)
53#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070054#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070055#endif
56
Jack Paleviche7b59062009-05-19 17:12:17 -070057
58#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070059#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070060#endif
Jack Palevicha6535612009-05-13 16:24:17 -070061
Jack Palevichbbf8ab52009-05-11 11:54:30 -070062namespace acc {
63
Jack Paleviche7b59062009-05-19 17:12:17 -070064class Compiler {
Jack Palevich21a15a22009-05-11 14:49:29 -070065 class CodeBuf {
66 char* ind;
67 char* pProgramBase;
Jack Palevichf0cbc922009-05-08 16:35:13 -070068
Jack Palevich21a15a22009-05-11 14:49:29 -070069 void release() {
70 if (pProgramBase != 0) {
71 free(pProgramBase);
72 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070073 }
Jack Palevich21a15a22009-05-11 14:49:29 -070074 }
75
76 public:
77 CodeBuf() {
78 pProgramBase = 0;
79 ind = 0;
80 }
81
82 ~CodeBuf() {
83 release();
84 }
85
86 void init(int size) {
87 release();
88 pProgramBase = (char*) calloc(1, size);
89 ind = pProgramBase;
90 }
91
Jack Palevich546b2242009-05-13 15:10:04 -070092 int o4(int n) {
Jack Palevich8b0624c2009-05-20 12:12:06 -070093 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -070094 * (int*) ind = n;
95 ind += 4;
96 return result;
97 }
98
Jack Palevich21a15a22009-05-11 14:49:29 -070099 /*
100 * Output a byte. Handles all values, 0..ff.
101 */
102 void ob(int n) {
103 *ind++ = n;
104 }
105
Jack Palevich21a15a22009-05-11 14:49:29 -0700106 inline void* getBase() {
107 return (void*) pProgramBase;
108 }
109
Jack Palevich8b0624c2009-05-20 12:12:06 -0700110 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700111 return ind - pProgramBase;
112 }
113
Jack Palevich8b0624c2009-05-20 12:12:06 -0700114 intptr_t getPC() {
115 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700116 }
117 };
118
119 class CodeGenerator {
120 public:
121 CodeGenerator() {}
122 virtual ~CodeGenerator() {}
123
Jack Palevich22305132009-05-13 10:58:45 -0700124 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700125 this->pCodeBuf = pCodeBuf;
126 }
127
Jack Palevich22305132009-05-13 10:58:45 -0700128 /* returns address to patch with local variable size
129 */
Jack Palevich546b2242009-05-13 15:10:04 -0700130 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700131
Jack Palevich546b2242009-05-13 15:10:04 -0700132 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700133
134 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700135 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700136
137 virtual int gjmp(int t) = 0;
138
139 /* l = 0: je, l == 1: jne */
140 virtual int gtst(bool l, int t) = 0;
141
142 virtual void gcmp(int op) = 0;
143
Jack Palevich546b2242009-05-13 15:10:04 -0700144 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700145
146 virtual void clearECX() = 0;
147
148 virtual void pushEAX() = 0;
149
150 virtual void popECX() = 0;
151
152 virtual void storeEAXToAddressECX(bool isInt) = 0;
153
154 virtual void loadEAXIndirect(bool isInt) = 0;
155
156 virtual void leaEAX(int ea) = 0;
157
158 virtual void storeEAX(int ea) = 0;
159
Jack Palevich4d93f302009-05-15 13:30:00 -0700160 virtual void loadEAX(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700161
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700162 virtual int beginFunctionCallArguments() = 0;
163
Jack Palevich7810bc92009-05-15 14:31:47 -0700164 virtual void storeEAToArg(int l) = 0;
165
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700166 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700167
Jack Palevich22305132009-05-13 10:58:45 -0700168
169 virtual int callForward(int symbol) = 0;
170
171 virtual void callRelative(int t) = 0;
172
173 virtual void callIndirect(int l) = 0;
174
Jack Palevich7810bc92009-05-15 14:31:47 -0700175 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700176
Jack Palevicha6535612009-05-13 16:24:17 -0700177 virtual int disassemble(FILE* out) = 0;
178
Jack Palevich21a15a22009-05-11 14:49:29 -0700179 /* output a symbol and patch all calls to it */
Jack Paleviche7b59062009-05-19 17:12:17 -0700180 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700181
Jack Palevich546b2242009-05-13 15:10:04 -0700182 virtual int finishCompile() {
183#if defined(__arm__)
Jack Palevicha6535612009-05-13 16:24:17 -0700184 const long base = long(pCodeBuf->getBase());
185 const long curr = base + long(pCodeBuf->getSize());
186 int err = cacheflush(base, curr, 0);
187 return err;
Jack Palevich546b2242009-05-13 15:10:04 -0700188#else
Jack Palevicha6535612009-05-13 16:24:17 -0700189 return 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700190#endif
191 }
192
Jack Palevicha6535612009-05-13 16:24:17 -0700193 /**
194 * Adjust relative branches by this amount.
195 */
196 virtual int jumpOffset() = 0;
197
Jack Palevich21a15a22009-05-11 14:49:29 -0700198 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700199 /*
200 * Output a byte. Handles all values, 0..ff.
201 */
202 void ob(int n) {
203 pCodeBuf->ob(n);
204 }
205
Jack Palevich8b0624c2009-05-20 12:12:06 -0700206 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700207 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700208 }
209
Jack Palevich8b0624c2009-05-20 12:12:06 -0700210 intptr_t getBase() {
211 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700212 }
213
Jack Palevich8b0624c2009-05-20 12:12:06 -0700214 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 return pCodeBuf->getPC();
216 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 private:
218 CodeBuf* pCodeBuf;
219 };
220
Jack Paleviche7b59062009-05-19 17:12:17 -0700221#ifdef PROVIDE_ARM_CODEGEN
222
Jack Palevich22305132009-05-13 10:58:45 -0700223 class ARMCodeGenerator : public CodeGenerator {
224 public:
225 ARMCodeGenerator() {}
226 virtual ~ARMCodeGenerator() {}
227
228 /* returns address to patch with local variable size
229 */
Jack Palevich546b2242009-05-13 15:10:04 -0700230 virtual int functionEntry(int argCount) {
231 fprintf(stderr, "functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700232 // sp -> arg4 arg5 ...
233 // Push our register-based arguments back on the stack
234 if (argCount > 0) {
235 int regArgCount = argCount <= 4 ? argCount : 4;
236 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
237 }
238 // sp -> arg0 arg1 ...
239 o4(0xE92D4800); // stmfd sp!, {fp, lr}
240 // sp, fp -> oldfp, retadr, arg0 arg1 ....
241 o4(0xE1A0B00D); // mov fp, sp
242 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700243 }
244
Jack Palevich546b2242009-05-13 15:10:04 -0700245 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
246 fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700247 // Patch local variable allocation code:
248 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700249 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700250 }
Jack Palevich69796b62009-05-14 15:42:26 -0700251 *(char*) (localVariableAddress) = localVariableSize;
252
253 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
254 o4(0xE1A0E00B); // mov lr, fp
255 o4(0xE59BB000); // ldr fp, [fp]
256 o4(0xE28ED004); // add sp, lr, #4
257 // sp -> retadr, arg0, ...
258 o4(0xE8BD4000); // ldmfd sp!, {lr}
259 // sp -> arg0 ....
260 if (argCount > 0) {
261 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700262 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700263 // earlier. We don't need to actually store them anywhere,
264 // just adjust the stack.
265 int regArgCount = argCount <= 4 ? argCount : 4;
266 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
267 }
268 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700269 }
270
271 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700272 virtual void li(int t) {
Jack Palevich22305132009-05-13 10:58:45 -0700273 fprintf(stderr, "li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700274 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700275 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700276 } else if (t >= -256 && t < 0) {
277 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700278 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700279 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700280 o4(0xE51F0000); // ldr r0, .L3
281 o4(0xEA000000); // b .L99
282 o4(t); // .L3: .word 0
283 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700284 }
Jack Palevich22305132009-05-13 10:58:45 -0700285 }
286
287 virtual int gjmp(int t) {
288 fprintf(stderr, "gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700289 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700290 }
291
292 /* l = 0: je, l == 1: jne */
293 virtual int gtst(bool l, int t) {
294 fprintf(stderr, "gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700295 o4(0xE3500000); // cmp r0,#0
296 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
297 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700298 }
299
300 virtual void gcmp(int op) {
301 fprintf(stderr, "gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700302 o4(0xE1510000); // cmp r1, r1
303 switch(op) {
304 case OP_EQUALS:
305 o4(0x03A00001); // moveq r0,#1
306 o4(0x13A00000); // movne r0,#0
307 break;
308 case OP_NOT_EQUALS:
309 o4(0x03A00000); // moveq r0,#0
310 o4(0x13A00001); // movne r0,#1
311 break;
312 case OP_LESS_EQUAL:
313 o4(0xD3A00001); // movle r0,#1
314 o4(0xC3A00000); // movgt r0,#0
315 break;
316 case OP_GREATER:
317 o4(0xD3A00000); // movle r0,#0
318 o4(0xC3A00001); // movgt r0,#1
319 break;
320 case OP_GREATER_EQUAL:
321 o4(0xA3A00001); // movge r0,#1
322 o4(0xB3A00000); // movlt r0,#0
323 break;
324 case OP_LESS:
325 o4(0xA3A00000); // movge r0,#0
326 o4(0xB3A00001); // movlt r0,#1
327 break;
328 default:
329 error("Unknown comparison op %d", op);
330 break;
331 }
Jack Palevich22305132009-05-13 10:58:45 -0700332 }
333
Jack Palevich546b2242009-05-13 15:10:04 -0700334 virtual void genOp(int op) {
Jack Palevich22305132009-05-13 10:58:45 -0700335 fprintf(stderr, "genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700336 switch(op) {
337 case OP_MUL:
338 o4(0x0E0000091); // mul r0,r1,r0
339 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700340 case OP_DIV:
341 callRuntime(runtime_DIV);
342 break;
343 case OP_MOD:
344 callRuntime(runtime_MOD);
345 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700346 case OP_PLUS:
347 o4(0xE0810000); // add r0,r1,r0
348 break;
349 case OP_MINUS:
350 o4(0xE0410000); // sub r0,r1,r0
351 break;
352 case OP_SHIFT_LEFT:
353 o4(0xE1A00011); // lsl r0,r1,r0
354 break;
355 case OP_SHIFT_RIGHT:
356 o4(0xE1A00051); // asr r0,r1,r0
357 break;
358 case OP_BIT_AND:
359 o4(0xE0010000); // and r0,r1,r0
360 break;
361 case OP_BIT_XOR:
362 o4(0xE0210000); // eor r0,r1,r0
363 break;
364 case OP_BIT_OR:
365 o4(0xE1810000); // orr r0,r1,r0
366 break;
367 case OP_BIT_NOT:
368 o4(0xE1E00000); // mvn r0, r0
369 break;
370 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700371 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700372 break;
373 }
Jack Palevich22305132009-05-13 10:58:45 -0700374#if 0
375 o(decodeOp(op));
376 if (op == OP_MOD)
377 o(0x92); /* xchg %edx, %eax */
378#endif
379 }
380
381 virtual void clearECX() {
382 fprintf(stderr, "clearECX();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700383 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700384 }
385
386 virtual void pushEAX() {
387 fprintf(stderr, "pushEAX();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700388 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700389 }
390
391 virtual void popECX() {
392 fprintf(stderr, "popECX();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700393 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700394 }
395
396 virtual void storeEAXToAddressECX(bool isInt) {
397 fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700398 if (isInt) {
399 o4(0xE5810000); // str r0, [r1]
400 } else {
401 o4(0xE5C10000); // strb r0, [r1]
402 }
Jack Palevich22305132009-05-13 10:58:45 -0700403 }
404
405 virtual void loadEAXIndirect(bool isInt) {
406 fprintf(stderr, "loadEAXIndirect(%d);\n", isInt);
407 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700408 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700409 else
Jack Palevich69796b62009-05-14 15:42:26 -0700410 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700411 }
412
413 virtual void leaEAX(int ea) {
Jack Palevichbd894902009-05-14 19:35:31 -0700414 fprintf(stderr, "leaEAX(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700415 if (ea < LOCAL) {
416 // Local, fp relative
417 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
418 error("Offset out of range: %08x", ea);
419 }
420 if (ea < 0) {
421 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
422 } else {
423 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
424 }
Jack Palevichbd894902009-05-14 19:35:31 -0700425 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700426 // Global, absolute.
427 o4(0xE59F0000); // ldr r0, .L1
428 o4(0xEA000000); // b .L99
429 o4(ea); // .L1: .word 0
430 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700431 }
Jack Palevich22305132009-05-13 10:58:45 -0700432 }
433
434 virtual void storeEAX(int ea) {
435 fprintf(stderr, "storeEAX(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700436 if (ea < LOCAL) {
437 // Local, fp relative
438 if (ea < -4095 || ea > 4095) {
439 error("Offset out of range: %08x", ea);
440 }
441 if (ea < 0) {
442 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
443 } else {
444 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
445 }
446 } else{
447 // Global, absolute
448 o4(0xE59F1000); // ldr r1, .L1
449 o4(0xEA000000); // b .L99
450 o4(ea); // .L1: .word 0
451 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700452 }
Jack Palevich22305132009-05-13 10:58:45 -0700453 }
454
Jack Palevich4d93f302009-05-15 13:30:00 -0700455 virtual void loadEAX(int ea, bool isIncDec, int op) {
456 fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op);
457 if (ea < LOCAL) {
458 // Local, fp relative
459 if (ea < -4095 || ea > 4095) {
460 error("Offset out of range: %08x", ea);
461 }
462 if (ea < 0) {
463 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
464 } else {
465 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
466 }
Jack Palevich69796b62009-05-14 15:42:26 -0700467 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700468 // Global, absolute
469 o4(0xE59F2000); // ldr r2, .L1
470 o4(0xEA000000); // b .L99
471 o4(ea); // .L1: .word ea
472 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700473 }
Jack Palevich22305132009-05-13 10:58:45 -0700474
Jack Palevich4d93f302009-05-15 13:30:00 -0700475 if (isIncDec) {
476 switch (op) {
477 case OP_INCREMENT:
478 o4(0xE2801001); // add r1, r0, #1
479 break;
480 case OP_DECREMENT:
481 o4(0xE2401001); // sub r1, r0, #1
482 break;
483 default:
484 error("unknown opcode: %d", op);
485 }
486 if (ea < LOCAL) {
487 // Local, fp relative
488 // Don't need range check, was already checked above
489 if (ea < 0) {
490 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
491 } else {
492 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
493 }
494 } else{
495 // Global, absolute
496 // r2 is already set up from before.
497 o4(0xE5821000); // str r1, [r2]
498 }
Jack Palevichbd894902009-05-14 19:35:31 -0700499 }
Jack Palevich22305132009-05-13 10:58:45 -0700500 }
501
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700502 virtual int beginFunctionCallArguments() {
503 fprintf(stderr, "beginFunctionCallArguments();\n");
504 return o4(0xE24DDF00); // Placeholder
505 }
506
Jack Palevich7810bc92009-05-15 14:31:47 -0700507 virtual void storeEAToArg(int l) {
508 fprintf(stderr, "storeEAToArg(%d);\n", l);
509 if (l < 0 || l > 4096-4) {
510 error("l out of range for stack offset: 0x%08x", l);
511 }
512 o4(0xE58D0000 + l); // str r0, [sp, #4]
513 }
514
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700515 virtual void endFunctionCallArguments(int a, int l) {
516 fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l);
517 if (l < 0 || l > 0x3FC) {
518 error("L out of range for stack adjustment: 0x%08x", l);
519 }
520 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
521 int argCount = l >> 2;
522 if (argCount > 0) {
523 int regArgCount = argCount > 4 ? 4 : argCount;
524 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
525 }
Jack Palevich22305132009-05-13 10:58:45 -0700526 }
527
Jack Palevich22305132009-05-13 10:58:45 -0700528 virtual int callForward(int symbol) {
529 fprintf(stderr, "callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700530 // Forward calls are always short (local)
531 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700532 }
533
534 virtual void callRelative(int t) {
535 fprintf(stderr, "callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700536 int abs = t + getPC() + jumpOffset();
Jack Palevichbd894902009-05-14 19:35:31 -0700537 fprintf(stderr, "abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700538 if (t >= - (1 << 25) && t < (1 << 25)) {
539 o4(0xEB000000 | encodeAddress(t));
540 } else {
541 // Long call.
542 o4(0xE59FC000); // ldr r12, .L1
543 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700544 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700545 o4(0xE08CC00F); // .L99: add r12,pc
546 o4(0xE12FFF3C); // blx r12
547 }
Jack Palevich22305132009-05-13 10:58:45 -0700548 }
549
550 virtual void callIndirect(int l) {
551 fprintf(stderr, "callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700552 int argCount = l >> 2;
553 int poppedArgs = argCount > 4 ? 4 : argCount;
554 int adjustedL = l - (poppedArgs << 2);
555 if (adjustedL < 0 || adjustedL > 4096-4) {
556 error("l out of range for stack offset: 0x%08x", l);
557 }
558 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
559 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700560 }
561
Jack Palevich7810bc92009-05-15 14:31:47 -0700562 virtual void adjustStackAfterCall(int l, bool isIndirect) {
563 fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700564 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700565 int stackArgs = argCount > 4 ? argCount - 4 : 0;
566 int stackUse = stackArgs + (isIndirect ? 1 : 0);
567 if (stackUse) {
568 if (stackUse < 0 || stackUse > 255) {
569 error("L out of range for stack adjustment: 0x%08x", l);
570 }
571 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700572 }
Jack Palevich22305132009-05-13 10:58:45 -0700573 }
574
Jack Palevicha6535612009-05-13 16:24:17 -0700575 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700576 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700577 }
578
579 /* output a symbol and patch all calls to it */
580 virtual void gsym(int t) {
581 fprintf(stderr, "gsym(0x%x)\n", t);
582 int n;
583 int base = getBase();
584 int pc = getPC();
585 fprintf(stderr, "pc = 0x%x\n", pc);
586 while (t) {
587 int data = * (int*) t;
588 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
589 if (decodedOffset == 0) {
590 n = 0;
591 } else {
592 n = base + decodedOffset; /* next value */
593 }
594 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
595 | encodeRelAddress(pc - t - 8);
596 t = n;
597 }
598 }
599
600 virtual int disassemble(FILE* out) {
601 disasmOut = out;
602 disasm_interface_t di;
603 di.di_readword = disassemble_readword;
604 di.di_printaddr = disassemble_printaddr;
605 di.di_printf = disassemble_printf;
606
607 int base = getBase();
608 int pc = getPC();
609 for(int i = base; i < pc; i += 4) {
610 fprintf(out, "%08x: %08x ", i, *(int*) i);
611 ::disasm(&di, i, 0);
612 }
613 return 0;
614 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700615
Jack Palevich22305132009-05-13 10:58:45 -0700616 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700617 static FILE* disasmOut;
618
619 static u_int
620 disassemble_readword(u_int address)
621 {
622 return(*((u_int *)address));
623 }
624
625 static void
626 disassemble_printaddr(u_int address)
627 {
628 fprintf(disasmOut, "0x%08x", address);
629 }
630
631 static void
632 disassemble_printf(const char *fmt, ...) {
633 va_list ap;
634 va_start(ap, fmt);
635 vfprintf(disasmOut, fmt, ap);
636 va_end(ap);
637 }
638
639 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
640
641 /** Encode a relative address that might also be
642 * a label.
643 */
644 int encodeAddress(int value) {
645 int base = getBase();
646 if (value >= base && value <= getPC() ) {
647 // This is a label, encode it relative to the base.
648 value = value - base;
649 }
650 return encodeRelAddress(value);
651 }
652
653 int encodeRelAddress(int value) {
654 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
655 }
Jack Palevich22305132009-05-13 10:58:45 -0700656
Jack Palevich3d474a72009-05-15 15:12:38 -0700657 typedef int (*int2FnPtr)(int a, int b);
658 void callRuntime(int2FnPtr fn) {
659 o4(0xE59F2000); // ldr r2, .L1
660 o4(0xEA000000); // b .L99
661 o4((int) fn); //.L1: .word fn
662 o4(0xE12FFF32); //.L99: blx r2
663 }
664
665 static int runtime_DIV(int a, int b) {
666 return b / a;
667 }
668
669 static int runtime_MOD(int a, int b) {
670 return b % a;
671 }
672
Jack Palevich546b2242009-05-13 15:10:04 -0700673 void error(const char* fmt,...) {
674 va_list ap;
675 va_start(ap, fmt);
676 vfprintf(stderr, fmt, ap);
677 va_end(ap);
678 exit(12);
679 }
Jack Palevich22305132009-05-13 10:58:45 -0700680 };
681
Jack Paleviche7b59062009-05-19 17:12:17 -0700682#endif // PROVIDE_X86_CODEGEN
683
684#ifdef PROVIDE_X86_CODEGEN
685
Jack Palevich21a15a22009-05-11 14:49:29 -0700686 class X86CodeGenerator : public CodeGenerator {
687 public:
688 X86CodeGenerator() {}
689 virtual ~X86CodeGenerator() {}
690
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700691 /* returns address to patch with local variable size
692 */
Jack Palevich546b2242009-05-13 15:10:04 -0700693 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700694 o(0xe58955); /* push %ebp, mov %esp, %ebp */
695 return oad(0xec81, 0); /* sub $xxx, %esp */
696 }
697
Jack Palevich546b2242009-05-13 15:10:04 -0700698 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700699 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700700 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700701 }
702
Jack Palevich21a15a22009-05-11 14:49:29 -0700703 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700704 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700705 oad(0xb8, t); /* mov $xx, %eax */
706 }
707
Jack Palevich22305132009-05-13 10:58:45 -0700708 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700709 return psym(0xe9, t);
710 }
711
712 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700713 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700714 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
715 return psym(0x84 + l, t);
716 }
717
Jack Palevich22305132009-05-13 10:58:45 -0700718 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700719 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700720 o(0xc139); /* cmp %eax,%ecx */
721 li(0);
722 o(0x0f); /* setxx %al */
723 o(t + 0x90);
724 o(0xc0);
725 }
726
Jack Palevich546b2242009-05-13 15:10:04 -0700727 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700728 o(decodeOp(op));
729 if (op == OP_MOD)
730 o(0x92); /* xchg %edx, %eax */
731 }
732
Jack Palevich22305132009-05-13 10:58:45 -0700733 virtual void clearECX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700734 oad(0xb9, 0); /* movl $0, %ecx */
735 }
736
Jack Palevich22305132009-05-13 10:58:45 -0700737 virtual void pushEAX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700738 o(0x50); /* push %eax */
739 }
740
Jack Palevich22305132009-05-13 10:58:45 -0700741 virtual void popECX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700742 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700743 }
744
Jack Palevich22305132009-05-13 10:58:45 -0700745 virtual void storeEAXToAddressECX(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700746 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
747 }
748
Jack Palevich22305132009-05-13 10:58:45 -0700749 virtual void loadEAXIndirect(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700750 if (isInt)
751 o(0x8b); /* mov (%eax), %eax */
752 else
753 o(0xbe0f); /* movsbl (%eax), %eax */
754 ob(0); /* add zero in code */
755 }
756
Jack Palevich22305132009-05-13 10:58:45 -0700757 virtual void leaEAX(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700758 gmov(10, ea); /* leal EA, %eax */
759 }
760
Jack Palevich22305132009-05-13 10:58:45 -0700761 virtual void storeEAX(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700762 gmov(6, ea); /* mov %eax, EA */
763 }
764
Jack Palevich4d93f302009-05-15 13:30:00 -0700765 virtual void loadEAX(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700766 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700767 if (isIncDec) {
768 /* Implement post-increment or post decrement.
769 */
770 gmov(0, ea); /* 83 ADD */
771 o(decodeOp(op));
772 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700773 }
774
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700775 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700776 return oad(0xec81, 0); /* sub $xxx, %esp */
777 }
778
Jack Palevich22305132009-05-13 10:58:45 -0700779 virtual void storeEAToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700780 oad(0x248489, l); /* movl %eax, xxx(%esp) */
781 }
782
Jack Palevich7810bc92009-05-15 14:31:47 -0700783 virtual void endFunctionCallArguments(int a, int l) {
784 * (int*) a = l;
785 }
786
Jack Palevich22305132009-05-13 10:58:45 -0700787 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700788 return psym(0xe8, symbol); /* call xxx */
789 }
790
Jack Palevich22305132009-05-13 10:58:45 -0700791 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700792 psym(0xe8, t); /* call xxx */
793 }
794
Jack Palevich22305132009-05-13 10:58:45 -0700795 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700796 oad(0x2494ff, l); /* call *xxx(%esp) */
797 }
798
Jack Palevich7810bc92009-05-15 14:31:47 -0700799 virtual void adjustStackAfterCall(int l, bool isIndirect) {
800 if (isIndirect) {
801 l += 4;
802 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700803 oad(0xc481, l); /* add $xxx, %esp */
804 }
805
Jack Palevicha6535612009-05-13 16:24:17 -0700806 virtual int jumpOffset() {
807 return 5;
808 }
809
810 virtual int disassemble(FILE* out) {
811 return 1;
812 }
813
Jack Paleviche7b59062009-05-19 17:12:17 -0700814 /* output a symbol and patch all calls to it */
815 virtual void gsym(int t) {
816 int n;
817 int pc = getPC();
818 while (t) {
819 n = *(int *) t; /* next value */
820 *(int *) t = pc - t - 4;
821 t = n;
822 }
823 }
824
Jack Palevich21a15a22009-05-11 14:49:29 -0700825 private:
Jack Paleviche7b59062009-05-19 17:12:17 -0700826
827 /** Output 1 to 4 bytes.
828 *
829 */
830 void o(int n) {
831 /* cannot use unsigned, so we must do a hack */
832 while (n && n != -1) {
833 ob(n & 0xff);
834 n = n >> 8;
835 }
836 }
837
838 /* psym is used to put an instruction with a data field which is a
839 reference to a symbol. It is in fact the same as oad ! */
840 int psym(int n, int t) {
841 return oad(n, t);
842 }
843
844 /* instruction + address */
845 int oad(int n, int t) {
846 o(n);
847 int result = getPC();
848 o4(t);
849 return result;
850 }
851
852
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700853 static const int operatorHelper[];
854
855 int decodeOp(int op) {
856 if (op < 0 || op > OP_COUNT) {
857 fprintf(stderr, "Out-of-range operator: %d\n", op);
858 exit(1);
859 }
860 return operatorHelper[op];
861 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700862
Jack Palevich546b2242009-05-13 15:10:04 -0700863 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700864 o(l + 0x83);
865 oad((t < LOCAL) << 7 | 5, t);
866 }
867 };
868
Jack Paleviche7b59062009-05-19 17:12:17 -0700869#endif // PROVIDE_X86_CODEGEN
870
Jack Palevich21a15a22009-05-11 14:49:29 -0700871 /* vars: value of variables
872 loc : local variable index
873 glo : global variable index
874 ind : output code ptr
875 rsym: return symbol
876 prog: output code
877 dstk: define stack
878 dptr, dch: macro state
879 */
Jack Palevich8b0624c2009-05-20 12:12:06 -0700880 intptr_t tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk,
Jack Palevich21a15a22009-05-11 14:49:29 -0700881 dptr, dch, last_id;
882 void* pSymbolBase;
883 void* pGlobalBase;
884 void* pVarsBase;
885 FILE* file;
886
887 CodeBuf codeBuf;
Jack Palevich22305132009-05-13 10:58:45 -0700888 CodeGenerator* pGen;
Jack Palevich21a15a22009-05-11 14:49:29 -0700889
890 static const int ALLOC_SIZE = 99999;
891
892 /* depends on the init string */
893 static const int TOK_STR_SIZE = 48;
894 static const int TOK_IDENT = 0x100;
895 static const int TOK_INT = 0x100;
896 static const int TOK_IF = 0x120;
897 static const int TOK_ELSE = 0x138;
898 static const int TOK_WHILE = 0x160;
899 static const int TOK_BREAK = 0x190;
900 static const int TOK_RETURN = 0x1c0;
901 static const int TOK_FOR = 0x1f8;
902 static const int TOK_DEFINE = 0x218;
903 static const int TOK_MAIN = 0x250;
904
905 static const int TOK_DUMMY = 1;
906 static const int TOK_NUM = 2;
907
908 static const int LOCAL = 0x200;
909
910 static const int SYM_FORWARD = 0;
911 static const int SYM_DEFINE = 1;
912
913 /* tokens in string heap */
914 static const int TAG_TOK = ' ';
915 static const int TAG_MACRO = 2;
916
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700917 static const int OP_INCREMENT = 0;
918 static const int OP_DECREMENT = 1;
919 static const int OP_MUL = 2;
920 static const int OP_DIV = 3;
921 static const int OP_MOD = 4;
922 static const int OP_PLUS = 5;
923 static const int OP_MINUS = 6;
924 static const int OP_SHIFT_LEFT = 7;
925 static const int OP_SHIFT_RIGHT = 8;
926 static const int OP_LESS_EQUAL = 9;
927 static const int OP_GREATER_EQUAL = 10;
928 static const int OP_LESS = 11;
929 static const int OP_GREATER = 12;
930 static const int OP_EQUALS = 13;
931 static const int OP_NOT_EQUALS = 14;
932 static const int OP_LOGICAL_AND = 15;
933 static const int OP_LOGICAL_OR = 16;
934 static const int OP_BIT_AND = 17;
935 static const int OP_BIT_XOR = 18;
936 static const int OP_BIT_OR = 19;
937 static const int OP_BIT_NOT = 20;
938 static const int OP_LOGICAL_NOT = 21;
939 static const int OP_COUNT = 22;
940
941 /* Operators are searched from front, the two-character operators appear
942 * before the single-character operators with the same first character.
943 * @ is used to pad out single-character operators.
944 */
945 static const char* operatorChars;
946 static const char operatorLevel[];
947
Jack Palevich21a15a22009-05-11 14:49:29 -0700948 void pdef(int t) {
949 *(char *) dstk++ = t;
950 }
951
952 void inp() {
953 if (dptr) {
954 ch = *(char *) dptr++;
955 if (ch == TAG_MACRO) {
956 dptr = 0;
957 ch = dch;
958 }
959 } else
960 ch = fgetc(file);
961 /* printf("ch=%c 0x%x\n", ch, ch); */
962 }
963
964 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -0700965 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -0700966 }
967
968 /* read a character constant */
969 void getq() {
970 if (ch == '\\') {
971 inp();
972 if (ch == 'n')
973 ch = '\n';
974 }
975 }
976
977 void next() {
978 int l, a;
979
Jack Palevich546b2242009-05-13 15:10:04 -0700980 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700981 if (ch == '#') {
982 inp();
983 next();
984 if (tok == TOK_DEFINE) {
985 next();
986 pdef(TAG_TOK); /* fill last ident tag */
987 *(int *) tok = SYM_DEFINE;
988 *(int *) (tok + 4) = dstk; /* define stack */
989 }
990 /* well we always save the values ! */
991 while (ch != '\n') {
992 pdef(ch);
993 inp();
994 }
995 pdef(ch);
996 pdef(TAG_MACRO);
997 }
998 inp();
999 }
1000 tokl = 0;
1001 tok = ch;
1002 /* encode identifiers & numbers */
1003 if (isid()) {
1004 pdef(TAG_TOK);
1005 last_id = dstk;
1006 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001007 pdef(ch);
1008 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001009 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001010 if (isdigit(tok)) {
1011 tokc = strtol((char*) last_id, 0, 0);
1012 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001013 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001014 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we
1015 suppose data is initialized to zero by calloc) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001016 tok = (intptr_t) (strstr((char*) sym_stk, (char*) (last_id - 1))
Jack Palevich21a15a22009-05-11 14:49:29 -07001017 - sym_stk);
1018 *(char *) dstk = 0; /* mark real end of ident for dlsym() */
1019 tok = tok * 8 + TOK_IDENT;
1020 if (tok > TOK_DEFINE) {
1021 tok = vars + tok;
1022 /* printf("tok=%s %x\n", last_id, tok); */
1023 /* define handling */
1024 if (*(int *) tok == SYM_DEFINE) {
1025 dptr = *(int *) (tok + 4);
1026 dch = ch;
1027 inp();
1028 next();
1029 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001030 }
1031 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001032 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001033 inp();
1034 if (tok == '\'') {
1035 tok = TOK_NUM;
1036 getq();
1037 tokc = ch;
1038 inp();
1039 inp();
Jack Palevich546b2242009-05-13 15:10:04 -07001040 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001041 inp();
1042 while (ch) {
1043 while (ch != '*')
1044 inp();
1045 inp();
1046 if (ch == '/')
1047 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001048 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001049 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001050 next();
Jack Palevichbd894902009-05-14 19:35:31 -07001051 } else if ((tok == '/') & (ch == '/')) {
1052 inp();
1053 while (ch && (ch != '\n')) {
1054 inp();
1055 }
1056 inp();
1057 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001058 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001059 const char* t = operatorChars;
1060 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001061 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001062 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001063 tokl = operatorLevel[opIndex];
1064 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07001065 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001066#if 0
1067 printf("%c%c -> tokl=%d tokc=0x%x\n",
1068 l, a, tokl, tokc);
1069#endif
1070 if (a == ch) {
1071 inp();
1072 tok = TOK_DUMMY; /* dummy token for double tokens */
1073 }
1074 break;
1075 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001076 opIndex++;
1077 }
1078 if (l == 0) {
1079 tokl = 0;
1080 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001081 }
1082 }
1083 }
1084#if 0
1085 {
1086 int p;
1087
1088 printf("tok=0x%x ", tok);
1089 if (tok >= TOK_IDENT) {
1090 printf("'");
1091 if (tok> TOK_DEFINE)
1092 p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8;
1093 else
1094 p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
1095 while (*(char *)p != TAG_TOK && *(char *)p)
1096 printf("%c", *(char *)p++);
1097 printf("'\n");
1098 } else if (tok == TOK_NUM) {
1099 printf("%d\n", tokc);
1100 } else {
1101 printf("'%c'\n", tok);
1102 }
1103 }
1104#endif
1105 }
1106
1107 void error(const char *fmt, ...) {
1108 va_list ap;
1109
1110 va_start(ap, fmt);
1111 fprintf(stderr, "%ld: ", ftell((FILE *) file));
1112 vfprintf(stderr, fmt, ap);
1113 fprintf(stderr, "\n");
1114 va_end(ap);
1115 exit(1);
1116 }
1117
Jack Palevich8b0624c2009-05-20 12:12:06 -07001118 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001119 if (tok != c) {
1120 error("'%c' expected", c);
1121 }
1122 next();
1123 }
1124
Jack Palevich21a15a22009-05-11 14:49:29 -07001125 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001126 void unary(intptr_t l) {
1127 intptr_t n, t, a, c;
Jack Palevich546b2242009-05-13 15:10:04 -07001128 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001129 n = 1; /* type of expression 0 = forward, 1 = value, other =
1130 lvalue */
1131 if (tok == '\"') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001132 pGen->li(glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001133 while (ch != '\"') {
1134 getq();
1135 *(char *) glo++ = ch;
1136 inp();
1137 }
1138 *(char *) glo = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001139 glo = (glo + 4) & -4; /* align heap */
Jack Palevich21a15a22009-05-11 14:49:29 -07001140 inp();
1141 next();
1142 } else {
1143 c = tokl;
1144 a = tokc;
1145 t = tok;
1146 next();
1147 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001148 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001149 } else if (c == 2) {
1150 /* -, +, !, ~ */
1151 unary(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001152 pGen->clearECX();
Jack Palevich21a15a22009-05-11 14:49:29 -07001153 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001154 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001155 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001156 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001157 } else if (t == '(') {
1158 expr();
1159 skip(')');
1160 } else if (t == '*') {
1161 /* parse cast */
1162 skip('(');
1163 t = tok; /* get type */
1164 next(); /* skip int/char/void */
1165 next(); /* skip '*' or '(' */
1166 if (tok == '*') {
1167 /* function type */
1168 skip('*');
1169 skip(')');
1170 skip('(');
1171 skip(')');
1172 t = 0;
1173 }
1174 skip(')');
1175 unary(0);
1176 if (tok == '=') {
1177 next();
1178 pGen->pushEAX();
1179 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001180 pGen->popECX();
1181 pGen->storeEAXToAddressECX(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001182 } else if (t) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001183 pGen->loadEAXIndirect(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001184 }
1185 } else if (t == '&') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001186 pGen->leaEAX(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001187 next();
1188 } else {
1189 n = *(int *) t;
1190 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001191 if (!n) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07001192 n = (intptr_t) dlsym(RTLD_DEFAULT, (char*) last_id);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001193 }
Jack Palevich546b2242009-05-13 15:10:04 -07001194 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001195 /* assignment */
1196 next();
1197 expr();
1198 pGen->storeEAX(n);
1199 } else if (tok != '(') {
1200 /* variable */
Jack Palevich4d93f302009-05-15 13:30:00 -07001201 pGen->loadEAX(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001202 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001203 next();
1204 }
1205 }
1206 }
1207 }
1208
1209 /* function call */
1210 if (tok == '(') {
1211 if (n == 1)
1212 pGen->pushEAX();
1213
1214 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001215 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07001216 next();
1217 l = 0;
1218 while (tok != ')') {
1219 expr();
1220 pGen->storeEAToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001221 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001222 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001223 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001224 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001225 pGen->endFunctionCallArguments(a, l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001226 next();
1227 if (!n) {
1228 /* forward reference */
1229 t = t + 4;
1230 *(int *) t = pGen->callForward(*(int *) t);
1231 } else if (n == 1) {
1232 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001233 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07001234 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07001235 }
Jack Palevich3d474a72009-05-15 15:12:38 -07001236 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07001237 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001238 }
1239 }
1240
Jack Palevich8b0624c2009-05-20 12:12:06 -07001241 void sum(intptr_t l) {
1242 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07001243 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001244 if (l-- == 1)
1245 unary(1);
1246 else {
1247 sum(l);
1248 a = 0;
1249 while (l == tokl) {
1250 n = tok;
1251 t = tokc;
1252 next();
1253
1254 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001255 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07001256 sum(l);
1257 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001258 pGen->pushEAX();
Jack Palevich21a15a22009-05-11 14:49:29 -07001259 sum(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001260 pGen->popECX();
Jack Palevich21a15a22009-05-11 14:49:29 -07001261
Jack Palevich546b2242009-05-13 15:10:04 -07001262 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001263 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001264 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001265 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001266 }
1267 }
1268 }
1269 /* && and || output code generation */
1270 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001271 a = pGen->gtst(t == OP_LOGICAL_OR, a);
1272 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07001273 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001274 pGen->gsym(a);
1275 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07001276 }
1277 }
1278 }
1279
1280 void expr() {
1281 sum(11);
1282 }
1283
1284 int test_expr() {
1285 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001286 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001287 }
1288
Jack Palevich8b0624c2009-05-20 12:12:06 -07001289 void block(intptr_t l) {
1290 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001291
1292 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001293 next();
1294 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07001295 a = test_expr();
1296 skip(')');
1297 block(l);
1298 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001299 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001300 n = pGen->gjmp(0); /* jmp */
1301 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001302 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001303 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001304 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001305 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001306 }
Jack Palevich546b2242009-05-13 15:10:04 -07001307 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001308 t = tok;
1309 next();
1310 skip('(');
1311 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07001312 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07001313 a = test_expr();
1314 } else {
1315 if (tok != ';')
1316 expr();
1317 skip(';');
1318 n = codeBuf.getPC();
1319 a = 0;
1320 if (tok != ';')
1321 a = test_expr();
1322 skip(';');
1323 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001324 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001325 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07001326 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001327 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001328 n = t + 4;
1329 }
1330 }
1331 skip(')');
Jack Palevich8b0624c2009-05-20 12:12:06 -07001332 block((intptr_t) &a);
Jack Palevicha6535612009-05-13 16:24:17 -07001333 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001334 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001335 } else if (tok == '{') {
1336 next();
1337 /* declarations */
1338 decl(1);
1339 while (tok != '}')
1340 block(l);
1341 next();
1342 } else {
1343 if (tok == TOK_RETURN) {
1344 next();
1345 if (tok != ';')
1346 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001347 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001348 } else if (tok == TOK_BREAK) {
1349 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001350 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001351 } else if (tok != ';')
1352 expr();
1353 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001354 }
1355 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001356
1357 /* 'l' is true if local declarations */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001358 void decl(bool l) {
1359 intptr_t a;
Jack Palevich21a15a22009-05-11 14:49:29 -07001360
Jack Palevich546b2242009-05-13 15:10:04 -07001361 while ((tok == TOK_INT) | ((tok != -1) & (!l))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001362 if (tok == TOK_INT) {
1363 next();
1364 while (tok != ';') {
1365 if (l) {
1366 loc = loc + 4;
1367 *(int *) tok = -loc;
1368 } else {
1369 *(int *) tok = glo;
1370 glo = glo + 4;
1371 }
1372 next();
1373 if (tok == ',')
1374 next();
1375 }
1376 skip(';');
1377 } else {
1378 /* patch forward references (XXX: do not work for function
1379 pointers) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001380 pGen->gsym(*(int *) (tok + 4));
Jack Palevich21a15a22009-05-11 14:49:29 -07001381 /* put function address */
1382 *(int *) tok = codeBuf.getPC();
1383 next();
1384 skip('(');
1385 a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07001386 int argCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001387 while (tok != ')') {
1388 /* read param name and compute offset */
1389 *(int *) tok = a;
1390 a = a + 4;
1391 next();
1392 if (tok == ',')
1393 next();
Jack Palevich546b2242009-05-13 15:10:04 -07001394 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07001395 }
1396 next(); /* skip ')' */
1397 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001398 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07001399 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001400 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07001401 pGen->functionExit(argCount, a, loc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001402 }
1403 }
1404 }
1405
1406 void cleanup() {
1407 if (sym_stk != 0) {
1408 free((void*) sym_stk);
1409 sym_stk = 0;
1410 }
1411 if (pGlobalBase != 0) {
1412 free((void*) pGlobalBase);
1413 pGlobalBase = 0;
1414 }
1415 if (pVarsBase != 0) {
1416 free(pVarsBase);
1417 pVarsBase = 0;
1418 }
1419 if (pGen) {
1420 delete pGen;
1421 pGen = 0;
1422 }
1423 }
1424
1425 void clear() {
1426 tok = 0;
1427 tokc = 0;
1428 tokl = 0;
1429 ch = 0;
1430 vars = 0;
1431 rsym = 0;
1432 loc = 0;
1433 glo = 0;
1434 sym_stk = 0;
1435 dstk = 0;
1436 dptr = 0;
1437 dch = 0;
1438 last_id = 0;
1439 file = 0;
1440 pGlobalBase = 0;
1441 pVarsBase = 0;
1442 pGen = 0;
1443 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001444
Jack Palevich22305132009-05-13 10:58:45 -07001445 void setArchitecture(const char* architecture) {
1446 delete pGen;
1447 pGen = 0;
1448
1449 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001450#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07001451 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07001452 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07001453 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001454#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07001455#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07001456 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07001457 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07001458 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001459#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07001460 if (!pGen ) {
1461 fprintf(stderr, "Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07001462 }
1463 }
1464
1465 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001466#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07001467 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07001468#elif defined(DEFAULT_X86_CODEGEN)
1469 pGen = new X86CodeGenerator();
1470#endif
1471 }
1472 if (pGen == NULL) {
1473 fprintf(stderr, "No code generator defined.");
Jack Palevich22305132009-05-13 10:58:45 -07001474 }
1475 }
1476
Jack Palevich77ae76e2009-05-10 19:59:24 -07001477public:
Jack Palevich22305132009-05-13 10:58:45 -07001478 struct args {
1479 args() {
1480 architecture = 0;
1481 }
1482 const char* architecture;
1483 };
1484
Jack Paleviche7b59062009-05-19 17:12:17 -07001485 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001486 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001487 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001488
Jack Paleviche7b59062009-05-19 17:12:17 -07001489 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001490 cleanup();
1491 }
1492
Jack Palevich22305132009-05-13 10:58:45 -07001493 int compile(FILE* in, args& args) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001494 cleanup();
1495 clear();
1496 codeBuf.init(ALLOC_SIZE);
Jack Palevich22305132009-05-13 10:58:45 -07001497 setArchitecture(args.architecture);
Jack Palevich8b0624c2009-05-20 12:12:06 -07001498 if (!pGen) {
1499 return -1;
1500 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001501 pGen->init(&codeBuf);
1502 file = in;
Jack Palevich8b0624c2009-05-20 12:12:06 -07001503 sym_stk = (intptr_t) calloc(1, ALLOC_SIZE);
1504 dstk = (intptr_t) strcpy((char*) sym_stk,
Jack Palevich21a15a22009-05-11 14:49:29 -07001505 " int if else while break return for define main ")
1506 + TOK_STR_SIZE;
1507 pGlobalBase = calloc(1, ALLOC_SIZE);
Jack Palevich8b0624c2009-05-20 12:12:06 -07001508 glo = (intptr_t) pGlobalBase;
Jack Palevich21a15a22009-05-11 14:49:29 -07001509 pVarsBase = calloc(1, ALLOC_SIZE);
Jack Palevich8b0624c2009-05-20 12:12:06 -07001510 vars = (intptr_t) pVarsBase;
Jack Palevich21a15a22009-05-11 14:49:29 -07001511 inp();
1512 next();
1513 decl(0);
Jack Palevich546b2242009-05-13 15:10:04 -07001514 pGen->finishCompile();
Jack Palevich21a15a22009-05-11 14:49:29 -07001515 return 0;
1516 }
1517
1518 int run(int argc, char** argv) {
1519 typedef int (*mainPtr)(int argc, char** argv);
1520 mainPtr aMain = (mainPtr) *(int*) (vars + TOK_MAIN);
1521 if (!aMain) {
1522 fprintf(stderr, "Could not find function \"main\".\n");
1523 return -1;
1524 }
1525 return aMain(argc, argv);
1526 }
1527
1528 int dump(FILE* out) {
1529 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
1530 return 0;
1531 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07001532
Jack Palevicha6535612009-05-13 16:24:17 -07001533 int disassemble(FILE* out) {
1534 return pGen->disassemble(out);
1535 }
1536
Jack Palevich77ae76e2009-05-10 19:59:24 -07001537};
1538
Jack Paleviche7b59062009-05-19 17:12:17 -07001539const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001540 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
1541
Jack Paleviche7b59062009-05-19 17:12:17 -07001542const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001543 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
1544 5, 5, /* ==, != */
1545 9, 10, /* &&, || */
1546 6, 7, 8, /* & ^ | */
1547 2, 2 /* ~ ! */
1548 };
1549
Jack Palevich8b0624c2009-05-20 12:12:06 -07001550#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001551FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07001552#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001553
Jack Palevich8b0624c2009-05-20 12:12:06 -07001554#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001555const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001556 0x1, // ++
1557 0xff, // --
1558 0xc1af0f, // *
1559 0xf9f79991, // /
1560 0xf9f79991, // % (With manual assist to swap results)
1561 0xc801, // +
1562 0xd8f7c829, // -
1563 0xe0d391, // <<
1564 0xf8d391, // >>
1565 0xe, // <=
1566 0xd, // >=
1567 0xc, // <
1568 0xf, // >
1569 0x4, // ==
1570 0x5, // !=
1571 0x0, // &&
1572 0x1, // ||
1573 0xc821, // &
1574 0xc831, // ^
1575 0xc809, // |
1576 0xd0f7, // ~
1577 0x4 // !
1578};
Jack Palevich8b0624c2009-05-20 12:12:06 -07001579#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001580
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001581} // namespace acc
1582
Jack Palevich546b2242009-05-13 15:10:04 -07001583// This is a separate function so it can easily be set by breakpoint in gdb.
Jack Paleviche7b59062009-05-19 17:12:17 -07001584int run(acc::Compiler& c, int argc, char** argv) {
Jack Palevich546b2242009-05-13 15:10:04 -07001585 return c.run(argc, argv);
1586}
1587
Jack Palevich77ae76e2009-05-10 19:59:24 -07001588int main(int argc, char** argv) {
Jack Palevich22305132009-05-13 10:58:45 -07001589 bool doDump = false;
Jack Palevicha6535612009-05-13 16:24:17 -07001590 bool doDisassemble = false;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001591 const char* inFile = NULL;
1592 const char* outFile = NULL;
Jack Paleviche7b59062009-05-19 17:12:17 -07001593 const char* architecture = NULL;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001594 int i;
Jack Palevich21a15a22009-05-11 14:49:29 -07001595 for (i = 1; i < argc; i++) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001596 char* arg = argv[i];
1597 if (arg[0] == '-') {
1598 switch (arg[1]) {
Jack Palevich22305132009-05-13 10:58:45 -07001599 case 'a':
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001600 if (i + 1 >= argc) {
Jack Palevich22305132009-05-13 10:58:45 -07001601 fprintf(stderr, "Expected architecture after -a\n");
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001602 return 2;
1603 }
Jack Palevich22305132009-05-13 10:58:45 -07001604 architecture = argv[i+1];
1605 i += 1;
1606 break;
1607 case 'd':
1608 if (i + 1 >= argc) {
1609 fprintf(stderr, "Expected filename after -d\n");
1610 return 2;
1611 }
1612 doDump = true;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001613 outFile = argv[i + 1];
1614 i += 1;
1615 break;
Jack Palevicha6535612009-05-13 16:24:17 -07001616 case 'S':
1617 doDisassemble = true;
1618 break;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001619 default:
1620 fprintf(stderr, "Unrecognized flag %s\n", arg);
1621 return 3;
1622 }
1623 } else if (inFile == NULL) {
1624 inFile = arg;
1625 } else {
1626 break;
1627 }
1628 }
1629
1630 FILE* in = stdin;
1631 if (inFile) {
1632 in = fopen(inFile, "r");
Jack Palevich21a15a22009-05-11 14:49:29 -07001633 if (!in) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001634 fprintf(stderr, "Could not open input file %s\n", inFile);
1635 return 1;
1636 }
1637 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001638 acc::Compiler compiler;
1639 acc::Compiler::args args;
1640 if (architecture != NULL) {
1641 args.architecture = architecture;
1642 }
Jack Palevich22305132009-05-13 10:58:45 -07001643 int compileResult = compiler.compile(in, args);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001644 if (in != stdin) {
1645 fclose(in);
1646 }
1647 if (compileResult) {
1648 fprintf(stderr, "Compile failed: %d\n", compileResult);
1649 return 6;
1650 }
Jack Palevicha6535612009-05-13 16:24:17 -07001651 if (doDisassemble) {
1652 compiler.disassemble(stderr);
1653 }
Jack Palevich22305132009-05-13 10:58:45 -07001654 if (doDump) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001655 FILE* save = fopen(outFile, "w");
Jack Palevich21a15a22009-05-11 14:49:29 -07001656 if (!save) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001657 fprintf(stderr, "Could not open output file %s\n", outFile);
1658 return 5;
1659 }
1660 compiler.dump(save);
1661 fclose(save);
1662 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001663 fprintf(stderr, "Executing compiled code:\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07001664 int codeArgc = argc - i + 1;
1665 char** codeArgv = argv + i - 1;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001666 codeArgv[0] = (char*) (inFile ? inFile : "stdin");
Jack Palevich546b2242009-05-13 15:10:04 -07001667 int result = run(compiler, codeArgc, codeArgv);
Jack Palevich22305132009-05-13 10:58:45 -07001668 fprintf(stderr, "result: %d\n", result);
1669 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001670 }
1671
1672 return 0;
1673}