/*ident	"@(#)ctrans:src/typ2.c	1.1.5.17" */
/**************************************************************************

	C++ source for cfront, the C++ compiler front-end
	written in the computer science research center of Bell Labs

	Copyright (c) 1984 AT&T, Inc. All rigths Reserved
	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.

typ2.c:

***************************************************************************/
 
#include "cfront.h"
#include "size.h"

extern int chars_in_largest;
int largest_int;

void typ_init()
{	
	chars_in_largest = strlen(LARGEST_INT);
	largest_int = int(str_to_long(LARGEST_INT));

	defa_type = new basetype(INT,0);	// note defa_type!=int_type
	int_type = new basetype(INT,0);		// but they both represent `int'

	PERM(int_type);
	PERM(defa_type);

	moe_type = new basetype(INT,0);
	PERM(moe_type);
	moe_type->b_const = 1;
	moe_type->check(0);

	uint_type = new basetype(INT,0);
	PERM(uint_type);
	uint_type->type_adj(UNSIGNED);
	uint_type->check(0);

	long_type = new basetype(LONG,0);
	PERM(long_type);
	long_type->check(0);

	ulong_type = new basetype(LONG,0);
	PERM(ulong_type);
	ulong_type->type_adj(UNSIGNED);
	ulong_type->check(0);

	short_type = new basetype(SHORT,0);
	PERM(short_type);
	short_type->check(0);

	ushort_type = new basetype(SHORT,0);
	PERM(ushort_type);
	ushort_type->type_adj(UNSIGNED);
	ushort_type->check(0);

	float_type = new basetype(FLOAT,0);
	PERM(float_type);

	double_type = new basetype(DOUBLE,0);
	PERM(double_type);

	ldouble_type = new basetype(LDOUBLE,0);
	PERM(ldouble_type);

	zero_type = new basetype(ZTYPE,0);
	PERM(zero_type);
	zero->tp = zero_type;

	void_type = new basetype(VOID,0);
	PERM(void_type);

	char_type = new basetype(CHAR,0);
	PERM(char_type);

	uchar_type = new basetype(CHAR,0);
	PERM(uchar_type);
	uchar_type->type_adj(UNSIGNED);
	uchar_type->check(0);

	Pchar_type = char_type->addrof();
	PERM(Pchar_type);

	Pint_type = int_type->addrof();
	PERM(Pint_type);

	Pvoid_type = void_type->addrof();
	PERM(Pvoid_type);

	Pfctvec_type = new fct(int_type,0,0);	
	Pfctvec_type = Pfctvec_type->addrof();
	Pfctvec_type = Pfctvec_type->addrof();
	PERM(Pfctvec_type);

	gtbl = new table(GTBLSIZE,0,0);
	gtbl->t_name = new name("global");
	ptbl = new table(CTBLSIZE,0,0);
	ptbl->t_name = new name("ptbl");
}

bit enum_promote;

Pbase basetype::arit_conv(Pbase t)
/*
	perform the "usual arithmetic conversions" C ref Manual 6.6
	on "this" op "t"
	"this" and "t" are integral or floating
	"t" may be 0
*/
{
	while (base == TYPE) this = Pbase(Pbase(this)->b_name->tp);
// error('d', "arit_conv: this: %k %d %t %d", base, base, this, this );

	bit l;
	bit u;
	bit f;
	bit l1 = (base == LONG);
	bit u1 = b_unsigned;
	bit f1 = (base==FLOAT || base==DOUBLE || base==LDOUBLE);
	if (t) {
		while (t->base == TYPE) t = Pbase(Pbase(t)->b_name->tp);
// error('d', "arit_conv: t: %k %d %t %d", t->base, t->base, t, t );

		bit l2 = (t->base == LONG);
		bit u2 = t->b_unsigned;
		bit f2 = (t->base==FLOAT || t->base==DOUBLE || base==LDOUBLE);
		l = l1 || l2;
		u = u1 || u2;
		f = f1 || f2;
	}
	else {
		l = l1;
		u = u1;
		f = f1;
	}

	if (f) {
		if (base==LDOUBLE || (t && t->base==LDOUBLE)) return ldouble_type;
		if (base==DOUBLE || (t && t->base==DOUBLE)) return double_type;
		return float_type;
	}
	if (l & u) return ulong_type;
	if (l & !u) return long_type;
	if (u) {
		if (base==INT || (t && t->base==INT)) return uint_type;
		if (SZ_SHORT==SZ_INT) // ANSIism
			if (base==SHORT || (t && t->base==SHORT)) return uint_type;
		return int_type;
	}

	if (t && t->base == EOBJ && base == EOBJ) enum_promote = 1;
	return int_type;
}

bit vec_const = 0;
bit fct_const = 0;

bit type::tconst()
/*
	is this type a constant
*/
{
	Ptype t = this;
	vec_const = 0;
	fct_const = 0;
//error('d',"tconst %t",t);
xxx:
	switch (t->base) {
	case TYPE:
		if (Pbase(t)->b_const) return 1;
		t = Pbase(t)->b_name->tp;
		goto xxx;
	case VEC:
		vec_const = 1;
		return 1;
	case PTR:
	case RPTR:
		return Pptr(t)->rdo;
	case FCT:
	case OVERLOAD:
		fct_const = 1;
		return 1;
	default:
		return Pbase(t)->b_const;
	}
}

TOK type::set_const(bit mode)
/*
	make someting a constant or variable, return old status
*/
{
	Ptype t = this;
	int m;
xxx:
	switch (t->base) {
	case TYPE:
		m = Pbase(t)->b_const;
		Pbase(t)->b_const = mode;
		t = Pbase(t)->b_name->tp;
		goto xxx;
	case ANY:
	case RPTR:
	case VEC:
		return t->base;		// constant by definition
	case PTR:
		m = Pptr(t)->rdo;
		Pptr(t)->rdo = mode;
		return m;
	default:
		m = Pbase(t)->b_const;
		Pbase(t)->b_const = mode;
		return m;
	}
}

Pptr type::is_ref()
{
	Ptype t = this;
xxx:
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
	case RPTR:	return Pptr(t);
	default:	return 0;
	}
}

Pclass Mptr;

Pptr type::is_ptr()
{
	Ptype t = this;
xxx:
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
	case PTR:
	case VEC:	Mptr = Pptr(t)->memof;
			return Pptr(t);
	default:	return 0;
	}
}

Pptr type::is_ptr_or_ref()
{
	Ptype t = this;
xxx:
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
	case PTR:
	case RPTR:
	case VEC:	Mptr = Pptr(t)->memof;
			return Pptr(t);
	default:	return 0;
	}
}

int type::align()
{
	Ptype t = this;
xx:
/*fprintf(stderr,"align %d %d\n",t,t->base);*/
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xx;
	case COBJ:	t = Pbase(t)->b_name->tp; goto xx;
	case VEC:	t = Pvec(t)->typ; goto xx;
	case ANY:	return 1;
	case CHAR:	return AL_CHAR;
	case SHORT:	return AL_SHORT;
	case INT:	return AL_INT;
	case LONG:	return AL_LONG;
	case FLOAT:	return AL_FLOAT;
	case DOUBLE:	return AL_DOUBLE;
	case LDOUBLE:	return AL_LDOUBLE;
	case PTR:
	case RPTR:	return AL_WPTR;
	case CLASS:	return Pclass(t)->obj_align;
	case ENUM:
	case EOBJ:	return AL_INT;
	case VOID:	error("illegal use of void"); return AL_INT;
	default:	error('i',"(%d,%k)->type::align",t,t->base);
	}
}

bit fake_sizeof;

int type::tsizeof(int ptmc)
/*
	the sizeof type operator
	return the size in bytes of the types representation
*/
{
	Ptype t = this;
zx:
//error('d',"zx %t %d",t,t->base);
	if (t == 0) error('i',"typ.tsizeof(t==0)");
	switch (t->base) {
	case TYPE:
		t = Pbase(t)->b_name->tp;
		goto zx;
	case COBJ:
		t = Pbase(t)->b_name->tp;
		if (t == 0) return 0;	// ``fake'' generated classes: _Sdd
		goto zx;

	case ANY:	return 1;
	case VOID:	return 0;
	case ZTYPE:	return SZ_WPTR;	/* assume pointer */
	case CHAR:	return SZ_CHAR;
	case SHORT:	return SZ_SHORT;
	case INT:	return SZ_INT;
	case LONG:	return SZ_LONG;
	case FLOAT:	return SZ_FLOAT;
	case DOUBLE:	return SZ_DOUBLE;
	case LDOUBLE:	return SZ_LDOUBLE;

	case VEC:
		{	Pvec v = Pvec(t);
			if (v->size == 0) {
				if (fake_sizeof == 0) error('w',"sizeof array with undeclared dimension");
				return SZ_WPTR;	// vector argument has sizeof ptr
			}
			return v->size * v->typ->tsizeof();
		}
	case RPTR:	
	case PTR:
	{	
		int k = (Pptr(t)->memof && !ptmc)?sizeof(short)+sizeof(short):0;
		t = Pptr(t)->typ;
	xxx:
		switch (t->base) {
		default:	return SZ_WPTR;
		case CHAR:	return SZ_BPTR;
		case FCT:	return SZ_WPTR+k;
		case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
		}
	}
	case FIELD:
		error("sizeof(field)");
		return Pbase(t)->b_bits/BI_IN_BYTE+1;
	case FCT:
		error("sizeof(function)");
		return 0;

	case CLASS:	
	{
                Pclass cl = Pclass(t);
		if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
			error("%tU, size not known",cl);
			return SZ_INT;
		}
	 	if (cl->c_body == 1)	// detect first allocation or sizeof
	 		cl->dcl_print(0);
		return cl->obj_size;
	}

	case EOBJ:
	case ENUM:	return SZ_INT;

	default:	return 0;	// deref can be called for any type
			//error('i',"sizeof(%d)",t->base);
	}
}

bit type::vec_type()
{
	Ptype t = this;
xx:
	switch (t->base) {
	case ANY:
	case VEC:
	case PTR:
	case RPTR:	return 1;
	case TYPE:	t = Pbase(t)->b_name->tp; goto xx;
	default:	return 0;
	}
}

int ref_initializer;

Ptype type::deref()
/*	index==1:	*p
	index==0:	p[expr]
*/
{
//error('d',"%t -> deref() refd %d",this,ref_initializer);
	Ptype t = this;
xx:
	switch (t->base) {
	case TYPE:
		t = Pbase(t)->b_name->tp;
		goto xx;
	case PTR:
	case RPTR:
	case VEC:
	{	if (t == Pvoid_type) error("void* dereferenced");
		Ptype tt = t = Pvec(t)->typ;
		if (ref_initializer == 0) {
			while (tt->base == TYPE) tt = Pbase(tt)->b_name->tp;
			if (tt->base == COBJ) { 
                        	tt = Pbase(tt)->b_name->tp;
                        	if (tt && Pclass(tt)->defined&(DEFINED|SIMPLIFIED))
                                	(void) t->tsizeof();
                        }
		}
		// no break
	}
	case ANY:
		return t;
	default:
		error("nonP dereferenced");
		return any_type;
	}
}

Pfct type::memptr()
// is ``this'' a pointer to member function
{
	Ptype t = this;
	while (t->base == TYPE) t = Pbase(t)->b_name->tp;
	if (t->base != PTR || Pptr(t)->memof==0) return 0;

	t = Pptr(t)->typ;
	while (t->base == TYPE) t = Pbase(t)->b_name->tp;
	return (t->base == FCT) ? Pfct(t) : 0;
}
