Exemple #1
0
Fichier : parse.c Projet : xtao/c
static Node *
mkunop(SrcPos *p, int op, Node *o)
{
	Node *n;
	
	n = mknode(NUNOP, p);
	n->Unop.op = op;
	switch(op) {
	case '&':
		if(!islval(o))
			errorposf(&o->pos, "& expects an lvalue");
		n->type = mkptr(o->type);
		break;
	case '*':
		if(!isptr(o->type))
			errorposf(&o->pos, "cannot deref non pointer");
		n->type = o->type->Ptr.subty;
		break;
	default:
		o = ipromote(o);
		n->type = o->type;
		break;
	}
	n->Unop.operand = o;
	return n;
}
Exemple #2
0
Fichier : parse.c Projet : xtao/c
static Node *
decl()
{
	Node   *n, *init;
	char   *name;
	CTy    *type, *basety;
	SrcPos *pos;
	Sym    *sym;
	Vec    *syms;
	int     sclass;

	pos = &tok->pos;
	syms  = vec();
	basety = declspecs(&sclass);
	while(tok->k != ';' && tok->k != TOKEOF) {
		type = declarator(basety, &name, &init);
		switch(sclass){
		case SCNONE:
			if(isglobal()) {
				sclass = SCGLOBAL;
			} else {
				sclass = SCAUTO;
			}
			break;
		case SCTYPEDEF:
			if(init)
				errorposf(pos, "typedef cannot have an initializer");
			break;
		}
		if(!name)
			errorposf(pos, "decl needs to specify a name");
		sym = definesym(pos, sclass, name, type, init);
		vecappend(syms, sym);
		if(isglobal() && tok->k == '{') {
			if(init)
				errorposf(pos, "function declaration has an initializer");
			if(type->t != CFUNC)
				errorposf(pos, "expected a function");
			curfunc = mknode(NFUNC, pos);
			curfunc->type = type;
			curfunc->Func.name = name;
			curfunc->Func.params = vec();
			curfunc->Func.stkslots = vec();
			fbody();
			definesym(pos, sclass, name, type, curfunc);
			curfunc = 0;
			goto done;
		}
		if(tok->k == ',')
			next();
		else
			break;
	}
	expect(';');
  done:
	n = mknode(NDECL, pos);
	n->Decl.syms = syms;
	return n;
}
Exemple #3
0
Fichier : parse.c Projet : xtao/c
/* Declarator is what introduces names into the program. */
static CTy *
declarator(CTy *basety, char **name, Node **init) 
{
	CTy *t;

	while (tok->k == TOKCONST || tok->k == TOKVOLATILE)
		next();
	switch(tok->k) {
	case '*':
		next();
		basety = mkptr(basety);
		t = declarator(basety, name, init);
		return t;
	default:
		t = directdeclarator(basety, name);
		if(tok->k == '=') {
			if(!init)
				errorposf(&tok->pos, "unexpected initializer");
			next();
			*init = declinit();
		} else {
			if(init)
				*init = 0;
		}
		return t; 
	}

}
Exemple #4
0
Fichier : parse.c Projet : xtao/c
static void
fbody(void)
{
	Node   *gotofixup;
	int     i;
	char   *l;
	NameTy *nt;
	Sym    *sym;

	pushscope();
	labels = map();
	gotos = vec();
	for(i = 0; i < curfunc->type->Func.params->len; i++) {
		nt = vecget(curfunc->type->Func.params, i);
		if(nt->name) {
			sym = definesym(&curfunc->pos, SCAUTO, nt->name, nt->type, 0);
			vecappend(curfunc->Func.params, sym);
		}
	}
	curfunc->Func.body = block();
	popscope();
	for(i = 0 ; i < gotos->len ; i++) {
		gotofixup = vecget(gotos, i);
		l = mapget(labels, gotofixup->Goto.name);
		if(!l)
			errorposf(&gotofixup->pos, "goto target does not exist");
		gotofixup->Goto.l = l;
	}
}
Exemple #5
0
Fichier : parse.c Projet : xtao/c
static void
params(CTy *fty)
{
	int     sclass;
	CTy    *t;
	char   *name;
	SrcPos *pos;

	fty->Func.isvararg = 0;
	if(tok->k == ')')
		return;
	for(;;) {
		pos = &tok->pos;
		t = declspecs(&sclass);
		t = declarator(t, &name, 0);
		if(sclass != SCNONE)
			errorposf(pos, "storage class not allowed in parameter decl");
		vecappend(fty->Func.params, newnamety(name, t));
		if(tok->k != ',')
			break;
		next();
	}
	if(tok->k == TOKELLIPSIS) {
		fty->Func.isvararg = 1;
		next();
	}
}
Exemple #6
0
Fichier : parse.c Projet : xtao/c
static CTy *
directdeclarator(CTy *basety, char **name) 
{
	CTy *ty, *stub;

	*name = 0;
	switch(tok->k) {
	case '(':
		expect('(');
		stub = gcmalloc(sizeof(CTy));
		*stub = *basety;
		ty = declarator(stub, name, 0);
		expect(')');
		*stub = *declaratortail(basety);
		return ty;
	case TOKIDENT:
		if(name)
			*name = tok->v;
		next();
		return declaratortail(basety);
	default:
		if(!name)
			errorposf(&tok->pos, "expected ident or ( but got %s", tokktostr(tok->k));
		return declaratortail(basety);
	}
	errorf("unreachable");
	return 0;
}
Exemple #7
0
Fichier : emit.c Projet : a8m/c
static void
call(Node *n)
{
	int i, nargs, nintargs, cleanup;
	Vec  *args;
	Node *arg;

	args = n->Call.args;
	i = nargs = args->len;
	/* Push args in reverse order */
	while(i-- != 0) {
		arg = vecget(args, i);
		if(!isitype(arg->type) && !isptr(arg->type) && !isarray(arg->type) && !isfunc(arg->type))
			errorposf(&arg->pos, "unimplemented arg type\n");
		expr(arg);
		pushq("rax");
	}
	nintargs = nargs;
	if(nintargs > 6)
		nintargs = 6;
	for(i = 0; i < nintargs; i++)
		popq(intargregs[i]);
	expr(n->Call.funclike);
	outi("call *%%rax\n");
	cleanup = 8 * (nargs - nintargs);
	if(cleanup) {
		outi("add $%d, %%rsp\n", cleanup);
		stackoffset -= cleanup;
	}
}
Exemple #8
0
Fichier : parse.c Projet : xtao/c
static void
expect(int kind) 
{
	if(tok->k != kind)
		errorposf(&tok->pos,"expected %s, got %s", 
			tokktostr(kind), tokktostr(tok->k));
	next();
}
Exemple #9
0
Fichier : parse.c Projet : xtao/c
static CTy *
declaratortail(CTy *basety)
{
	SrcPos *p;
	CTy    *t, *newt;
	Const  *c;
	
	t = basety;
	for(;;) {
		c = 0;
		switch (tok->k) {
		case '[':
			newt = newtype(CARR);
			newt->Arr.subty = t;
			newt->Arr.dim = -1;
			next();
			if(tok->k != ']') {
				p = &tok->pos;
				c = constexpr();
				if(c->p)
					errorposf(p, "pointer derived constant in array size");
				newt->Arr.dim = c->v;
				newt->size = newt->Arr.dim * newt->Arr.subty->size;
			}
			newt->align = newt->Arr.subty->align;
			expect(']');
			t = newt;
			break;
		case '(':
			newt = newtype(CFUNC);
			newt->Func.rtype = basety;
			newt->Func.params = vec();
			next();
			params(newt);
			if(tok->k != ')')
				errorposf(&tok->pos, "expected valid parameter or )");
			next();
			t = newt;
			break;
		default:
			return t;
		}
	}
Exemple #10
0
Fichier : parse.c Projet : xtao/c
static Node *
mkincdec(SrcPos *p, int op, int post, Node *operand)
{
	Node *n;

	if(!islval(operand))
		errorposf(&operand->pos, "++ and -- expects an lvalue");
	n = mknode(NINCDEC, p);
	n->Incdec.op = op;
	n->Incdec.post = post;
	n->Incdec.operand = operand;
	n->type = operand->type;
	return n;
}
Exemple #11
0
Fichier : emit.c Projet : a8m/c
static void
data(Data *d)
{
	InitMember *initmemb;
	int   i, offset;
	char *l;
	
	if(!d->init) {
		out(".comm %s, %d, %d\n", d->label, d->type->size, d->type->align);
		return;
	}
	if(d->isglobal)
		out(".globl %s\n", d->label);
	out("%s:\n", d->label);
	
	if(ischararray(d->type))
	if(d->init->t == NSTR) {
		out(".string %s\n", d->init->Str.v);
		return;
	}
	
	if(ischarptr(d->type))
	if(d->init->t == NSTR) {
		l = newlabel();
		out(".quad %s\n", l);
		out("%s:\n", l);
		out(".string %s\n", d->init->Str.v);
		return;
	}
	if(isitype(d->type) || isptr(d->type)) {
		itypedata(d->init);
		return;
	}
	if(isarray(d->type) || isstruct(d->type)) {
		if(d->init->t != NINIT)
			errorposf(&d->init->pos, "array/struct expects a '{' style initializer");
		offset = 0;
		for(i = 0; i < d->init->Init.inits->len ; i++) {
			initmemb = vecget(d->init->Init.inits, i);
			if(initmemb->offset != offset)
				out(".fill %d, 1, 0\n", initmemb->offset - offset);
			itypedata(initmemb->n);
			offset = initmemb->offset + initmemb->n->type->size;
		}
		if(offset < d->type->size)
			out(".fill %d, 1, 0\n", d->type->size - offset);
		return;
	}
	panic("internal error");
}
Exemple #12
0
Fichier : emit.c Projet : a8m/c
static void
ereturn(Node *r)
{
	CTy *ty;
	
	if(r->Return.expr) {
		ty = r->Return.expr->type;
		if(!isitype(ty) && !isptr(ty))
			errorposf(&r->pos, "unimplemented return type");
		expr(r->Return.expr);
	}
	/* No need to cleanup with leave */
	outi("leave\n");
	outi("ret\n");
}
Exemple #13
0
Fichier : parse.c Projet : xtao/c
static Node *
ipromote(Node *n)
{
	if(!isitype(n->type))
		errorposf(&n->pos, "internal error - ipromote expects itype got %d", n->type->t);
	switch(n->type->Prim.type) {
	case PRIMCHAR:
	case PRIMSHORT:
		if(n->type->Prim.issigned)
			return mkcast(&n->pos, n, cint);
		else
			return mkcast(&n->pos, n, cuint);
	}
	return n;
}
Exemple #14
0
Fichier : parse.c Projet : xtao/c
static Sym *
defineenum(SrcPos *p, char *name, CTy *type, int64 v)
{
	Sym *sym;

	sym = gcmalloc(sizeof(Sym));
	sym->pos = p;
	sym->name = name;
	sym->type = type;
	sym->k = SYMENUM;
	sym->Enum.v = v;
	if(!define(syms, name, sym))
		errorposf(p, "redefinition of %s", name);
	return sym;
}
Exemple #15
0
Fichier : emit.c Projet : a8m/c
static void
func(Node *f, char *label, int isglobal)
{
	Vec *v;
	Sym *sym;
	int  i;
	
	calcslotoffsets(f);
	out("\n");
	out(".text\n");
	out("# function %s\n", f->Func.name);
	if(isglobal)
		out(".globl %s\n", label);
	out("%s:\n", label);
	pushq("rbp");
	outi("movq %%rsp, %%rbp\n");
	if(f->type->Func.isvararg) {
		stackoffset += 176;
		outi("sub $176, %%rsp\n");
		outi("movq %%rdi, (%%rsp)\n");
		outi("movq %%rsi, 8(%%rsp)\n");
		outi("movq %%rdx, 16(%%rsp)\n");
		outi("movq %%rcx, 24(%%rsp)\n");
		outi("movq %%r8, 32(%%rsp)\n");
		outi("movq %%r9, 40(%%rsp)\n");
	}
	if(f->Func.localsz) {
		outi("sub $%d, %%rsp\n", f->Func.localsz);
		stackoffset += f->Func.localsz;
	}
	v = f->Func.params;
	for(i = 0; i < v->len; i++) {
		sym = vecget(v, i);
		if(!isitype(sym->type) && !isptr(sym->type) && !isarray(sym->type))
			errorposf(&f->pos, "unimplemented arg type");
		if(i < 6) {
			outi("movq %%%s, %d(%%rbp)\n", intargregs[i], sym->Local.slot->offset);
		} else {
			outi("movq %d(%%rbp), %%rcx\n", 16 + 8 * (i - 6));
			outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset);
			store(sym->type);
		}
	}
	block(f->Func.body);
	outi("leave\n");
	outi("ret\n");
}
Exemple #16
0
Fichier : emit.c Projet : a8m/c
static void
itypedata(Node *prim)
{
	Const *c;

	if(!isitype(prim->type) && !isptr(prim->type))
		panic("internal error %d");
	c = foldexpr(prim);
	if(!c)
		errorposf(&prim->pos, "not a constant expression");
	if(c->p) {
		switch(prim->type->size) {
		case 8:
			out(".quad %s + %d\n", c->p, c->v);
			return;
		case 4:
			out(".long %s + %d\n", c->p, c->v);
			return;
		case 2:
			out(".short %s + %d\n", c->p, c->v);
			return;
		case 1:
			out(".byte %s + %d\n", c->p, c->v);
			return;
		default:
			panic("unimplemented");
		}
	}
	switch(prim->type->size) {
	case 8:
		out(".quad %d\n", c->v);
		return;
	case 4:
		out(".long %d\n", c->v);
		return;
	case 2:
		out(".short %d\n", c->v);
		return;
	case 1:
		out(".byte %d\n", c->v);
		return;
	default:
		panic("unimplemented");
	}
	panic("internal error");
}
Exemple #17
0
Fichier : parse.c Projet : xtao/c
static Node *
mkassign(SrcPos *p, int op, Node *l, Node *r)
{
	Node *n;
	CTy  *t;

	if(!islval(l))
		errorposf(&l->pos, "assign expects an lvalue");
	r = mkcast(p, r, l->type);
	t = l->type;
	n = mknode(NASSIGN, p);
	switch(op) {
	case '=':
		n->Assign.op = '=';
		break;
	case TOKADDASS:
		n->Assign.op = '+';
		break;
	case TOKSUBASS:
		n->Assign.op = '-';
		break;
	case TOKORASS:
		n->Assign.op = '|';
		break;
	case TOKANDASS:
		n->Assign.op = '&';
		break;
	case TOKMULASS:
		n->Assign.op = '*';
		break;
	default:
		panic("mkassign");
	}
	n->Assign.l = l;
	n->Assign.r = r;
	n->type = t;
	return n;
}
Exemple #18
0
static void
directive()
{
	Tok  *t;
	char *dir;

	t = ppnoexpand();
	dir = t->v;
	if(strcmp(dir, "include") == 0)
		include();
	else if(strcmp(dir, "define")  == 0)
		define();
	else if(strcmp(dir, "if")  == 0)
		pif();
	else if(strcmp(dir, "elseif")  == 0)
		elseif();
	else if(strcmp(dir, "else")  == 0)
		pelse();
	else if(strcmp(dir, "endif")  == 0)
		endif();
	else
		errorposf(&t->pos, "invalid directive %s", dir);
}
Exemple #19
0
Fichier : types.c Projet : xtao/c
void
addstructmember(SrcPos *pos, CTy *t, char *name, CTy *membt)
{
	StructMember *sm, *subsm;
	int i, align, sz;

	sm = gcmalloc(sizeof(StructMember));
	sm->name = name;
	sm->type = membt;
	if(!isstruct(t))
		panic("internal error");
	if(sm->name == 0 && isstruct(sm->type)) {
		for(i = 0; i < sm->type->Struct.members->len; i++) {
			subsm = vecget(sm->type->Struct.members, i);
			addstructmember(pos, t, subsm->name, subsm->type);
		}
		return;
	}
	if(sm->name) {
		for(i = 0; i < t->Struct.members->len; i++) {
			subsm = vecget(t->Struct.members, i);
			if(subsm->name)
			if(strcmp(sm->name, subsm->name) == 0)
				errorposf(pos ,"struct already has a member named %s", sm->name);
		}
	}
	if(membt->align < t->align)
		t->align = membt->align;
	sz = t->size;
	align = membt->align;
	if(sz % align)
		sz = sz + align - (sz % align);
	sm->offset = sz;
	sz += sm->type->size;
	t->size = sz;
	vecappend(t->Struct.members, sm);
}
Exemple #20
0
Fichier : parse.c Projet : xtao/c
static Sym *
definesym(SrcPos *p, int sclass, char *name, CTy *type, Node *n)
{
	Sym *sym;

	if(sclass == SCAUTO || n != 0)
		if(type->incomplete)
			errorposf(p, "cannot use incomplete type in this context");
	if(sclass == SCAUTO && isglobal())
		errorposf(p, "defining local symbol in global scope");
	sym = mapget(syms[nscopes - 1], name);
	if(sym) {
		switch(sym->k) {
		case SYMTYPE:
			if(sclass != SCTYPEDEF || !sametype(sym->type, type))
				errorposf(p, "incompatible redefinition of typedef %s", name);
			break;
		case SYMGLOBAL:
			if(sym->Global.sclass != sclass)
				errorposf(p, "redefinition of %s with differing storage class", name);
			if(sym->init && n)
				errorposf(p, "%s already initialized", name);
			if(!sym->init && n) {
				sym->init = n;
				emitsym(sym);
				removetentativesym(sym);
			}
			break;
		default:
			errorposf(p, "redefinition of %s", name);
		}
		return sym;
	}
	sym = gcmalloc(sizeof(Sym));
	sym->name = name;
	sym->type = type;
	sym->init = n;
	switch(sclass) {
	case SCAUTO:
		sym->k = SYMLOCAL;
		sym->Local.slot = gcmalloc(sizeof(StkSlot));
		sym->Local.slot->size = sym->type->size;
		sym->Local.slot->align = sym->type->align;
		vecappend(curfunc->Func.stkslots, sym->Local.slot);
		break;
	case SCTYPEDEF:
		sym->k = SYMTYPE;
		break;
	case SCGLOBAL:
		sym->k = SYMGLOBAL;
		sym->Global.label = name;
		sym->Global.sclass = SCGLOBAL;
		break;
	case SCSTATIC:
		sym->k = SYMGLOBAL;
		sym->Global.label = newlabel();
		sym->Global.sclass = SCSTATIC;
		break;
	}
	if(sym->k == SYMGLOBAL) {
		if(sym->init)
			emitsym(sym);
		else
			if(!isfunc(sym->type))
				addtentativesym(sym);
	}
	if(!define(syms, name, sym))
		panic("internal error");
	return sym;
}
Exemple #21
0
Fichier : emit.c Projet : a8m/c
static void
expr(Node *n)
{
	switch(n->t){
	case NCOMMA:
		comma(n);
		break;
	case NCAST:
		cast(n);
		break;
	case NSTR:
		str(n);
		break;
	case NSIZEOF:
		outi("movq $%lld, %%rax\n", n->Sizeof.type->size);
		break;
	case NNUM:
		outi("movq $%lld, %%rax\n", n->Num.v);
		break;
	case NIDENT:
		ident(n);
		break;
	case NUNOP:
		unop(n);
		break;
	case NASSIGN:
		assign(n);
		break;
	case NBINOP:
		binop(n);
		break;
	case NIDX:
		idx(n);
		break;
	case NSEL:
		sel(n);
		break;
	case NCOND:
		cond(n);
		break;
	case NCALL:
		call(n);
		break;
	case NPTRADD:
		ptradd(n);
		break;
	case NINCDEC:
		incdec(n);
		break;
	case NBUILTIN:
		switch(n->Builtin.t) {
		case BUILTIN_VASTART:
			vastart(n);
			break;
		default:
			errorposf(&n->pos, "unimplemented builtin");
		}
		break;
	default:
		errorf("unimplemented emit expr %d\n", n->t);
	}
}
Exemple #22
0
Fichier : parse.c Projet : xtao/c
static CTy *
declspecs(int *sclass)
{
	CTy    *t;
	SrcPos *pos;
	Sym    *sym;
	int     bits;

	enum {
		BITCHAR = 1<<0,
		BITSHORT = 1<<1,
		BITINT = 1<<2,
		BITLONG = 1<<3,
		BITLONGLONG = 1<<4,
		BITSIGNED = 1<<5,
		BITUNSIGNED = 1<<6,
		BITFLOAT = 1<<7,
		BITDOUBLE = 1<<8,
		BITENUM = 1<<9,
		BITSTRUCT = 1<<10,
		BITVOID = 1<<11,
		BITIDENT = 1<<12,
	};

	t = 0;
	bits = 0;
	pos = &tok->pos;
	*sclass = SCNONE;

	for(;;) {
		if(issclasstok(tok)) {
			if(*sclass != SCNONE)
				errorposf(pos, "multiple storage classes in declaration specifiers.");
			switch(tok->k) {
			case TOKEXTERN:
				*sclass = SCEXTERN;
				break;
			case TOKSTATIC:
				*sclass = SCSTATIC;
				break;
			case TOKREGISTER:
				*sclass = SCREGISTER;
				break;
			case TOKAUTO:
				*sclass = SCAUTO;
				break;
			case TOKTYPEDEF:
				*sclass = SCTYPEDEF;
				break;
			default:
				panic("internal error");
			}
			next();
			continue;
		}
		switch(tok->k) {
		case TOKCONST:
		case TOKVOLATILE:
			next();
			break;
		case TOKSTRUCT:
		case TOKUNION:
			if(bits)
				goto err;
			bits |= BITSTRUCT;
			t = ptag();
			goto done;
		case TOKENUM:
			if(bits)
				goto err;
			bits |= BITENUM;
			t = ptag();
			goto done;
		case TOKVOID:
			if(bits&BITVOID)
				goto err;
			bits |= BITVOID;
			next();
			goto done;
		case TOKCHAR:
			if(bits&BITCHAR)
				goto err;
			bits |= BITCHAR;
			next();
			break;
		case TOKSHORT:
			if(bits&BITSHORT)
				goto err;
			bits |= BITSHORT;
			next();
			break;
		case TOKINT:
			if(bits&BITINT)
				goto err;
			bits |= BITINT;
			next();
			break;
		case TOKLONG:
			if(bits&BITLONGLONG)
				goto err;
			if(bits&BITLONG) {
				bits &= ~BITLONG;
				bits |= BITLONGLONG;
			} else {
				bits |= BITLONG;
			}
			next();
			break;
		case TOKFLOAT:
			if(bits&BITFLOAT)
				goto err;
			bits |= BITFLOAT;
			next();
			break;
		case TOKDOUBLE:
			if(bits&BITDOUBLE)
				goto err;
			bits |= BITDOUBLE;
			next();
			break;
		case TOKSIGNED:
			if(bits&BITSIGNED)
				goto err;
			bits |= BITSIGNED;
			next();
			break;
		case TOKUNSIGNED:
			if(bits&BITUNSIGNED)
				goto err;
			bits |= BITUNSIGNED;
			next();
			break;
		case TOKIDENT:
			sym = lookup(syms, tok->v);
			if(sym && sym->k == SYMTYPE)
				t = sym->type;
			if(t && !bits) {
				bits |= BITIDENT;
				next();
				goto done;
			}
			/* fallthrough */
		default:
			goto done;
		}
	}
	done:
	switch(bits){
	case BITFLOAT:
		return cfloat;
	case BITDOUBLE:
		return cdouble;
	case BITLONG|BITDOUBLE:
		return cldouble;
	case BITSIGNED|BITCHAR:
	case BITCHAR:
		return cchar;
	case BITUNSIGNED|BITCHAR:
		return cuchar;
	case BITSIGNED|BITSHORT|BITINT:
	case BITSHORT|BITINT:
	case BITSHORT:
		return cshort;
	case BITUNSIGNED|BITSHORT|BITINT:
	case BITUNSIGNED|BITSHORT:
		return cushort;
	case BITSIGNED|BITINT:
	case BITSIGNED:
	case BITINT:
	case 0:
		return cint;
	case BITUNSIGNED|BITINT:
	case BITUNSIGNED:
		return cuint;
	case BITSIGNED|BITLONG|BITINT:
	case BITSIGNED|BITLONG:
	case BITLONG|BITINT:
	case BITLONG:
		return clong;
	case BITUNSIGNED|BITLONG|BITINT:
	case BITUNSIGNED|BITLONG:
		return culong;
	case BITSIGNED|BITLONGLONG|BITINT:
	case BITSIGNED|BITLONGLONG:
	case BITLONGLONG|BITINT:
	case BITLONGLONG:
		return cllong;
	case BITUNSIGNED|BITLONGLONG|BITINT:
	case BITUNSIGNED|BITLONGLONG:
		return cullong;
	case BITVOID:
		t = cvoid;
		return t;
	case BITENUM:
	case BITSTRUCT:
	case BITIDENT:
		return t;
	default:
		goto err;
	}
	err:
	errorposf(pos, "invalid declaration specifiers");
	return 0;
}