blob: cefe01d968bcf50c2edd5a800d0c8a42a1273b16 [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 Palevichae54f1f2009-05-08 14:54:15 -070037#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070038#include <stdlib.h>
39#include <string.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070040
Jack Palevich546b2242009-05-13 15:10:04 -070041#if defined(__arm__)
42#include <unistd.h>
43#endif
44
Jack Paleviche7b59062009-05-19 17:12:17 -070045#if defined(__arm__)
46#define DEFAULT_ARM_CODEGEN
47#elif defined(__i386__)
48#define DEFAULT_X86_CODEGEN
49#elif defined(__x86_64__)
50#define DEFAULT_X64_CODEGEN
51#endif
52
53#define PROVIDE_X86_CODEGEN
54#define PROVIDE_ARM_CODEGEN
55
56#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070057#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070058#endif
Jack Palevicha6535612009-05-13 16:24:17 -070059
Jack Palevichbbf8ab52009-05-11 11:54:30 -070060namespace acc {
61
Jack Paleviche7b59062009-05-19 17:12:17 -070062class Compiler {
Jack Palevich21a15a22009-05-11 14:49:29 -070063 class CodeBuf {
64 char* ind;
65 char* pProgramBase;
Jack Palevichf0cbc922009-05-08 16:35:13 -070066
Jack Palevich21a15a22009-05-11 14:49:29 -070067 void release() {
68 if (pProgramBase != 0) {
69 free(pProgramBase);
70 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070071 }
Jack Palevich21a15a22009-05-11 14:49:29 -070072 }
73
74 public:
75 CodeBuf() {
76 pProgramBase = 0;
77 ind = 0;
78 }
79
80 ~CodeBuf() {
81 release();
82 }
83
84 void init(int size) {
85 release();
86 pProgramBase = (char*) calloc(1, size);
87 ind = pProgramBase;
88 }
89
Jack Palevich546b2242009-05-13 15:10:04 -070090 int o4(int n) {
91 int result = (int) ind;
92 * (int*) ind = n;
93 ind += 4;
94 return result;
95 }
96
Jack Palevich21a15a22009-05-11 14:49:29 -070097 /*
98 * Output a byte. Handles all values, 0..ff.
99 */
100 void ob(int n) {
101 *ind++ = n;
102 }
103
Jack Palevich21a15a22009-05-11 14:49:29 -0700104 inline void* getBase() {
105 return (void*) pProgramBase;
106 }
107
108 int getSize() {
109 return ind - pProgramBase;
110 }
111
112 int getPC() {
113 return (int) ind;
114 }
115 };
116
117 class CodeGenerator {
118 public:
119 CodeGenerator() {}
120 virtual ~CodeGenerator() {}
121
Jack Palevich22305132009-05-13 10:58:45 -0700122 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700123 this->pCodeBuf = pCodeBuf;
124 }
125
Jack Palevich22305132009-05-13 10:58:45 -0700126 /* returns address to patch with local variable size
127 */
Jack Palevich546b2242009-05-13 15:10:04 -0700128 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700129
Jack Palevich546b2242009-05-13 15:10:04 -0700130 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700131
132 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700133 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700134
135 virtual int gjmp(int t) = 0;
136
137 /* l = 0: je, l == 1: jne */
138 virtual int gtst(bool l, int t) = 0;
139
140 virtual void gcmp(int op) = 0;
141
Jack Palevich546b2242009-05-13 15:10:04 -0700142 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700143
144 virtual void clearECX() = 0;
145
146 virtual void pushEAX() = 0;
147
148 virtual void popECX() = 0;
149
150 virtual void storeEAXToAddressECX(bool isInt) = 0;
151
152 virtual void loadEAXIndirect(bool isInt) = 0;
153
154 virtual void leaEAX(int ea) = 0;
155
156 virtual void storeEAX(int ea) = 0;
157
Jack Palevich4d93f302009-05-15 13:30:00 -0700158 virtual void loadEAX(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700159
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700160 virtual int beginFunctionCallArguments() = 0;
161
Jack Palevich7810bc92009-05-15 14:31:47 -0700162 virtual void storeEAToArg(int l) = 0;
163
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700164 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700165
Jack Palevich22305132009-05-13 10:58:45 -0700166
167 virtual int callForward(int symbol) = 0;
168
169 virtual void callRelative(int t) = 0;
170
171 virtual void callIndirect(int l) = 0;
172
Jack Palevich7810bc92009-05-15 14:31:47 -0700173 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700174
Jack Palevicha6535612009-05-13 16:24:17 -0700175 virtual int disassemble(FILE* out) = 0;
176
Jack Palevich21a15a22009-05-11 14:49:29 -0700177 /* output a symbol and patch all calls to it */
Jack Paleviche7b59062009-05-19 17:12:17 -0700178 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700179
Jack Palevich546b2242009-05-13 15:10:04 -0700180 virtual int finishCompile() {
181#if defined(__arm__)
Jack Palevicha6535612009-05-13 16:24:17 -0700182 const long base = long(pCodeBuf->getBase());
183 const long curr = base + long(pCodeBuf->getSize());
184 int err = cacheflush(base, curr, 0);
185 return err;
Jack Palevich546b2242009-05-13 15:10:04 -0700186#else
Jack Palevicha6535612009-05-13 16:24:17 -0700187 return 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700188#endif
189 }
190
Jack Palevicha6535612009-05-13 16:24:17 -0700191 /**
192 * Adjust relative branches by this amount.
193 */
194 virtual int jumpOffset() = 0;
195
Jack Palevich21a15a22009-05-11 14:49:29 -0700196 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700197 /*
198 * Output a byte. Handles all values, 0..ff.
199 */
200 void ob(int n) {
201 pCodeBuf->ob(n);
202 }
203
Jack Paleviche7b59062009-05-19 17:12:17 -0700204 int o4(int data) {
205 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700206 }
207
Jack Palevicha6535612009-05-13 16:24:17 -0700208 int getBase() {
209 return (int) pCodeBuf->getBase();
210 }
211
Jack Palevich21a15a22009-05-11 14:49:29 -0700212 int getPC() {
213 return pCodeBuf->getPC();
214 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 private:
216 CodeBuf* pCodeBuf;
217 };
218
Jack Paleviche7b59062009-05-19 17:12:17 -0700219#ifdef PROVIDE_ARM_CODEGEN
220
Jack Palevich22305132009-05-13 10:58:45 -0700221 class ARMCodeGenerator : public CodeGenerator {
222 public:
223 ARMCodeGenerator() {}
224 virtual ~ARMCodeGenerator() {}
225
226 /* returns address to patch with local variable size
227 */
Jack Palevich546b2242009-05-13 15:10:04 -0700228 virtual int functionEntry(int argCount) {
229 fprintf(stderr, "functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700230 // sp -> arg4 arg5 ...
231 // Push our register-based arguments back on the stack
232 if (argCount > 0) {
233 int regArgCount = argCount <= 4 ? argCount : 4;
234 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
235 }
236 // sp -> arg0 arg1 ...
237 o4(0xE92D4800); // stmfd sp!, {fp, lr}
238 // sp, fp -> oldfp, retadr, arg0 arg1 ....
239 o4(0xE1A0B00D); // mov fp, sp
240 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700241 }
242
Jack Palevich546b2242009-05-13 15:10:04 -0700243 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
244 fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700245 // Patch local variable allocation code:
246 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700247 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700248 }
Jack Palevich69796b62009-05-14 15:42:26 -0700249 *(char*) (localVariableAddress) = localVariableSize;
250
251 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
252 o4(0xE1A0E00B); // mov lr, fp
253 o4(0xE59BB000); // ldr fp, [fp]
254 o4(0xE28ED004); // add sp, lr, #4
255 // sp -> retadr, arg0, ...
256 o4(0xE8BD4000); // ldmfd sp!, {lr}
257 // sp -> arg0 ....
258 if (argCount > 0) {
259 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700260 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700261 // earlier. We don't need to actually store them anywhere,
262 // just adjust the stack.
263 int regArgCount = argCount <= 4 ? argCount : 4;
264 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
265 }
266 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700267 }
268
269 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700270 virtual void li(int t) {
Jack Palevich22305132009-05-13 10:58:45 -0700271 fprintf(stderr, "li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700272 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700273 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700274 } else if (t >= -256 && t < 0) {
275 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700276 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700277 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700278 o4(0xE51F0000); // ldr r0, .L3
279 o4(0xEA000000); // b .L99
280 o4(t); // .L3: .word 0
281 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700282 }
Jack Palevich22305132009-05-13 10:58:45 -0700283 }
284
285 virtual int gjmp(int t) {
286 fprintf(stderr, "gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700287 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700288 }
289
290 /* l = 0: je, l == 1: jne */
291 virtual int gtst(bool l, int t) {
292 fprintf(stderr, "gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700293 o4(0xE3500000); // cmp r0,#0
294 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
295 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700296 }
297
298 virtual void gcmp(int op) {
299 fprintf(stderr, "gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700300 o4(0xE1510000); // cmp r1, r1
301 switch(op) {
302 case OP_EQUALS:
303 o4(0x03A00001); // moveq r0,#1
304 o4(0x13A00000); // movne r0,#0
305 break;
306 case OP_NOT_EQUALS:
307 o4(0x03A00000); // moveq r0,#0
308 o4(0x13A00001); // movne r0,#1
309 break;
310 case OP_LESS_EQUAL:
311 o4(0xD3A00001); // movle r0,#1
312 o4(0xC3A00000); // movgt r0,#0
313 break;
314 case OP_GREATER:
315 o4(0xD3A00000); // movle r0,#0
316 o4(0xC3A00001); // movgt r0,#1
317 break;
318 case OP_GREATER_EQUAL:
319 o4(0xA3A00001); // movge r0,#1
320 o4(0xB3A00000); // movlt r0,#0
321 break;
322 case OP_LESS:
323 o4(0xA3A00000); // movge r0,#0
324 o4(0xB3A00001); // movlt r0,#1
325 break;
326 default:
327 error("Unknown comparison op %d", op);
328 break;
329 }
Jack Palevich22305132009-05-13 10:58:45 -0700330 }
331
Jack Palevich546b2242009-05-13 15:10:04 -0700332 virtual void genOp(int op) {
Jack Palevich22305132009-05-13 10:58:45 -0700333 fprintf(stderr, "genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700334 switch(op) {
335 case OP_MUL:
336 o4(0x0E0000091); // mul r0,r1,r0
337 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700338 case OP_DIV:
339 callRuntime(runtime_DIV);
340 break;
341 case OP_MOD:
342 callRuntime(runtime_MOD);
343 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700344 case OP_PLUS:
345 o4(0xE0810000); // add r0,r1,r0
346 break;
347 case OP_MINUS:
348 o4(0xE0410000); // sub r0,r1,r0
349 break;
350 case OP_SHIFT_LEFT:
351 o4(0xE1A00011); // lsl r0,r1,r0
352 break;
353 case OP_SHIFT_RIGHT:
354 o4(0xE1A00051); // asr r0,r1,r0
355 break;
356 case OP_BIT_AND:
357 o4(0xE0010000); // and r0,r1,r0
358 break;
359 case OP_BIT_XOR:
360 o4(0xE0210000); // eor r0,r1,r0
361 break;
362 case OP_BIT_OR:
363 o4(0xE1810000); // orr r0,r1,r0
364 break;
365 case OP_BIT_NOT:
366 o4(0xE1E00000); // mvn r0, r0
367 break;
368 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700369 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700370 break;
371 }
Jack Palevich22305132009-05-13 10:58:45 -0700372#if 0
373 o(decodeOp(op));
374 if (op == OP_MOD)
375 o(0x92); /* xchg %edx, %eax */
376#endif
377 }
378
379 virtual void clearECX() {
380 fprintf(stderr, "clearECX();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700381 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700382 }
383
384 virtual void pushEAX() {
385 fprintf(stderr, "pushEAX();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700386 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700387 }
388
389 virtual void popECX() {
390 fprintf(stderr, "popECX();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700391 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700392 }
393
394 virtual void storeEAXToAddressECX(bool isInt) {
395 fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700396 if (isInt) {
397 o4(0xE5810000); // str r0, [r1]
398 } else {
399 o4(0xE5C10000); // strb r0, [r1]
400 }
Jack Palevich22305132009-05-13 10:58:45 -0700401 }
402
403 virtual void loadEAXIndirect(bool isInt) {
404 fprintf(stderr, "loadEAXIndirect(%d);\n", isInt);
405 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700406 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700407 else
Jack Palevich69796b62009-05-14 15:42:26 -0700408 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700409 }
410
411 virtual void leaEAX(int ea) {
Jack Palevichbd894902009-05-14 19:35:31 -0700412 fprintf(stderr, "leaEAX(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700413 if (ea < LOCAL) {
414 // Local, fp relative
415 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
416 error("Offset out of range: %08x", ea);
417 }
418 if (ea < 0) {
419 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
420 } else {
421 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
422 }
Jack Palevichbd894902009-05-14 19:35:31 -0700423 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700424 // Global, absolute.
425 o4(0xE59F0000); // ldr r0, .L1
426 o4(0xEA000000); // b .L99
427 o4(ea); // .L1: .word 0
428 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700429 }
Jack Palevich22305132009-05-13 10:58:45 -0700430 }
431
432 virtual void storeEAX(int ea) {
433 fprintf(stderr, "storeEAX(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700434 if (ea < LOCAL) {
435 // Local, fp relative
436 if (ea < -4095 || ea > 4095) {
437 error("Offset out of range: %08x", ea);
438 }
439 if (ea < 0) {
440 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
441 } else {
442 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
443 }
444 } else{
445 // Global, absolute
446 o4(0xE59F1000); // ldr r1, .L1
447 o4(0xEA000000); // b .L99
448 o4(ea); // .L1: .word 0
449 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700450 }
Jack Palevich22305132009-05-13 10:58:45 -0700451 }
452
Jack Palevich4d93f302009-05-15 13:30:00 -0700453 virtual void loadEAX(int ea, bool isIncDec, int op) {
454 fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op);
455 if (ea < LOCAL) {
456 // Local, fp relative
457 if (ea < -4095 || ea > 4095) {
458 error("Offset out of range: %08x", ea);
459 }
460 if (ea < 0) {
461 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
462 } else {
463 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
464 }
Jack Palevich69796b62009-05-14 15:42:26 -0700465 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700466 // Global, absolute
467 o4(0xE59F2000); // ldr r2, .L1
468 o4(0xEA000000); // b .L99
469 o4(ea); // .L1: .word ea
470 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700471 }
Jack Palevich22305132009-05-13 10:58:45 -0700472
Jack Palevich4d93f302009-05-15 13:30:00 -0700473 if (isIncDec) {
474 switch (op) {
475 case OP_INCREMENT:
476 o4(0xE2801001); // add r1, r0, #1
477 break;
478 case OP_DECREMENT:
479 o4(0xE2401001); // sub r1, r0, #1
480 break;
481 default:
482 error("unknown opcode: %d", op);
483 }
484 if (ea < LOCAL) {
485 // Local, fp relative
486 // Don't need range check, was already checked above
487 if (ea < 0) {
488 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
489 } else {
490 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
491 }
492 } else{
493 // Global, absolute
494 // r2 is already set up from before.
495 o4(0xE5821000); // str r1, [r2]
496 }
Jack Palevichbd894902009-05-14 19:35:31 -0700497 }
Jack Palevich22305132009-05-13 10:58:45 -0700498 }
499
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700500 virtual int beginFunctionCallArguments() {
501 fprintf(stderr, "beginFunctionCallArguments();\n");
502 return o4(0xE24DDF00); // Placeholder
503 }
504
Jack Palevich7810bc92009-05-15 14:31:47 -0700505 virtual void storeEAToArg(int l) {
506 fprintf(stderr, "storeEAToArg(%d);\n", l);
507 if (l < 0 || l > 4096-4) {
508 error("l out of range for stack offset: 0x%08x", l);
509 }
510 o4(0xE58D0000 + l); // str r0, [sp, #4]
511 }
512
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700513 virtual void endFunctionCallArguments(int a, int l) {
514 fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l);
515 if (l < 0 || l > 0x3FC) {
516 error("L out of range for stack adjustment: 0x%08x", l);
517 }
518 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
519 int argCount = l >> 2;
520 if (argCount > 0) {
521 int regArgCount = argCount > 4 ? 4 : argCount;
522 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
523 }
Jack Palevich22305132009-05-13 10:58:45 -0700524 }
525
Jack Palevich22305132009-05-13 10:58:45 -0700526 virtual int callForward(int symbol) {
527 fprintf(stderr, "callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700528 // Forward calls are always short (local)
529 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700530 }
531
532 virtual void callRelative(int t) {
533 fprintf(stderr, "callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700534 int abs = t + getPC() + jumpOffset();
Jack Palevichbd894902009-05-14 19:35:31 -0700535 fprintf(stderr, "abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700536 if (t >= - (1 << 25) && t < (1 << 25)) {
537 o4(0xEB000000 | encodeAddress(t));
538 } else {
539 // Long call.
540 o4(0xE59FC000); // ldr r12, .L1
541 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700542 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700543 o4(0xE08CC00F); // .L99: add r12,pc
544 o4(0xE12FFF3C); // blx r12
545 }
Jack Palevich22305132009-05-13 10:58:45 -0700546 }
547
548 virtual void callIndirect(int l) {
549 fprintf(stderr, "callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700550 int argCount = l >> 2;
551 int poppedArgs = argCount > 4 ? 4 : argCount;
552 int adjustedL = l - (poppedArgs << 2);
553 if (adjustedL < 0 || adjustedL > 4096-4) {
554 error("l out of range for stack offset: 0x%08x", l);
555 }
556 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
557 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700558 }
559
Jack Palevich7810bc92009-05-15 14:31:47 -0700560 virtual void adjustStackAfterCall(int l, bool isIndirect) {
561 fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700562 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700563 int stackArgs = argCount > 4 ? argCount - 4 : 0;
564 int stackUse = stackArgs + (isIndirect ? 1 : 0);
565 if (stackUse) {
566 if (stackUse < 0 || stackUse > 255) {
567 error("L out of range for stack adjustment: 0x%08x", l);
568 }
569 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700570 }
Jack Palevich22305132009-05-13 10:58:45 -0700571 }
572
Jack Palevicha6535612009-05-13 16:24:17 -0700573 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700574 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700575 }
576
577 /* output a symbol and patch all calls to it */
578 virtual void gsym(int t) {
579 fprintf(stderr, "gsym(0x%x)\n", t);
580 int n;
581 int base = getBase();
582 int pc = getPC();
583 fprintf(stderr, "pc = 0x%x\n", pc);
584 while (t) {
585 int data = * (int*) t;
586 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
587 if (decodedOffset == 0) {
588 n = 0;
589 } else {
590 n = base + decodedOffset; /* next value */
591 }
592 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
593 | encodeRelAddress(pc - t - 8);
594 t = n;
595 }
596 }
597
598 virtual int disassemble(FILE* out) {
599 disasmOut = out;
600 disasm_interface_t di;
601 di.di_readword = disassemble_readword;
602 di.di_printaddr = disassemble_printaddr;
603 di.di_printf = disassemble_printf;
604
605 int base = getBase();
606 int pc = getPC();
607 for(int i = base; i < pc; i += 4) {
608 fprintf(out, "%08x: %08x ", i, *(int*) i);
609 ::disasm(&di, i, 0);
610 }
611 return 0;
612 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700613
Jack Palevich22305132009-05-13 10:58:45 -0700614 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700615 static FILE* disasmOut;
616
617 static u_int
618 disassemble_readword(u_int address)
619 {
620 return(*((u_int *)address));
621 }
622
623 static void
624 disassemble_printaddr(u_int address)
625 {
626 fprintf(disasmOut, "0x%08x", address);
627 }
628
629 static void
630 disassemble_printf(const char *fmt, ...) {
631 va_list ap;
632 va_start(ap, fmt);
633 vfprintf(disasmOut, fmt, ap);
634 va_end(ap);
635 }
636
637 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
638
639 /** Encode a relative address that might also be
640 * a label.
641 */
642 int encodeAddress(int value) {
643 int base = getBase();
644 if (value >= base && value <= getPC() ) {
645 // This is a label, encode it relative to the base.
646 value = value - base;
647 }
648 return encodeRelAddress(value);
649 }
650
651 int encodeRelAddress(int value) {
652 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
653 }
Jack Palevich22305132009-05-13 10:58:45 -0700654
Jack Palevich3d474a72009-05-15 15:12:38 -0700655 typedef int (*int2FnPtr)(int a, int b);
656 void callRuntime(int2FnPtr fn) {
657 o4(0xE59F2000); // ldr r2, .L1
658 o4(0xEA000000); // b .L99
659 o4((int) fn); //.L1: .word fn
660 o4(0xE12FFF32); //.L99: blx r2
661 }
662
663 static int runtime_DIV(int a, int b) {
664 return b / a;
665 }
666
667 static int runtime_MOD(int a, int b) {
668 return b % a;
669 }
670
Jack Palevich546b2242009-05-13 15:10:04 -0700671 void error(const char* fmt,...) {
672 va_list ap;
673 va_start(ap, fmt);
674 vfprintf(stderr, fmt, ap);
675 va_end(ap);
676 exit(12);
677 }
Jack Palevich22305132009-05-13 10:58:45 -0700678 };
679
Jack Paleviche7b59062009-05-19 17:12:17 -0700680#endif // PROVIDE_X86_CODEGEN
681
682#ifdef PROVIDE_X86_CODEGEN
683
Jack Palevich21a15a22009-05-11 14:49:29 -0700684 class X86CodeGenerator : public CodeGenerator {
685 public:
686 X86CodeGenerator() {}
687 virtual ~X86CodeGenerator() {}
688
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700689 /* returns address to patch with local variable size
690 */
Jack Palevich546b2242009-05-13 15:10:04 -0700691 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700692 o(0xe58955); /* push %ebp, mov %esp, %ebp */
693 return oad(0xec81, 0); /* sub $xxx, %esp */
694 }
695
Jack Palevich546b2242009-05-13 15:10:04 -0700696 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700697 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700698 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700699 }
700
Jack Palevich21a15a22009-05-11 14:49:29 -0700701 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700702 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700703 oad(0xb8, t); /* mov $xx, %eax */
704 }
705
Jack Palevich22305132009-05-13 10:58:45 -0700706 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700707 return psym(0xe9, t);
708 }
709
710 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700711 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700712 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
713 return psym(0x84 + l, t);
714 }
715
Jack Palevich22305132009-05-13 10:58:45 -0700716 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700717 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700718 o(0xc139); /* cmp %eax,%ecx */
719 li(0);
720 o(0x0f); /* setxx %al */
721 o(t + 0x90);
722 o(0xc0);
723 }
724
Jack Palevich546b2242009-05-13 15:10:04 -0700725 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700726 o(decodeOp(op));
727 if (op == OP_MOD)
728 o(0x92); /* xchg %edx, %eax */
729 }
730
Jack Palevich22305132009-05-13 10:58:45 -0700731 virtual void clearECX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700732 oad(0xb9, 0); /* movl $0, %ecx */
733 }
734
Jack Palevich22305132009-05-13 10:58:45 -0700735 virtual void pushEAX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700736 o(0x50); /* push %eax */
737 }
738
Jack Palevich22305132009-05-13 10:58:45 -0700739 virtual void popECX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700740 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700741 }
742
Jack Palevich22305132009-05-13 10:58:45 -0700743 virtual void storeEAXToAddressECX(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700744 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
745 }
746
Jack Palevich22305132009-05-13 10:58:45 -0700747 virtual void loadEAXIndirect(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700748 if (isInt)
749 o(0x8b); /* mov (%eax), %eax */
750 else
751 o(0xbe0f); /* movsbl (%eax), %eax */
752 ob(0); /* add zero in code */
753 }
754
Jack Palevich22305132009-05-13 10:58:45 -0700755 virtual void leaEAX(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700756 gmov(10, ea); /* leal EA, %eax */
757 }
758
Jack Palevich22305132009-05-13 10:58:45 -0700759 virtual void storeEAX(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700760 gmov(6, ea); /* mov %eax, EA */
761 }
762
Jack Palevich4d93f302009-05-15 13:30:00 -0700763 virtual void loadEAX(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700764 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700765 if (isIncDec) {
766 /* Implement post-increment or post decrement.
767 */
768 gmov(0, ea); /* 83 ADD */
769 o(decodeOp(op));
770 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700771 }
772
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700773 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700774 return oad(0xec81, 0); /* sub $xxx, %esp */
775 }
776
Jack Palevich22305132009-05-13 10:58:45 -0700777 virtual void storeEAToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700778 oad(0x248489, l); /* movl %eax, xxx(%esp) */
779 }
780
Jack Palevich7810bc92009-05-15 14:31:47 -0700781 virtual void endFunctionCallArguments(int a, int l) {
782 * (int*) a = l;
783 }
784
Jack Palevich22305132009-05-13 10:58:45 -0700785 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700786 return psym(0xe8, symbol); /* call xxx */
787 }
788
Jack Palevich22305132009-05-13 10:58:45 -0700789 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700790 psym(0xe8, t); /* call xxx */
791 }
792
Jack Palevich22305132009-05-13 10:58:45 -0700793 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700794 oad(0x2494ff, l); /* call *xxx(%esp) */
795 }
796
Jack Palevich7810bc92009-05-15 14:31:47 -0700797 virtual void adjustStackAfterCall(int l, bool isIndirect) {
798 if (isIndirect) {
799 l += 4;
800 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700801 oad(0xc481, l); /* add $xxx, %esp */
802 }
803
Jack Palevicha6535612009-05-13 16:24:17 -0700804 virtual int jumpOffset() {
805 return 5;
806 }
807
808 virtual int disassemble(FILE* out) {
809 return 1;
810 }
811
Jack Paleviche7b59062009-05-19 17:12:17 -0700812 /* output a symbol and patch all calls to it */
813 virtual void gsym(int t) {
814 int n;
815 int pc = getPC();
816 while (t) {
817 n = *(int *) t; /* next value */
818 *(int *) t = pc - t - 4;
819 t = n;
820 }
821 }
822
Jack Palevich21a15a22009-05-11 14:49:29 -0700823 private:
Jack Paleviche7b59062009-05-19 17:12:17 -0700824
825 /** Output 1 to 4 bytes.
826 *
827 */
828 void o(int n) {
829 /* cannot use unsigned, so we must do a hack */
830 while (n && n != -1) {
831 ob(n & 0xff);
832 n = n >> 8;
833 }
834 }
835
836 /* psym is used to put an instruction with a data field which is a
837 reference to a symbol. It is in fact the same as oad ! */
838 int psym(int n, int t) {
839 return oad(n, t);
840 }
841
842 /* instruction + address */
843 int oad(int n, int t) {
844 o(n);
845 int result = getPC();
846 o4(t);
847 return result;
848 }
849
850
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700851 static const int operatorHelper[];
852
853 int decodeOp(int op) {
854 if (op < 0 || op > OP_COUNT) {
855 fprintf(stderr, "Out-of-range operator: %d\n", op);
856 exit(1);
857 }
858 return operatorHelper[op];
859 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700860
Jack Palevich546b2242009-05-13 15:10:04 -0700861 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700862 o(l + 0x83);
863 oad((t < LOCAL) << 7 | 5, t);
864 }
865 };
866
Jack Paleviche7b59062009-05-19 17:12:17 -0700867#endif // PROVIDE_X86_CODEGEN
868
Jack Palevich21a15a22009-05-11 14:49:29 -0700869 /* vars: value of variables
870 loc : local variable index
871 glo : global variable index
872 ind : output code ptr
873 rsym: return symbol
874 prog: output code
875 dstk: define stack
876 dptr, dch: macro state
877 */
878 int tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk,
879 dptr, dch, last_id;
880 void* pSymbolBase;
881 void* pGlobalBase;
882 void* pVarsBase;
883 FILE* file;
884
885 CodeBuf codeBuf;
Jack Palevich22305132009-05-13 10:58:45 -0700886 CodeGenerator* pGen;
Jack Palevich21a15a22009-05-11 14:49:29 -0700887
888 static const int ALLOC_SIZE = 99999;
889
890 /* depends on the init string */
891 static const int TOK_STR_SIZE = 48;
892 static const int TOK_IDENT = 0x100;
893 static const int TOK_INT = 0x100;
894 static const int TOK_IF = 0x120;
895 static const int TOK_ELSE = 0x138;
896 static const int TOK_WHILE = 0x160;
897 static const int TOK_BREAK = 0x190;
898 static const int TOK_RETURN = 0x1c0;
899 static const int TOK_FOR = 0x1f8;
900 static const int TOK_DEFINE = 0x218;
901 static const int TOK_MAIN = 0x250;
902
903 static const int TOK_DUMMY = 1;
904 static const int TOK_NUM = 2;
905
906 static const int LOCAL = 0x200;
907
908 static const int SYM_FORWARD = 0;
909 static const int SYM_DEFINE = 1;
910
911 /* tokens in string heap */
912 static const int TAG_TOK = ' ';
913 static const int TAG_MACRO = 2;
914
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700915 static const int OP_INCREMENT = 0;
916 static const int OP_DECREMENT = 1;
917 static const int OP_MUL = 2;
918 static const int OP_DIV = 3;
919 static const int OP_MOD = 4;
920 static const int OP_PLUS = 5;
921 static const int OP_MINUS = 6;
922 static const int OP_SHIFT_LEFT = 7;
923 static const int OP_SHIFT_RIGHT = 8;
924 static const int OP_LESS_EQUAL = 9;
925 static const int OP_GREATER_EQUAL = 10;
926 static const int OP_LESS = 11;
927 static const int OP_GREATER = 12;
928 static const int OP_EQUALS = 13;
929 static const int OP_NOT_EQUALS = 14;
930 static const int OP_LOGICAL_AND = 15;
931 static const int OP_LOGICAL_OR = 16;
932 static const int OP_BIT_AND = 17;
933 static const int OP_BIT_XOR = 18;
934 static const int OP_BIT_OR = 19;
935 static const int OP_BIT_NOT = 20;
936 static const int OP_LOGICAL_NOT = 21;
937 static const int OP_COUNT = 22;
938
939 /* Operators are searched from front, the two-character operators appear
940 * before the single-character operators with the same first character.
941 * @ is used to pad out single-character operators.
942 */
943 static const char* operatorChars;
944 static const char operatorLevel[];
945
Jack Palevich21a15a22009-05-11 14:49:29 -0700946 void pdef(int t) {
947 *(char *) dstk++ = t;
948 }
949
950 void inp() {
951 if (dptr) {
952 ch = *(char *) dptr++;
953 if (ch == TAG_MACRO) {
954 dptr = 0;
955 ch = dch;
956 }
957 } else
958 ch = fgetc(file);
959 /* printf("ch=%c 0x%x\n", ch, ch); */
960 }
961
962 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -0700963 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -0700964 }
965
966 /* read a character constant */
967 void getq() {
968 if (ch == '\\') {
969 inp();
970 if (ch == 'n')
971 ch = '\n';
972 }
973 }
974
975 void next() {
976 int l, a;
977
Jack Palevich546b2242009-05-13 15:10:04 -0700978 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700979 if (ch == '#') {
980 inp();
981 next();
982 if (tok == TOK_DEFINE) {
983 next();
984 pdef(TAG_TOK); /* fill last ident tag */
985 *(int *) tok = SYM_DEFINE;
986 *(int *) (tok + 4) = dstk; /* define stack */
987 }
988 /* well we always save the values ! */
989 while (ch != '\n') {
990 pdef(ch);
991 inp();
992 }
993 pdef(ch);
994 pdef(TAG_MACRO);
995 }
996 inp();
997 }
998 tokl = 0;
999 tok = ch;
1000 /* encode identifiers & numbers */
1001 if (isid()) {
1002 pdef(TAG_TOK);
1003 last_id = dstk;
1004 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001005 pdef(ch);
1006 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001007 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001008 if (isdigit(tok)) {
1009 tokc = strtol((char*) last_id, 0, 0);
1010 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001011 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001012 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we
1013 suppose data is initialized to zero by calloc) */
1014 tok = (int) (strstr((char*) sym_stk, (char*) (last_id - 1))
1015 - sym_stk);
1016 *(char *) dstk = 0; /* mark real end of ident for dlsym() */
1017 tok = tok * 8 + TOK_IDENT;
1018 if (tok > TOK_DEFINE) {
1019 tok = vars + tok;
1020 /* printf("tok=%s %x\n", last_id, tok); */
1021 /* define handling */
1022 if (*(int *) tok == SYM_DEFINE) {
1023 dptr = *(int *) (tok + 4);
1024 dch = ch;
1025 inp();
1026 next();
1027 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001028 }
1029 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001030 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001031 inp();
1032 if (tok == '\'') {
1033 tok = TOK_NUM;
1034 getq();
1035 tokc = ch;
1036 inp();
1037 inp();
Jack Palevich546b2242009-05-13 15:10:04 -07001038 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001039 inp();
1040 while (ch) {
1041 while (ch != '*')
1042 inp();
1043 inp();
1044 if (ch == '/')
1045 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001046 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001047 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001048 next();
Jack Palevichbd894902009-05-14 19:35:31 -07001049 } else if ((tok == '/') & (ch == '/')) {
1050 inp();
1051 while (ch && (ch != '\n')) {
1052 inp();
1053 }
1054 inp();
1055 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001056 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001057 const char* t = operatorChars;
1058 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001059 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001060 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001061 tokl = operatorLevel[opIndex];
1062 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07001063 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001064#if 0
1065 printf("%c%c -> tokl=%d tokc=0x%x\n",
1066 l, a, tokl, tokc);
1067#endif
1068 if (a == ch) {
1069 inp();
1070 tok = TOK_DUMMY; /* dummy token for double tokens */
1071 }
1072 break;
1073 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001074 opIndex++;
1075 }
1076 if (l == 0) {
1077 tokl = 0;
1078 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001079 }
1080 }
1081 }
1082#if 0
1083 {
1084 int p;
1085
1086 printf("tok=0x%x ", tok);
1087 if (tok >= TOK_IDENT) {
1088 printf("'");
1089 if (tok> TOK_DEFINE)
1090 p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8;
1091 else
1092 p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
1093 while (*(char *)p != TAG_TOK && *(char *)p)
1094 printf("%c", *(char *)p++);
1095 printf("'\n");
1096 } else if (tok == TOK_NUM) {
1097 printf("%d\n", tokc);
1098 } else {
1099 printf("'%c'\n", tok);
1100 }
1101 }
1102#endif
1103 }
1104
1105 void error(const char *fmt, ...) {
1106 va_list ap;
1107
1108 va_start(ap, fmt);
1109 fprintf(stderr, "%ld: ", ftell((FILE *) file));
1110 vfprintf(stderr, fmt, ap);
1111 fprintf(stderr, "\n");
1112 va_end(ap);
1113 exit(1);
1114 }
1115
1116 void skip(int c) {
1117 if (tok != c) {
1118 error("'%c' expected", c);
1119 }
1120 next();
1121 }
1122
Jack Palevich21a15a22009-05-11 14:49:29 -07001123 /* l is one if '=' parsing wanted (quick hack) */
1124 void unary(int l) {
1125 int n, t, a, c;
Jack Palevich546b2242009-05-13 15:10:04 -07001126 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001127 n = 1; /* type of expression 0 = forward, 1 = value, other =
1128 lvalue */
1129 if (tok == '\"') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001130 pGen->li(glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001131 while (ch != '\"') {
1132 getq();
1133 *(char *) glo++ = ch;
1134 inp();
1135 }
1136 *(char *) glo = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001137 glo = (glo + 4) & -4; /* align heap */
Jack Palevich21a15a22009-05-11 14:49:29 -07001138 inp();
1139 next();
1140 } else {
1141 c = tokl;
1142 a = tokc;
1143 t = tok;
1144 next();
1145 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001146 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001147 } else if (c == 2) {
1148 /* -, +, !, ~ */
1149 unary(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001150 pGen->clearECX();
Jack Palevich21a15a22009-05-11 14:49:29 -07001151 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001152 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001153 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001154 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001155 } else if (t == '(') {
1156 expr();
1157 skip(')');
1158 } else if (t == '*') {
1159 /* parse cast */
1160 skip('(');
1161 t = tok; /* get type */
1162 next(); /* skip int/char/void */
1163 next(); /* skip '*' or '(' */
1164 if (tok == '*') {
1165 /* function type */
1166 skip('*');
1167 skip(')');
1168 skip('(');
1169 skip(')');
1170 t = 0;
1171 }
1172 skip(')');
1173 unary(0);
1174 if (tok == '=') {
1175 next();
1176 pGen->pushEAX();
1177 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001178 pGen->popECX();
1179 pGen->storeEAXToAddressECX(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001180 } else if (t) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001181 pGen->loadEAXIndirect(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001182 }
1183 } else if (t == '&') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001184 pGen->leaEAX(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001185 next();
1186 } else {
1187 n = *(int *) t;
1188 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001189 if (!n) {
1190 n = (int) dlsym(RTLD_DEFAULT, (char*) last_id);
1191 }
Jack Palevich546b2242009-05-13 15:10:04 -07001192 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001193 /* assignment */
1194 next();
1195 expr();
1196 pGen->storeEAX(n);
1197 } else if (tok != '(') {
1198 /* variable */
Jack Palevich4d93f302009-05-15 13:30:00 -07001199 pGen->loadEAX(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001200 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001201 next();
1202 }
1203 }
1204 }
1205 }
1206
1207 /* function call */
1208 if (tok == '(') {
1209 if (n == 1)
1210 pGen->pushEAX();
1211
1212 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001213 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07001214 next();
1215 l = 0;
1216 while (tok != ')') {
1217 expr();
1218 pGen->storeEAToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001219 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001220 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001221 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001222 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001223 pGen->endFunctionCallArguments(a, l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001224 next();
1225 if (!n) {
1226 /* forward reference */
1227 t = t + 4;
1228 *(int *) t = pGen->callForward(*(int *) t);
1229 } else if (n == 1) {
1230 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001231 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07001232 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07001233 }
Jack Palevich3d474a72009-05-15 15:12:38 -07001234 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07001235 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001236 }
1237 }
1238
1239 void sum(int l) {
1240 int t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07001241 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001242 if (l-- == 1)
1243 unary(1);
1244 else {
1245 sum(l);
1246 a = 0;
1247 while (l == tokl) {
1248 n = tok;
1249 t = tokc;
1250 next();
1251
1252 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001253 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07001254 sum(l);
1255 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001256 pGen->pushEAX();
Jack Palevich21a15a22009-05-11 14:49:29 -07001257 sum(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001258 pGen->popECX();
Jack Palevich21a15a22009-05-11 14:49:29 -07001259
Jack Palevich546b2242009-05-13 15:10:04 -07001260 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001261 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001262 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001263 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001264 }
1265 }
1266 }
1267 /* && and || output code generation */
1268 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001269 a = pGen->gtst(t == OP_LOGICAL_OR, a);
1270 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07001271 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001272 pGen->gsym(a);
1273 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07001274 }
1275 }
1276 }
1277
1278 void expr() {
1279 sum(11);
1280 }
1281
1282 int test_expr() {
1283 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001284 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001285 }
1286
1287 void block(int l) {
1288 int a, n, t;
1289
1290 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001291 next();
1292 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07001293 a = test_expr();
1294 skip(')');
1295 block(l);
1296 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001297 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001298 n = pGen->gjmp(0); /* jmp */
1299 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001300 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001301 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001302 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001303 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001304 }
Jack Palevich546b2242009-05-13 15:10:04 -07001305 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001306 t = tok;
1307 next();
1308 skip('(');
1309 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07001310 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07001311 a = test_expr();
1312 } else {
1313 if (tok != ';')
1314 expr();
1315 skip(';');
1316 n = codeBuf.getPC();
1317 a = 0;
1318 if (tok != ';')
1319 a = test_expr();
1320 skip(';');
1321 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001322 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001323 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07001324 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001325 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001326 n = t + 4;
1327 }
1328 }
1329 skip(')');
1330 block((int) &a);
Jack Palevicha6535612009-05-13 16:24:17 -07001331 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001332 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001333 } else if (tok == '{') {
1334 next();
1335 /* declarations */
1336 decl(1);
1337 while (tok != '}')
1338 block(l);
1339 next();
1340 } else {
1341 if (tok == TOK_RETURN) {
1342 next();
1343 if (tok != ';')
1344 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001345 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001346 } else if (tok == TOK_BREAK) {
1347 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001348 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001349 } else if (tok != ';')
1350 expr();
1351 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001352 }
1353 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001354
1355 /* 'l' is true if local declarations */
1356 void decl(int l) {
1357 int a;
1358
Jack Palevich546b2242009-05-13 15:10:04 -07001359 while ((tok == TOK_INT) | ((tok != -1) & (!l))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001360 if (tok == TOK_INT) {
1361 next();
1362 while (tok != ';') {
1363 if (l) {
1364 loc = loc + 4;
1365 *(int *) tok = -loc;
1366 } else {
1367 *(int *) tok = glo;
1368 glo = glo + 4;
1369 }
1370 next();
1371 if (tok == ',')
1372 next();
1373 }
1374 skip(';');
1375 } else {
1376 /* patch forward references (XXX: do not work for function
1377 pointers) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001378 pGen->gsym(*(int *) (tok + 4));
Jack Palevich21a15a22009-05-11 14:49:29 -07001379 /* put function address */
1380 *(int *) tok = codeBuf.getPC();
1381 next();
1382 skip('(');
1383 a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07001384 int argCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001385 while (tok != ')') {
1386 /* read param name and compute offset */
1387 *(int *) tok = a;
1388 a = a + 4;
1389 next();
1390 if (tok == ',')
1391 next();
Jack Palevich546b2242009-05-13 15:10:04 -07001392 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07001393 }
1394 next(); /* skip ')' */
1395 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001396 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07001397 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001398 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07001399 pGen->functionExit(argCount, a, loc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001400 }
1401 }
1402 }
1403
1404 void cleanup() {
1405 if (sym_stk != 0) {
1406 free((void*) sym_stk);
1407 sym_stk = 0;
1408 }
1409 if (pGlobalBase != 0) {
1410 free((void*) pGlobalBase);
1411 pGlobalBase = 0;
1412 }
1413 if (pVarsBase != 0) {
1414 free(pVarsBase);
1415 pVarsBase = 0;
1416 }
1417 if (pGen) {
1418 delete pGen;
1419 pGen = 0;
1420 }
1421 }
1422
1423 void clear() {
1424 tok = 0;
1425 tokc = 0;
1426 tokl = 0;
1427 ch = 0;
1428 vars = 0;
1429 rsym = 0;
1430 loc = 0;
1431 glo = 0;
1432 sym_stk = 0;
1433 dstk = 0;
1434 dptr = 0;
1435 dch = 0;
1436 last_id = 0;
1437 file = 0;
1438 pGlobalBase = 0;
1439 pVarsBase = 0;
1440 pGen = 0;
1441 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001442
Jack Palevich22305132009-05-13 10:58:45 -07001443 void setArchitecture(const char* architecture) {
1444 delete pGen;
1445 pGen = 0;
1446
1447 if (architecture != NULL) {
1448 if (strcmp(architecture, "arm") == 0) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001449#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich22305132009-05-13 10:58:45 -07001450 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07001451#else
1452 fprintf(stderr, "Unsupported architecture %s", architecture);
1453#endif
Jack Palevich22305132009-05-13 10:58:45 -07001454 } else if (strcmp(architecture, "x86") == 0) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001455#ifdef PROVIDE_X86_CODEGEN
Jack Palevich22305132009-05-13 10:58:45 -07001456 pGen = new X86CodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07001457#else
1458 fprintf(stderr, "Unsupported architecture %s", architecture);
1459#endif
Jack Palevich22305132009-05-13 10:58:45 -07001460 } else {
1461 fprintf(stderr, "Unknown architecture %s", architecture);
1462 }
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 Palevich21a15a22009-05-11 14:49:29 -07001498 pGen->init(&codeBuf);
1499 file = in;
1500 sym_stk = (int) calloc(1, ALLOC_SIZE);
1501 dstk = (int) strcpy((char*) sym_stk,
1502 " int if else while break return for define main ")
1503 + TOK_STR_SIZE;
1504 pGlobalBase = calloc(1, ALLOC_SIZE);
1505 glo = (int) pGlobalBase;
1506 pVarsBase = calloc(1, ALLOC_SIZE);
1507 vars = (int) pVarsBase;
1508 inp();
1509 next();
1510 decl(0);
Jack Palevich546b2242009-05-13 15:10:04 -07001511 pGen->finishCompile();
Jack Palevich21a15a22009-05-11 14:49:29 -07001512 return 0;
1513 }
1514
1515 int run(int argc, char** argv) {
1516 typedef int (*mainPtr)(int argc, char** argv);
1517 mainPtr aMain = (mainPtr) *(int*) (vars + TOK_MAIN);
1518 if (!aMain) {
1519 fprintf(stderr, "Could not find function \"main\".\n");
1520 return -1;
1521 }
1522 return aMain(argc, argv);
1523 }
1524
1525 int dump(FILE* out) {
1526 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
1527 return 0;
1528 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07001529
Jack Palevicha6535612009-05-13 16:24:17 -07001530 int disassemble(FILE* out) {
1531 return pGen->disassemble(out);
1532 }
1533
Jack Palevich77ae76e2009-05-10 19:59:24 -07001534};
1535
Jack Paleviche7b59062009-05-19 17:12:17 -07001536const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001537 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
1538
Jack Paleviche7b59062009-05-19 17:12:17 -07001539const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001540 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
1541 5, 5, /* ==, != */
1542 9, 10, /* &&, || */
1543 6, 7, 8, /* & ^ | */
1544 2, 2 /* ~ ! */
1545 };
1546
Jack Paleviche7b59062009-05-19 17:12:17 -07001547FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevicha6535612009-05-13 16:24:17 -07001548
Jack Paleviche7b59062009-05-19 17:12:17 -07001549const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001550 0x1, // ++
1551 0xff, // --
1552 0xc1af0f, // *
1553 0xf9f79991, // /
1554 0xf9f79991, // % (With manual assist to swap results)
1555 0xc801, // +
1556 0xd8f7c829, // -
1557 0xe0d391, // <<
1558 0xf8d391, // >>
1559 0xe, // <=
1560 0xd, // >=
1561 0xc, // <
1562 0xf, // >
1563 0x4, // ==
1564 0x5, // !=
1565 0x0, // &&
1566 0x1, // ||
1567 0xc821, // &
1568 0xc831, // ^
1569 0xc809, // |
1570 0xd0f7, // ~
1571 0x4 // !
1572};
1573
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001574} // namespace acc
1575
Jack Palevich546b2242009-05-13 15:10:04 -07001576// This is a separate function so it can easily be set by breakpoint in gdb.
Jack Paleviche7b59062009-05-19 17:12:17 -07001577int run(acc::Compiler& c, int argc, char** argv) {
Jack Palevich546b2242009-05-13 15:10:04 -07001578 return c.run(argc, argv);
1579}
1580
Jack Palevich77ae76e2009-05-10 19:59:24 -07001581int main(int argc, char** argv) {
Jack Palevich22305132009-05-13 10:58:45 -07001582 bool doDump = false;
Jack Palevicha6535612009-05-13 16:24:17 -07001583 bool doDisassemble = false;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001584 const char* inFile = NULL;
1585 const char* outFile = NULL;
Jack Paleviche7b59062009-05-19 17:12:17 -07001586 const char* architecture = NULL;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001587 int i;
Jack Palevich21a15a22009-05-11 14:49:29 -07001588 for (i = 1; i < argc; i++) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001589 char* arg = argv[i];
1590 if (arg[0] == '-') {
1591 switch (arg[1]) {
Jack Palevich22305132009-05-13 10:58:45 -07001592 case 'a':
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001593 if (i + 1 >= argc) {
Jack Palevich22305132009-05-13 10:58:45 -07001594 fprintf(stderr, "Expected architecture after -a\n");
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001595 return 2;
1596 }
Jack Palevich22305132009-05-13 10:58:45 -07001597 architecture = argv[i+1];
1598 i += 1;
1599 break;
1600 case 'd':
1601 if (i + 1 >= argc) {
1602 fprintf(stderr, "Expected filename after -d\n");
1603 return 2;
1604 }
1605 doDump = true;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001606 outFile = argv[i + 1];
1607 i += 1;
1608 break;
Jack Palevicha6535612009-05-13 16:24:17 -07001609 case 'S':
1610 doDisassemble = true;
1611 break;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001612 default:
1613 fprintf(stderr, "Unrecognized flag %s\n", arg);
1614 return 3;
1615 }
1616 } else if (inFile == NULL) {
1617 inFile = arg;
1618 } else {
1619 break;
1620 }
1621 }
1622
1623 FILE* in = stdin;
1624 if (inFile) {
1625 in = fopen(inFile, "r");
Jack Palevich21a15a22009-05-11 14:49:29 -07001626 if (!in) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001627 fprintf(stderr, "Could not open input file %s\n", inFile);
1628 return 1;
1629 }
1630 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001631 acc::Compiler compiler;
1632 acc::Compiler::args args;
1633 if (architecture != NULL) {
1634 args.architecture = architecture;
1635 }
Jack Palevich22305132009-05-13 10:58:45 -07001636 int compileResult = compiler.compile(in, args);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001637 if (in != stdin) {
1638 fclose(in);
1639 }
1640 if (compileResult) {
1641 fprintf(stderr, "Compile failed: %d\n", compileResult);
1642 return 6;
1643 }
Jack Palevicha6535612009-05-13 16:24:17 -07001644 if (doDisassemble) {
1645 compiler.disassemble(stderr);
1646 }
Jack Palevich22305132009-05-13 10:58:45 -07001647 if (doDump) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001648 FILE* save = fopen(outFile, "w");
Jack Palevich21a15a22009-05-11 14:49:29 -07001649 if (!save) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001650 fprintf(stderr, "Could not open output file %s\n", outFile);
1651 return 5;
1652 }
1653 compiler.dump(save);
1654 fclose(save);
1655 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001656 fprintf(stderr, "Executing compiled code:\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07001657 int codeArgc = argc - i + 1;
1658 char** codeArgv = argv + i - 1;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001659 codeArgv[0] = (char*) (inFile ? inFile : "stdin");
Jack Palevich546b2242009-05-13 15:10:04 -07001660 int result = run(compiler, codeArgc, codeArgv);
Jack Palevich22305132009-05-13 10:58:45 -07001661 fprintf(stderr, "result: %d\n", result);
1662 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001663 }
1664
1665 return 0;
1666}