File:  [MW Coherent from dump] / coherent / d / bin / cc / c / n0 / expand.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 preprocessor.
 * Macro expansion.
 */
#include <time.h>
#ifdef   vax
#include "INC$LIB:cc0.h"
#else
#include "cc0.h"
#endif

/*
 * Expand the string as an actual parameter.
 * This happens after the list of strings
 * in the substituted macro has been pushed
 * onto dstack; expand the string as if it
 * formed the rest of the source file and
 * substitute the expanded string back into
 * the source stream, with the hidden sets of
 * identifiers augmented by the macro name we
 * are substituting.
 */
char *argexpand(hide, p) int hide; char *p;
{
	register char *ap, *spshp;
	register int c;

	/* Push the parameter as input */
	dspush(DS_IEOF, NULL);
	dspush(DS_STRNG, p);
	/* Save the push buffer */
	spshp = dpshp;
	/* Scan the parameter as input */
	while ((c = get()) >= 0) {
		switch (ct[c]) {
		case QUOTE:
		case STRING:
			dpshstr(c);
			continue;
		case DOT:
		case CON:
			dpshnum(c);
			continue;
		case ID:
			if (expand(c))
				continue;
			dpshs(id);
			/* Augment hidden set */
			dpshc(hideaug(hide, idhide));
			continue;
		default:
			dpshc(c);
			continue;
		}
	}
	++dstackp;			/* pop IEOF */
	/* Now pop the expanded string off the push buffer */
	/* and onto the put buffer */
	p = dputp;
	for (ap = spshp; --ap >= dpshp; )
		dputc(*ap);
	dputc(0);
	/* Restore push buffer pointer */
	dpshp = spshp;
	/* Return pointer to expanded argument */
	return p;
}

/*
 * Scan and augment the hidden sets in a string.
 * An in place copy in essence.
 */
char *argpaste(hide, p) int hide; char *p;
{
	register int c;
	char *sputp;
	sputp = dputp;
	dputp = p;
	dspush(DS_IEOF, NULL);
	dspush(DS_STRNG, p);
	while ((c = get()) >= 0) {
		switch (ct[c]) {
		case QUOTE:
		case STRING:
			dputstr(c);
			continue;
		case DOT:
		case CON:
			dputnum(c);
			continue;
		case ID:
			getid(c);
			dputs(id);
			/* Augment hidden set */
			dputc(hideaug(hide, idhide));
			continue;
		default:
			dputc(c);
			continue;
		}
	}
	++dstackp;
	dputp = sputp;
	return p;
}


/*
 * Substitute for the macro specified.
 * Collect the actual parameters into the push buffer,
 * then reverse them onto the put buffer.
 * (Collecting the parameters may pop the dstackp.)
 * Then parse the macro body into the put buffer,
 * forming a list of literal strings
 * (with their hidden sets augmented),
 * # parameters, ## parameters, and
 * vanilla parameters.
 * Then scan the list pushed and
 * recursively expand the vanilla
 * parameters with argexpand(),
 * expanding each parameter only once
 * no matter how many times it appears
 * in the substituted body.
 * Then rescan the list pushed again
 * to augment the hidden sets of ## params.
 */
substitute(tp, sp) TOK *tp; CPPSYM *sp;
{
	register int c, d;
	register int narg, plev;
	register char *p, *pp;
	register DSTACK *dsp;
	DSTACK *dparamp, *dbodyp, *dbasep;
	char *cparamp;
	int tpidhide;

	/* Install hide set index */
	tpidhide = hideset(tp);

	/* Collect parameters */
	dparamp = dlistp;
	cparamp = dpshp;
	if (sp->s_value == XUSERA) {
		c = getskip();
		for (narg = 0; c >= 0 && c != ')'; narg += 1) {
			plev = 0; p = dpshp;
			while (c >= 0) {
				switch (ct[c]) {
				case QUOTE:
				case STRING:
					dpshstr(c); c = get(); continue;
				case LPAREN:
					plev++; break;
				case COMMA:
					if (!plev) goto next; break;
				case RPAREN:
					if (!plev) goto next; plev--; break;
				case SKIP:
					unget(getskip()); c = ' '; break;
				case ID:
					getid(c); dpshs(id); dpshc(idhide);
					c = get(); continue;
				case DOT:
				case CON:
					dpshnum(c); c = get(); continue;
				}
				dpshc(c); c = get();
			}
		next:	if (narg < sp->s_narg) {
				if (dpshp < p && dpshp[0] == ' ')
					++dpshp;
				dpshc(0);
				dslist(DS_PARAM, p);
			}
			if (c == ',')
				c = getskip();
		}
		if (c < 0) {
			cerror("EOF in macro \"%s\" invocation", tp->t_id);
			tp = NULL;
		}
		if (sp->s_narg != narg) {
			cerror("\"%s\" argument mismatch", tp->t_id);
			tp = NULL;
		}
		if (tp == NULL) {
			dlistp = dparamp;
			dpshp = cparamp;
			return 1;
		}
	}
	/* Copy the parameter strings onto the top of dbuf */
	dpshp = cparamp;
	cparamp = dputp;
	for (dsp = dparamp+sp->s_narg; --dsp >= dparamp; ) {
		p = dsp->ds_ptr;
		dsp->ds_ptr = dputp;
		while (d = *--p) dputc(d);
		dputc(d);
	}
	/* Copy the macro body into dbuf */
	dbodyp = dlistp;
	dspush(DS_IEOF, 0);
	dspush(DS_STRNG, sp->s_body);
	p = dputp;
	dsp = dparamp;
	while ((c = get()) >= 0) {
		switch (ct[c]) {
		case QUOTE:
		case STRING:
			dputstr(c); continue;
		case ID:
			getid(c);
			dputs(id);
			dputc(hideaug(tpidhide, idhide));
			continue;
		case CON:
		case DOT:
			dputnum(c); continue;
		default:
			dputc(c); continue;
		case HIGH0:		/* param */
			c -= ARG0;
			pp = dsp[c].ds_ptr;
			if (p != dputp) {
				dputc(0);
				dslist(DS_STRNG, p);
				p = dputp;
			}
			c = get();
			d = get();
			unget(d);
			unget(c);
			if (c == '#' && d == '#')
				dslist(DS_SHARP2, pp);
			else
				dslist(DS_PARAM, pp);
			continue;
		case SHARP:		/* # or ## */
			c = get();
			if (ct[c] == HIGH0) {
				c -= ARG0;
				pp = dsp[c].ds_ptr;
				if (p != dputp) {
					dputc(0);
					dslist(DS_STRNG, p);
					p = dputp;
				}
				dslistc(DS_UNGET, '"');
				dslist(DS_SHARP, pp);
				dslistc(DS_UNGET, '"');
				continue;
			}
			c = get();
			if (ct[c] == HIGH0) {
				c -= ARG0;
				pp = dsp[c].ds_ptr;
				if (p != dputp) {
					dputc(0);
					dslist(DS_STRNG, p);
					p = dputp;
				}
				dslist(DS_SHARP2, pp);
				continue;
			}
			unget(c);
			continue;
		}
	}
	if (p != dputp) {
		dputc(0);
		dslist(DS_STRNG, p);
		p = dputp;
	}
	++dstackp;	/* Pop IEOF */
	dbasep = dstackp;
	dspush(DS_NAME, tp);
	dspush(DS_DPUTP, cparamp);
	while (--dlistp >= dbodyp)
		*--dstackp = *dlistp;
	dlistp = dparamp;
	/* Expand parameters and augment their hidden sets */
	for (dsp = dstackp; dsp < dbasep; dsp += 1) {
		if (dsp->ds_type == DS_PARAM) {
			p = argexpand(tpidhide, pp = dsp->ds_ptr);
			/* Now make all references to pp */
			/* refer to the expanded version p */
			for (dparamp = dsp; dsp < dbasep; dsp += 1)
				if (dsp->ds_type == DS_PARAM
				 && dsp->ds_ptr == pp) {
					dsp->ds_type = DS_STRNG;
					dsp->ds_ptr = p;
				}
			dsp = dparamp;
		}
	}
	/* Now scan for glued parameters and augment their hidden sets */
	/* Done in a separate loop since ##param might appear before */
	/* param itself in the substitution list, and they both refer */
	/* to the same copy of the parameter in dbuf before argexpand */
	for (dsp = dstackp; dsp < dbasep; dsp += 1) {
		if (dsp->ds_type == DS_SHARP2) {
			p = argpaste(tpidhide, pp = dsp->ds_ptr);
			for (dparamp = dsp; dsp < dbasep; dsp += 1)
				if (dsp->ds_type == DS_SHARP2
				 && dsp->ds_ptr == pp) {
					dsp->ds_type = DS_STRNG;
					dsp->ds_ptr = p;
				}
			dsp = dparamp;
		}
	}
	return 1;
}

/*
 * Try macro expansion,
 * return true if it happened.
 * Read id[] starting with 'c'
 * and see if it is defined.
 * Since this is called for each
 * identifier read, it should use
 * minimal registers and defer most
 * processing to subfunctions.
 */
expand(c) register int c;
{
	char *p;
	CPPSYM *sp;
	TOK *tp;
	extern char *ctime();
	static char lineno[16];

	getid(c);
	tp = idp;
	if ((sp=idp->t_sym) == NULL
	 || sp->s_slevel != SL_CPP
	 || hidden()) {
 none_such:	if (incpp > 1) {	/* Parsing a #if expression */
			dspush(DS_STRNG, deffalse);
			return 1;
		}
		return 0;
	}

	switch (sp->s_value) {
	case XUSER:
		return substitute(tp, sp);
	case XUFILE:
		unget('"');
		dspush(DS_UFILE, file);
		unget('"');
		return 1;
	case XULINE:
		dspush(DS_STRNG, lineno);
		sprintf(lineno, "%d", line);
		return 1;
	case XUDATE:
	case XUTIME:
		p = ctime(&curtime);
		if (sp->s_value == XUDATE) {
			p[24] = 0;
			strcpy(p+11, p+20);
			p += 4;
		} else {
			p[19] = 0;
			p += 11;
		}
		unget('"');
		dspush(DS_STRNG, p);
		unget('"');
		return 1;
	case XUSTDC:
		dspush(DS_STRNG, deffalse);
		return 1;
	case XDEFINED:
		if (incpp < 2)
			return 0;
		if ((c = getnb()) == '(') {
			if ((c = getnb()) < 0 || ct[c] != ID)
				goto bad;
			getid(c);
			if ((c = getnb()) != ')')
				goto bad;
		} else if (ct[c] == ID)
			getid(c);
		else {
	bad:		cerror("illegal use of defined");
			dspush(DS_STRNG, deffalse);
			return 1;
		}
		tp = idp;
		if ((sp = tp->t_sym) != NULL
		 && sp->s_slevel == SL_CPP
		 && ! hidden())
			dspush(DS_STRNG, deftrue);
		else
			dspush(DS_STRNG, deffalse);
		return 1;
	case XUSERA:
		if (skipto('('))
			return substitute(tp, sp);
		goto none_such;
	default:
		cbotch("value %d in expand", sp->s_value);
	}
	return 0;
}


unix.superglobalmegacorp.com

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