⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c01.c

📁 unix v7是最后一个广泛发布的研究型UNIX版本
💻 C
字号:
#/* * C compiler * * */#include "c0.h"/* * Called from tree, this routine takes the top 1, 2, or 3 * operands on the expression stack, makes a new node with * the operator op, and puts it on the stack. * Essentially all the work is in inserting * appropriate conversions. */build(op){	register int t1;	int t2, t;	register struct tnode *p1, *p2;	struct tnode *p3;	int dope, leftc, cvn, pcvn;	/*	 * a[i] => *(a+i)	 */	if (op==LBRACK) {		build(PLUS);		op = STAR;	}	dope = opdope[op];	if ((dope&BINARY)!=0) {		p2 = chkfun(disarray(*--cp));		t2 = p2->type;	}	p1 = *--cp;	/*	 * sizeof gets turned into a number here.	 */	if (op==SIZEOF) {		t1 = cblock(length(p1));		t1->type = UNSIGN;		*cp++ = t1;		return;	}	if (op!=AMPER) {		p1 = disarray(p1);		if (op!=CALL)			p1 = chkfun(p1);	}	t1 = p1->type;	pcvn = 0;	t = INT;	switch (op) {	case CAST:		if ((t1&XTYPE)==FUNC || (t1&XTYPE)==ARRAY)			error("Disallowed conversion");		if (t1==UNSIGN && t2==CHAR) {			t2 = INT;			p2 = block(AND,INT,NULL,NULL,p2,cblock(0377));		}		break;	/* end of expression */	case 0:		*cp++ = p1;		return;	/* no-conversion operators */	case QUEST:		if (p2->op!=COLON)			error("Illegal conditional");		else			if (fold(QUEST, p1, p2))				return;	case SEQNC:		t = t2;	case COMMA:	case LOGAND:	case LOGOR:		*cp++ = block(op, t, NULL, NULL, p1, p2);		return;	case EXCLA:		t1 = INT;		break;	case CALL:		if ((t1&XTYPE) != FUNC)			error("Call of non-function");		*cp++ = block(CALL,decref(t1),p1->subsp,p1->strp,p1,p2);		return;	case STAR:		if ((t1&XTYPE) == FUNC)			error("Illegal indirection");		*cp++ = block(STAR, decref(t1), p1->subsp, p1->strp, p1);		return;	case AMPER:		if (p1->op==NAME || p1->op==STAR) {			*cp++ = block(op,incref(t1),p1->subsp,p1->strp,p1);			return;		}		error("Illegal lvalue");		break;	/*	 * a.b goes to (&a)->b	 */	case DOT:		if (p1->op==CALL && t1==STRUCT) {			t1 = incref(t1);			setype(p1, t1, p1);		} else {			*cp++ = p1;			build(AMPER);			p1 = *--cp;		}	/*	 * In a->b, a is given the type ptr-to-structure element;	 * then the offset is added in without conversion;	 * then * is tacked on to access the member.	 */	case ARROW:		if (p2->op!=NAME || p2->tr1->hclass!=MOS) {			error("Illegal structure ref");			*cp++ = p1;			return;		}		if (t2==INT && p2->tr1->hflag&FFIELD)			t2 = UNSIGN;		t = incref(t2);		chkw(p1, -1);		setype(p1, t, p2);		*cp++ = block(PLUS,t,p2->subsp,p2->strp,p1,cblock(p2->tr1->hoffset));		build(STAR);		if (p2->tr1->hflag&FFIELD)			*cp++ = block(FSEL,UNSIGN,NULL,NULL,*--cp,p2->tr1->hstrp);		return;	}	if ((dope&LVALUE)!=0)		chklval(p1);	if ((dope&LWORD)!=0)		chkw(p1, LONG);	if ((dope&RWORD)!=0)		chkw(p2, LONG);	if ((dope&BINARY)==0) {		if (op==ITOF)			t1 = DOUBLE;		else if (op==FTOI)			t1 = INT;		if (!fold(op, p1, 0))			*cp++ = block(op,t1,p1->subsp,p1->strp,p1);		return;	}	cvn = 0;	if (t1==STRUCT || t2==STRUCT) {		if (t1!=t2 || p1->strp != p2->strp)			error("Incompatible structures");		cvn = 0;	} else		cvn = cvtab[lintyp(t1)][lintyp(t2)];	leftc = (cvn>>4)&017;	cvn =& 017;	t = leftc? t2:t1;	if ((t==INT||t==CHAR) && (t1==UNSIGN||t2==UNSIGN))		t = UNSIGN;	if (dope&ASSGOP || op==CAST) {		t = t1;		if (op==ASSIGN || op==CAST) {			if (cvn==ITP||cvn==PTI)				cvn = leftc = 0;			else if (cvn==LTP) {				if (leftc==0)					cvn = LTI;				else {					cvn = ITL;					leftc = 0;				}			}		}		if (leftc)			cvn = leftc;		leftc = 0;	} else if (op==COLON || op==MAX || op==MIN) {		if (t1>=PTR && t1==t2)			cvn = 0;		if (op!=COLON && (t1>=PTR || t2>=PTR))			op =+ MAXP-MAX;	} else if (dope&RELAT) {		if (op>=LESSEQ && (t1>=PTR||t2>=PTR||(t1==UNSIGN||t2==UNSIGN)		 && (t==INT||t==CHAR||t==UNSIGN)))			op =+ LESSEQP-LESSEQ;		if (cvn==ITP || cvn==PTI)			cvn = 0;	}	if (cvn==PTI) {		cvn = 0;		if (op==MINUS) {			t = INT;			pcvn++;		} else {			if (t1!=t2 || t1!=(PTR+CHAR))				cvn = XX;		}	}	if (cvn) {		t1 = plength(p1);		t2 = plength(p2);		if (cvn==XX || (cvn==PTI&&t1!=t2))			error("Illegal conversion");		else if (leftc)			p1 = convert(p1, t, cvn, t2);		else			p2 = convert(p2, t, cvn, t1);	}	if (dope&RELAT)		t = INT;	if (t==FLOAT)		t = DOUBLE;	if (t==CHAR)		t = INT;	if (op==CAST) {		if (t!=DOUBLE && (t!=INT || p2->type!=CHAR)) {			p2->type = t;			p2->subsp = p1->subsp;			p2->strp = p1->strp;		}		if (t==INT && p1->type==CHAR)			p2 = block(ITOC, INT, NULL, NULL, p2);		*cp++ = p2;		return;	}	if (fold(op, p1, p2)==0) {		p3 = leftc?p2:p1;		*cp++ = block(op, t, p3->subsp, p3->strp, p1, p2);	}	if (pcvn && t1!=(PTR+CHAR)) {		p1 = *--cp;		*cp++ = convert(p1, 0, PTI, plength(p1->tr1));	}}/* * Generate the appropriate conversion operator. */struct tnode *convert(p, t, cvn, len)struct tnode *p;{	register int op;	op = cvntab[cvn];	if (opdope[op]&BINARY) {		if (len==0)			error("Illegal conversion");		return(block(op, t, NULL, NULL, p, cblock(len)));	}	return(block(op, t, NULL, NULL, p));}/* * Traverse an expression tree, adjust things * so the types of things in it are consistent * with the view that its top node has * type at. * Used with structure references. */setype(ap, at, anewp)struct tnode *ap, *anewp;{	register struct tnode *p, *newp;	register t;	p = ap;	t = at;	newp = anewp;	for (;; p = p->tr1) {		p->subsp = newp->subsp;		p->strp = newp->strp;		p->type = t;		if (p->op==AMPER)			t = decref(t);		else if (p->op==STAR)			t = incref(t);		else if (p->op!=PLUS)			break;	}}/* * A mention of a function name is turned into * a pointer to that function. */struct tnode *chkfun(ap)struct tnode *ap;{	register struct tnode *p;	register int t;	p = ap;	if (((t = p->type)&XTYPE)==FUNC && p->op!=ETYPE)		return(block(AMPER,incref(t),p->subsp,p->strp,p));	return(p);}/* * A mention of an array is turned into * a pointer to the base of the array. */struct tnode *disarray(ap)struct tnode *ap;{	register int t;	register struct tnode *p;	p = ap;	/* check array & not MOS and not typer */	if (((t = p->type)&XTYPE)!=ARRAY || p->op==NAME&&p->tr1->hclass==MOS	 || p->op==ETYPE)		return(p);	p->subsp++;	*cp++ = p;	setype(p, decref(t), p);	build(AMPER);	return(*--cp);}/* * make sure that p is a ptr to a node * with type int or char or 'okt.' * okt might be nonexistent or 'long' * (e.g. for <<). */chkw(p, okt)struct tnode *p;{	register int t;	if ((t=p->type)!=INT && t<PTR && t!=CHAR && t!=UNSIGN && t!=okt)		error("Illegal type of operand");	return;}/* *'linearize' a type for looking up in the * conversion table */lintyp(t){	switch(t) {	case INT:	case CHAR:	case UNSIGN:		return(0);	case FLOAT:	case DOUBLE:		return(1);	case LONG:		return(2);	default:		return(3);	}}/* * Report an error. */error(s, p1, p2, p3, p4, p5, p6){	nerror++;	if (filename[0])		fprintf(stderr, "%s:", filename);	fprintf(stderr, "%d: ", line);	fprintf(stderr, s, p1, p2, p3, p4, p5, p6);	fprintf(stderr, "\n");}/* * Generate a node in an expression tree, * setting the operator, type, dimen/struct table ptrs, * and the operands. */struct tnode *block(op, t, subs, str, p1,p2)int *subs;struct str *str;struct tnode *p1, *p2;{	register struct tnode *p;	p = gblock(sizeof(*p));	p->op = op;	p->type = t;	p->subsp = subs;	p->strp = str;	p->tr1 = p1;	if (opdope[op]&BINARY)		p->tr2 = p2;	else		p->tr2 = NULL;	return(p);}struct tnode *nblock(ads)struct hshtab *ads;{	register struct hshtab *ds;	ds = ads;	return(block(NAME, ds->htype, ds->hsubsp, ds->hstrp, ds));}/* * Generate a block for a constant */struct cnode *cblock(v){	register struct cnode *p;	p = gblock(sizeof(*p));	p->op = CON;	p->type = INT;	p->subsp = NULL;	p->strp = NULL;	p->value = v;	return(p);}/* * A block for a float or long constant */struct fnode *fblock(t, string)char *string;{	register struct fnode *p;	p = gblock(sizeof(*p));	p->op = FCON;	p->type = t;	p->subsp = NULL;	p->strp = NULL;	p->cstr = string;	return(p);}/* * Assign a block for use in the * expression tree. */char *gblock(n){	register int *p;	p = curbase;	if ((curbase =+ n) >= coremax) {		if (sbrk(1024) == -1) {			error("Out of space");			exit(1);		}		coremax =+ 1024;	}	return(p);}/* * Check that a tree can be used as an lvalue. */chklval(ap)struct tnode *ap;{	register struct tnode *p;	p = ap;	if (p->op==FSEL)		p = p->tr1;	if (p->op!=NAME && p->op!=STAR)		error("Lvalue required");}/* * reduce some forms of `constant op constant' * to a constant.  More of this is done in the next pass * but this is used to allow constant expressions * to be used in switches and array bounds. */fold(op, ap1, ap2)struct tnode *ap1, *ap2;{	register struct tnode *p1;	register int v1, v2;	int unsignf;	p1 = ap1;	if (p1->op!=CON)		return(0);	unsignf = p1->type==UNSIGN;	if (op==QUEST) {		if (ap2->tr1->op==CON && ap2->tr2->op==CON) {			p1->value = p1->value? ap2->tr1->value: ap2->tr2->value;			*cp++ = p1;			return(1);		}		return(0);	}	if (ap2) {		if (ap2->op!=CON)			return(0);		v2 = ap2->value;		unsignf |= ap2->type==UNSIGN;	}	v1 = p1->value;	switch (op) {	case PLUS:		v1 =+ v2;		break;	case MINUS:		v1 =- v2;		break;	case TIMES:		v1 =* v2;		break;	case DIVIDE:		if (v2==0)			goto divchk;		if (unsignf) {			v1 = (unsigned)v1 / v2;			break;		}		v1 =/ v2;		break;	case MOD:		if (v2==0)			goto divchk;		if (unsignf) {			v1 = (unsigned)v1 % v2;			break;		}		v1 =% v2;		break;	case AND:		v1 =& v2;		break;	case OR:		v1 =| v2;		break;	case EXOR:		v1 =^ v2;		break;	case NEG:		v1 = - v1;		break;	case COMPL:		v1 = ~ v1;		break;	case LSHIFT:		v1 =<< v2;		break;	case RSHIFT:		if (unsignf) {			v1 = (unsigned)v1 >> v2;			break;		}		v1 =>> v2;		break;	case EQUAL:		v1 = v1==v2;		break;	case NEQUAL:		v1 = v1!=v2;		break;	case LESS:		v1 = v1<v2;		break;	case GREAT:		v1 = v1>v2;		break;	case LESSEQ:		v1 = v1<=v2;		break;	case GREATEQ:		v1 = v1>=v2;		break;	divchk:		error("Divide check");	default:		return(0);	}	p1->value = v1;	*cp++ = p1;	return(1);}/* * Compile an expression expected to have constant value, * for example an array bound or a case value. */conexp(){	register struct tnode *t;	initflg++;	if (t = tree())		if (t->op != CON)			error("Constant required");	initflg--;	curbase = funcbase;	return(t->value);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -