blob: 0cc1a0f334ce11d174ed2d0e2ada573d3e71d363 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Palevich21a15a22009-05-11 14:49:29 -07002 Obfuscated Tiny C Compiler
Jack Palevich88311482009-05-08 13:57:37 -07003
Jack Palevich21a15a22009-05-11 14:49:29 -07004 Copyright (C) 2001-2003 Fabrice Bellard
Jack Palevichae54f1f2009-05-08 14:54:15 -07005
Jack Palevich21a15a22009-05-11 14:49:29 -07006 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
Jack Paleviche27bf3e2009-05-10 14:09:03 -07009
Jack Palevich21a15a22009-05-11 14:49:29 -070010 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it
12 freely, subject to the following restrictions:
Jack Paleviche27bf3e2009-05-10 14:09:03 -070013
Jack Palevich21a15a22009-05-11 14:49:29 -070014 1. The origin of this software must not be misrepresented; you must not
15 claim that you wrote the original software. If you use this software
16 in a product, an acknowledgment in the product and its documentation
17 *is* required.
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source distribution.
21 */
Jack Paleviche27bf3e2009-05-10 14:09:03 -070022
Jack Palevich77ae76e2009-05-10 19:59:24 -070023#include <ctype.h>
24#include <dlfcn.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070025#include <stdarg.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070026#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070027#include <stdlib.h>
28#include <string.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070029
Jack Palevich546b2242009-05-13 15:10:04 -070030#if defined(__arm__)
31#include <unistd.h>
32#endif
33
Jack Palevichbbf8ab52009-05-11 11:54:30 -070034namespace acc {
35
Jack Palevich77ae76e2009-05-10 19:59:24 -070036class compiler {
Jack Palevich21a15a22009-05-11 14:49:29 -070037 class CodeBuf {
38 char* ind;
39 char* pProgramBase;
Jack Palevichf0cbc922009-05-08 16:35:13 -070040
Jack Palevich21a15a22009-05-11 14:49:29 -070041 void release() {
42 if (pProgramBase != 0) {
43 free(pProgramBase);
44 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070045 }
Jack Palevich21a15a22009-05-11 14:49:29 -070046 }
47
48 public:
49 CodeBuf() {
50 pProgramBase = 0;
51 ind = 0;
52 }
53
54 ~CodeBuf() {
55 release();
56 }
57
58 void init(int size) {
59 release();
60 pProgramBase = (char*) calloc(1, size);
61 ind = pProgramBase;
62 }
63
64 void o(int n) {
65 /* cannot use unsigned, so we must do a hack */
66 while (n && n != -1) {
67 *ind++ = n;
68 n = n >> 8;
69 }
70 }
71
Jack Palevich546b2242009-05-13 15:10:04 -070072 int o4(int n) {
73 int result = (int) ind;
74 * (int*) ind = n;
75 ind += 4;
76 return result;
77 }
78
Jack Palevich21a15a22009-05-11 14:49:29 -070079 /*
80 * Output a byte. Handles all values, 0..ff.
81 */
82 void ob(int n) {
83 *ind++ = n;
84 }
85
86 /* output a symbol and patch all calls to it */
87 void gsym(int t) {
88 int n;
89 while (t) {
90 n = *(int *) t; /* next value */
91 *(int *) t = ((int) ind) - t - 4;
92 t = n;
93 }
94 }
95
96 /* psym is used to put an instruction with a data field which is a
97 reference to a symbol. It is in fact the same as oad ! */
98 int psym(int n, int t) {
99 return oad(n, t);
100 }
101
102 /* instruction + address */
103 int oad(int n, int t) {
104 o(n);
105 *(int *) ind = t;
106 t = (int) ind;
107 ind = ind + 4;
108 return t;
109 }
110
111 inline void* getBase() {
112 return (void*) pProgramBase;
113 }
114
115 int getSize() {
116 return ind - pProgramBase;
117 }
118
119 int getPC() {
120 return (int) ind;
121 }
122 };
123
124 class CodeGenerator {
125 public:
126 CodeGenerator() {}
127 virtual ~CodeGenerator() {}
128
Jack Palevich22305132009-05-13 10:58:45 -0700129 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700130 this->pCodeBuf = pCodeBuf;
131 }
132
Jack Palevich22305132009-05-13 10:58:45 -0700133 /* returns address to patch with local variable size
134 */
Jack Palevich546b2242009-05-13 15:10:04 -0700135 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700136
Jack Palevich546b2242009-05-13 15:10:04 -0700137 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700138
139 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700140 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700141
142 virtual int gjmp(int t) = 0;
143
144 /* l = 0: je, l == 1: jne */
145 virtual int gtst(bool l, int t) = 0;
146
147 virtual void gcmp(int op) = 0;
148
Jack Palevich546b2242009-05-13 15:10:04 -0700149 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700150
151 virtual void clearECX() = 0;
152
153 virtual void pushEAX() = 0;
154
155 virtual void popECX() = 0;
156
157 virtual void storeEAXToAddressECX(bool isInt) = 0;
158
159 virtual void loadEAXIndirect(bool isInt) = 0;
160
161 virtual void leaEAX(int ea) = 0;
162
163 virtual void storeEAX(int ea) = 0;
164
165 virtual void loadEAX(int ea) = 0;
166
167 virtual void postIncrementOrDecrement(int n, int op) = 0;
168
169 virtual int allocStackSpaceForArgs() = 0;
170
171 virtual void storeEAToArg(int l) = 0;
172
173 virtual int callForward(int symbol) = 0;
174
175 virtual void callRelative(int t) = 0;
176
177 virtual void callIndirect(int l) = 0;
178
179 virtual void adjustStackAfterCall(int l) = 0;
180
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 /* output a symbol and patch all calls to it */
Jack Palevich22305132009-05-13 10:58:45 -0700182 virtual void gsym(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700183 pCodeBuf->gsym(t);
184 }
185
Jack Palevich546b2242009-05-13 15:10:04 -0700186 virtual int finishCompile() {
187#if defined(__arm__)
188 const long base = long(pCodeBuf->getBase());
189 const long curr = base + long(pCodeBuf->getSize());
190 int err = cacheflush(base, curr, 0);
191 return err;
192#else
193 return 0;
194#endif
195 }
196
Jack Palevich21a15a22009-05-11 14:49:29 -0700197 protected:
198 void o(int n) {
199 pCodeBuf->o(n);
200 }
201
202 /*
203 * Output a byte. Handles all values, 0..ff.
204 */
205 void ob(int n) {
206 pCodeBuf->ob(n);
207 }
208
209 /* psym is used to put an instruction with a data field which is a
210 reference to a symbol. It is in fact the same as oad ! */
211 int psym(int n, int t) {
212 return oad(n, t);
213 }
214
215 /* instruction + address */
216 int oad(int n, int t) {
217 return pCodeBuf->oad(n,t);
218 }
219
220 int getPC() {
221 return pCodeBuf->getPC();
222 }
223
Jack Palevich546b2242009-05-13 15:10:04 -0700224 int o4(int data) {
225 return pCodeBuf->o4(data);
226 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700227 private:
228 CodeBuf* pCodeBuf;
229 };
230
Jack Palevich22305132009-05-13 10:58:45 -0700231 class ARMCodeGenerator : public CodeGenerator {
232 public:
233 ARMCodeGenerator() {}
234 virtual ~ARMCodeGenerator() {}
235
Jack Palevich546b2242009-05-13 15:10:04 -0700236 // The gnu ARM assembler prints the constants in little-endian,
237 // but C hexidecimal constants are big-endian. We trick the
238 // gnu assembler into putting out big-endian constants by
239 // using the -mbig-endian flag when assembling.
240
Jack Palevich22305132009-05-13 10:58:45 -0700241 /* returns address to patch with local variable size
242 */
Jack Palevich546b2242009-05-13 15:10:04 -0700243 virtual int functionEntry(int argCount) {
244 fprintf(stderr, "functionEntry(%d);\n", argCount);
245 /*
246 19 0000 E1A0C00D mov ip, sp
247 20 0004 E92DD800 stmfd sp!, {fp, ip, lr, pc}
248 21 0008 E24CB004 sub fp, ip, #4
249 22 000c E24DD008 sub sp, sp, #8
250 */
251 o4(0xE1A0C00D);
252 o4(0xE92DD800);
253 o4(0xE24CB004);
254 return o4(0xE24DD008);
Jack Palevich22305132009-05-13 10:58:45 -0700255 }
256
Jack Palevich546b2242009-05-13 15:10:04 -0700257 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
258 fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
259 /*
260 23 0010 E24BD00C sub sp, fp, #12
261 24 0014 E89DA800 ldmfd sp, {fp, sp, pc}
262 */
263 o4(0xE24BD00C);
264 o4(0xE89DA800);
265 if (localVariableSize < 0 || localVariableSize > 255-8) {
266 error("LocalVariableSize");
267 }
268 *(char*) (localVariableAddress) = localVariableSize + 8;
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);
274 oad(0xb8, t); /* mov $xx, %eax */
275 }
276
277 virtual int gjmp(int t) {
278 fprintf(stderr, "gjmp(%d);\n", t);
279 return psym(0xe9, t);
280 }
281
282 /* l = 0: je, l == 1: jne */
283 virtual int gtst(bool l, int t) {
284 fprintf(stderr, "gtst(%d, %d);\n", l, t);
285 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
286 return psym(0x84 + l, t);
287 }
288
289 virtual void gcmp(int op) {
290 fprintf(stderr, "gcmp(%d);\n", op);
291#if 0
292 int t = decodeOp(op);
293 o(0xc139); /* cmp %eax,%ecx */
294 li(0);
295 o(0x0f); /* setxx %al */
296 o(t + 0x90);
297 o(0xc0);
298#endif
299 }
300
Jack Palevich546b2242009-05-13 15:10:04 -0700301 virtual void genOp(int op) {
Jack Palevich22305132009-05-13 10:58:45 -0700302 fprintf(stderr, "genOp(%d);\n", op);
303#if 0
304 o(decodeOp(op));
305 if (op == OP_MOD)
306 o(0x92); /* xchg %edx, %eax */
307#endif
308 }
309
310 virtual void clearECX() {
311 fprintf(stderr, "clearECX();\n");
312 oad(0xb9, 0); /* movl $0, %ecx */
313 }
314
315 virtual void pushEAX() {
316 fprintf(stderr, "pushEAX();\n");
317 o(0x50); /* push %eax */
318 }
319
320 virtual void popECX() {
321 fprintf(stderr, "popECX();\n");
322 o(0x59); /* pop %ecx */
323 }
324
325 virtual void storeEAXToAddressECX(bool isInt) {
326 fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt);
327 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
328 }
329
330 virtual void loadEAXIndirect(bool isInt) {
331 fprintf(stderr, "loadEAXIndirect(%d);\n", isInt);
332 if (isInt)
333 o(0x8b); /* mov (%eax), %eax */
334 else
335 o(0xbe0f); /* movsbl (%eax), %eax */
336 ob(0); /* add zero in code */
337 }
338
339 virtual void leaEAX(int ea) {
340 fprintf(stderr, "leaEAX(%d);\n", ea);
341#if 0
342 gmov(10, ea); /* leal EA, %eax */
343#endif
344 }
345
346 virtual void storeEAX(int ea) {
347 fprintf(stderr, "storeEAX(%d);\n", ea);
348#if 0
349 gmov(6, ea); /* mov %eax, EA */
350#endif
351 }
352
353 virtual void loadEAX(int ea) {
354 fprintf(stderr, "loadEAX(%d);\n", ea);
355#if 0
356 gmov(8, ea); /* mov EA, %eax */
357#endif
358 }
359
360 virtual void postIncrementOrDecrement(int n, int op) {
361 fprintf(stderr, "postIncrementOrDecrement(%d, %d);\n", n, op);
362 /* Implement post-increment or post decrement.
363 */
364#if 0
365 gmov(0, n); /* 83 ADD */
366 o(decodeOp(op));
367#endif
368 }
369
370 virtual int allocStackSpaceForArgs() {
371 fprintf(stderr, "allocStackSpaceForArgs();\n");
372 return oad(0xec81, 0); /* sub $xxx, %esp */
373 }
374
375 virtual void storeEAToArg(int l) {
376 fprintf(stderr, "storeEAToArg(%d);\n", l);
377 oad(0x248489, l); /* movl %eax, xxx(%esp) */
378 }
379
380 virtual int callForward(int symbol) {
381 fprintf(stderr, "callForward(%d);\n", symbol);
382 return psym(0xe8, symbol); /* call xxx */
383 }
384
385 virtual void callRelative(int t) {
386 fprintf(stderr, "callRelative(%d);\n", t);
387 psym(0xe8, t); /* call xxx */
388 }
389
390 virtual void callIndirect(int l) {
391 fprintf(stderr, "callIndirect(%d);\n", l);
392 oad(0x2494ff, l); /* call *xxx(%esp) */
393 }
394
395 virtual void adjustStackAfterCall(int l) {
396 fprintf(stderr, "adjustStackAfterCall(%d);\n", l);
397 oad(0xc481, l); /* add $xxx, %esp */
398 }
399
400 private:
401
Jack Palevich546b2242009-05-13 15:10:04 -0700402 void error(const char* fmt,...) {
403 va_list ap;
404 va_start(ap, fmt);
405 vfprintf(stderr, fmt, ap);
406 va_end(ap);
407 exit(12);
408 }
Jack Palevich22305132009-05-13 10:58:45 -0700409 };
410
Jack Palevich21a15a22009-05-11 14:49:29 -0700411 class X86CodeGenerator : public CodeGenerator {
412 public:
413 X86CodeGenerator() {}
414 virtual ~X86CodeGenerator() {}
415
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700416 /* returns address to patch with local variable size
417 */
Jack Palevich546b2242009-05-13 15:10:04 -0700418 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700419 o(0xe58955); /* push %ebp, mov %esp, %ebp */
420 return oad(0xec81, 0); /* sub $xxx, %esp */
421 }
422
Jack Palevich546b2242009-05-13 15:10:04 -0700423 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700424 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700425 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700426 }
427
Jack Palevich21a15a22009-05-11 14:49:29 -0700428 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700429 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700430 oad(0xb8, t); /* mov $xx, %eax */
431 }
432
Jack Palevich22305132009-05-13 10:58:45 -0700433 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700434 return psym(0xe9, t);
435 }
436
437 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700438 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700439 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
440 return psym(0x84 + l, t);
441 }
442
Jack Palevich22305132009-05-13 10:58:45 -0700443 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700444 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700445 o(0xc139); /* cmp %eax,%ecx */
446 li(0);
447 o(0x0f); /* setxx %al */
448 o(t + 0x90);
449 o(0xc0);
450 }
451
Jack Palevich546b2242009-05-13 15:10:04 -0700452 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700453 o(decodeOp(op));
454 if (op == OP_MOD)
455 o(0x92); /* xchg %edx, %eax */
456 }
457
Jack Palevich22305132009-05-13 10:58:45 -0700458 virtual void clearECX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700459 oad(0xb9, 0); /* movl $0, %ecx */
460 }
461
Jack Palevich22305132009-05-13 10:58:45 -0700462 virtual void pushEAX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700463 o(0x50); /* push %eax */
464 }
465
Jack Palevich22305132009-05-13 10:58:45 -0700466 virtual void popECX() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700467 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700468 }
469
Jack Palevich22305132009-05-13 10:58:45 -0700470 virtual void storeEAXToAddressECX(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700471 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
472 }
473
Jack Palevich22305132009-05-13 10:58:45 -0700474 virtual void loadEAXIndirect(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700475 if (isInt)
476 o(0x8b); /* mov (%eax), %eax */
477 else
478 o(0xbe0f); /* movsbl (%eax), %eax */
479 ob(0); /* add zero in code */
480 }
481
Jack Palevich22305132009-05-13 10:58:45 -0700482 virtual void leaEAX(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700483 gmov(10, ea); /* leal EA, %eax */
484 }
485
Jack Palevich22305132009-05-13 10:58:45 -0700486 virtual void storeEAX(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700487 gmov(6, ea); /* mov %eax, EA */
488 }
489
Jack Palevich22305132009-05-13 10:58:45 -0700490 virtual void loadEAX(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700491 gmov(8, ea); /* mov EA, %eax */
492 }
493
Jack Palevich22305132009-05-13 10:58:45 -0700494 virtual void postIncrementOrDecrement(int n, int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700495 /* Implement post-increment or post decrement.
Jack Palevich21a15a22009-05-11 14:49:29 -0700496 */
497 gmov(0, n); /* 83 ADD */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700498 o(decodeOp(op));
Jack Palevich21a15a22009-05-11 14:49:29 -0700499 }
500
Jack Palevich22305132009-05-13 10:58:45 -0700501 virtual int allocStackSpaceForArgs() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700502 return oad(0xec81, 0); /* sub $xxx, %esp */
503 }
504
Jack Palevich22305132009-05-13 10:58:45 -0700505 virtual void storeEAToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700506 oad(0x248489, l); /* movl %eax, xxx(%esp) */
507 }
508
Jack Palevich22305132009-05-13 10:58:45 -0700509 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700510 return psym(0xe8, symbol); /* call xxx */
511 }
512
Jack Palevich22305132009-05-13 10:58:45 -0700513 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700514 psym(0xe8, t); /* call xxx */
515 }
516
Jack Palevich22305132009-05-13 10:58:45 -0700517 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700518 oad(0x2494ff, l); /* call *xxx(%esp) */
519 }
520
Jack Palevich22305132009-05-13 10:58:45 -0700521 virtual void adjustStackAfterCall(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700522 oad(0xc481, l); /* add $xxx, %esp */
523 }
524
Jack Palevich21a15a22009-05-11 14:49:29 -0700525 private:
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700526 static const int operatorHelper[];
527
528 int decodeOp(int op) {
529 if (op < 0 || op > OP_COUNT) {
530 fprintf(stderr, "Out-of-range operator: %d\n", op);
531 exit(1);
532 }
533 return operatorHelper[op];
534 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700535
Jack Palevich546b2242009-05-13 15:10:04 -0700536 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700537 o(l + 0x83);
538 oad((t < LOCAL) << 7 | 5, t);
539 }
540 };
541
542 /* vars: value of variables
543 loc : local variable index
544 glo : global variable index
545 ind : output code ptr
546 rsym: return symbol
547 prog: output code
548 dstk: define stack
549 dptr, dch: macro state
550 */
551 int tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk,
552 dptr, dch, last_id;
553 void* pSymbolBase;
554 void* pGlobalBase;
555 void* pVarsBase;
556 FILE* file;
557
558 CodeBuf codeBuf;
Jack Palevich22305132009-05-13 10:58:45 -0700559 CodeGenerator* pGen;
Jack Palevich21a15a22009-05-11 14:49:29 -0700560
561 static const int ALLOC_SIZE = 99999;
562
563 /* depends on the init string */
564 static const int TOK_STR_SIZE = 48;
565 static const int TOK_IDENT = 0x100;
566 static const int TOK_INT = 0x100;
567 static const int TOK_IF = 0x120;
568 static const int TOK_ELSE = 0x138;
569 static const int TOK_WHILE = 0x160;
570 static const int TOK_BREAK = 0x190;
571 static const int TOK_RETURN = 0x1c0;
572 static const int TOK_FOR = 0x1f8;
573 static const int TOK_DEFINE = 0x218;
574 static const int TOK_MAIN = 0x250;
575
576 static const int TOK_DUMMY = 1;
577 static const int TOK_NUM = 2;
578
579 static const int LOCAL = 0x200;
580
581 static const int SYM_FORWARD = 0;
582 static const int SYM_DEFINE = 1;
583
584 /* tokens in string heap */
585 static const int TAG_TOK = ' ';
586 static const int TAG_MACRO = 2;
587
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700588 static const int OP_INCREMENT = 0;
589 static const int OP_DECREMENT = 1;
590 static const int OP_MUL = 2;
591 static const int OP_DIV = 3;
592 static const int OP_MOD = 4;
593 static const int OP_PLUS = 5;
594 static const int OP_MINUS = 6;
595 static const int OP_SHIFT_LEFT = 7;
596 static const int OP_SHIFT_RIGHT = 8;
597 static const int OP_LESS_EQUAL = 9;
598 static const int OP_GREATER_EQUAL = 10;
599 static const int OP_LESS = 11;
600 static const int OP_GREATER = 12;
601 static const int OP_EQUALS = 13;
602 static const int OP_NOT_EQUALS = 14;
603 static const int OP_LOGICAL_AND = 15;
604 static const int OP_LOGICAL_OR = 16;
605 static const int OP_BIT_AND = 17;
606 static const int OP_BIT_XOR = 18;
607 static const int OP_BIT_OR = 19;
608 static const int OP_BIT_NOT = 20;
609 static const int OP_LOGICAL_NOT = 21;
610 static const int OP_COUNT = 22;
611
612 /* Operators are searched from front, the two-character operators appear
613 * before the single-character operators with the same first character.
614 * @ is used to pad out single-character operators.
615 */
616 static const char* operatorChars;
617 static const char operatorLevel[];
618
Jack Palevich21a15a22009-05-11 14:49:29 -0700619 void pdef(int t) {
620 *(char *) dstk++ = t;
621 }
622
623 void inp() {
624 if (dptr) {
625 ch = *(char *) dptr++;
626 if (ch == TAG_MACRO) {
627 dptr = 0;
628 ch = dch;
629 }
630 } else
631 ch = fgetc(file);
632 /* printf("ch=%c 0x%x\n", ch, ch); */
633 }
634
635 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -0700636 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -0700637 }
638
639 /* read a character constant */
640 void getq() {
641 if (ch == '\\') {
642 inp();
643 if (ch == 'n')
644 ch = '\n';
645 }
646 }
647
648 void next() {
649 int l, a;
650
Jack Palevich546b2242009-05-13 15:10:04 -0700651 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700652 if (ch == '#') {
653 inp();
654 next();
655 if (tok == TOK_DEFINE) {
656 next();
657 pdef(TAG_TOK); /* fill last ident tag */
658 *(int *) tok = SYM_DEFINE;
659 *(int *) (tok + 4) = dstk; /* define stack */
660 }
661 /* well we always save the values ! */
662 while (ch != '\n') {
663 pdef(ch);
664 inp();
665 }
666 pdef(ch);
667 pdef(TAG_MACRO);
668 }
669 inp();
670 }
671 tokl = 0;
672 tok = ch;
673 /* encode identifiers & numbers */
674 if (isid()) {
675 pdef(TAG_TOK);
676 last_id = dstk;
677 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700678 pdef(ch);
679 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -0700680 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700681 if (isdigit(tok)) {
682 tokc = strtol((char*) last_id, 0, 0);
683 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700684 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -0700685 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we
686 suppose data is initialized to zero by calloc) */
687 tok = (int) (strstr((char*) sym_stk, (char*) (last_id - 1))
688 - sym_stk);
689 *(char *) dstk = 0; /* mark real end of ident for dlsym() */
690 tok = tok * 8 + TOK_IDENT;
691 if (tok > TOK_DEFINE) {
692 tok = vars + tok;
693 /* printf("tok=%s %x\n", last_id, tok); */
694 /* define handling */
695 if (*(int *) tok == SYM_DEFINE) {
696 dptr = *(int *) (tok + 4);
697 dch = ch;
698 inp();
699 next();
700 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700701 }
702 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700703 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -0700704 inp();
705 if (tok == '\'') {
706 tok = TOK_NUM;
707 getq();
708 tokc = ch;
709 inp();
710 inp();
Jack Palevich546b2242009-05-13 15:10:04 -0700711 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700712 inp();
713 while (ch) {
714 while (ch != '*')
715 inp();
716 inp();
717 if (ch == '/')
718 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700719 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700720 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700721 next();
Jack Palevich21a15a22009-05-11 14:49:29 -0700722 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700723 const char* t = operatorChars;
724 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700725 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700726 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700727 tokl = operatorLevel[opIndex];
728 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -0700729 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700730#if 0
731 printf("%c%c -> tokl=%d tokc=0x%x\n",
732 l, a, tokl, tokc);
733#endif
734 if (a == ch) {
735 inp();
736 tok = TOK_DUMMY; /* dummy token for double tokens */
737 }
738 break;
739 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700740 opIndex++;
741 }
742 if (l == 0) {
743 tokl = 0;
744 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700745 }
746 }
747 }
748#if 0
749 {
750 int p;
751
752 printf("tok=0x%x ", tok);
753 if (tok >= TOK_IDENT) {
754 printf("'");
755 if (tok> TOK_DEFINE)
756 p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8;
757 else
758 p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
759 while (*(char *)p != TAG_TOK && *(char *)p)
760 printf("%c", *(char *)p++);
761 printf("'\n");
762 } else if (tok == TOK_NUM) {
763 printf("%d\n", tokc);
764 } else {
765 printf("'%c'\n", tok);
766 }
767 }
768#endif
769 }
770
771 void error(const char *fmt, ...) {
772 va_list ap;
773
774 va_start(ap, fmt);
775 fprintf(stderr, "%ld: ", ftell((FILE *) file));
776 vfprintf(stderr, fmt, ap);
777 fprintf(stderr, "\n");
778 va_end(ap);
779 exit(1);
780 }
781
782 void skip(int c) {
783 if (tok != c) {
784 error("'%c' expected", c);
785 }
786 next();
787 }
788
Jack Palevich21a15a22009-05-11 14:49:29 -0700789 /* l is one if '=' parsing wanted (quick hack) */
790 void unary(int l) {
791 int n, t, a, c;
Jack Palevich546b2242009-05-13 15:10:04 -0700792 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700793 n = 1; /* type of expression 0 = forward, 1 = value, other =
794 lvalue */
795 if (tok == '\"') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700796 pGen->li(glo);
Jack Palevich21a15a22009-05-11 14:49:29 -0700797 while (ch != '\"') {
798 getq();
799 *(char *) glo++ = ch;
800 inp();
801 }
802 *(char *) glo = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700803 glo = (glo + 4) & -4; /* align heap */
Jack Palevich21a15a22009-05-11 14:49:29 -0700804 inp();
805 next();
806 } else {
807 c = tokl;
808 a = tokc;
809 t = tok;
810 next();
811 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700812 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -0700813 } else if (c == 2) {
814 /* -, +, !, ~ */
815 unary(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700816 pGen->clearECX();
Jack Palevich21a15a22009-05-11 14:49:29 -0700817 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700818 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -0700819 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700820 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -0700821 } else if (t == '(') {
822 expr();
823 skip(')');
824 } else if (t == '*') {
825 /* parse cast */
826 skip('(');
827 t = tok; /* get type */
828 next(); /* skip int/char/void */
829 next(); /* skip '*' or '(' */
830 if (tok == '*') {
831 /* function type */
832 skip('*');
833 skip(')');
834 skip('(');
835 skip(')');
836 t = 0;
837 }
838 skip(')');
839 unary(0);
840 if (tok == '=') {
841 next();
842 pGen->pushEAX();
843 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700844 pGen->popECX();
845 pGen->storeEAXToAddressECX(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -0700846 } else if (t) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700847 pGen->loadEAXIndirect(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -0700848 }
849 } else if (t == '&') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700850 pGen->leaEAX(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -0700851 next();
852 } else {
853 n = *(int *) t;
854 /* forward reference: try dlsym */
855 if (!n)
856 n = (int) dlsym(0, (char*) last_id);
Jack Palevich546b2242009-05-13 15:10:04 -0700857 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700858 /* assignment */
859 next();
860 expr();
861 pGen->storeEAX(n);
862 } else if (tok != '(') {
863 /* variable */
864 pGen->loadEAX(n);
865 if (tokl == 11) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700866 pGen->postIncrementOrDecrement(n, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -0700867 next();
868 }
869 }
870 }
871 }
872
873 /* function call */
874 if (tok == '(') {
875 if (n == 1)
876 pGen->pushEAX();
877
878 /* push args and invert order */
879 a = pGen->allocStackSpaceForArgs();
880 next();
881 l = 0;
882 while (tok != ')') {
883 expr();
884 pGen->storeEAToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -0700885 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700886 next();
Jack Palevich21a15a22009-05-11 14:49:29 -0700887 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700888 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700889 *(int *) a = l;
890 next();
891 if (!n) {
892 /* forward reference */
893 t = t + 4;
894 *(int *) t = pGen->callForward(*(int *) t);
895 } else if (n == 1) {
896 pGen->callIndirect(l);
897 l = l + 4;
898 } else {
899 pGen->callRelative(n - codeBuf.getPC() - 5); /* call xxx */
900 }
901 if (l)
902 pGen->adjustStackAfterCall(l);
903 }
904 }
905
906 void sum(int l) {
907 int t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -0700908 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700909 if (l-- == 1)
910 unary(1);
911 else {
912 sum(l);
913 a = 0;
914 while (l == tokl) {
915 n = tok;
916 t = tokc;
917 next();
918
919 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700920 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -0700921 sum(l);
922 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700923 pGen->pushEAX();
Jack Palevich21a15a22009-05-11 14:49:29 -0700924 sum(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700925 pGen->popECX();
Jack Palevich21a15a22009-05-11 14:49:29 -0700926
Jack Palevich546b2242009-05-13 15:10:04 -0700927 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700928 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -0700929 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700930 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -0700931 }
932 }
933 }
934 /* && and || output code generation */
935 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700936 a = pGen->gtst(t == OP_LOGICAL_OR, a);
937 pGen->li(t != OP_LOGICAL_OR);
938 pGen->gjmp(5); /* jmp $ + 5 */
939 pGen->gsym(a);
940 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -0700941 }
942 }
943 }
944
945 void expr() {
946 sum(11);
947 }
948
949 int test_expr() {
950 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700951 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -0700952 }
953
954 void block(int l) {
955 int a, n, t;
956
957 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700958 next();
959 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -0700960 a = test_expr();
961 skip(')');
962 block(l);
963 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700964 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700965 n = pGen->gjmp(0); /* jmp */
966 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -0700967 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700968 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -0700969 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700970 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -0700971 }
Jack Palevich546b2242009-05-13 15:10:04 -0700972 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700973 t = tok;
974 next();
975 skip('(');
976 if (t == TOK_WHILE) {
977 n = codeBuf.getPC();
978 a = test_expr();
979 } else {
980 if (tok != ';')
981 expr();
982 skip(';');
983 n = codeBuf.getPC();
984 a = 0;
985 if (tok != ';')
986 a = test_expr();
987 skip(';');
988 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700989 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -0700990 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700991 pGen->gjmp(n - codeBuf.getPC() - 5);
992 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -0700993 n = t + 4;
994 }
995 }
996 skip(')');
997 block((int) &a);
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700998 pGen->gjmp(n - codeBuf.getPC() - 5); /* jmp */
999 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001000 } else if (tok == '{') {
1001 next();
1002 /* declarations */
1003 decl(1);
1004 while (tok != '}')
1005 block(l);
1006 next();
1007 } else {
1008 if (tok == TOK_RETURN) {
1009 next();
1010 if (tok != ';')
1011 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001012 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001013 } else if (tok == TOK_BREAK) {
1014 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001015 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001016 } else if (tok != ';')
1017 expr();
1018 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001019 }
1020 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001021
1022 /* 'l' is true if local declarations */
1023 void decl(int l) {
1024 int a;
1025
Jack Palevich546b2242009-05-13 15:10:04 -07001026 while ((tok == TOK_INT) | ((tok != -1) & (!l))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001027 if (tok == TOK_INT) {
1028 next();
1029 while (tok != ';') {
1030 if (l) {
1031 loc = loc + 4;
1032 *(int *) tok = -loc;
1033 } else {
1034 *(int *) tok = glo;
1035 glo = glo + 4;
1036 }
1037 next();
1038 if (tok == ',')
1039 next();
1040 }
1041 skip(';');
1042 } else {
1043 /* patch forward references (XXX: do not work for function
1044 pointers) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001045 pGen->gsym(*(int *) (tok + 4));
Jack Palevich21a15a22009-05-11 14:49:29 -07001046 /* put function address */
1047 *(int *) tok = codeBuf.getPC();
1048 next();
1049 skip('(');
1050 a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07001051 int argCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001052 while (tok != ')') {
1053 /* read param name and compute offset */
1054 *(int *) tok = a;
1055 a = a + 4;
1056 next();
1057 if (tok == ',')
1058 next();
Jack Palevich546b2242009-05-13 15:10:04 -07001059 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07001060 }
1061 next(); /* skip ')' */
1062 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001063 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07001064 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001065 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07001066 pGen->functionExit(argCount, a, loc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001067 }
1068 }
1069 }
1070
1071 void cleanup() {
1072 if (sym_stk != 0) {
1073 free((void*) sym_stk);
1074 sym_stk = 0;
1075 }
1076 if (pGlobalBase != 0) {
1077 free((void*) pGlobalBase);
1078 pGlobalBase = 0;
1079 }
1080 if (pVarsBase != 0) {
1081 free(pVarsBase);
1082 pVarsBase = 0;
1083 }
1084 if (pGen) {
1085 delete pGen;
1086 pGen = 0;
1087 }
1088 }
1089
1090 void clear() {
1091 tok = 0;
1092 tokc = 0;
1093 tokl = 0;
1094 ch = 0;
1095 vars = 0;
1096 rsym = 0;
1097 loc = 0;
1098 glo = 0;
1099 sym_stk = 0;
1100 dstk = 0;
1101 dptr = 0;
1102 dch = 0;
1103 last_id = 0;
1104 file = 0;
1105 pGlobalBase = 0;
1106 pVarsBase = 0;
1107 pGen = 0;
1108 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001109
Jack Palevich22305132009-05-13 10:58:45 -07001110 void setArchitecture(const char* architecture) {
1111 delete pGen;
1112 pGen = 0;
1113
1114 if (architecture != NULL) {
1115 if (strcmp(architecture, "arm") == 0) {
1116 pGen = new ARMCodeGenerator();
1117 } else if (strcmp(architecture, "x86") == 0) {
1118 pGen = new X86CodeGenerator();
1119 } else {
1120 fprintf(stderr, "Unknown architecture %s", architecture);
1121 }
1122 }
1123
1124 if (pGen == NULL) {
1125 pGen = new ARMCodeGenerator();
1126 }
1127 }
1128
Jack Palevich77ae76e2009-05-10 19:59:24 -07001129public:
Jack Palevich22305132009-05-13 10:58:45 -07001130 struct args {
1131 args() {
1132 architecture = 0;
1133 }
1134 const char* architecture;
1135 };
1136
Jack Palevich21a15a22009-05-11 14:49:29 -07001137 compiler() {
1138 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001139 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001140
Jack Palevich21a15a22009-05-11 14:49:29 -07001141 ~compiler() {
1142 cleanup();
1143 }
1144
Jack Palevich22305132009-05-13 10:58:45 -07001145 int compile(FILE* in, args& args) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001146 cleanup();
1147 clear();
1148 codeBuf.init(ALLOC_SIZE);
Jack Palevich22305132009-05-13 10:58:45 -07001149 setArchitecture(args.architecture);
Jack Palevich21a15a22009-05-11 14:49:29 -07001150 pGen->init(&codeBuf);
1151 file = in;
1152 sym_stk = (int) calloc(1, ALLOC_SIZE);
1153 dstk = (int) strcpy((char*) sym_stk,
1154 " int if else while break return for define main ")
1155 + TOK_STR_SIZE;
1156 pGlobalBase = calloc(1, ALLOC_SIZE);
1157 glo = (int) pGlobalBase;
1158 pVarsBase = calloc(1, ALLOC_SIZE);
1159 vars = (int) pVarsBase;
1160 inp();
1161 next();
1162 decl(0);
Jack Palevich546b2242009-05-13 15:10:04 -07001163 pGen->finishCompile();
Jack Palevich21a15a22009-05-11 14:49:29 -07001164 return 0;
1165 }
1166
1167 int run(int argc, char** argv) {
1168 typedef int (*mainPtr)(int argc, char** argv);
1169 mainPtr aMain = (mainPtr) *(int*) (vars + TOK_MAIN);
1170 if (!aMain) {
1171 fprintf(stderr, "Could not find function \"main\".\n");
1172 return -1;
1173 }
1174 return aMain(argc, argv);
1175 }
1176
1177 int dump(FILE* out) {
1178 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
1179 return 0;
1180 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07001181
1182};
1183
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001184const char* compiler::operatorChars =
1185 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
1186
1187const char compiler::operatorLevel[] =
1188 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
1189 5, 5, /* ==, != */
1190 9, 10, /* &&, || */
1191 6, 7, 8, /* & ^ | */
1192 2, 2 /* ~ ! */
1193 };
1194
1195const int compiler::X86CodeGenerator::operatorHelper[] = {
1196 0x1, // ++
1197 0xff, // --
1198 0xc1af0f, // *
1199 0xf9f79991, // /
1200 0xf9f79991, // % (With manual assist to swap results)
1201 0xc801, // +
1202 0xd8f7c829, // -
1203 0xe0d391, // <<
1204 0xf8d391, // >>
1205 0xe, // <=
1206 0xd, // >=
1207 0xc, // <
1208 0xf, // >
1209 0x4, // ==
1210 0x5, // !=
1211 0x0, // &&
1212 0x1, // ||
1213 0xc821, // &
1214 0xc831, // ^
1215 0xc809, // |
1216 0xd0f7, // ~
1217 0x4 // !
1218};
1219
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001220} // namespace acc
1221
Jack Palevich546b2242009-05-13 15:10:04 -07001222// This is a separate function so it can easily be set by breakpoint in gdb.
1223int run(acc::compiler& c, int argc, char** argv) {
1224 return c.run(argc, argv);
1225}
1226
Jack Palevich77ae76e2009-05-10 19:59:24 -07001227int main(int argc, char** argv) {
Jack Palevich22305132009-05-13 10:58:45 -07001228 bool doDump = false;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001229 const char* inFile = NULL;
1230 const char* outFile = NULL;
Jack Palevich22305132009-05-13 10:58:45 -07001231 const char* architecture = "arm";
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001232 int i;
Jack Palevich21a15a22009-05-11 14:49:29 -07001233 for (i = 1; i < argc; i++) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001234 char* arg = argv[i];
1235 if (arg[0] == '-') {
1236 switch (arg[1]) {
Jack Palevich22305132009-05-13 10:58:45 -07001237 case 'a':
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001238 if (i + 1 >= argc) {
Jack Palevich22305132009-05-13 10:58:45 -07001239 fprintf(stderr, "Expected architecture after -a\n");
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001240 return 2;
1241 }
Jack Palevich22305132009-05-13 10:58:45 -07001242 architecture = argv[i+1];
1243 i += 1;
1244 break;
1245 case 'd':
1246 if (i + 1 >= argc) {
1247 fprintf(stderr, "Expected filename after -d\n");
1248 return 2;
1249 }
1250 doDump = true;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001251 outFile = argv[i + 1];
1252 i += 1;
1253 break;
1254 default:
1255 fprintf(stderr, "Unrecognized flag %s\n", arg);
1256 return 3;
1257 }
1258 } else if (inFile == NULL) {
1259 inFile = arg;
1260 } else {
1261 break;
1262 }
1263 }
1264
1265 FILE* in = stdin;
1266 if (inFile) {
1267 in = fopen(inFile, "r");
Jack Palevich21a15a22009-05-11 14:49:29 -07001268 if (!in) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001269 fprintf(stderr, "Could not open input file %s\n", inFile);
1270 return 1;
1271 }
1272 }
1273 acc::compiler compiler;
Jack Palevich22305132009-05-13 10:58:45 -07001274 acc::compiler::args args;
1275 args.architecture = architecture;
1276 int compileResult = compiler.compile(in, args);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001277 if (in != stdin) {
1278 fclose(in);
1279 }
1280 if (compileResult) {
1281 fprintf(stderr, "Compile failed: %d\n", compileResult);
1282 return 6;
1283 }
Jack Palevich22305132009-05-13 10:58:45 -07001284 if (doDump) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001285 FILE* save = fopen(outFile, "w");
Jack Palevich21a15a22009-05-11 14:49:29 -07001286 if (!save) {
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001287 fprintf(stderr, "Could not open output file %s\n", outFile);
1288 return 5;
1289 }
1290 compiler.dump(save);
1291 fclose(save);
1292 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001293 fprintf(stderr, "Executing compiled code:\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07001294 int codeArgc = argc - i + 1;
1295 char** codeArgv = argv + i - 1;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001296 codeArgv[0] = (char*) (inFile ? inFile : "stdin");
Jack Palevich546b2242009-05-13 15:10:04 -07001297 int result = run(compiler, codeArgc, codeArgv);
Jack Palevich22305132009-05-13 10:58:45 -07001298 fprintf(stderr, "result: %d\n", result);
1299 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001300 }
1301
1302 return 0;
1303}