/* type.c - type and storage-class routines for bcc */

/* Copyright (C) 1992 Bruce Evans */

#include "bcc.h"
#include "align.h"
#include "gencode.h"		/* s.b. switches.h */
#include "sc.h"
#include "scan.h"
#include "table.h"

#undef EXTERN
#define EXTERN
#include "type.h"

PUBLIC uoffset_T ctypesize = 1;
PUBLIC uoffset_T dtypesize = 8;
PUBLIC uoffset_T ftypesize = 0;
PUBLIC uoffset_T itypesize = 2;
PUBLIC uoffset_T ptypesize = 2;
PUBLIC uoffset_T stypesize = 2;

PRIVATE char skey0;
PRIVATE char skey1;

PUBLIC struct typestruct *addstruct(structname)
char *structname;
{
    unsigned namelength;
    struct symstruct *symptr;
    struct typestruct *structype;

    (structype = newtype())->constructor = STRUCTU;
    structype->alignmask = ctype->alignmask;
    if (++skey1 == 0)
    {
	++skey1;		/* must be nonzero or key string would end */
	++skey0;		/* will never reach 'A' to be an identifier */
    }
    structype->structkey[0] = skey0;
    structype->structkey[1] = skey1;
    if (*structname != 0)
    {
	symptr = addlorg(structname, structype);
	symptr->storage = 0;
	symptr->flags = STRUCTNAME;
	if (charptr + (namelength = strlen(structname)) >= chartop)
	    growheap(namelength + 1);
#ifdef TS
++ts_n_structname;
ts_s_structname += namelength + 1;
#endif
	structype->tname = strcpy(charptr, structname);
	charptr += namelength + 1;
    }
    return structype;
}

#ifndef VERY_SMALL_MEMORY
PUBLIC void laststruct(char *sname)
{
    sname[0] = skey0;
    sname[1] = skey1;
}
#endif

PUBLIC struct typestruct *iscalartotype(scalar)
scalar_pt scalar;
{
    if (scalar & LONG)
    {
	if (scalar & UNSIGNED)
	    return ultype;
	return ltype;
    }
    if (scalar & UNSIGNED)
	return uitype;
    return itype;
}

PUBLIC struct typestruct *newtype()
{
    register struct typestruct *type;

    type = qmalloc(sizeof *type);
#ifdef TS
++ts_n_type;
ts_s_type += sizeof *type;
#endif
    type->typesize =		/* (uoffset_T) */
	type->scalar =		/* (scalar_t) */
	type->constructor =	/* (constr_t) */
	type->structkey[0] = 0;
    type->nexttype =
	type->prevtype =
	type->sidetype = NULL;
    type->listtype = NULL;
    type->tname = "";
    return type;
}

PUBLIC void outntypechar(type)
struct typestruct *type;
{
    outnbyte(*type->tname);
}

PUBLIC struct typestruct *pointype(type)
struct typestruct *type;
{
    return prefix(POINTER, ptypesize, type);
}

PUBLIC struct typestruct *prefix(constructor, size, type)
constr_pt constructor;
uoffset_T size;
struct typestruct *type;
{
    register struct typestruct *searchtype;

    for (searchtype = type->prevtype; searchtype != NULL;
	 searchtype = searchtype->sidetype)
	if (searchtype->constructor == (constr_t) constructor &&
	    searchtype->typesize == size)
	    return searchtype;
    switch ((searchtype = newtype())->constructor = constructor)
    {
    case ARRAY:
	searchtype->alignmask = type->alignmask;
	break;
    case FUNCTION:
	searchtype->alignmask = ~(uoffset_T) 0;
	break;
    case POINTER:
	searchtype->alignmask = ~(ptypesize - 1) | alignmask;
	break;
    case STRUCTU:
	bugerror("prefixing structure/union");
	searchtype->alignmask = alignmask;
	break;
    }
    searchtype->typesize = size;
    searchtype->nexttype = type;
    searchtype->sidetype = type->prevtype;
    return type->prevtype = searchtype;
}

PUBLIC struct typestruct *promote(type)
struct typestruct *type;
{
    scalar_t scalar;

    if ((scalar = type->scalar) & (CHAR | SHORT))
    {
	if (scalar & UNSIGNED)
	    return uitype;
	return itype;
    }
    if (scalar & FLOAT)
	return dtype;
    if (type->constructor & ARRAY)
	return pointype(type->nexttype);
    if (type->constructor & FUNCTION)
	return pointype(type);
    return type;
}

PUBLIC struct typestruct *tosigned(type)
struct typestruct *type;
{
    switch (type->scalar & ~(UNSIGNED | DLONG))
    {
    case CHAR:
	return sctype;
    case SHORT:
	return stype;
    case INT:
	return itype;
    case LONG:
	return ltype;
    default:
	error("signed only applies to integral types");
	return type;
    }
}

PUBLIC struct typestruct *tounsigned(type)
struct typestruct *type;
{
    switch (type->scalar & ~(UNSIGNED | DLONG))
    {
    case CHAR:
	return uctype;
    case SHORT:
	return ustype;
    case INT:
	return uitype;
    case LONG:
	return ultype;
    default:
	error("unsigned only applies to integral types");
	return type;
    }
}

PUBLIC void typeinit()
{
#ifdef I80386
    if (i386_32)
    {
	uitype->typesize =
	itype->typesize =
	ptypesize =
	itypesize = 4;
	dtype->alignmask =
	    fltype->alignmask =
	    uitype->alignmask =
	    ltype->alignmask =
	    ultype->alignmask =
	    itype->alignmask = ~(uoffset_T) (4 - 1);
	ltype->scalar = LONG;	/* not DLONG */
	ultype->scalar = UNSIGNED | LONG;
    }
#endif
    fitype = prefix(FUNCTION, ftypesize, itype);
    pctype = pointype(ctype);
    skey0 = 1;
    vtype->constructor = VOID;
}
