| #include "e.h" | 
 | #include "y.tab.h" | 
 | #include <ctype.h> | 
 |  | 
 | Infile	infile[10]; | 
 | Infile	*curfile = infile; | 
 |  | 
 | #define	MAXSRC	50 | 
 | Src	src[MAXSRC];	/* input source stack */ | 
 | Src	*srcp	= src; | 
 |  | 
 | extern int getarg(char *); | 
 | extern	void eprint(void); | 
 |  | 
 | void pushsrc(int type, char *ptr)	/* new input source */ | 
 | { | 
 | 	if (++srcp >= src + MAXSRC) | 
 | 		ERROR "inputs nested too deep" FATAL; | 
 | 	srcp->type = type; | 
 | 	srcp->sp = ptr; | 
 | 	if (dbg > 1) { | 
 | 		printf("\n%3ld ", (long)(srcp - src)); | 
 | 		switch (srcp->type) { | 
 | 		case File: | 
 | 			printf("push file %s\n", ((Infile *)ptr)->fname); | 
 | 			break; | 
 | 		case Macro: | 
 | 			printf("push macro <%s>\n", ptr); | 
 | 			break; | 
 | 		case Char: | 
 | 			printf("push char <%c>\n", *ptr); | 
 | 			break; | 
 | 		case String: | 
 | 			printf("push string <%s>\n", ptr); | 
 | 			break; | 
 | 		case Free: | 
 | 			printf("push free <%s>\n", ptr); | 
 | 			break; | 
 | 		default: | 
 | 			ERROR "pushed bad type %d\n", srcp->type FATAL; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | void popsrc(void)	/* restore an old one */ | 
 | { | 
 | 	if (srcp <= src) | 
 | 		ERROR "too many inputs popped" FATAL; | 
 | 	if (dbg > 1) { | 
 | 		printf("%3ld ", (long)(srcp - src)); | 
 | 		switch (srcp->type) { | 
 | 		case File: | 
 | 			printf("pop file\n"); | 
 | 			break; | 
 | 		case Macro: | 
 | 			printf("pop macro\n"); | 
 | 			break; | 
 | 		case Char: | 
 | 			printf("pop char <%c>\n", *srcp->sp); | 
 | 			break; | 
 | 		case String: | 
 | 			printf("pop string\n"); | 
 | 			break; | 
 | 		case Free: | 
 | 			printf("pop free\n"); | 
 | 			break; | 
 | 		default: | 
 | 			ERROR "pop weird input %d\n", srcp->type FATAL; | 
 | 		} | 
 | 	} | 
 | 	srcp--; | 
 | } | 
 |  | 
 | Arg	args[10];	/* argument frames */ | 
 | Arg	*argfp = args;	/* frame pointer */ | 
 | int	argcnt;		/* number of arguments seen so far */ | 
 |  | 
 | void dodef(tbl *stp)	/* collect args and switch input to defn */ | 
 | { | 
 | 	int i, len; | 
 | 	char *p; | 
 | 	Arg *ap; | 
 |  | 
 | 	ap = argfp+1; | 
 | 	if (ap >= args+10) | 
 | 		ERROR "more than arguments\n" FATAL; | 
 | 	argcnt = 0; | 
 | 	if (input() != '(') | 
 | 		ERROR "disaster in dodef\n"FATAL; | 
 | 	if (ap->argval == 0) | 
 | 		ap->argval = malloc(1000); | 
 | 	for (p = ap->argval; (len = getarg(p)) != -1; p += len) { | 
 | 		ap->argstk[argcnt++] = p; | 
 | 		if (input() == ')') | 
 | 			break; | 
 | 	} | 
 | 	for (i = argcnt; i < MAXARGS; i++) | 
 | 		ap->argstk[i] = ""; | 
 | 	if (dbg) | 
 | 		for (i = 0; i < argcnt; i++) | 
 | 			printf("arg %ld.%d = <%s>\n", (long)(ap-args), i+1, ap->argstk[i]); | 
 | 	argfp = ap; | 
 | 	pushsrc(Macro, stp->cval); | 
 | } | 
 |  | 
 | int | 
 | getarg(char *p)	/* pick up single argument, store in p, return length */ | 
 | { | 
 | 	int n, c, npar; | 
 |  | 
 | 	n = npar = 0; | 
 | 	for ( ;; ) { | 
 | 		c = input(); | 
 | 		if (c == EOF) | 
 | 			ERROR "end of file in getarg!\n" FATAL; | 
 | 		if (npar == 0 && (c == ',' || c == ')')) | 
 | 			break; | 
 | 		if (c == '"')	/* copy quoted stuff intact */ | 
 | 			do { | 
 | 				*p++ = c; | 
 | 				n++; | 
 | 			} while ((c = input()) != '"' && c != EOF); | 
 | 		else if (c == '(') | 
 | 			npar++; | 
 | 		else if (c == ')') | 
 | 			npar--; | 
 | 		n++; | 
 | 		*p++ = c; | 
 | 	} | 
 | 	*p = 0; | 
 | 	unput(c); | 
 | 	return(n + 1); | 
 | } | 
 |  | 
 | #define	PBSIZE	2000 | 
 | char	pbuf[PBSIZE];		/* pushback buffer */ | 
 | char	*pb	= pbuf-1;	/* next pushed back character */ | 
 |  | 
 | char	ebuf[200];		/* collect input here for error reporting */ | 
 | char	*ep	= ebuf; | 
 |  | 
 | int | 
 | input(void) | 
 | { | 
 | 	register int c = 0; | 
 |  | 
 |   loop: | 
 | 	switch (srcp->type) { | 
 | 	case File: | 
 | 		c = getc(curfile->fin); | 
 | 		if (c == EOF) { | 
 | 			if (curfile == infile) | 
 | 				break; | 
 | 			if (curfile->fin != stdin) { | 
 | 				fclose(curfile->fin); | 
 | 				free(curfile->fname);	/* assumes allocated */ | 
 | 			} | 
 | 			curfile--; | 
 | 			printf(".lf %d %s\n", curfile->lineno, curfile->fname); | 
 | 			popsrc(); | 
 | 			goto loop; | 
 | 		} | 
 | 		if (c == '\n') | 
 | 			curfile->lineno++; | 
 | 		break; | 
 | 	case Char: | 
 | 		if (pb >= pbuf) { | 
 | 			c = *pb--; | 
 | 			popsrc(); | 
 | 			break; | 
 | 		} else {	/* can't happen? */ | 
 | 			popsrc(); | 
 | 			goto loop; | 
 | 		} | 
 | 	case String: | 
 | 		c = *srcp->sp++; | 
 | 		if (c == '\0') { | 
 | 			popsrc(); | 
 | 			goto loop; | 
 | 		} else { | 
 | 			if (*srcp->sp == '\0')	/* empty, so pop */ | 
 | 				popsrc(); | 
 | 			break; | 
 | 		} | 
 | 	case Macro: | 
 | 		c = *srcp->sp++; | 
 | 		if (c == '\0') { | 
 | 			if (--argfp < args) | 
 | 				ERROR "argfp underflow" FATAL; | 
 | 			popsrc(); | 
 | 			goto loop; | 
 | 		} else if (c == '$' && isdigit((unsigned char)*srcp->sp)) { | 
 | 			int n = 0; | 
 | 			while (isdigit((unsigned char)*srcp->sp)) | 
 | 				n = 10 * n + *srcp->sp++ - '0'; | 
 | 			if (n > 0 && n <= MAXARGS) | 
 | 				pushsrc(String, argfp->argstk[n-1]); | 
 | 			goto loop; | 
 | 		} | 
 | 		break; | 
 | 	case Free:	/* free string */ | 
 | 		free(srcp->sp); | 
 | 		popsrc(); | 
 | 		goto loop; | 
 | 	} | 
 | 	if (ep >= ebuf + sizeof ebuf) | 
 | 		ep = ebuf; | 
 | 	*ep++ = c; | 
 | 	return c; | 
 | } | 
 |  | 
 | int | 
 | unput(int c) | 
 | { | 
 | 	if (++pb >= pbuf + sizeof pbuf) | 
 | 		ERROR "pushback overflow\n"FATAL; | 
 | 	if (--ep < ebuf) | 
 | 		ep = ebuf + sizeof(ebuf) - 1; | 
 | 	*pb = c; | 
 | 	pushsrc(Char, pb); | 
 | 	return c; | 
 | } | 
 |  | 
 | void pbstr(char *s) | 
 | { | 
 | 	pushsrc(String, s); | 
 | } | 
 |  | 
 | void error(int die, char *s) | 
 | { | 
 | 	extern char *cmdname; | 
 |  | 
 | 	if (synerr) | 
 | 		return; | 
 | 	fprintf(stderr, "%s: %s", cmdname, s); | 
 | 	if (errno > 0) | 
 | 		perror("???"); | 
 | 	if (curfile->fin) | 
 | 		fprintf(stderr, " near %s:%d", | 
 | 			curfile->fname, curfile->lineno+1); | 
 | 	fprintf(stderr, "\n"); | 
 | 	eprint(); | 
 | 	synerr = 1; | 
 | 	errno = 0; | 
 | 	if (die) { | 
 | 		if (dbg) | 
 | 			abort(); | 
 | 		else | 
 | 			exit(1); | 
 | 	} | 
 | } | 
 |  | 
 | void yyerror(char *s) | 
 | { | 
 | 	error(0, s);	/* temporary */ | 
 | } | 
 |  | 
 | char errbuf[200]; | 
 |  | 
 | void eprint(void)	/* try to print context around error */ | 
 | { | 
 | 	char *p, *q; | 
 |  | 
 | 	if (ep == ebuf) | 
 | 		return;				/* no context */ | 
 | 	p = ep - 1; | 
 | 	if (p > ebuf && *p == '\n') | 
 | 		p--; | 
 | 	for ( ; p >= ebuf && *p != '\n'; p--) | 
 | 		; | 
 | 	while (*p == '\n') | 
 | 		p++; | 
 | 	fprintf(stderr, " context is\n\t"); | 
 | 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) | 
 | 		; | 
 | 	while (p < q) | 
 | 		putc(*p++, stderr); | 
 | 	fprintf(stderr, " >>> "); | 
 | 	while (p < ep) | 
 | 		putc(*p++, stderr); | 
 | 	fprintf(stderr, " <<< "); | 
 | 	while (pb >= pbuf) | 
 | 		putc(*pb--, stderr); | 
 | 	if (curfile->fin) | 
 | 		fgets(ebuf, sizeof ebuf, curfile->fin); | 
 | 	fprintf(stderr, "%s", ebuf); | 
 | 	pbstr("\n.EN\n");	/* safety first */ | 
 | 	ep = ebuf; | 
 | } |