1 #ifndef lint
2 static char sccsid[] = "@(#)pic2.c	1.1 (CWI) 85/07/19";
3 #endif lint
4 
5 #include	<stdio.h>
6 #include	<ctype.h>
7 #include	"pic.h"
8 #include	"y.tab.h"
9 
10 extern	FILE	*yyin;
11 extern	int	lineno;
12 extern	char	*filename;
13 extern	int	synerr;
14 
15 definition(s)	/* collect definition for s and install */
16 	char *s;	/* definitions picked up lexically */
17 {
18 	char buf[2000], *p, *tostring();
19 	int c, delim;
20 	struct symtab *stp;
21 
22 	while ((delim = input()) == ' ' || delim == '\t')
23 		;
24 	for (p = buf; (c = input()) != delim; ) {
25 		if (p >= buf + sizeof(buf)) {
26 			yyerror("definition of %s is too long", s);
27 			exit(1);
28 		}
29 		if (c == EOF) {
30 			yyerror("end of file while defining %s", s);
31 			exit(1);
32 		}
33 		*p++ = c;
34 	}
35 	*p = '\0';
36 	p = tostring(buf);
37 	stp = lookup(s);
38 	if (stp != NULL) {	/* it's there before */
39 		if (stp->s_type != DEFNAME) {
40 			yyerror("%s used as variable and definition\n", s);
41 			return;
42 		}
43 		free(stp->s_val.p);
44 		stp->s_val.p = p;
45 	} else {
46 		YYSTYPE u;
47 		u.p = p;
48 		makevar(tostring(s), DEFNAME, u);
49 	}
50 	dprintf("installing %s as `%s'\n", s, p);
51 }
52 
53 char *argstk[10];	/* pointers to actual arguments in argval */
54 char argval[1000];	/* arguments stored here end to end */
55 char *argp;		/* current position in argval */
56 int argcnt;		/* number of arguments seen so far */
57 
58 dodef(stp)	/* collect args and push back defn for name in table slot n */
59 	struct symtab *stp;
60 {
61 	int i, c, len;
62 	char *p;
63 
64 	argcnt = 0;
65 	if (input() != '(')
66 		yyerror("disaster in dodef\n");
67 	for (argp = argval; (len = getarg(argp)) != -1; argp += len) {
68 		argstk[argcnt++] = argp;
69 		if (input() == ')')
70 			break;
71 	}
72 	for (i = argcnt; i < 10; i++)
73 		argstk[i] = "";
74 	if (dbg) {
75 		for (i = 0; i < argcnt; i++)
76 			printf("arg %d = %s\n", i, argstk[i]);
77 	}
78 
79 	/* push them back */
80 	for (p = stp->s_val.p; *p; p++)
81 		;		/* find the end */
82 	for (--p; p >= stp->s_val.p; p--) {
83 		if (*(p-1) == '$') {
84 			if (isdigit(*p)) {
85 				pbstr(argstk[*p - '0' - 1]);
86 				p--;
87 			}
88 			else
89 				unput(*p);
90 		} else {
91 			unput(*p);
92 		}
93 	}
94 }
95 
96 getarg(p)	/* pick up single argument, store in p, return length */
97 	char *p;
98 {
99 	int n, c, npar;
100 
101 	n = npar = 0;
102 	for ( ;; ) {
103 		c = input();
104 		if (c == EOF)
105 			yyerror("end of file in getarg!\n");
106 		if (npar == 0 && (c == ',' || c == ')'))
107 			break;
108 		if (c == '"')	/* copy quoted stuff intact */
109 			do {
110 				*p++ = c;
111 				n++;
112 			} while ((c = input()) != '"' && c != EOF);
113 		else if (c == '(')
114 			npar++;
115 		else if (c == ')')
116 			npar--;
117 		n++;
118 		*p++ = c;
119 	}
120 	*p = 0;
121 	unput(c);
122 	return(n + 1);
123 }
124 
125 #define	PBSIZE	2000
126 char	pbuf[PBSIZE];		/* pushback buffer */
127 char	*pb	= pbuf-1;	/* next pushed back character */
128 
129 char	ebuf[200];		/* collect input here for error reporting */
130 char	*ep	= ebuf;
131 
132 input()
133 {
134 	register int c;
135 
136 	if (pb >= pbuf) {
137 		c = *pb--;
138 	} else {
139 		c = getc(yyin);
140 		if (c == '\n')
141 			lineno++;
142 		else if (c == EOF) {
143 			yyerror("end of file inside .PS/.PE");
144 			exit(1);
145 		}
146 	}
147 	if (ep >= ebuf + sizeof ebuf)
148 		ep = ebuf;
149 	return (*ep++ = c);
150 }
151 
152 unput(c)
153 {
154 	if (++pb >= pbuf + sizeof pbuf) {
155 		yyerror("pushback overflow\n");
156 		exit(1);
157 	}
158 	if (--ep < ebuf)
159 		ep = ebuf + sizeof(ebuf) - 1;
160 	return(*pb = c);
161 }
162 
163 pbstr(s)
164 	char *s;
165 {
166 	int n;
167 
168 	n = strlen(s);
169 	while (--n >= 0)
170 		unput(s[n]);
171 }
172 
173 yyerror(s, s1, s2, s3, s4)
174 	char *s, *s1, *s2, *s3, *s4;
175 {
176 	if (synerr)
177 		return;
178 	fprintf(stderr, "pic: ");
179 	fprintf(stderr, s, s1, s2, s3, s4);
180 	fprintf(stderr, " near line %d, file %s\n", lineno, filename);
181 	eprint();
182 	synerr = 1;
183 }
184 
185 eprint()	/* try to print context around error */
186 {
187 	char *p, *q;
188 	int c;
189 
190 	p = ep - 1;
191 	if (p > ebuf && *p == '\n')
192 		p--;
193 	for ( ; p >= ebuf && *p != '\n'; p--)
194 		;
195 	while (*p == '\n')
196 		p++;
197 	fprintf(stderr, " context is\n\t");
198 	while (p < ep)
199 		putc(*p++, stderr);
200 	fprintf(stderr, " ^ ");
201 	while (pb >= pbuf)
202 		putc(*pb--, stderr);
203 	fgets(ebuf, sizeof ebuf, yyin);
204 	fprintf(stderr, "%s", ebuf);
205 	pbstr(".PE\n");	/* safety first */
206 	ep = ebuf;
207 }
208 
209 yywrap() {;}
210