Exemplo n.º 1
0
Ptype np_promote(TOK oper, TOK r1, TOK r2, Ptype t1, Ptype t2, TOK p, bit perr)
/*
	an arithmetic operator "oper" is applied to "t1" and "t2",
	types t1 and t2 has been checked and belongs to catagories
	"r1" and "r2", respectively:
		A	ANY
		Z	ZERO
		I	CHAR, SHORT, INT, LONG, LLONG, FIELD, or EOBJ
		F	FLOAT DOUBLE LDOUBLE
		P	PTR (to something) or VEC (of something)
	test for compatability of the operands,
	if (p) return the promoted result type
*/
{
	if (r2 == 'A')
		return t1;

	switch (r1) {
	case 'A':
		return t2;
	case 'Z':
		switch (oper) {
		case ASMOD:
		case ASAND:
		case ASOR:
		case ASLS:
		case ASRS:
		case ASPLUS:
		case ASMINUS:
			return any_type;
		}
		switch (r2) {
		case 'Z':		return int_type;
		case 'F':
			switch (oper) {
			case MOD:
			case AND:
			case ER:
			case OR:
			case LS:
			case RS:
				return any_type;
			}
			// no break
		case 'I':
			switch (oper) {
			case DEREF:
				return any_type;
			case LS: // result type is that of promoted left op
			case RS:
				return int_type;
			}
			return	(p)
				?
				Pbase(t2->skiptypedefs())->arit_conv(0)
				:
				0;
		case 'P':
			switch (oper) {
			case MOD:
			case AND:
			case ER:
			case OR:
			case LS:
			case RS:
			case GE:
			case GT:
			case LE:
			case LT:
				return any_type;
			case PLUS:
			case ASPLUS:
				if(t2!=Pvoid_type)
					break;
			case EQ:
			case NE:
			case QUEST:
				break;
			default:
				return any_type;
			}
			return t2;
		case FCT:
			switch (oper) {
			case QUEST:
				return any_type;
			case EQ:
			case NE:
				return t2;
			}
			if(perr) error("zero%kF",oper);
			return any_type;
		default:
			error('i',"zero(%d)",r2);
		}
	case 'I':
		switch (r2) {
		case 'Z':
			t2 = 0;
			switch (oper) {
			case DEREF:
				return any_type;
			}
			return	(p)
				?
				Pbase(t1->skiptypedefs())->arit_conv(Pbase(t2))
				:
				0;
		case 'F': 
			switch (oper) {
			case MOD:
			case AND:
			case ER:
			case OR:
			case LS:
			case RS:
			case ASMOD:
			case ASAND:
			case ASOR:
			case ASLS:
			case ASRS:
				return any_type;
			}
			// no break;
		case 'I':
			switch (oper) {
			case DEREF:
				return any_type;
			case LS: // result type is that of promoted left op
			case RS:
				return (p)
					?
					Pbase(t1->skiptypedefs())->arit_conv(Pbase(0))
					:
					0;
			}
			return	(p)
				?
				Pbase(t1->skiptypedefs())->arit_conv(Pbase(t2))
				:
				0;
		case 'P':
			switch (oper) {
			case DEREF:
				break;
			case PLUS:
			case ASPLUS:
				if(t2!=Pvoid_type)
					break;
			default:
				if(perr) error("int%kP",oper);
				return any_type;
			}
			return t2;
		case FCT:
			if(perr) error("int%kF",oper);
			return any_type;
		default:
			error('i',"int(%d)",r2);
			return any_type;
		}
	case 'F':
		switch (oper) {
		case MOD:
		case ASMOD:
		case AND:
		case ER:
		case OR:
		case ASAND:
		case ASOR:
		case LS:
		case RS:
		case ASLS:
		case ASRS:
			return any_type;
		}
		switch (r2) {
		case 'Z':
			t2 = 0;
		case 'I':
		case 'F': 
			if(oper==DEREF)
				return any_type;
			return	(p)
				?
				Pbase(t1->skiptypedefs())->arit_conv(Pbase(t2))
				:
				0;
		case 'P':
			if(perr) error("float%kP",oper);
			return any_type;
		case FCT:
			if(perr) error("float%kF",oper);
			return any_type;
		default:
			error('i',"float(%d)",r2);
			return any_type;
		}
	case 'P':
		switch(oper) {
		case LS:
		case RS:
		case ASLS:
		case ASRS:
		case MOD:
		case ASMOD:
		case ER:
		case OR:
		case ASOR:
		case AND:
		case ASAND:
		case DIV:
		case MUL:
			return any_type;
		}
		switch (r2) {
		case 'Z':
			switch (oper) {
			case GE:
			case GT:
			case LE:
			case LT:
				return any_type;
			}
			return t1;
		case 'I':
			switch (oper) {
			case DEREF:
			case PLUS:
			case MINUS:
			case ASPLUS:
			case ASMINUS:
				if (t1->check(Pvoid_type,0)==0) {
					return any_type;
				}
				break;
			default:
				if(perr) error("P%k int",oper);
				return any_type;
			}
			return t1;
		case 'F':
			if(perr) error("P%k float",oper);
			return any_type;
		case 'P':
			if (t1->check(t2,ASSIGN)) {
				Ptype tt1 = t1->is_ptr()->typ->skiptypedefs();
				Ptype tt2 = t2->is_ptr()->typ->skiptypedefs();
				switch (oper) {
				case EQ:
				case NE:
				case LE:
				case GE:
				case GT:
				case LT:
				case MINUS:
				case QUEST:
				    if (tt1 && tt2 
					&& 
					tt1->base==COBJ && tt2->base==COBJ
				    ) {
					Pclass c1=tt1->classtype();
					Pclass c2=tt2->classtype();
					if (c1 && c2 
					    && 
					    c1->baseof(c2) || c2->baseof(c1)
					) goto zz; 
				    }
				    if (t2->check(t1,ASSIGN) == 0) {
					if (oper == QUEST) return t2;
					goto zz;
				    }
				    break;
				case REFMUL:
					{
				    Pname cn = tt1->is_cl_obj();
				    if (cn && tt2->base == FCT 
					&& 
					same_class(Pclass(cn->tp),Pfct(tt2)->memof)
				    ) 
					return t2;
					}
				}
				if(perr) error("T mismatch:%t %k%t",t1,oper,t2);
				return any_type;
			}
			zz:
			switch (oper) {
			case MINUS:	
				return	(t2!=Pvoid_type)
					?
					int_type
					:
					any_type;
			case ASMINUS:
				if(perr) error("P -=P");
				return any_type;
			case PLUS:
				if(perr) error("P +P");
				return any_type;
			case ASPLUS:
				if(perr) error("P +=P");
				return any_type;
			case MOD:
			case ASMOD:
			case AND:
			case ER:
			case OR:
			case ASAND:
			case ASOR:
			case ASLS:
			case ASRS:
			case LS:
			case RS:
			case DEREF:
				return any_type;
			default:
				return t1;
			}
		case FCT:
			return t1;
		default:
			error('i',"P(%d)",r2);
		}
	case FCT:
		if(oper == QUEST) {
			switch (r2) {
			case 'Z':
				return any_type;
			case 'P':
				return t2;
			case 'I':
			case 'F':
				if(perr) error("F%k%t",oper,t2);
			default:
				return t1;
			}
		}
		if(Pfct(t1)->memof && r2=='P' && t2->memptr())
			return t2;
		if((oper == EQ || oper == NE) && r2=='Z') return t1;
		if(perr) error("F%k%t",oper,t2);
		return any_type;
	default:
		error('i',"np_promote(%d,%d)",r1,r2);
		return 0;
	}
}