summaryrefslogtreecommitdiffstats
path: root/libacc
diff options
context:
space:
mode:
Diffstat (limited to 'libacc')
-rw-r--r--libacc/acc.cpp256
-rw-r--r--libacc/tests/expr.c60
2 files changed, 207 insertions, 109 deletions
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 0c6acd4..0f8e606 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -161,6 +161,17 @@ class compiler {
X86CodeGenerator() {}
virtual ~X86CodeGenerator() {}
+ /* returns address to patch with local variable size
+ */
+ int functionEntry() {
+ o(0xe58955); /* push %ebp, mov %esp, %ebp */
+ return oad(0xec81, 0); /* sub $xxx, %esp */
+ }
+
+ void functionExit() {
+ o(0xc3c9); /* leave, ret */
+ }
+
/* load immediate value */
int li(int t) {
oad(0xb8, t); /* mov $xx, %eax */
@@ -176,7 +187,8 @@ class compiler {
return psym(0x84 + l, t);
}
- int gcmp(int t) {
+ int gcmp(int op) {
+ int t = decodeOp(op);
o(0xc139); /* cmp %eax,%ecx */
li(0);
o(0x0f); /* setxx %al */
@@ -184,6 +196,12 @@ class compiler {
o(0xc0);
}
+ int genOp(int op) {
+ o(decodeOp(op));
+ if (op == OP_MOD)
+ o(0x92); /* xchg %edx, %eax */
+ }
+
void clearECX() {
oad(0xb9, 0); /* movl $0, %ecx */
}
@@ -192,8 +210,11 @@ class compiler {
o(0x50); /* push %eax */
}
- void storeEAXIntoPoppedLVal(bool isInt) {
+ void popECX() {
o(0x59); /* pop %ecx */
+ }
+
+ void storeEAXToAddressECX(bool isInt) {
o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
}
@@ -217,12 +238,11 @@ class compiler {
gmov(8, ea); /* mov EA, %eax */
}
- void puzzleAdd(int n, int tokc) {
- /* Not sure what this does, related to variable loading with an
- * operator at level 11.
+ void postIncrementOrDecrement(int n, int op) {
+ /* Implement post-increment or post decrement.
*/
gmov(0, n); /* 83 ADD */
- o(tokc);
+ o(decodeOp(op));
}
int allocStackSpaceForArgs() {
@@ -249,14 +269,16 @@ class compiler {
oad(0xc481, l); /* add $xxx, %esp */
}
- void oHack(int n) {
- o(n);
- }
+ private:
+ static const int operatorHelper[];
- void oadHack(int n, int t) {
- oad(n, t);
+ int decodeOp(int op) {
+ if (op < 0 || op > OP_COUNT) {
+ fprintf(stderr, "Out-of-range operator: %d\n", op);
+ exit(1);
+ }
+ return operatorHelper[op];
}
- private:
int gmov(int l, int t) {
o(l + 0x83);
@@ -310,6 +332,37 @@ class compiler {
static const int TAG_TOK = ' ';
static const int TAG_MACRO = 2;
+ static const int OP_INCREMENT = 0;
+ static const int OP_DECREMENT = 1;
+ static const int OP_MUL = 2;
+ static const int OP_DIV = 3;
+ static const int OP_MOD = 4;
+ static const int OP_PLUS = 5;
+ static const int OP_MINUS = 6;
+ static const int OP_SHIFT_LEFT = 7;
+ static const int OP_SHIFT_RIGHT = 8;
+ static const int OP_LESS_EQUAL = 9;
+ static const int OP_GREATER_EQUAL = 10;
+ static const int OP_LESS = 11;
+ static const int OP_GREATER = 12;
+ static const int OP_EQUALS = 13;
+ static const int OP_NOT_EQUALS = 14;
+ static const int OP_LOGICAL_AND = 15;
+ static const int OP_LOGICAL_OR = 16;
+ static const int OP_BIT_AND = 17;
+ static const int OP_BIT_XOR = 18;
+ static const int OP_BIT_OR = 19;
+ static const int OP_BIT_NOT = 20;
+ static const int OP_LOGICAL_NOT = 21;
+ static const int OP_COUNT = 22;
+
+ /* Operators are searched from front, the two-character operators appear
+ * before the single-character operators with the same first character.
+ * @ is used to pad out single-character operators.
+ */
+ static const char* operatorChars;
+ static const char operatorLevel[];
+
void pdef(int t) {
*(char *) dstk++ = t;
}
@@ -414,14 +467,12 @@ class compiler {
inp();
next();
} else {
- const char
- * 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";
+ const char* t = operatorChars;
+ int opIndex = 0;
while (l = *t++) {
a = *t++;
- tokc = 0;
- while ((tokl = *t++ - 'b') < 0)
- tokc = tokc * 64 + tokl + 64;
+ tokl = operatorLevel[opIndex];
+ tokc = opIndex;
if (l == tok & (a == ch | a == '@')) {
#if 0
printf("%c%c -> tokl=%d tokc=0x%x\n",
@@ -433,6 +484,11 @@ class compiler {
}
break;
}
+ opIndex++;
+ }
+ if (l == 0) {
+ tokl = 0;
+ tokc = 0;
}
}
}
@@ -477,59 +533,6 @@ class compiler {
next();
}
- /* load immediate value */
- int li(int t) {
- return pGen->li(t);
- }
-
- int gjmp(int t) {
- return pGen->gjmp(t);
- }
-
- /* l = 0: je, l == 1: jne */
- int gtst(int l, int t) {
- return pGen->gtst(l, t);
- }
-
- int gcmp(int t) {
- return pGen->gcmp(t);
- }
-
- void clearEXC() {
- pGen->clearECX();
- }
-
- void storeEAXIntoPoppedLVal(bool isInt) {
- pGen->storeEAXIntoPoppedLVal(isInt);
- }
-
- void loadEAXIndirect(bool isInt) {
- pGen->loadEAXIndirect(isInt);
- }
-
- void leaEAX(int ea) {
- pGen->leaEAX(ea);
- }
-
- /* Temporary hack for emitting x86 code directly. */
- void o(int n) {
- pGen->oHack(n);
- }
-
- /* instruction + address */
- int oad(int n, int t) {
- pGen->oadHack(n,t);
- }
-
- /* instruction + address */
- int psym(int n, int t) {
- pGen->oadHack(n,t);
- }
-
- void gsym(int n) {
- pGen->gsym(n);
- }
-
/* l is one if '=' parsing wanted (quick hack) */
void unary(int l) {
int n, t, a, c;
@@ -537,7 +540,7 @@ class compiler {
n = 1; /* type of expression 0 = forward, 1 = value, other =
lvalue */
if (tok == '\"') {
- li(glo);
+ pGen->li(glo);
while (ch != '\"') {
getq();
*(char *) glo++ = ch;
@@ -553,15 +556,15 @@ class compiler {
t = tok;
next();
if (t == TOK_NUM) {
- li(a);
+ pGen->li(a);
} else if (c == 2) {
/* -, +, !, ~ */
unary(0);
- clearEXC();
+ pGen->clearECX();
if (t == '!')
- gcmp(a);
+ pGen->gcmp(a);
else
- o(a);
+ pGen->genOp(a);
} else if (t == '(') {
expr();
skip(')');
@@ -585,12 +588,13 @@ class compiler {
next();
pGen->pushEAX();
expr();
- storeEAXIntoPoppedLVal(t == TOK_INT);
+ pGen->popECX();
+ pGen->storeEAXToAddressECX(t == TOK_INT);
} else if (t) {
- loadEAXIndirect(t == TOK_INT);
+ pGen->loadEAXIndirect(t == TOK_INT);
}
} else if (t == '&') {
- leaEAX(*(int *) tok);
+ pGen->leaEAX(*(int *) tok);
next();
} else {
n = *(int *) t;
@@ -606,7 +610,7 @@ class compiler {
/* variable */
pGen->loadEAX(n);
if (tokl == 11) {
- pGen->puzzleAdd(n, tokc);
+ pGen->postIncrementOrDecrement(n, tokc);
next();
}
}
@@ -660,29 +664,27 @@ class compiler {
next();
if (l > 8) {
- a = gtst(t, a); /* && and || output code generation */
+ a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
sum(l);
} else {
- o(0x50); /* push %eax */
+ pGen->pushEAX();
sum(l);
- o(0x59); /* pop %ecx */
+ pGen->popECX();
if (l == 4 | l == 5) {
- gcmp(t);
+ pGen->gcmp(t);
} else {
- o(t);
- if (n == '%')
- o(0x92); /* xchg %edx, %eax */
+ pGen->genOp(t);
}
}
}
/* && and || output code generation */
if (a && l > 8) {
- a = gtst(t, a);
- li(t ^ 1);
- gjmp(5); /* jmp $ + 5 */
- gsym(a);
- li(t);
+ a = pGen->gtst(t == OP_LOGICAL_OR, a);
+ pGen->li(t != OP_LOGICAL_OR);
+ pGen->gjmp(5); /* jmp $ + 5 */
+ pGen->gsym(a);
+ pGen->li(t == OP_LOGICAL_OR);
}
}
}
@@ -693,7 +695,7 @@ class compiler {
int test_expr() {
expr();
- return gtst(0, 0);
+ return pGen->gtst(0, 0);
}
void block(int l) {
@@ -707,12 +709,12 @@ class compiler {
block(l);
if (tok == TOK_ELSE) {
next();
- n = gjmp(0); /* jmp */
- gsym(a);
+ n = pGen->gjmp(0); /* jmp */
+ pGen->gsym(a);
block(l);
- gsym(n); /* patch else jmp */
+ pGen->gsym(n); /* patch else jmp */
} else {
- gsym(a); /* patch if test */
+ pGen->gsym(a); /* patch if test */
}
} else if (tok == TOK_WHILE | tok == TOK_FOR) {
t = tok;
@@ -731,17 +733,17 @@ class compiler {
a = test_expr();
skip(';');
if (tok != ')') {
- t = gjmp(0);
+ t = pGen->gjmp(0);
expr();
- gjmp(n - codeBuf.getPC() - 5);
- gsym(t);
+ pGen->gjmp(n - codeBuf.getPC() - 5);
+ pGen->gsym(t);
n = t + 4;
}
}
skip(')');
block((int) &a);
- gjmp(n - codeBuf.getPC() - 5); /* jmp */
- gsym(a);
+ pGen->gjmp(n - codeBuf.getPC() - 5); /* jmp */
+ pGen->gsym(a);
} else if (tok == '{') {
next();
/* declarations */
@@ -754,10 +756,10 @@ class compiler {
next();
if (tok != ';')
expr();
- rsym = gjmp(rsym); /* jmp */
+ rsym = pGen->gjmp(rsym); /* jmp */
} else if (tok == TOK_BREAK) {
next();
- *(int *) l = gjmp(*(int *) l);
+ *(int *) l = pGen->gjmp(*(int *) l);
} else if (tok != ';')
expr();
skip(';');
@@ -787,7 +789,7 @@ class compiler {
} else {
/* patch forward references (XXX: do not work for function
pointers) */
- gsym(*(int *) (tok + 4));
+ pGen->gsym(*(int *) (tok + 4));
/* put function address */
*(int *) tok = codeBuf.getPC();
next();
@@ -803,11 +805,10 @@ class compiler {
}
next(); /* skip ')' */
rsym = loc = 0;
- o(0xe58955); /* push %ebp, mov %esp, %ebp */
- a = oad(0xec81, 0); /* sub $xxx, %esp */
+ a = pGen->functionEntry();
block(0);
- gsym(rsym);
- o(0xc3c9); /* leave, ret */
+ pGen->gsym(rsym);
+ pGen->functionExit();
*(int *) a = loc; /* save local variables */
}
}
@@ -899,6 +900,42 @@ public:
};
+const char* compiler::operatorChars =
+ "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
+
+const char compiler::operatorLevel[] =
+ {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
+ 5, 5, /* ==, != */
+ 9, 10, /* &&, || */
+ 6, 7, 8, /* & ^ | */
+ 2, 2 /* ~ ! */
+ };
+
+const int compiler::X86CodeGenerator::operatorHelper[] = {
+ 0x1, // ++
+ 0xff, // --
+ 0xc1af0f, // *
+ 0xf9f79991, // /
+ 0xf9f79991, // % (With manual assist to swap results)
+ 0xc801, // +
+ 0xd8f7c829, // -
+ 0xe0d391, // <<
+ 0xf8d391, // >>
+ 0xe, // <=
+ 0xd, // >=
+ 0xc, // <
+ 0xf, // >
+ 0x4, // ==
+ 0x5, // !=
+ 0x0, // &&
+ 0x1, // ||
+ 0xc821, // &
+ 0xc831, // ^
+ 0xc809, // |
+ 0xd0f7, // ~
+ 0x4 // !
+};
+
} // namespace acc
int main(int argc, char** argv) {
@@ -956,6 +993,7 @@ int main(int argc, char** argv) {
compiler.dump(save);
fclose(save);
} else {
+ fprintf(stderr, "Executing compiled code:\n");
int codeArgc = argc - i + 1;
char** codeArgv = argv + i - 1;
codeArgv[0] = (char*) (inFile ? inFile : "stdin");
diff --git a/libacc/tests/expr.c b/libacc/tests/expr.c
new file mode 100644
index 0000000..4f2d2e7
--- /dev/null
+++ b/libacc/tests/expr.c
@@ -0,0 +1,60 @@
+/* Test operators */
+
+testInc() { int a, b; a = 3; b = a++; printf("3++ = %d %d\n", b, a); }
+testDec() { int a, b; a = 3; b = a--; printf("3-- = %d %d\n", b, a); }
+testTimes(){ printf("%d * %d = %d\n", 10, 4, 10 * 4); }
+testDiv(){ printf("%d / %d = %d\n", 11, 4, 11 / 4); }
+testMod(){ printf("%d %% %d = %d\n", 11, 4, 11 % 4); }
+testPlus(){ printf("%d + %d = %d\n", 10, 4, 10 + 4); }
+testMinus(){ printf("%d - %d = %d\n", 10, 4, 10 - 4); }
+testShiftLeft(){ printf("%d << %d = %d\n", 10, 4, 10 << 4); }
+testShiftRight(){ printf("%d >> %d = %d\n", 100, 4, 100 >> 4); }
+testLess(){ printf("%d < %d = %d\n", 10, 4, 10 < 4); }
+testLesEqual(){ printf("%d <= %d = %d\n", 10, 4, 10 <= 4); }
+testGreater(){ printf("%d > %d = %d\n", 10, 4, 10 > 4); }
+testGreaterEqual(){ printf("%d >= %d = %d\n", 10, 4, 10 >= 4); }
+testEqualTo(){ printf("%d == %d = %d\n", 10, 4, 10 == 4); }
+testNotEqualTo(){ printf("%d != %d = %d\n", 10, 4, 10 != 4); }
+testBitAnd(){ printf("%d & %d = %d\n", 10, 7, 10 & 7); }
+testBitXor(){ printf("%d ^ %d = %d\n", 10, 7, 10 ^ 7); }
+testBitOr(){ printf("%d | %d = %d\n", 10, 4, 10 | 4); }
+testAssignment(){ int a, b; a = 3; b = a; printf("b == %d\n", b); }
+testLogicalAnd(){ printf("%d && %d = %d\n", 10, 4, 10 && 4); }
+testLogicalOr(){ printf("%d || %d = %d\n", 10, 4, 10 || 4); }
+testAddressOf(){ int a; printf("&a is %d\n", &a); }
+testPointerIndirection(){ int a, b; a = &b; b = 17; printf("*%d = %d =?= %d\n", a, * (int*) a, b); }
+testNegation(){ printf("-%d = %d\n", 10, -10); }
+testUnaryPlus(){ printf("+%d = %d\n", 10, +10); }
+testUnaryNot(){ printf("!%d = %d\n", 10, !10); }
+testBitNot(){ printf("~%d = %d\n", 10, ~10); }
+
+main(a,b) {
+ testInc();
+ testDec();
+ testTimes();
+ testDiv();
+ testMod();
+ testPlus();
+ testMinus();
+ testShiftLeft();
+ testShiftRight();
+ testLess();
+ testLesEqual();
+ testGreater();
+ testGreaterEqual();
+ testEqualTo();
+ testNotEqualTo();
+ testBitAnd();
+ testBinXor();
+ testBitOr();
+ testAssignment();
+ testLogicalAnd();
+ testLogicalOr();
+ testAddressOf();
+ testPointerIndirection();
+ testNegation();
+ testUnaryPlus();
+ testUnaryNot();
+ testBitNot();
+ return 0;
+} \ No newline at end of file