#include "b.h" /* * Code generation (EM) */ static int shiftsize(void) { switch (wordsize) { case 1: return 0; case 2: return 1; case 4: return 2; case 8: return 3; default: error("unsupported word size"); exit(1); } } void tonativeaddr(void) { C_loc(shiftsize()); C_slu(wordsize); } void fromnativeaddr(void) { C_loc(shiftsize()); C_sru(wordsize); } char* manglename(char* name, char prefix) { static char buffer[NCPS+3]; buffer[0] = prefix; buffer[1] = '_'; strcpy(buffer+2, name); return buffer; } void binary(struct tnode *tr) { rcexpr(tr->tr1); rcexpr(tr->tr2); } int pushargs(struct tnode *tr) { int stk; if (tr == NULL) return 0; if (tr->op == COMMA) { rcexpr(tr->tr2); stk = pushargs(tr->tr1); return stk+wordsize; } rcexpr(tr); return wordsize; } 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); tonativeaddr(); if ((tr->op == DECBEF) || (tr->op == INCBEF)) { C_dup(wordsize); /* ( addr addr -- ) */ C_loi(wordsize); /* ( addr val -- ) */ if (tr->op == DECBEF) C_dec(); /* ( addr newval -- ) */ else C_inc(); /* ( addr newval -- ) */ C_exg(wordsize); /* ( newval addr -- ) */ C_dup(wordsize*2); /* ( newval addr newval addr -- ) */ C_sti(wordsize); /* ( newval addr -- ) */ C_asp(wordsize); /* ( newval -- ) */ } else { C_dup(wordsize); /* ( addr addr -- ) */ C_loi(wordsize); /* ( addr val -- ) */ C_dup(wordsize*2); /* ( addr val addr val -- ) */ if (tr->op == DECAFT) C_dec(); /* ( addr val addr newval -- ) */ else C_inc(); /* ( addr val addr newval -- ) */ C_exg(wordsize); /* ( addr val newval addr -- ) */ C_sti(wordsize); /* ( addr val -- ) */ C_exg(wordsize); /* ( val addr -- ) */ C_asp(wordsize); /* ( val -- ) */ } } else { /* NAME, checked in "build" */ bs = (struct hshtab *) tr->tr1->tr1; if (bs->class == EXTERN) { switch (tr->op) { case INCBEF: C_ine_dnam(manglename(bs->name, 'b'), 0); C_loe_dnam(manglename(bs->name, 'b'), 0); break; case DECBEF: C_dee_dnam(manglename(bs->name, 'b'), 0); C_loe_dnam(manglename(bs->name, 'b'), 0); break; case INCAFT: C_loe_dnam(manglename(bs->name, 'b'), 0); C_ine_dnam(manglename(bs->name, 'b'), 0); break; case DECAFT: C_loe_dnam(manglename(bs->name, 'b'), 0); C_dee_dnam(manglename(bs->name, 'b'), 0); break; } } else if (bs->class == AUTO) { switch (tr->op) { case INCBEF: C_inl(bs->offset); C_lol(bs->offset); break; case DECBEF: C_del(bs->offset); C_lol(bs->offset); break; case INCAFT: C_lol(bs->offset); C_inl(bs->offset); break; case DECAFT: C_lol(bs->offset); C_del(bs->offset); break; } } else goto classerror; } return; case ASSIGN: rcexpr(tr->tr2); C_dup(wordsize); if (tr->tr1->op == STAR) { rcexpr(tr->tr1->tr1); tonativeaddr(); C_sti(wordsize); } else { /* NAME */ bs = (struct hshtab *) tr->tr1->tr1; if (bs->class == EXTERN) { C_ste_dnam(manglename(bs->name, 'b'), 0); } else if (bs->class == AUTO) { C_stl(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: case ASEOR: 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: C_loc(tr->value); return; case STRING: C_lae_dlb(tr->value, 0); fromnativeaddr(); return; case NAME: /* only rvalue */ bs = (struct hshtab *) tr->tr1; if (bs->class == EXTERN) C_loe_dnam(manglename(bs->name, 'b'), 0); else if (bs->class == AUTO) C_lol(bs->offset); else goto classerror; return; case CALL: stk = pushargs(tr->tr2); rcexpr(tr->tr1); tonativeaddr(); C_cai(); if (stk) C_asp(stk); C_lfr(wordsize); return; case AMPER: bs = (struct hshtab *) tr->tr1->tr1; if (bs->class == EXTERN) { C_lae_dnam(manglename(bs->name, 'b'), 0); } else if (bs->class == AUTO) { C_lal(bs->offset); } else goto classerror; fromnativeaddr(); return; case STAR: /* only rvalue */ rcexpr(tr->tr1); tonativeaddr(); C_loi(wordsize); return; case PLUS: binary(tr); C_adi(wordsize); return; case MINUS: binary(tr); C_sbi(wordsize); return; case TIMES: binary(tr); C_mli(wordsize); return; case DIVIDE: binary(tr); C_dvi(wordsize); return; case MOD: binary(tr); C_rmi(wordsize); return; case AND: binary(tr); C_and(wordsize); return; case OR: binary(tr); C_ior(wordsize); return; case EOR: binary(tr); C_xor(wordsize); return; case LSHIFT: binary(tr); C_sli(wordsize); return; case RSHIFT: binary(tr); C_sri(wordsize); return; case EQUAL: case NEQUAL: case LESS: case LESSEQ: case GREAT: case GREATEQ: binary(tr); C_cmi(wordsize); switch (tr->op) { case EQUAL: C_teq(); break; case NEQUAL: C_tne(); break; case LESS: C_tlt(); break; case LESSEQ: C_tle(); break; case GREAT: C_tgt(); break; case GREATEQ: C_tge(); break; } return; case EXCLA: rcexpr(tr->tr1); C_teq(); return; case NEG: rcexpr(tr->tr1); C_ngi(wordsize); return; case NOT: rcexpr(tr->tr1); C_com(wordsize); return; case QUEST: cbranch(tr->tr1, o1=isn++); rcexpr(tr->tr2->tr1); jump(o2 = isn++); fnlabel(o1); rcexpr(tr->tr2->tr2); fnlabel(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); } } */