ack/lang/b/compiler/b1.c

335 lines
5.6 KiB
C

#include "b.h"
/*
* Code generation (x86 assembly)
*/
void
push(void)
{
printf("\tpush\t%%eax\n");
}
void
pop(char *s)
{
printf("\tpop\t%%%s\n", s);
}
void
binary(struct tnode *tr)
{
rcexpr(tr->tr1);
push();
rcexpr(tr->tr2);
}
int
pushargs(struct tnode *tr)
{
int stk;
if (tr == NULL)
return 0;
if (tr->op == COMMA) {
rcexpr(tr->tr2);
push();
stk = pushargs(tr->tr1);
return stk+NCPW;
}
rcexpr(tr);
push();
return NCPW;
}
void
lvalexp(struct tnode *tr)
{
struct hshtab *bs;
char memloc[64];
switch (tr->op) {
case DECBEF:
case INCBEF:
case DECAFT:
case INCAFT:
if (tr->tr1->op == STAR) {
rcexpr(tr->tr1->tr1);
printf("\tmov\t%%eax,%%ebx\n");
sprintf(memloc,"(,%%ebx,4)");
} else { /* NAME, checked in "build" */
bs = (struct hshtab *) tr->tr1->tr1;
if (bs->class == EXTERN)
sprintf(memloc,"_%s", bs->name);
else if (bs->class == AUTO)
sprintf(memloc,"%d(%%ebp)", bs->offset);
else
goto classerror;
}
if (tr->op == DECBEF || tr->op == INCBEF) {
printf("\t%s\t%s\n", tr->op == DECBEF ? "decl" : "incl",
memloc);
printf("\tmov\t%s,%%eax\n", memloc);
} else {
printf("\tmov\t%s,%%eax\n", memloc);
printf("\t%s\t%s\n", tr->op == DECAFT ? "decl" : "incl",
memloc);
}
return;
case ASSIGN:
rcexpr(tr->tr2);
if (tr->tr1->op == STAR) {
push();
rcexpr(tr->tr1->tr1);
pop("ebx");
printf("\tmov\t%%ebx,(,%%eax,4)\n");
} else { /* NAME */
bs = (struct hshtab *) tr->tr1->tr1;
if (bs->class == EXTERN)
printf("\tmov\t%%eax,_%s\n", bs->name);
else if (bs->class == AUTO)
printf("\tmov\t%%eax,%d(%%ebp)\n", bs->offset);
else
goto classerror;
}
return;
case ASPLUS:
case ASMINUS:
case ASMOD:
case ASTIMES:
case ASDIV:
case ASOR:
case ASAND:
case ASLSH:
case ASRSH:
case ASEQUAL:
case ASNEQL:
case ASLEQ:
case ASLESS:
case ASGTQ:
case ASGREAT:
tr->op -= ASPLUS-PLUS;
rcexpr(block(ASSIGN,0,tr->tr1,tr));
return;
}
classerror:
error("Storage class");
}
void
rcexpr(struct tnode *tr)
{
int o1, o2;
int stk;
struct hshtab *bs;
if (tr == NULL)
return;
if (opdope[tr->op]&02) {
lvalexp(tr);
return;
}
switch (tr->op) {
case CON:
printf("\tmov\t$%d,%%eax\n", tr->value);
return;
case STRING:
printf("\tmov\t$L%d,%%eax\n", tr->value);
printf("\tshr\t$2,%%eax\n");
return;
case NAME: /* only rvalue */
bs = (struct hshtab *) tr->tr1;
if (bs->class == EXTERN)
printf("\tmov\t_%s,%%eax\n", bs->name);
else if (bs->class == AUTO)
printf("\tmov\t%d(%%ebp),%%eax\n", bs->offset);
else
goto classerror;
return;
case CALL:
stk = pushargs(tr->tr2);
rcexpr(tr->tr1);
printf("\tshl\t$2,%%eax\n");
printf("\tcall\t*%%eax\n");
if (stk)
printf("\tadd\t$%d,%%esp\n",stk);
return;
case AMPER:
bs = (struct hshtab *) tr->tr1->tr1;
if (bs->class == EXTERN) {
printf("\tmov\t$_%s,%%eax\n", bs->name);
printf("\tshr\t$2,%%eax\n");
} else if (bs->class == AUTO) {
printf("\tlea\t%d(%%ebp),%%eax\n", bs->offset);
printf("\tshr\t$2,%%eax\n");
} else
goto classerror;
return;
case STAR: /* only rvalue */
rcexpr(tr->tr1);
printf("\tmov\t(,%%eax,4),%%eax\n");
return;
case PLUS:
binary(tr);
pop("ebx");
printf("\tadd\t%%ebx,%%eax\n");
return;
case MINUS:
binary(tr);
printf("\tmov\t%%eax,%%ebx\n");
pop("eax");
printf("\tsub\t%%ebx,%%eax\n");
return;
case TIMES:
binary(tr);
pop("ebx");
printf("\tmul\t%%ebx\n");
return;
case DIVIDE:
binary(tr);
printf("\tmov\t%%eax,%%ebx\n");
pop("eax");
printf("\txor\t%%edx,%%edx\n");
printf("\tdiv\t%%ebx\n");
return;
case MOD:
binary(tr);
printf("\tmov\t%%eax,%%ebx\n");
pop("eax");
printf("\txor\t%%edx,%%edx\n");
printf("\tdiv\t%%ebx\n");
printf("\tmov\t%%edx,%%eax\n");
return;
case AND:
binary(tr);
pop("ebx");
printf("\tand\t%%ebx,%%eax\n");
return;
case OR:
binary(tr);
pop("ebx");
printf("\tor\t%%ebx,%%eax\n");
return;
case LSHIFT:
binary(tr);
printf("\tmov\t%%eax,%%ecx\n");
pop("eax");
printf("\tshl\t%%cl,%%eax\n");
return;
case RSHIFT:
binary(tr);
printf("\tmov\t%%eax,%%ecx\n");
pop("eax");
printf("\tshr\t%%cl,%%eax\n");
return;
case EQUAL:
case NEQUAL:
case LESS:
case LESSEQ:
case GREAT:
case GREATEQ:
binary(tr);
pop("ebx");
printf("\tcmp\t%%eax,%%ebx\n");
switch (tr->op) {
case EQUAL:
printf("\tsete\t%%al\n");
break;
case NEQUAL:
printf("\tsetne\t%%al\n");
break;
case LESS:
printf("\tsetl\t%%al\n");
break;
case LESSEQ:
printf("\tsetle\t%%al\n");
break;
case GREAT:
printf("\tsetg\t%%al\n");
break;
case GREATEQ:
printf("\tsetge\t%%al\n");
break;
}
printf("\tmovzb\t%%al,%%eax\n");
return;
case EXCLA:
rcexpr(tr->tr1);
printf("\ttest\t%%eax,%%eax\n");
printf("\tsete\t%%al\n");
printf("\tmovzb\t%%al,%%eax\n");
return;
case NEG:
rcexpr(tr->tr1);
printf("\tneg\t%%eax\n");
return;
case QUEST:
cbranch(tr->tr1, o1=isn++, 0);
rcexpr(tr->tr2->tr1);
jump(o2 = isn++);
label(o1);
rcexpr(tr->tr2->tr2);
label(o2);
return;
default:
error("Can't print tree (op: %d)", tr->op);
}
classerror:
error("Storage class");
}
/* Prints the tree in RPN, for debugging */
/*
void
rcexpr(struct tnode *tr)
{
struct hshtab *bs;
if (tr == NULL)
printf("(NULL) ");
else if (tr->op == CON)
printf("%d ", tr->value);
else if (tr->op == STRING)
printf("s(L%d) ", tr->value);
else if (tr->op == NAME) {
bs = (struct hshtab *)tr->tr1;
if (bs->class == AUTO)
printf("%s(%d) ", bs->name, bs->offset);
else
printf("%s ", bs->name);
} else {
rcexpr(tr->tr1);
if (opdope[tr->op]&01)
rcexpr(tr->tr2);
printtoken(tr->op, stdout);
}
}
*/