Replace acc.c with the contents of otccn.c, update tests.
We are no longer checking if the constant data is the same, just the
generated code.
diff --git a/libacc/acc.c b/libacc/acc.c
index a8505cd..7fa376f 100644
--- a/libacc/acc.c
+++ b/libacc/acc.c
@@ -1,525 +1,625 @@
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
+ Obfuscated Tiny C Compiler
-/* Based upon the freeware version of the Obfuscated Tiny C Compiler
- * by Francis Bellard. <francis@bellard.org>.
- */
+ Copyright (C) 2001-2003 Fabrice Bellard
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product and its documentation
+ *is* required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <stdarg.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#define TOKEN_OPERATOR 1
-#define TOKEN_NUMBER 2
+/* vars: value of variables
+ loc : local variable index
+ glo : global variable index
+ ind : output code ptr
+ rsym: return symbol
+ prog: output code
+ dstk: define stack
+ dptr, dch: macro state
+*/
+int tok, tokc, tokl, ch, vars, rsym, prog, ind, loc, glo, file, sym_stk, dstk, dptr, dch, last_id;
-#define TOKEN_SYMBOL_BASE 256
-#define TOKEN_INT 256
-#define TOKEN_IF 288
-#define TOKEN_ELSE 312
-#define TOKEN_WHILE 352
-#define TOKEN_BREAK 400
-#define TOKEN_RETURN 448
-#define TOKEN_FOR 504
-#define TOKEN_DEFINE 536
+#define ALLOC_SIZE 99999
-static int currentToken;
-static int currentTokenData;
-static int gCurrentTokenOperatorLevel;
-static int currentChar;
-static int gEndOfFunctionTarget;
-static int gProgramCounter;
-static int gFunctionStackSize;
-static int savedChar;
-static char* pInProgressMacro;
-static char* P;
-static char* ac;
-static char* gStringTable;
-static char* pSymbolTable;
-static char* M;
-static char* R;
-static FILE* pInput;
+/* depends on the init string */
+#define TOK_STR_SIZE 48
+#define TOK_IDENT 0x100
+#define TOK_INT 0x100
+#define TOK_IF 0x120
+#define TOK_ELSE 0x138
+#define TOK_WHILE 0x160
+#define TOK_BREAK 0x190
+#define TOK_RETURN 0x1c0
+#define TOK_FOR 0x1f8
+#define TOK_DEFINE 0x218
+#define TOK_MAIN 0x250
-static void parseDeclarations (int isLocal);
-static void parseExpression();
+#define TOK_DUMMY 1
+#define TOK_NUM 2
-static void addToSymbolTable(char e) {
- *pSymbolTable++ = e;
+#define LOCAL 0x200
+
+#define SYM_FORWARD 0
+#define SYM_DEFINE 1
+
+/* tokens in string heap */
+#define TAG_TOK ' '
+#define TAG_MACRO 2
+
+pdef(t)
+{
+ *(char *)dstk++ = t;
}
-static void nextChar() {
- if (pInProgressMacro) {
- currentChar = *(char*) pInProgressMacro++;
- if (currentChar == 2) {
- pInProgressMacro = NULL;
- currentChar = savedChar;
+inp()
+{
+ if (dptr) {
+ ch = *(char *)dptr++;
+ if (ch == TAG_MACRO) {
+ dptr = 0;
+ ch = dch;
}
} else
- currentChar = fgetc(pInput);
+ ch = fgetc(file);
+ /* printf("ch=%c 0x%x\n", ch, ch); */
}
-static int isSymbolChar() {
- return isalnum(currentChar) || currentChar == '_';
+isid()
+{
+ return isalnum(ch) | ch == '_';
}
-static void unescapeCurrentChar() {
- if (currentChar == '\\') {
- nextChar();
- if (currentChar == 'n')
- currentChar = '\n';
+/* read a character constant */
+getq()
+{
+ if (ch == '\\') {
+ inp();
+ if (ch == 'n')
+ ch = '\n';
}
}
-static void nextToken() {
- int j, m;
- while (isspace(currentChar) || currentChar == '#') {
- if (currentChar == '#') {
- nextChar();
- nextToken();
- if (currentToken == TOKEN_DEFINE) {
- nextToken();
- addToSymbolTable(' ');
- *(int*) currentToken = 1;
- *(int*) (currentToken + 4) = (int) pSymbolTable;
+next()
+{
+ int t, l, a;
+
+ while (isspace(ch) | ch == '#') {
+ if (ch == '#') {
+ inp();
+ next();
+ if (tok == TOK_DEFINE) {
+ next();
+ pdef(TAG_TOK); /* fill last ident tag */
+ *(int *)tok = SYM_DEFINE;
+ *(int *)(tok + 4) = dstk; /* define stack */
}
- while (currentChar != '\n') {
- addToSymbolTable(currentChar);
- nextChar();
+ /* well we always save the values ! */
+ while (ch != '\n') {
+ pdef(ch);
+ inp();
}
- addToSymbolTable(currentChar);
- addToSymbolTable(2);
+ pdef(ch);
+ pdef(TAG_MACRO);
}
- nextChar();
+ inp();
}
- gCurrentTokenOperatorLevel = 0;
- currentToken = currentChar;
- if (isSymbolChar()) {
- addToSymbolTable(' ');
- M = pSymbolTable;
- while (isSymbolChar()) {
- addToSymbolTable(currentChar);
- nextChar();
+ tokl = 0;
+ tok = ch;
+ /* encode identifiers & numbers */
+ if (isid()) {
+ pdef(TAG_TOK);
+ last_id = dstk;
+ while (isid()) {
+ pdef(ch);
+ inp();
}
- if (isdigit(currentToken)) {
- currentTokenData = strtol(M, 0, 0);
- currentToken = TOKEN_NUMBER;
+ if (isdigit(tok)) {
+ tokc = strtol(last_id, 0, 0);
+ tok = TOK_NUM;
} else {
- *(char*) pSymbolTable = ' ';
- currentToken = strstr(R, M - 1) - R;
- *(char*) pSymbolTable = 0;
- currentToken = currentToken * 8 + TOKEN_SYMBOL_BASE;
- if (currentToken > TOKEN_DEFINE) {
- currentToken = ((int) P) + currentToken;
- if (*(int*) currentToken == 1) {
- pInProgressMacro = (char*) (*(int*) (currentToken + 4));
- savedChar = currentChar;
- nextChar();
- nextToken();
+ *(char *)dstk = TAG_TOK; /* no need to mark end of string (we
+ suppose data is initied to zero */
+ tok = strstr(sym_stk, last_id - 1) - sym_stk;
+ *(char *)dstk = 0; /* mark real end of ident for dlsym() */
+ tok = tok * 8 + TOK_IDENT;
+ if (tok > TOK_DEFINE) {
+ tok = vars + tok;
+ /* printf("tok=%s %x\n", last_id, tok); */
+ /* define handling */
+ if (*(int *)tok == SYM_DEFINE) {
+ dptr = *(int *)(tok + 4);
+ dch = ch;
+ inp();
+ next();
}
}
}
} else {
- nextChar();
- if (currentToken == '\'') {
- currentToken = TOKEN_NUMBER;
- unescapeCurrentChar();
- currentTokenData = currentChar;
- nextChar();
- nextChar();
- } else if (currentToken == '/' & currentChar == '*') {
- nextChar();
- while (currentChar) {
- while (currentChar != '*')
- nextChar();
- nextChar();
- if (currentChar == '/')
- currentChar = 0;
+ inp();
+ if (tok == '\'') {
+ tok = TOK_NUM;
+ getq();
+ tokc = ch;
+ inp();
+ inp();
+ } else if (tok == '/' & ch == '*') {
+ inp();
+ while (ch) {
+ while (ch != '*')
+ inp();
+ inp();
+ if (ch == '/')
+ ch = 0;
}
- nextChar();
- nextToken();
- } else {
- char* e = "++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<<Z/03e>>`/03e<=0f>=/f<@.f>@1f==&g!='g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b";
- while (j = *(char*) e++) {
- m = *(char*) e++;
- currentTokenData = 0;
- while ((gCurrentTokenOperatorLevel = *(char*) e++ - 98) < 0)
- currentTokenData = currentTokenData * 64 + gCurrentTokenOperatorLevel + 64;
- if (j == currentToken && (m == currentChar || m == 64)) {
- if (m == currentChar) {
- nextChar();
- currentToken = TOKEN_OPERATOR;
+ inp();
+ next();
+ } else
+ {
+ t = "++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<<Z/03e>>`/03e<=0f>=/f<@.f>@1f==&g!=\'g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b";
+ while (l = *(char *)t++) {
+ a = *(char *)t++;
+ tokc = 0;
+ while ((tokl = *(char *)t++ - 'b') < 0)
+ tokc = tokc * 64 + tokl + 64;
+ if (l == tok & (a == ch | a == '@')) {
+#if 0
+ printf("%c%c -> tokl=%d tokc=0x%x\n",
+ l, a, tokl, tokc);
+#endif
+ if (a == ch) {
+ inp();
+ tok = TOK_DUMMY; /* dummy token for double tokens */
}
break;
}
}
}
}
-}
+#if 0
+ {
+ int p;
-/*
- * Emit 1 to 4 bytes of code. Little-endian, doesn't emit high bytes that
- * are 0x00 or 0xff
- */
-static void emitCode(int g) {
- while( g && g != -1) {
- *(char*) gProgramCounter++=g;
- g=g>>8;
- }
-}
-
-static void fixupAddress(e) {
- int g;
- while( e) {
- g=*(int*) e;
- *(int*) e=gProgramCounter-e-4;
- e=g;
- }
-}
-
-static int emitCodeWithImmediate( g, e) {
- emitCode(g);
- *(int*) gProgramCounter = e;
- e = gProgramCounter;
- gProgramCounter = gProgramCounter + 4;
- return e;
-}
-
-static int emitLoadAccumulatorImmediate(e) {
- emitCodeWithImmediate(0xb8,e); /* Move immediate a, e */
-}
-
-static int emitBranch(e) {
- return emitCodeWithImmediate(0xe9,e); /* Jump relative */
-}
-
-static int emitTest( j, e) {
- emitCode(0x0FC085); /* 85 C0 FC TEST */
- return emitCodeWithImmediate(0x84 + j, e); /* TEST */
-}
-
-static void emitSetCC(int condition) {
- emitCode( 0xC139); /* 39 C1 CMP */
- emitLoadAccumulatorImmediate(0);
- emitCode( 0x0F); /* Two byte opcode prefix */
- emitCode( condition+0x90); /* Set byte on condition (controlled by e) */
- emitCode( 0xC0); /* I think this is part of the SETcc instruction */
-}
-
-static void emitNumericOp( int op, int e) {
- emitCode(op + 0x83);
- emitCodeWithImmediate((e < 512) << 7 | 5, e);
-}
-
-static void parseTerminal (int level) {
- int g,e,m,aa;
- g=1;
- if( currentToken == '"') {
- emitLoadAccumulatorImmediate(gStringTable);
- while( currentChar != '"') {
- unescapeCurrentChar ();
- *(char*) gStringTable++=currentChar;
- nextChar ();
- }
- *(char*) gStringTable=0;
- gStringTable= (char*) (((int)gStringTable) +4&-4);
- nextChar();
- nextToken();
- }
- else {
- aa=gCurrentTokenOperatorLevel;
- m= currentTokenData;
- e=currentToken;
- nextToken();
- if( e == TOKEN_NUMBER) {
- emitLoadAccumulatorImmediate(m);
- }
- else if( aa == 2) {
- parseTerminal(0);
- emitCodeWithImmediate(0xB9,0); /* MOV r1, immediate */
- if( e == '!')emitSetCC(m);
- else emitCode( m);
- }
- else if( e == '(') {
- parseExpression ();
- nextToken();
- }
- else if( e == '*') {
- nextToken();
- e=currentToken;
- nextToken();
- nextToken();
- if( currentToken == '*') {
- nextToken();
- nextToken();
- nextToken();
- nextToken();
- e=0;
- }
- nextToken();
- parseTerminal(0);
- if( currentToken == '=') {
- nextToken();
- emitCode( 0x50); /* PUSH r0 */
- parseExpression ();
- emitCode( 0x59); /* POP r1 */
- emitCode( 0x188 + (e == TOKEN_INT)); /* 88 01 MOV */
- }
- else if( e) {
- if( e == TOKEN_INT)emitCode( 0x8B); /* MOV */
- else emitCode( 0xBE0F); /* 0F BE MOVSX move with sign extension */
- gProgramCounter++;
- }
- }
- else if( e == '&') {
- emitNumericOp(10,*(int*) currentToken); /* 8D LEA */
- nextToken();
- }
- else {
- g=*(int*) e;
- if(!g)g=dlsym(0,M);
- if( currentToken == '=' & level) {
- nextToken();
- parseExpression ();
- emitNumericOp(6,g); /* 89 MOV */
- }
- else if( currentToken!= '(') {
- emitNumericOp(8,g); /* 8B MOV sreg */
- if( gCurrentTokenOperatorLevel == 11) {
- emitNumericOp(0,g); /* 83 ADD */
- emitCode( currentTokenData);
- nextToken();
- }
- }
+ printf("tok=0x%x ", tok);
+ if (tok >= TOK_IDENT) {
+ printf("'");
+ if (tok > TOK_DEFINE)
+ p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8;
+ else
+ p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
+ while (*(char *)p != TAG_TOK && *(char *)p)
+ printf("%c", *(char *)p++);
+ printf("'\n");
+ } else if (tok == TOK_NUM) {
+ printf("%d\n", tokc);
+ } else {
+ printf("'%c'\n", tok);
}
}
- if( currentToken == '(') {
- if( g == 1)emitCode( 0x50); /* push */
- m= emitCodeWithImmediate(0xEC81,0); /* 81 EC Cmp ?? */
- nextToken();
- level=0;
- while( currentToken!= ')') {
- parseExpression ();
- emitCodeWithImmediate(0x248489,level); /* 89 84 24 MOV sp + level*/
- if( currentToken == ',')nextToken();
- level=level +4;
- }
- *(int*) m= level;
- nextToken();
- if(!g) {
- e=e +4;
- *(int*) e=emitCodeWithImmediate(0xE8,*(int*) e); /* Call */
- }
- else if( g == 1) {
- emitCodeWithImmediate(0x2494FF,level); /* FF 94 24 */
- level=level +4;
- }
- else {
- emitCodeWithImmediate(0xE8,g-gProgramCounter-5); /* CALL */
- }
- if( level)emitCodeWithImmediate(0xC481,level); /* 81 C4 adjust stack pointer */
- }
-}
-
-static void parseBinaryOp (int level) {
- int e,g,m;
- if( level--== 1)parseTerminal(1);
- else {
- parseBinaryOp (level);
- m= 0;
- while( level == gCurrentTokenOperatorLevel) {
- g=currentToken;
- e=currentTokenData;
- nextToken();
- if( level>8) {
- m= emitTest(e,m);
- parseBinaryOp (level);
- }
- else {
- emitCode( 0x50);
- parseBinaryOp (level);
- emitCode( 0x59);
- if( level == 4 | level == 5) {
- emitSetCC(e);
- }
- else {
- emitCode( e);
- if( g == '%')emitCode( 0x92); /* XCHG */
- }
- }
- }
- if( m&&level>8) {
- m= emitTest(e,m);
- emitLoadAccumulatorImmediate(e^1);
- emitBranch(5); /* Jump relative +5 */
- fixupAddress(m);
- emitLoadAccumulatorImmediate(e);
- }
- }
-}
-
-static void parseExpression() {
- parseBinaryOp(11);
-}
-
-static int parseExpressionEmitTest() {
- parseExpression();
- return emitTest(0, 0);
-}
-
-static void parseStatement (int* pBreakTarget) {
- int m,g,e;
- if( currentToken == TOKEN_IF) {
- nextToken();
- nextToken();
- m= parseExpressionEmitTest ();
- nextToken();
- parseStatement (pBreakTarget);
- if( currentToken == TOKEN_ELSE) {
- nextToken();
- g=emitBranch(0);
- fixupAddress(m);
- parseStatement (pBreakTarget);
- fixupAddress(g);
- }
- else {
- fixupAddress(m);
- }
- }
- else if ( currentToken == TOKEN_WHILE || currentToken == TOKEN_FOR) {
- e = currentToken;
- nextToken();
- nextToken();
- if( e == TOKEN_WHILE) {
- g=gProgramCounter;
- m= parseExpressionEmitTest ();
- }
- else {
- if( currentToken != ';')parseExpression ();
- nextToken();
- g=gProgramCounter;
- m= 0;
- if( currentToken != ';')m= parseExpressionEmitTest ();
- nextToken();
- if( currentToken!= ')') {
- e=emitBranch(0);
- parseExpression ();
- emitBranch(g-gProgramCounter-5);
- fixupAddress(e);
- g=e +4;
- }
- }
- nextToken();
- parseStatement(&m);
- emitBranch(g-gProgramCounter-5);
- fixupAddress(m);
- }
- else if( currentToken == '{') {
- nextToken();
- parseDeclarations(1);
- while( currentToken != '}') parseStatement(pBreakTarget);
- nextToken();
- }
- else {
- if( currentToken == TOKEN_RETURN) {
- nextToken();
- if( currentToken != ';') parseExpression();
- gEndOfFunctionTarget=emitBranch(gEndOfFunctionTarget);
- }
- else if( currentToken == TOKEN_BREAK) {
- nextToken();
- *pBreakTarget = emitBranch(*pBreakTarget);
- }
- else if( currentToken != ';') parseExpression();
- nextToken();
- }
-}
-
-static void parseDeclarations (int isLocal) {
- int m;
- while( currentToken == TOKEN_INT | currentToken != -1 & !isLocal ) {
- if( currentToken == TOKEN_INT) {
- nextToken();
- while( currentToken != ';') {
- if( isLocal ) {
- gFunctionStackSize=gFunctionStackSize +4;
- *(int*) currentToken=-gFunctionStackSize;
- }
- else {
- *(char**) currentToken = gStringTable;
- gStringTable=gStringTable +4;
- }
- nextToken();
- if( currentToken == ',')nextToken();
- }
- nextToken();
- }
- else {
- fixupAddress(*(int*)(currentToken + 4));
- *(int*) currentToken=gProgramCounter;
- nextToken();
- nextToken();
- m= 8;
- while( currentToken != ')') {
- *(int*) currentToken=m;
- m= m +4;
- nextToken();
- if( currentToken == ',')nextToken();
- }
- nextToken();
- gEndOfFunctionTarget=gFunctionStackSize=0;
- emitCode( 0xE58955); /* 55 89 E5 PUSH */
- m= emitCodeWithImmediate(0xEC81,0); /* 81 EC */
- parseStatement(0);
- fixupAddress(gEndOfFunctionTarget);
- emitCode( 0xC3C9); /* C9 C3 LEAVE */
- *(int*) m= gFunctionStackSize;
- }
- }
-}
-
-int main( int argc, char** argv) {
- pInput = stdin;
- if (argc-- > 1) {
- char* file = argv[1];
- argv += 1;
- pInput = fopen(file, "r");
- if (pInput == NULL) {
- fprintf(stderr, "Could not open file \"%s\"\n", file);
- return -1;
- }
- }
- pSymbolTable = strcpy(R = calloc(1, 99999),
- " int if else while break return for define main ") + 48;
- gStringTable = calloc(1, 99999);
- ac = calloc(1, 99999);
- gProgramCounter = (int) ac;
- P = calloc(1, 99999);
- nextChar();
- nextToken();
- parseDeclarations(0);
-#if 1
- fwrite(R, 1, 99999, stdout);
- fwrite(ac, 1, 99999, stdout);
- fwrite(P, 1, 99999, stdout);
- return 0;
-#else
- /* Look up the address of "main" in the symbol table and call it.
- * We put main in at a known offset, so we know the address.
- */
- return (*(int(*)()) *(int*) (P + 592))(argc, argv);
#endif
}
+void error(char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "%d: ", ftell((FILE *)file));
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ exit(1);
+ va_end(ap);
+}
+
+void skip(c)
+{
+ if (tok != c) {
+ error("'%c' expected", c);
+ }
+ next();
+}
+
+o(n)
+{
+ /* cannot use unsigned, so we must do a hack */
+ while (n && n != -1) {
+ *(char *)ind++ = n;
+ n = n >> 8;
+ }
+}
+
+/* output a symbol and patch all calls to it */
+gsym(t)
+{
+ int n;
+ while (t) {
+ n = *(int *)t; /* next value */
+ *(int *)t = ind - t - 4;
+ t = n;
+ }
+}
+
+/* psym is used to put an instruction with a data field which is a
+ reference to a symbol. It is in fact the same as oad ! */
+#define psym oad
+
+/* instruction + address */
+oad(n, t)
+{
+ o(n);
+ *(int *)ind = t;
+ t = ind;
+ ind = ind + 4;
+ return t;
+}
+
+/* load immediate value */
+li(t)
+{
+ oad(0xb8, t); /* mov $xx, %eax */
+}
+
+gjmp(t)
+{
+ return psym(0xe9, t);
+}
+
+/* l = 0: je, l == 1: jne */
+gtst(l, t)
+{
+ o(0x0fc085); /* test %eax, %eax, je/jne xxx */
+ return psym(0x84 + l, t);
+}
+
+gcmp(t)
+{
+ o(0xc139); /* cmp %eax,%ecx */
+ li(0);
+ o(0x0f); /* setxx %al */
+ o(t + 0x90);
+ o(0xc0);
+}
+
+gmov(l, t)
+{
+ o(l + 0x83);
+ oad((t < LOCAL) << 7 | 5, t);
+}
+
+/* l is one if '=' parsing wanted (quick hack) */
+unary(l)
+{
+ int n, t, a, c;
+
+ n = 1; /* type of expression 0 = forward, 1 = value, other =
+ lvalue */
+ if (tok == '\"') {
+ li(glo);
+ while (ch != '\"') {
+ getq();
+ *(char *)glo++ = ch;
+ inp();
+ }
+ *(char *)glo = 0;
+ glo = glo + 4 & -4; /* align heap */
+ inp();
+ next();
+ } else {
+ c = tokl;
+ a = tokc;
+ t = tok;
+ next();
+ if (t == TOK_NUM) {
+ li(a);
+ } else if (c == 2) {
+ /* -, +, !, ~ */
+ unary(0);
+ oad(0xb9, 0); /* movl $0, %ecx */
+ if (t == '!')
+ gcmp(a);
+ else
+ o(a);
+ } else if (t == '(') {
+ expr();
+ skip(')');
+ } else if (t == '*') {
+ /* parse cast */
+ skip('(');
+ t = tok; /* get type */
+ next(); /* skip int/char/void */
+ next(); /* skip '*' or '(' */
+ if (tok == '*') {
+ /* function type */
+ skip('*');
+ skip(')');
+ skip('(');
+ skip(')');
+ t = 0;
+ }
+ skip(')');
+ unary(0);
+ if (tok == '=') {
+ next();
+ o(0x50); /* push %eax */
+ expr();
+ o(0x59); /* pop %ecx */
+ o(0x0188 + (t == TOK_INT)); /* movl %eax/%al, (%ecx) */
+ } else if (t) {
+ if (t == TOK_INT)
+ o(0x8b); /* mov (%eax), %eax */
+ else
+ o(0xbe0f); /* movsbl (%eax), %eax */
+ ind++; /* add zero in code */
+ }
+ } else if (t == '&') {
+ gmov(10, *(int *)tok); /* leal EA, %eax */
+ next();
+ } else {
+ n = *(int *)t;
+ /* forward reference: try dlsym */
+ if (!n)
+ n = dlsym(0, last_id);
+ if (tok == '=' & l) {
+ /* assignment */
+ next();
+ expr();
+ gmov(6, n); /* mov %eax, EA */
+ } else if (tok != '(') {
+ /* variable */
+ gmov(8, n); /* mov EA, %eax */
+ if (tokl == 11) {
+ gmov(0, n);
+ o(tokc);
+ next();
+ }
+ }
+ }
+ }
+
+ /* function call */
+ if (tok == '(') {
+ if (n == 1)
+ o(0x50); /* push %eax */
+
+ /* push args and invert order */
+ a = oad(0xec81, 0); /* sub $xxx, %esp */
+ next();
+ l = 0;
+ while(tok != ')') {
+ expr();
+ oad(0x248489, l); /* movl %eax, xxx(%esp) */
+ if (tok == ',')
+ next();
+ l = l + 4;
+ }
+ *(int *)a = l;
+ next();
+ if (!n) {
+ /* forward reference */
+ t = t + 4;
+ *(int *)t = psym(0xe8, *(int *)t);
+ } else if (n == 1) {
+ oad(0x2494ff, l); /* call *xxx(%esp) */
+ l = l + 4;
+ } else {
+ oad(0xe8, n - ind - 5); /* call xxx */
+ }
+ if (l)
+ oad(0xc481, l); /* add $xxx, %esp */
+ }
+}
+
+sum(l)
+{
+ int t, n, a;
+
+ if (l-- == 1)
+ unary(1);
+ else {
+ sum(l);
+ a = 0;
+ while (l == tokl) {
+ n = tok;
+ t = tokc;
+ next();
+
+ if (l > 8) {
+ a = gtst(t, a); /* && and || output code generation */
+ sum(l);
+ } else {
+ o(0x50); /* push %eax */
+ sum(l);
+ o(0x59); /* pop %ecx */
+
+ if (l == 4 | l == 5) {
+ gcmp(t);
+ } else {
+ o(t);
+ if (n == '%')
+ o(0x92); /* xchg %edx, %eax */
+ }
+ }
+ }
+ /* && and || output code generation */
+ if (a && l > 8) {
+ a = gtst(t, a);
+ li(t ^ 1);
+ gjmp(5); /* jmp $ + 5 */
+ gsym(a);
+ li(t);
+ }
+ }
+}
+
+expr()
+{
+ sum(11);
+}
+
+
+test_expr()
+{
+ expr();
+ return gtst(0, 0);
+}
+
+block(l)
+{
+ int a, n, t;
+
+ if (tok == TOK_IF) {
+ next();
+ skip('(');
+ a = test_expr();
+ skip(')');
+ block(l);
+ if (tok == TOK_ELSE) {
+ next();
+ n = gjmp(0); /* jmp */
+ gsym(a);
+ block(l);
+ gsym(n); /* patch else jmp */
+ } else {
+ gsym(a); /* patch if test */
+ }
+ } else if (tok == TOK_WHILE | tok == TOK_FOR) {
+ t = tok;
+ next();
+ skip('(');
+ if (t == TOK_WHILE) {
+ n = ind;
+ a = test_expr();
+ } else {
+ if (tok != ';')
+ expr();
+ skip(';');
+ n = ind;
+ a = 0;
+ if (tok != ';')
+ a = test_expr();
+ skip(';');
+ if (tok != ')') {
+ t = gjmp(0);
+ expr();
+ gjmp(n - ind - 5);
+ gsym(t);
+ n = t + 4;
+ }
+ }
+ skip(')');
+ block(&a);
+ gjmp(n - ind - 5); /* jmp */
+ gsym(a);
+ } else if (tok == '{') {
+ next();
+ /* declarations */
+ decl(1);
+ while(tok != '}')
+ block(l);
+ next();
+ } else {
+ if (tok == TOK_RETURN) {
+ next();
+ if (tok != ';')
+ expr();
+ rsym = gjmp(rsym); /* jmp */
+ } else if (tok == TOK_BREAK) {
+ next();
+ *(int *)l = gjmp(*(int *)l);
+ } else if (tok != ';')
+ expr();
+ skip(';');
+ }
+}
+
+/* 'l' is true if local declarations */
+decl(l)
+{
+ int a;
+
+ while (tok == TOK_INT | tok != -1 & !l) {
+ if (tok == TOK_INT) {
+ next();
+ while (tok != ';') {
+ if (l) {
+ loc = loc + 4;
+ *(int *)tok = -loc;
+ } else {
+ *(int *)tok = glo;
+ glo = glo + 4;
+ }
+ next();
+ if (tok == ',')
+ next();
+ }
+ skip(';');
+ } else {
+ /* patch forward references (XXX: do not work for function
+ pointers) */
+ gsym(*(int *)(tok + 4));
+ /* put function address */
+ *(int *)tok = ind;
+ next();
+ skip('(');
+ a = 8;
+ while (tok != ')') {
+ /* read param name and compute offset */
+ *(int *)tok = a;
+ a = a + 4;
+ next();
+ if (tok == ',')
+ next();
+ }
+ next(); /* skip ')' */
+ rsym = loc = 0;
+ o(0xe58955); /* push %ebp, mov %esp, %ebp */
+ a = oad(0xec81, 0); /* sub $xxx, %esp */
+ block(0);
+ gsym(rsym);
+ o(0xc3c9); /* leave, ret */
+ *(int *)a = loc; /* save local variables */
+ }
+ }
+}
+
+main(n, t)
+{
+ file = stdin;
+ if (n-- > 1) {
+ t = t + 4;
+ file = fopen(*(int *)t, "r");
+ }
+ dstk = strcpy(sym_stk = calloc(1, ALLOC_SIZE),
+ " int if else while break return for define main ") + TOK_STR_SIZE;
+ glo = calloc(1, ALLOC_SIZE);
+ ind = prog = calloc(1, ALLOC_SIZE);
+ vars = calloc(1, ALLOC_SIZE);
+ inp();
+ next();
+ decl(0);
+#ifdef TEST
+ {
+ FILE *f;
+ f = fopen(*(char **)(t + 4), "w");
+ fwrite((void *)prog, 1, ind - prog, f);
+ fclose(f);
+ return 0;
+ }
+#else
+ return (*(int (*)())*(int *)(vars + TOK_MAIN)) (n, t);
+#endif
+}