403 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			403 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #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);
 | |
| 	}
 | |
| }
 | |
| */
 |