xref: /plan9/sys/src/cmd/eqn/input.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include "e.h"
2 #include "y.tab.h"
3 #include <ctype.h>
4 #include <errno.h>
5 
6 Infile	infile[10];
7 Infile	*curfile = infile;
8 
9 #define	MAXSRC	50
10 Src	src[MAXSRC];	/* input source stack */
11 Src	*srcp	= src;
12 
13 extern int getarg(char *);
14 extern	void eprint(void);
15 
pushsrc(int type,char * ptr)16 void pushsrc(int type, char *ptr)	/* new input source */
17 {
18 	if (++srcp >= src + MAXSRC)
19 		ERROR "inputs nested too deep" FATAL;
20 	srcp->type = type;
21 	srcp->sp = ptr;
22 	if (dbg > 1) {
23 		printf("\n%3d ", srcp - src);
24 		switch (srcp->type) {
25 		case File:
26 			printf("push file %s\n", ((Infile *)ptr)->fname);
27 			break;
28 		case Macro:
29 			printf("push macro <%s>\n", ptr);
30 			break;
31 		case Char:
32 			printf("push char <%c>\n", *ptr);
33 			break;
34 		case String:
35 			printf("push string <%s>\n", ptr);
36 			break;
37 		case Free:
38 			printf("push free <%s>\n", ptr);
39 			break;
40 		default:
41 			ERROR "pushed bad type %d\n", srcp->type FATAL;
42 		}
43 	}
44 }
45 
popsrc(void)46 void popsrc(void)	/* restore an old one */
47 {
48 	if (srcp <= src)
49 		ERROR "too many inputs popped" FATAL;
50 	if (dbg > 1) {
51 		printf("%3d ", srcp - src);
52 		switch (srcp->type) {
53 		case File:
54 			printf("pop file\n");
55 			break;
56 		case Macro:
57 			printf("pop macro\n");
58 			break;
59 		case Char:
60 			printf("pop char <%c>\n", *srcp->sp);
61 			break;
62 		case String:
63 			printf("pop string\n");
64 			break;
65 		case Free:
66 			printf("pop free\n");
67 			break;
68 		default:
69 			ERROR "pop weird input %d\n", srcp->type FATAL;
70 		}
71 	}
72 	srcp--;
73 }
74 
75 Arg	args[10];	/* argument frames */
76 Arg	*argfp = args;	/* frame pointer */
77 int	argcnt;		/* number of arguments seen so far */
78 
dodef(tbl * stp)79 void dodef(tbl *stp)	/* collect args and switch input to defn */
80 {
81 	int i, len;
82 	char *p;
83 	Arg *ap;
84 
85 	ap = argfp+1;
86 	if (ap >= args+10)
87 		ERROR "more than arguments\n" FATAL;
88 	argcnt = 0;
89 	if (input() != '(')
90 		ERROR "disaster in dodef\n"FATAL;
91 	if (ap->argval == 0)
92 		ap->argval = malloc(1000);
93 	for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
94 		ap->argstk[argcnt++] = p;
95 		if (input() == ')')
96 			break;
97 	}
98 	for (i = argcnt; i < MAXARGS; i++)
99 		ap->argstk[i] = "";
100 	if (dbg)
101 		for (i = 0; i < argcnt; i++)
102 			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
103 	argfp = ap;
104 	pushsrc(Macro, stp->cval);
105 }
106 
getarg(char * p)107 getarg(char *p)	/* pick up single argument, store in p, return length */
108 {
109 	int n, c, npar;
110 
111 	n = npar = 0;
112 	for ( ;; ) {
113 		c = input();
114 		if (c == EOF)
115 			ERROR "end of file in getarg!\n" FATAL;
116 		if (npar == 0 && (c == ',' || c == ')'))
117 			break;
118 		if (c == '"')	/* copy quoted stuff intact */
119 			do {
120 				*p++ = c;
121 				n++;
122 			} while ((c = input()) != '"' && c != EOF);
123 		else if (c == '(')
124 			npar++;
125 		else if (c == ')')
126 			npar--;
127 		n++;
128 		*p++ = c;
129 	}
130 	*p = 0;
131 	unput(c);
132 	return(n + 1);
133 }
134 
135 #define	PBSIZE	2000
136 char	pbuf[PBSIZE];		/* pushback buffer */
137 char	*pb	= pbuf-1;	/* next pushed back character */
138 
139 char	ebuf[200];		/* collect input here for error reporting */
140 char	*ep	= ebuf;
141 
input(void)142 input(void)
143 {
144 	register int c = 0;
145 
146   loop:
147 	switch (srcp->type) {
148 	case File:
149 		c = getc(curfile->fin);
150 		if (c == EOF) {
151 			if (curfile == infile)
152 				break;
153 			if (curfile->fin != stdin) {
154 				fclose(curfile->fin);
155 				free(curfile->fname);	/* assumes allocated */
156 			}
157 			curfile--;
158 			printf(".lf %d %s\n", curfile->lineno, curfile->fname);
159 			popsrc();
160 			goto loop;
161 		}
162 		if (c == '\n')
163 			curfile->lineno++;
164 		break;
165 	case Char:
166 		if (pb >= pbuf) {
167 			c = *pb--;
168 			popsrc();
169 			break;
170 		} else {	/* can't happen? */
171 			popsrc();
172 			goto loop;
173 		}
174 	case String:
175 		c = *srcp->sp++;
176 		if (c == '\0') {
177 			popsrc();
178 			goto loop;
179 		} else {
180 			if (*srcp->sp == '\0')	/* empty, so pop */
181 				popsrc();
182 			break;
183 		}
184 	case Macro:
185 		c = *srcp->sp++;
186 		if (c == '\0') {
187 			if (--argfp < args)
188 				ERROR "argfp underflow" FATAL;
189 			popsrc();
190 			goto loop;
191 		} else if (c == '$' && isdigit(*srcp->sp)) {
192 			int n = 0;
193 			while (isdigit(*srcp->sp))
194 				n = 10 * n + *srcp->sp++ - '0';
195 			if (n > 0 && n <= MAXARGS)
196 				pushsrc(String, argfp->argstk[n-1]);
197 			goto loop;
198 		}
199 		break;
200 	case Free:	/* free string */
201 		free(srcp->sp);
202 		popsrc();
203 		goto loop;
204 	}
205 	if (ep >= ebuf + sizeof ebuf)
206 		ep = ebuf;
207 	*ep++ = c;
208 	return c;
209 }
210 
211 
unput(int c)212 unput(int c)
213 {
214 	if (++pb >= pbuf + sizeof pbuf)
215 		ERROR "pushback overflow\n"FATAL;
216 	if (--ep < ebuf)
217 		ep = ebuf + sizeof(ebuf) - 1;
218 	*pb = c;
219 	pushsrc(Char, pb);
220 	return c;
221 }
222 
pbstr(char * s)223 void pbstr(char *s)
224 {
225 	pushsrc(String, s);
226 }
227 
error(int die,char * s)228 void error(int die, char *s)
229 {
230 	extern char *cmdname;
231 
232 	if (synerr)
233 		return;
234 	fprintf(stderr, "%s: ", cmdname);
235 	fprintf(stderr, s);
236 	if (errno > 0)
237 		perror("???");
238 	if (curfile->fin)
239 		fprintf(stderr, " near %s:%d",
240 			curfile->fname, curfile->lineno+1);
241 	fprintf(stderr, "\n");
242 	eprint();
243 	synerr = 1;
244 	errno = 0;
245 	if (die) {
246 		if (dbg)
247 			abort();
248 		else
249 			exit(1);
250 	}
251 }
252 
yyerror(char * s)253 void yyerror(char *s)
254 {
255 	error(0, s);	/* temporary */
256 }
257 
258 char errbuf[200];
259 
eprint(void)260 void eprint(void)	/* try to print context around error */
261 {
262 	char *p, *q;
263 
264 	if (ep == ebuf)
265 		return;				/* no context */
266 	p = ep - 1;
267 	if (p > ebuf && *p == '\n')
268 		p--;
269 	for ( ; p >= ebuf && *p != '\n'; p--)
270 		;
271 	while (*p == '\n')
272 		p++;
273 	fprintf(stderr, " context is\n\t");
274 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
275 		;
276 	while (p < q)
277 		putc(*p++, stderr);
278 	fprintf(stderr, " >>> ");
279 	while (p < ep)
280 		putc(*p++, stderr);
281 	fprintf(stderr, " <<< ");
282 	while (pb >= pbuf)
283 		putc(*pb--, stderr);
284 	if (curfile->fin)
285 		fgets(ebuf, sizeof ebuf, curfile->fin);
286 	fprintf(stderr, "%s", ebuf);
287 	pbstr("\n.EN\n");	/* safety first */
288 	ep = ebuf;
289 }
290