File:  [MW Coherent from dump] / coherent / d / bin / cc / c / n0 / stat.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * C compiler.
 * Statement compilation.
 * The routines in this file compile C statements.
 * This file also contains a number of small routines that are
 * only used by the statement compilation code.
 * This is the new VAX/VMS base version.
 */
#ifdef   vax
#include "INC$LIB:cc0.h"
#else
#include "cc0.h"
#endif

/*
 * Compile one statement.
 * On entry, 's' contains the first symbol of the new statement.
 * On exit, 's' contains the first token beyond the end of the statement.
 */
statement()
{
	register TREE	*tp;
	register int	lab1, lab2;
	TREE 		*lp, *rp;
	TREE 		*itree, *ctree, *stree;
	SBLOCK		*ssbp;
	int 		i, sclab, sblab, tt;
	ival_t		v;

loop:
	dbstat(s, line);
	switch (s) {

	case EOF:
		cerror("unexpected end of file");
		break;

	case SEMI:
		lex();
		break;

	case LBRACE:
		lex();
		savelocals();
		++llex;
		locals();
		putautos();
		while (s!=EOF && s!=RBRACE)
			statement();
		mustbe(RBRACE);
		--llex;
		downlex();
		dbstat(RBRACE, line);
		restlocals();
		break;

	case BREAK:
		lex();
		if (cblab == 0)
			cerror("break not in a loop");
		jump(cblab);
		mustbe(SEMI);
		break;

	case CONTINUE:
		lex();
		if (cclab == 0)
			cerror("continue not in a loop");
		jump(cclab);
		mustbe(SEMI);
		break;

	case CASE:
		lex();
		newtree(sizeof(TREE));
		++incase;
		v = iconexpr();
		--incase;
		mustbe(COLON);
		if (sbp == NULL)
			cerror("case not in a switch");
		else
			newcase(v);
		goto loop;

	case DEFAULT:
		lex();
		mustbe(COLON);
		if (sbp == NULL)
			cerror("default label not in a switch");
		else {
			if (sbp->sb_dlab != 0)
				cerror("only one default label allowed");
			sbp->sb_dlab = here();
		}
		goto loop;

	case GOTO:
		lex();
		if (s != ID) {
			cerror("missing label name in goto");
			skip();
		} else {
			dogoto();
			lex();
			mustbe(SEMI);
		}
		break;

	case IF:
		lex();
		tp = pexpr();
		truth(tp);
		tput(FEXPR, lab1=newlab(), tp);
		statement();
		if (s == ELSE) {
			lab2 = newlab();
			jump(lab2);
			label(lab1);
			lex();
			statement();
			label(lab2);
			break;
		}
		label(lab1);
		break;

	case DO:
		sblab = cblab;
		sclab = cclab;
		cblab = newlab();
		cclab = newlab();
		lab1 = here();
		lex();
		statement();
		label(cclab);
		dbstat(s, line);
		mustbe(WHILE);
		tp = pexpr();
		truth(tp);
		tput(TEXPR, lab1, tp);
		label(cblab);
		mustbe(SEMI);
		cclab = sclab;
		cblab = sblab;
		break;

	case WHILE:
		sblab = cblab;
		sclab = cclab;
		cblab = newlab();
		cclab = here();
		lex();
		tp = pexpr();
		truth(tp);
		tput(FEXPR, cblab, tp);
		statement();
		jump(cclab);
		label(cblab);
		cclab = sclab;
		cblab = sblab;
		break;

	case SWITCH:
		lex();
		tp = pexpr();
		tt = tltype(tp);
		if (tt > T_UINT)
			cerror("switch of non integer");
		if (tt != T_INT) {
			rp = NULL;
			if (tt == T_PTR)
				rp = bzcon(psize(tp));
			tp = bconvert(tp, T_INT, NULL, NULL, rp);
		}
		tput(SEXPR, 0, tp);
		ssbp = sbp;
		sbp = (SBLOCK *) new(sizeof(SBLOCK));
		sbp->sb_dlab = 0;
		sbp->sb_ncase = 0;
		sblab = cblab;
		cblab = newlab();
		statement();
		jump(cblab);
		if (sbp->sb_dlab==0 && sbp->sb_ncase==0)
			cwarn("empty switch");
		if (sbp->sb_dlab == 0)
			sbp->sb_dlab = cblab;
		bput(SBODY);
		iput((ival_t) sbp->sb_dlab);
		iput((ival_t) sbp->sb_ncase);
		for (i=0; i<sbp->sb_ncase; ++i) {
			iput((ival_t) sbp->sb_case[i].sc_val);
			iput((ival_t) sbp->sb_case[i].sc_lab);
		}
		label(cblab);
		cblab = sblab;
		free((char *) sbp);
		sbp = ssbp;
		break;

	case FOR:
		lex();
		mustbe(LPAREN);
		newtree(sizeof(TREE));
		itree = NULL;
		if (s != SEMI)
			itree = expr();
		mustbe(SEMI);
		ctree = NULL;
		if (s != SEMI) {
			ctree = expr();
			truth(ctree);
		}
		mustbe(SEMI);
		stree = NULL;
		if (s != RPAREN)
			stree = expr();
		mustbe(RPAREN);
		sblab = cblab;
		sclab = cclab;
		cblab = newlab();
		cclab = newlab();
		if (itree != NULL) {
			tput(EEXPR, 0, itree);
		}
		if (stree != NULL)
			jump(lab1 = newlab());
		label(cclab);
		if (stree != NULL) {
			tput(EEXPR, 0, stree);
			label(lab1);
		}
		if (ctree != NULL) {
			tput(FEXPR, cblab, ctree);
		}
		statement();
		jump(cclab);
		label(cblab);
		cclab = sclab;
		cblab = sblab;
		break;

	case RETURN:
		lex();
		if (s != SEMI) {
			newtree(sizeof(TREE));
			tp = expr();
			lp = talloc();
			lp->t_op   = CONVERT;
			lp->t_type = cfsym->s_type;
			lp->t_dp   = cfsym->s_dp->d_dp;  /* Skip D_FUNC */
			lp->t_ip   = cfsym->s_ip;
			if (lp->t_dp==NULL && lp->t_type==T_VOID) {
				cerror("return(e) illegal in void function");
				mustbe(SEMI);
				break;
			}
			if ((tltype(lp)==T_STRUCT || tltype(tp)==T_STRUCT)
			   && (lp->t_type!=tp->t_type||lp->t_dp!=tp->t_dp||lp->t_ip!=tp->t_ip)) {
				cerror("return type/function type mismatch");
				mustbe(SEMI);
				break;
			}
			if (bitcompat(tltype(lp), tltype(tp)))
				adjust(tp, lp->t_type, lp->t_dp, lp->t_ip);
			else {
				lp->t_lp = tp;
				tp = lp;
			}
			tput(REXPR, 0, tp);
		}
		jump(cflab);
		mustbe(SEMI);
		break;

	case ID:
		if (spnextis(':')) {
			dolabel();
			lex();
			lex();
			goto loop;
		}

	default:
		newtree(sizeof(TREE));
		tp = expr();
		tput(EEXPR, 0, tp);
		mustbe(SEMI);
	}
}

/*
 * Check if the given tree can be used in a truth value context.
 * Put out the appropriate diagnostics.
 * What does this have to do with stat()?
 */
truth(tp)
TREE	*tp;
{
	register int	tt, op;

	tt = tltype(tp);
	op = tp->t_op;
	if (tt>=T_STRUCT && tt<=T_FUNION)
		cerror("structure or union used in truth context");
	if (incpp)
		return;
	if (isvariant(VSCCON) && (op==ICON || op==LCON || op==DCON))
		cstrict("constant used in truth context");
	if (isvariant(VSRTVC)) {
		if ((tt>=T_PTR && tt<=T_DOUBLE)
		 || (op==EQ && tp->t_lp->t_type==T_DOUBLE))
			cstrict("risky type in truth context");
	}
}

/*
 * Read an expression enclosed in parentheses.
 * Used to read the control expressions in 'if', 'do', 'while' and 'switch'.
 */
TREE *
pexpr()
{
	register TREE	*tp;

	mustbe(LPAREN);
	newtree(sizeof(TREE));
	tp = expr();
	mustbe(RPAREN);
	return (tp);
}

/*
 * Labels.
 */
dolabel()
{
	register SYM	*sp;
	register int	c;

	sp = deflookup(SL_LAB, 2);
	c  = sp->s_class;
	if (c==C_NONE || c==C_FREF) {
		if (c == C_NONE)
			sp->s_value = newlab();
		sp->s_class = C_LAB;
		label(sp->s_value);
		dblabel(sp);
	} else
		cerror("illegal label \"%s\"", sp->s_id);
}

/*
 * The dreaded 'goto' statement.
 */
dogoto()
{
	register SYM	*sp;
	register int	c;

	sp = deflookup(SL_LAB, 2);
	c  = sp->s_class;
	if (c == C_NONE) {
		sp->s_class = C_FREF;
		sp->s_value = newlab();
	} else if (c!=C_LAB && c!=C_FREF)
		cerror("identifier \"%s\" is not a label", sp->s_id);
	jump(sp->s_value);
	sp->s_flag |= S_USED;
}

/*
 * Append a new case to the current switch,
 * adjusting the size of the switch block if necessary and possible.
 */
newcase(v)
ival_t	v;
{
	SBLOCK *ssbp;
	register SCASE *scp, *ocp;
	register int i;

	i = sbp->sb_ncase;
	scp = sbp->sb_case;
	while (--i >= 0) {
		if (scp->sc_val == v) {
			cerror("duplicated case constant");
			return;
		} else
			scp += 1;
	}
	i = sbp->sb_ncase;
	scp = &sbp->sb_case[i];
	if ((i % 32) == 0) {
		ssbp = sbp;
		sbp = new(sizeof(SBLOCK) + (i+32) * sizeof(SCASE));
		sbp->sb_ncase = ssbp->sb_ncase;
		sbp->sb_dlab = ssbp->sb_dlab;
		scp = sbp->sb_case;
		ocp = ssbp->sb_case;
		while (--i >= 0) {
			scp->sc_val = ocp->sc_val;
			scp->sc_lab = ocp->sc_lab;
			scp += 1;
			ocp += 1;
		}
		free((char *) ssbp);
		scp = &sbp->sb_case[sbp->sb_ncase];
	}
	scp->sc_val = v;
	scp->sc_lab = here();
	sbp->sb_ncase += 1;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.