diff options
Diffstat (limited to 'libacc')
-rw-r--r-- | libacc/acc.cpp | 256 | ||||
-rw-r--r-- | libacc/tests/expr.c | 60 |
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 |