shithub: scc

ref: 627efdb4af18c26fa5707e247fc276837cfed3db
dir: /decl.c/

View raw version
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "sizes.h"
#include "cc.h"
#include "tokens.h"
#include "syntax.h"
#include "symbol.h"

int8_t forbid_eof;

struct dcldata {
	uint8_t op;
	union {
		unsigned short nelem;
		struct symbol *sym;
		struct funpars *pars;
		uint8_t qlf;
	} u;
};

static struct dcldata
	*declarator0(struct dcldata *dp, uint8_t ns, int8_t flags);

static struct dcldata *
arydcl(struct dcldata *dp)
{
	expect('[');
	expect(']');
	if (dp->op == 255)
		error("too much declarators");
	dp->u.nelem = 0;
	dp->op = ARY;
	return dp + 1;
}

static struct dcldata *
fundcl(struct dcldata *dp)
{
	expect('(');
	expect(')');;
	if (dp->op == 255)
		error("too much declarators");
	dp->op = FTN;
	dp->u.pars = NULL;
	return dp + 1;
}

static struct dcldata*
directdcl(struct dcldata *dp, uint8_t ns, int8_t flags)
{
	register struct symbol *sym;
	char *err;

	if (accept('(')) {
		dp = declarator0(dp, ns, flags);
		expect(')');
	} else if (flags) {
		if (yytoken != IDEN) {
			if (flags > 0)
				goto expected;
			sym = install(NULL, ns);
		} else {
			sym = lookup(yytext, ns);
			if (sym && sym->ctx == curctx)
				goto redeclared;
			sym = install(yytext, ns);
			next();
		}
		dp->op = IDEN;
		dp->u.sym = sym;
		++dp;
	}

	for (;;) {
		switch (yytoken) {
		case '(':  dp = fundcl(dp); break;
		case '[':  dp = arydcl(dp); break;
		default:   return dp;
		}
	}

redeclared:
	err = "redeclaration of '%s'";
	goto error;
expected:
	err = "expected '(' or identifier before of '%s'";
error:	error(err, yytext);
}

static struct dcldata*
declarator0(struct dcldata *dp, uint8_t ns, int8_t flags)
{
	uint8_t buffer[NR_DECLARATORS];
	register uint8_t *bp, n, qlf;

	bp = buffer;
	for (n = 0; accept('*'); ++n) {
		if (n == NR_DECLARATORS)
			goto too_much_declarators;
		qlf = 0;
		if (yytoken == TQUALIFIER) {
			qlf |= yylval.sym->u.c;
			next();
		}
		*bp++ = qlf;
	}

	dp = directdcl(dp, ns, flags);

	bp = buffer;
	while (n--) {
		if (dp->op == 255)
			goto too_much_declarators;
		dp->op = PTR;
		dp->u.qlf = *bp++;
		++dp;
	}

	return dp;

too_much_declarators:
	error("too much declarators");
}

static struct symbol *
declarator(struct ctype *tp, uint8_t ns, int8_t flags)
{
	struct dcldata data[NR_DECLARATORS+1];
	register struct dcldata *bp;
	struct symbol *sym;

	data[NR_DECLARATORS].op = 255;
	for (bp = declarator0(data, ns, flags); bp >= data; --bp) {
		switch (bp->op) {
		case PTR:
			tp = qualifier(mktype(tp, PTR, NULL, 0), bp->u.qlf);
			break;
		case ARY:
			tp = mktype(tp, ARY, NULL, bp->u.nelem);
			break;
		case FTN:
			tp = mktype(tp, FTN, NULL, 0);
			break;
		case IDEN:
			sym = bp->u.sym;
			break;
		}
	}
	sym->type = tp;
	return sym;
}

static struct ctype *structdcl(uint8_t tag), *enumdcl(uint8_t tag);

static struct ctype *
specifier(int8_t *sclass)
{
	struct ctype *tp = NULL;
	int8_t qlf, sign, type, cls, cplex, size, t;

	qlf = sign = type = cls = size = cplex = 0;

	for (;;) {
		register uint8_t *p;
		struct symbol *sym = yylval.sym;

		switch (yytoken) {
		case SCLASS: p = &cls; break;
		case TQUALIFIER:
			if ((qlf |= sym->u.c) & RESTRICT)
				goto invalid_type;
			goto next_token;
		case TYPE:
			switch (sym->u.c) {
			case ENUM: case STRUCT: case UNION:
				t = sym->u.c;
				tp = (t == UNION) ? enumdcl(t) : structdcl(t);
				p = &type;
				goto check_spec;
			case TYPENAME:
				tp = yylval.sym->type;
			case VOID:   case BOOL:  case CHAR:
			case INT:    case FLOAT: case DOUBLE:
				p = &type; goto next_token;
			case SIGNED: case UNSIGNED:
				p = &sign; break;
			case LONG:
				if (size == LONG) {
					size = LONG+LONG;
					goto next_token;
				}
			case SHORT:
				p = &size; goto next_token;
			case COMPLEX: case IMAGINARY:
				p = &cplex; goto next_token;
			}
			break;
		default:
			goto check_types;
		}
next_token:	next();
check_spec:	if (*p)
			goto invalid_type;
		*p = sym->u.c;
	}

check_types:
	if (!type) {
		if (!sign && !size) {
			warn(options.implicit,
			     "type defaults to 'int' in declaration");
		}
		type = INT;
	}
	if (sign && type != INT && type != CHAR ||
	    cplex && type != FLOAT && type != DOUBLE ||
	    size == SHORT && type != INT ||
	    size == LONG  && type != INT && type != DOUBLE ||
	    size == LONG+LONG && type != INT) {
		goto invalid_type;
	}
	if (sclass)
		*sclass = cls;
	if (!tp)
		tp = ctype(type, sign, size, cplex);
	return (qlf) ? qualifier(tp, qlf) : tp;

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

static struct node *
initializer(register struct ctype *tp)
{
	if (accept('{')) {
		initializer(tp);
		expect('}');
	} else {
		do {
			expr();
		} while (accept(','));
	}
}

/* TODO: add define for the 3 parameter of declarator */
/* TODO: bitfields */
static short
fielddcl(uint8_t ns, uint8_t type)
{
	struct ctype *tp;
	struct symbol *sym;
	short offset = 0, size;

	switch (yytoken) {
	case IDEN:
		warn(options.implicit,
		     "type defaults to 'int' in declaration");
		tp = inttype;
		break;
	case SCLASS:
		error("storage class '%s' in struct/union field", yytext);
	case TYPE: case TQUALIFIER:
		tp = specifier(NULL);
		break;
	case ';':
		break;
	default:
		error("declaration expected");
	}

	if (yytoken != ';') {
		do {
			sym = declarator(tp, ns, 1);
			sym->u.offset = offset;
			size = sym->type->size;
			if (type == STRUCT)
				offset += size;
			else if (offset < size)
				offset = size;
		} while (accept(','));
	}

	expect(';');
	return offset;
}

static struct ctype *
structdcl(uint8_t tag)
{
	register struct symbol *sym;
	struct ctype *tp;
	short size;
	extern uint8_t namespace;

	next();
	if (yytoken == IDEN) {
		sym = lookup(yytext, NS_TAG);
		if (sym) {
			if (sym->type->op != tag)
				goto bad_tag;
		} else {
			sym = install(yytext, NS_TAG);
		}
		next();
	} else {
		sym = install(NULL, NS_TAG);
	}
	sym->type = tp = mktype(NULL, STRUCT, NULL, 0);
	++namespace;

	if (yytoken != ';') {
		expect('{');
		while (!accept('}'))
			size = fielddcl(namespace, tag);
	} else {
		size = 0;
	}
	tp->size = size;

	return tp;

bad_tag:
	error("error '%s' defined as wrong kind of tag", yytext);
}

static struct ctype *
enumdcl(uint8_t token)
{
	return NULL;
}

struct node *
decl(void)
{
	struct ctype *tp;
	struct symbol *sym;
	int8_t sclass;

	tp = specifier(&sclass);
	if (yytoken != ';') {
		do {
			 sym = declarator(tp, NS_IDEN, 1);
			/* assign storage class */
			if (accept('='))
				initializer(sym->type);
		} while (accept(','));
	}

	expect(';');
	return NULL;
}

struct node *
typename(void)
{
	declarator(specifier(NULL), NS_IDEN, -1)->type;
	return  NULL;
}

struct node *
extdecl(void)
{
	struct ctype *tp;
	int8_t sclass;
	struct symbol *sym;
	extern struct symbol *curfun;

	forbid_eof = 1;

	switch (yytoken) {
	case IDEN:
		warn(options.implicit,
		     "type defaults to 'int' in declaration");
		tp = inttype;
		break;
	case TYPE: case SCLASS: case TQUALIFIER:
		tp = specifier(&sclass);
		if (sclass == REGISTER || sclass == AUTO)
			error("incorrect storage class for file-scope declaration");
		break;
	case ';':
		break;
	default:
		error("declaration expected");
	}

	if (yytoken != ';') {
		do {
			extern void printtype(struct ctype *tp);
			sym = declarator(tp, NS_IDEN, 1);
			printtype(sym->type);
			/* assign storage class */
			if (isfun(sym)) {
				if (yytoken == '{') {
					curfun = sym;
					context(function);
					freesyms(NS_LABEL);
				}
			} else if (accept('=')) {
				initializer(sym->type);
			}
		} while (accept(','));
	}

	forbid_eof = 0;
	expect(';');
	return NULL;
}