shithub: scc

ref: 9197be5ac4cb884d119aed4d5b0c66d602c9614b
dir: /cc1/types.c/

View raw version

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sizes.h>
#include <cc.h>
#include "cc1.h"

#define NR_TYPE_HASH 16

Type
	*voidtype = &(Type) {
		.op = VOID,
		.letter = L_VOID
	},
	*pvoidtype = &(Type) {
		.op = PTR,
		.letter = L_POINTER
	},
	*booltype = &(Type) {
		.op = INT,
		.letter = L_BOOL,
		.defined = 1,
		.n.rank = RANK_BOOL
	},
	*schartype = &(Type) {
		.op = INT,
		.letter = L_SCHAR,
		.defined = 1,
		.n.rank = RANK_SCHAR
	},
	*uchartype = &(Type) {
		.op = INT,
		.letter = L_UCHAR,
		.sign = 1,
		.defined = 1,
		.n.rank = RANK_UCHAR
	},
	*chartype = &(Type) {
		.op = INT,
		.letter = L_CHAR,
		.sign = 1,
		.defined = 1,
		.n.rank = RANK_CHAR
	},
	*ushortype = &(Type) {
		.op = INT,
		.letter = L_USHORT,
		.defined = 1,
		.n.rank = RANK_USHORT
	},
	*shortype = &(Type) {
		.op = INT,
		.letter = L_SHORT,
		.defined = 1,
		.n.rank = RANK_SHORT
	},
	*uinttype = &(Type) {
		.op = INT,
		.letter = L_UINT,
		.sign = 1,
		.defined = 1,
		.n.rank = RANK_UINT
	},
	*inttype = &(Type) {
		.op = INT,
		.letter = L_INT,
		.defined = 1,
		.n.rank = RANK_INT
	},
	*longtype = &(Type) {
		.op = INT,
		.letter = L_LONG,
		.defined = 1,
		.n.rank = RANK_LONG
	},
	*ulongtype = &(Type) {
		.op = INT,
		.letter = L_ULONG,
		.sign = 1,
		.defined = 1,
		.n.rank = RANK_ULONG
	},
	*ullongtype = &(Type) {
		.op = INT,
		.letter = L_ULLONG,
		.sign = 1,
		.defined = 1,
		.n.rank = RANK_ULLONG
	},
	*llongtype = &(Type) {
		.op = INT,
		.letter = L_LLONG,
		.defined = 1,
		.n.rank = RANK_LLONG
	},
	*floattype = &(Type) {
		.op = FLOAT,
		.letter = L_FLOAT,
		.defined = 1,
		.n.rank = RANK_FLOAT
	},
	*doubletype = &(Type) {
		.op = FLOAT,
		.letter = L_DOUBLE,
		.defined = 1,
		.n.rank = RANK_DOUBLE
	},
	*ldoubletype = &(Type) {
		.op = FLOAT,
		.letter = L_LDOUBLE,
		.defined = 1,
		.n.rank = RANK_LDOUBLE
	};

Type *
ctype(int8_t type, int8_t sign, int8_t size)
{
	switch (type) {
	case CHAR:
		if (size)
			goto invalid_type;
		switch (sign) {
		case 0:
			return chartype;
		case SIGNED:
			return schartype;
		case UNSIGNED:
			return uchartype;
		}
		break;
	case VOID:
		if (size || sign)
			goto invalid_type;
		return voidtype;
	case BOOL:
		if (size || sign)
			goto invalid_type;
		return booltype;
	case 0:
		if (!sign && !size) {
			warn(options.implicit,
			     "type defaults to 'int' in declaration");
		}
		/* fallthrough */
	case INT:
		switch (size) {
		case 0:
			return (sign == UNSIGNED) ? uinttype   : inttype;
		case SHORT:
			return (sign == UNSIGNED) ? ushortype  : shortype;
		case LONG:
			return (sign == UNSIGNED) ? ulongtype  : longtype;
		case LONG+LONG:
			return (sign == UNSIGNED) ? ullongtype : llongtype;
		}
		break;
	case DOUBLE:
		if (size == LONG+LONG)
			goto invalid_type;
		size += LONG;
		goto floating;
	case FLOAT:
		if (size == LONG+LONG)
			goto invalid_type;
	floating:
		if (sign)
			goto invalid_type;
		switch (size) {
		case 0:
			return floattype;
		case LONG:
			return doubletype;
		case LONG+LONG:
			return ldoubletype;
		}
		break;
	}
	fputs("internal type error, aborting\n", stderr);
	abort();

invalid_type:
	error("invalid type specification");
}

Type *
mktype(Type *tp, uint8_t op, short nelem, void *data)
{
	static Type *typetab[NR_TYPE_HASH], **tbl, type;
	static uint8_t t;
	register Type *bp;
	static char letters[] = {
		[PTR] = L_POINTER,   [ARY] = L_ARRAY,
		[FTN] = L_FUNCTION,  [ENUM] = L_INT,
		[STRUCT] = L_STRUCT, [UNION] = L_UNION
	};

	if (op == PTR && tp == voidtype)
		return pvoidtype;

	type.type = tp;
	type.op = op;
	type.sign = 0;
	type.letter = letters[op];
	type.pars = data;
	type.n.elem = nelem;
	type.ns = 0;

	if (op == ARY && nelem == 0 || op == STRUCT || op == UNION)
		type.defined = 0;
	else
		type.defined = 1;

	t = (op ^ (uint8_t) ((unsigned short) tp >> 3)) & NR_TYPE_HASH-1;
	tbl = &typetab[t];
	for (bp = *tbl; bp; bp = bp->next) {
		if (eqtype(bp, &type))
			return bp;
	}

	bp = xmalloc(sizeof(*bp));
	*bp = type;
	bp->next = *tbl;
	return *tbl = bp;
}

bool
eqtype(Type *tp1, Type *tp2)
{
	uint8_t n;
	Type **p1, **p2;

	if (tp1 == tp2)
		return 1;
	if (tp1->op != tp2->op || tp1->n.elem != tp2->n.elem)
		return 0;
	switch (tp1->op) {
	case ARY:
	case PTR:
		return eqtype(tp1->type, tp2->type);
	case UNION:
	case STRUCT:
	case FTN:
		p1 = tp1->pars, p2 = tp2->pars;
		for (n = tp1->n.elem; n != 0; --n) {
			if (!eqtype(*p1++, *p2++))
				return 0;
		}
		return 1;
	case ENUM:
		/* TODO: Check when two enum are the same type */
	case INT: case FLOAT:
		return tp1->letter == tp2->letter;
	default:
		fputs("internal type error, aborting\n", stderr);
		abort();
	}
}