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

/*
 * n0/cc0.c
 * C compiler.
 * Syntax analyser mainline.
 * Impure stuff.
 */

#ifdef   vax
#include "INC$LIB:cc0.h"
#else
#include "cc0.h"
#endif
#include <path.h>

/*
 * Impure areas.
 * All external impure data is here
 * and is reinitialized by the overlaid version of the mainline.
 * This permits the compiler to be called many times if loaded as a big block.
 */
#if	!OVERLAID
int	line = 1;		/* Source line */
char	file[NFNAME];		/* Current source file name */
char	basefile[NFNAME];	/* Original source file name */
char	id[NCSYMB];		/* Identifier buffer */
FILE	*ifp;			/* Input file pointer */
FILE	*ofp;			/* Output file pointer */
VARIANT	variant;		/* Variant template */
#endif

/* Cpp variables */
char	dbuf[NDBUF];		/* Substitution buffer */
char	*dputp = dbuf;			/* Define buffer pointer */
char	*dpshp = dbuf+sizeof(dbuf);	/* Define buffer pointer */
DSTACK	dstack[NDLEV];		/* Substitution stack  */
DSTACK	*dlistp=dstack;		/* Substitution list */
DSTACK	*dstackp=dstack+NDLEV-1;	/* Input stack */
ISTACK	istack[NLEV];		/* Include stack */
ISTACK	*istackp=istack+NLEV;	/* Include stack pointer */
CSTACK	cstack[NLEV];		/* Condition stack pointer */
CSTACK	*cstackp=cstack+NLEV;	/* Condition stack pointer */
int	cstate;			/* Conditional state == true */
int	ndirs;			/* Number of include directories */
char	*incdirs[NDIRS+3];	/* Include directory list */
char	deftrue[]  = "1";
char	deffalse[] = "0";
long	curtime;		/* NB should be time_t */

int	incpp;			/* "in a cpp control" flag */
int	instring;		/* "in a string" flag */
int	notskip;		/* count of not skipped chars */
int	lastchar;		/* Last character read from a file */
int	ininit;			/* "in an initializer" flag */
int	incase;			/* "in a case" flag */
int	nargs;			/* # of args this function */
SYM	*args[NARGS];		/* The args themselves */
int	llex;			/* Lexical level */
int	lsym = SL_MOS;		/* Symbol table level */
ival_t	ival;			/* Return for lex */
lval_t	lval;			/* Return for lex */
dval_t	dval;			/* Return for lex */
short	tval;			/* Return for lex int/long constant type */
unsigned	idhash;		/* Hash number for symbol */
unsigned	idhide;		/* Hide set for symbol */
HIDESET	*hidefree, *hidesets;	/* Hide set management */
int	idsize;			/* Length of symbol */
TOK	*tfile;			/* Source file token */
TOK	*idp;			/* Hashed identifier token */
TOK	*hash0[NHASH];		/* Hash table */
int	cblab;			/* Break label */
int	cclab;			/* Continue label */
SBLOCK	*sbp;			/* Current switch block */
SYM	*cfsym;			/* Current symbol */
int     cflab;                  /* Current return label */
int	s;			/* Lexical window */

/* Externals. */
extern char *index();
extern char *getenv();

/*
 * It all starts here.
 * Open the source file.
 * Open the output stream file.
 * Put reserved words into the symbol table.
 * Parse externals until end of file.
 * Finish off the output stream and exit.
 */
#if	OVERLAID
/*
 * This is the mainline of the syntax analysis phase
 * if the compiler is being run as an overlay job.
 */
cc0(argc, argv) int argc; char *argv[];
#else
main(argc, argv) int argc; char *argv[];
#endif
{
	register char	*p;
	register int	i;
	char *argv2;

	passname = "cc0";
#if	OVERLAID
	if (setjmp(death) != 0)	{
		llex = -1;
		downlex();
		cppfinal();
		return ABORT;
	}
#if	MONOLITHIC
	/*
	 * The impure area must be reinitialized if monolithic,
	 * because the code can be called again and again.
	 */
	line   = 1;
	llex = 0;
	incpp = 0;
	instring = 0;
	notskip = 0;
	lastchar = 0;
	ininit = 0;
	incase = 0;
	cblab = 0;
	cclab = 0;
	sbp = NULL;
	cfsym = NULL;
	lsym = SL_MOS;
	ndirs = 0;
	dputp = dbuf;
	dpshp = dbuf+sizeof(dbuf);
	dstackp = dstack + NDLEV-1;
	dlistp = dstack;
	istackp = istack + NLEV;
	cstackp	= cstack + NLEV;
	cstate = 0;
#endif
#else
	if (argc < 4)
		usage();
	getvariant(argv[1]);
	if (isvariant(VCPP) && strcmp(argv[2], "-") == 0)
		ifp = stdin;
	else if ((ifp = fopen(argv[2], "r")) == NULL) {
		fprintf(stderr, "%s: cannot open.\n", argv[2]);
		exit(BAD);
	}
	if (isvariant(VCPP)) {
		if (strcmp(argv[3], "-") == 0)
			ofp = stdout;
		else if ((ofp = fopen(argv[3], "w")) == NULL) {
			fprintf(stderr, "%s: cannot create.\n", argv[3]);
			exit(BAD);
		}
	} else if ((ofp=fopen(argv[3], SWMODE)) == NULL) {
		fprintf(stderr, "%s: cannot create.\n", argv[3]);
		exit(BAD);
	}
#endif
	argv2 = new(strlen(argv[2]) + 1);
	strcpy(argv2, argv[2]);		/* impure copy for source directory */
	vinit();
	kinit();
	time(&curtime);
	newtree(sizeof(TREE));

	/* Wired-in cpp definitions. */
	cppd(MACHINE, deftrue);
	cppd(SYSTEM, deftrue);
	cppd(LOCATION, deftrue);
	cppd(FPFORMAT, deftrue);
	/* And again, this time ISO-compliant versions for nigel. */
	cppd("_"  MACHINE  "__", deftrue);	/* NB MACHINE has leading '_' */
	cppd("__" SYSTEM   "__", deftrue);
	cppd("__" LOCATION "__", deftrue);
	cppd("_"  FPFORMAT "__", deftrue);	/* NB FPFORMAT has leading '_' */

	cppi(argv2);			/* source directory will be parsed later */
	for (i=4; i<argc; ++i) {
		if (argv[i][0] != '-')
			break;
		switch (argv[i][1]) {
		case 'I':	cppi(argv[i]+2);	break;
		case 'U':	cppu(argv[i]+2);	break;
		case 'D':
			if (p = index(argv[i]+2, '=')) {
				*p = '\0';
				cppd(argv[i]+2, p+1);
				*p = '=';
				break;
			} else {
				cppd(argv[i]+2, deftrue);
				break;
			}
		default:
#if	OVERLAID
			cbotch("cpp args");
#else
			usage();
#endif
		}
	}
	if ((p = getenv("INCDIR")) == 0)
		p = DEFDISK;
	cppi(p);
	cppi(argv2);		/* second copy of source directory */
	setid(argv2);
	setfname();
	strncpy(basefile, idp->t_id, NFNAME);	/* save again for __BASE_FILE__ */
	/* Now parse the source file directory */
	i = 0;
	for (p = argv2; *p != 0; p += 1)
		if (*p == PATHSEP)
			i = p-argv2;
	argv2[i] = '\0';
	emptyfilep();
	if (notvariant(VCPP)) {
		dbfname(file);
		setmname();
		labgen = 0;
		oldseg = -1;
		while (lex() != EOF)
			xdef();
		llex = -1;
		downlex();
		bput(FINISH);
	} else
		cppwork();
	free(argv2);
#if	OVERLAID
	cppfinal();
	return (nerr != 0) ? BAD : OK;
#else
	exit (nerr != 0) ? BAD : OK;
#endif
}

#if	!OVERLAID
/*
 * Print usage message.
 */
usage()
{
	fprintf(stderr,
	"Usage: cc0 variant in out [-Dname[=value]] [-Idirectory] [-Uname]\n"
	);
	exit(BAD);
}
#endif

#if	OVERLAID
cppfinal()
{
	register SYM *sp, **spp;
	register int i, flag;
	register TOK **tpp, *tp;

	/* Clean up malloc'ed TOK and SYM symbol table entries. */
	for (i = 0; i < NHASH; ++i) {
		for (tpp = &hash0[i]; (tp = *tpp) != NULL; ) {
			flag = 0;
			for (spp = &tp->t_sym; (sp = *spp) != NULL; ) {
				flag = (sp->s_slevel == SL_CPP
				     && (sp->s_value == XUSER || sp->s_value == XUSERA));
				if (flag) {
					*spp = sp->s_sp;
					free(sp);
				} else
					spp = &sp->s_sp;
			}
			if (flag) {
				*tpp = tp->t_tp;
				free(tp);
			} else
				tpp = &tp->t_tp;
		}
		hash0[i] = NULL;
	}
	freetree();		/* free tree pool */
	freehide();		/* clean up hide sets */
}
#endif

/*
 * Given the file name token in idp,
 * inform the usual parties of the change.
 */
setfname()
{
	tfile = idp;
	strncpy(file, idp->t_id, NFNAME);
	if (notvariant(VCPP)) {
		bput(FNAME);
		sput(file);
	} else if (notvariant(VCPPE))
		fprintf(ofp, "#line %d \"%s\"\n", line, file);
}

/*
 * Given a file name string,
 * make up the associated module name.
 * And then send it on it's way.
 * This routine is tinkered for UDI, DEC systems, MS-DOS
 * and for the Coherent-like systems.
 * Of course, the MNAME item is pointless
 * to all systems except .omf, but we do
 * it anyway.
 * NB, id[] is used as a buffer
 * to construct the module name.
 */
setmname()
{
	register char *tp, *p1, *p2;

	tp = id;
	p1 = file;
	while (*p1 != 0)
		++p1;
	p2 = p1;
	while (p1>file
	    && (p1[-1]!=':' && p1[-1]!='/' && p1[-1]!=']' && p1[-1]!='\\'))
		--p1;
	while (p2>p1 && p2[0]!='.')
		--p2;
	while (p1 < p2)
		*tp++ = *p1++;
	*tp = 0;
	bput(MNAME);
	sput(id);
}

/*
 * Process an external declaration.
 * On entry, 's' contains the first token of the external.
 * On exit, 's' contains the last token in the declaration.
 */
xdef()
{
	register SYM	*sp;
	SYM		*nsp;
	DIM		*dp, *ndp;
	INFO		*ip;
	int		c;
	int		t;
	int		rf;
	int		seg;

	if (s == SEMI)
		return;
	gcandt(&c, &t, &dp, &ip, &rf);
	if (c == C_NONE)
		c = C_GDEF;
	else if (c == C_SIN)
		c = C_SEX;
	else if (c!=C_GREF && c!=C_TYPE) {
		cerror("bad external storage class");
		c = C_GDEF;
	}
	if (s == SEMI) {
		xdropinfo(t, ip);
		return;
	}
	if (t == T_NONE)
		t = T_INT;
	for (;;) {
		nargs = 0;
		if (!gdecl(&nsp, &ndp, dp, c, SL_VAR)) {
			cerror("external syntax");
			while (s!=EOF && s!=SEMI && s!=LBRACE && s!=RBRACE)
				skip();
			if (s == LBRACE)
				statement();
			break;
		}
		sp = nsp;
		sp = declare(sp, c, t, ndp, ip, rf);
		if (c!=C_GREF && sp->s_class!=C_GREF && sp->s_class!=C_TYPE) {
			if (isfunc(sp)) {
				xfunc(sp);
				break;
			}
			seg = SPURE;
			if (s==EOF || s==COMMA || s==SEMI) {
				if ((rf&S_RONLY) == 0)
					seg = SBSS;
				sp->s_seg = seg;
				if (isvariant(VCOMM)
				 && sp->s_class == C_GDEF
				 && seg == SBSS) {
					sp->s_class = C_GREF;
					bput(COMM);
					nput(sp->s_id);
				} else {
					newseg(seg);
					align(sp);
					xlabel(sp);
					bput(BLOCK);
				}
				zput(ssize(sp));
			} else {
				if ((rf&S_RONLY) == 0)
					seg = SDATA;
				sp->s_seg = seg;
				newseg(seg);
				align(sp);
				xlabel(sp);
				/*
				 * The following gives a warning rather than an
				 * error (over steve's objection) so programs
				 * using old style initializers e.g. "int i 1;"
				 * will compile; see K&R "Anachronisms" p. 212.
				 */
				if (s != ASSIGN)
					cwarn("missing '='");
				else
					lex();
				init(sp, sp->s_dp, (sizeof_t)0, 1);
			}
			dbdecl(sp);
		}
		if (s != COMMA) {
			if (s != SEMI) {
				if (c==C_TYPE)
					cerror("illegal typedef");
				else
					cerror("missing semicolon");
			}
			break;
		}
		lex();
	}
	xdropinfo(t, ip);
}

/*
 * Test if the symbol pointed to by 'sp' is a function.
 */
isfunc(sp)
SYM	*sp;
{
	register DIM	*dp;

	return ((dp=sp->s_dp)!=NULL && dp->d_type==D_FUNC);
}

/*
 * Compile a function.
 * 'sp' points at the symbol table node for the function name.
 * 's' is the first token after the function declaration.
 */
xfunc(sp)
register SYM	*sp;
{
	register SYM	*fsp;
	SYM		*nfsp;
	DIM		*dp, *fdp;
	INFO		*ip;
	int		c;
	int		t;
	int		rf;
	int		fline;

	fline = line;
	for (;;) {
		gcandt(&c, &t, &dp, &ip, &rf);
		if (c==C_NONE && t==T_NONE)
			break;
		if (c == C_NONE)
			c = C_PAUTO;
		else if (c == C_REG)
			c = C_PREG;
		else {
			cerror("bad argument storage class");
			c = C_PAUTO;
		}
		if (t == T_NONE)
			t = T_INT;
		for (;;) {
			if (gdecl(&nfsp, &fdp, dp, c, SL_VAR)) {
				fsp = nfsp;
				fsp = declare(fsp, c, t, fdp, ip, rf);
			}
			if (s != COMMA)
				break;
			lex();
		}
		xdropinfo(t, ip);
		mustbe(SEMI);
	}
	initlocals();
	bindargs();
	newseg(SCODE);
	sp->s_seg = SCODE;
	xlabel(sp);
	bput(PROLOG);
	loadargs();
	dbdecl(sp);
	dbargs();
	dbstat(LBRACE, line);
	cfsym = sp;
	cflab = newlab();
	if (s != LBRACE)
		cerror("compound statement required");
	else
		lex();
	llex = LL_AUTO;
	locals();
	putautos();
	while (s!=EOF && s!=RBRACE)
		statement();
	if (s != RBRACE)
		cerror("missing right brace");
	llex = LL_EXT;
	downlex();
	label(cflab);
	dbstat(RBRACE, line);
	bput(EPILOG);
	cfsym = NULL;
}

/*
 * Emit an external label.
 */
xlabel(sp)
register SYM	*sp;
{
	bput((sp->s_class==C_GDEF) ? GLABEL : SLABEL);
	nput(sp->s_id);
}

/*
 * Conditionally drop a structure information block.
 * Sometimes a non null info pointer is a symbol table pointer!
 */
xdropinfo(t, ip)
register int	t;
register INFO	*ip;
{
	if (t==T_FSTRUCT || t==T_FUNION || t==T_FENUM)
		return;
	dropinfo(ip);
}

/* end of n0/cc0.c */

unix.superglobalmegacorp.com

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