xref: /original-bsd/usr.bin/pascal/pxp/yycomm.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)yycomm.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 /*
13  * pxp - Pascal execution profiler
14  *
15  * Bill Joy UCB
16  * Version 1.2 January 1979
17  */
18 
19 #include "whoami.h"
20 #include "0.h"
21 #include "yy.h"
22 
23 /*
24  * COMMENT PROCESSING CLUSTER
25  *
26  * The global organization of this cluster is as follows.
27  * While parsing the program information is saved in the tree which
28  * tells the source text coordinates (sequence numbers and columns)
29  * bounding each production.  The comments from the source program
30  * are also saved, with information about their source text position
31  * and a classification as to their kind.
32  *
33  * When printing the reformatted program we flush out the comments
34  * at various points using the information in the comments and the parse
35  * tree to "resynchronize".  A number of special cases are recognized to
36  * deal with the vagarities of producing a true "fixed point" so that
37  * a prettyprinted program will re-prettyprint to itself.
38  */
39 
40 /*
41  * Save sequence id's and column markers bounding a production
42  * for later use in placing comments.  We save the sequence id
43  * and column of the leftmost token and the following token, and
44  * the sequence id of the last token in this reduction.
45  * See putcm, putcml, and putcmp below for motivation.
46  */
47 line2of(l)
48 	int l;
49 {
50 
51 	return (lineNof(l, 2));
52 }
53 
54 lineof(l)
55 	int l;
56 {
57 
58 	return (lineNof(l, 1));
59 }
60 
61 lineNof(l, i)
62 	int l, i;
63 {
64 
65 	return(tree(6, l, yypw[i].Wseqid, yypw[i].Wcol, yyseqid, yycol, yypw[N].Wseqid));
66 }
67 
68 /*
69  * After a call to setline, Seqid is set to the sequence id
70  * of the symbol which followed the reduction in which the
71  * lineof call was embedded, Col to the associated column,
72  * and LSeqid to the sequence id of the last symbol in the reduction
73  * (Note that this is exact only if the last symbol was a terminal
74  * this is always true when it matters.)
75  */
76 int	Seqid, Col, LSeqid;
77 
78 /*
79  * Retrieve the information from a call to lineof before beginning the
80  * output of a tree from a reduction.  First flush to the left margin
81  * of the production, and then set so that later calls to putcm, putcml
82  * and putcmp will deal with the right margin of this comment.
83  *
84  * The routine setinfo is called when the lineof has no embedded line
85  * number to avoid trashing the current "line".
86  *
87  * The routine setinfo is often called after completing the output of
88  * the text of a tree to restore Seqid, Col, and LSeqid which may have
89  * been destroyed by the nested processing calls to setline.
90  * In this case the only effect of the call to setinfo is to
91  * modify the above three variables as a side effect.
92  *
93  * We return a word giving information about the comments which were
94  * actually put out.  See putcm for details.
95  */
96 setline(ip)
97 	int *ip;
98 {
99 
100 	line = ip[0];
101 	return(setinfo(ip));
102 }
103 
104 setinfo(ip)
105 	register int *ip;
106 {
107 	register int i;
108 
109 	ip++;
110 	Seqid = *ip++;
111 	Col = *ip++;
112 	i = putcm();
113 	Seqid = *ip++;
114 	Col = *ip++;
115 	LSeqid = *ip++;
116 	return (i);
117 }
118 
119 char	cmeof, incomm;
120 
121 /*
122  * Get the text of a comment from the input stream,
123  * recording its type and linking it into the linked
124  * list of comments headed by cmhp.
125  */
126 getcm(cmdelim)
127 	char cmdelim;
128 {
129 	int cmjust, col;
130 	register struct comment *cp;
131 	register struct commline *kp;
132 
133 	incomm = 1;
134 	if (cmdelim == '*' && yycol == 10 || cmdelim == '{' && yycol == 9)
135 		cmjust = CLMARG;
136 	else if (yytokcnt <= 1)
137 		cmjust = CALIGN;
138 	else if (yywhcnt < 2)
139 		cmjust = CTRAIL;
140 	else
141 		cmjust = CRMARG;
142 	col = yycol - (cmdelim == '{' ? 1 : 2);
143 	cp = tree5(NIL, cmdelim, NIL, cmjust, yyseqid);
144 	cmeof = 0;
145 	do {
146 		kp = getcmline(cmdelim);
147 		if (cp->cml == NIL) {
148 			kp->cml = kp;
149 			kp->cmcol = col;
150 		} else {
151 			kp->cml = cp->cml->cml;
152 			cp->cml->cml = kp;
153 			switch (cp->cmjust) {
154 				case CTRAIL:
155 				case CRMARG:
156 					cp->cmjust = CALIGN;
157 			}
158 		}
159 		cp->cml = kp;
160 	} while (!cmeof);
161 	newcomm(cp);
162 	incomm = 0;
163 }
164 
165 /*
166  * Chain the new comment at "cp" onto the linked list of comments.
167  */
168 newcomm(cp)
169 	register struct comment *cp;
170 {
171 
172 	if (cmhp == NIL)
173 		cp->cmnext = cp;
174 	else {
175 		cp->cmnext = cmhp->cmnext;
176 		cmhp->cmnext = cp;
177 	}
178 	cmhp = cp;
179 }
180 
181 
182 int	nilcml[3];
183 
184 quickcomm(t)
185 	int t;
186 {
187 
188 	if (incomm)
189 		return;
190 	newcomm(tree5(nilcml, NIL, NIL, t, yyseqid));
191 }
192 
193 commincl(cp, ch)
194 	char *cp, ch;
195 {
196 
197 	newcomm(tree5(nilcml, savestr(cp), ch, CINCLUD, yyseqid));
198 }
199 
200 getcmline(cmdelim)
201 	char cmdelim;
202 {
203 	char lastc;
204 	register char *tp;
205 	register CHAR c;
206 	register struct commline *kp;
207 
208 	c = readch();
209 	kp = tree3(NIL, yycol, NIL);
210 	tp = token;
211 	lastc = 0;
212 	for (;;) {
213 		switch (c) {
214 			case '}':
215 				if (cmdelim == '{')
216 					goto endcm;
217 				break;
218 			case ')':
219 				if (cmdelim == '*' && lastc == '*') {
220 					--tp;
221 					goto endcm;
222 				}
223 				break;
224 			case '\n':
225 				goto done;
226 			case -1:
227 				yerror("Comment does not terminate - QUIT");
228 				pexit(ERRS);
229 		}
230 		lastc = c;
231 		*tp++ = c;
232 		c = readch();
233 	}
234 endcm:
235 	cmeof++;
236 done:
237 	*tp = 0;
238 	kp->cmtext = copystr(token);
239 	return (kp);
240 }
241 
242 /*
243  * Flush through the line this token is on.
244  * Ignore if next token on same line as this one.
245  */
246 putcml()
247 {
248 	register int i, SSeqid, SCol;
249 
250 	if (Seqid == LSeqid)
251 		return (1);
252 	SSeqid = Seqid, SCol = Col;
253 	Seqid = LSeqid, Col = 32767;
254 	i = putcm();
255 	Seqid = SSeqid, Col = SCol;
256 	return (i);
257 }
258 
259 /*
260  * Flush to the beginning of the line this token is on.
261  * Ignore if this token is on the same line as the previous one
262  * (effectively since all such already then flushed.)
263  */
264 putcmp()
265 {
266 	register int i, SSeqid, SCol;
267 
268 	SSeqid = Seqid, SCol = Col;
269 	Seqid = LSeqid, Col = 0;
270 	i = putcm();
271 	Seqid = SSeqid, Col = SCol;
272 	return (i);
273 }
274 
275 /*
276  * Put out the comments to the border indicated by Seqid and Col
277  */
278 putcm()
279 {
280 	register struct comment *cp;
281 	register int i;
282 
283 	cp = cmhp;
284 	if (cp == NIL)
285 		return (0);
286 	i = 0;
287 	cp = cp->cmnext;
288 	while (cp->cmseqid < Seqid || cp->cmseqid == Seqid && cp->cml->cmcol < Col) {
289 		putone(cp);
290 		i |= 1 << cp->cmjust;
291 		if (cp->cmnext == cp) {
292 			cmhp = NIL;
293 			break;
294 		}
295 		cp = cp->cmnext;
296 		cmhp->cmnext = cp;
297 	}
298 	return (i);
299 }
300 
301 /*
302  * Put out one comment.
303  * Note that empty lines, form feeds and #include statements
304  * are treated as comments are regurgitated here.
305  */
306 putone(cp)
307 	register struct comment *cp;
308 {
309 	register struct commline *cml, *cmf;
310 
311 	align(cp);
312 	switch (cp->cmjust) {
313 		case CINCLUD:
314 		     /* ppflush() */
315 			if (noinclude == 0) {
316 				putchar('\f');
317 				return;
318 			}
319 			printf("#include %c%s%c", cp->cml, cp->cmdelim, cp->cml);
320 			return;
321 	}
322 	if (stripcomm)
323 		return;
324 	switch (cp->cmjust) {
325 		case CFORM:
326 			ppop("\f");
327 			ppnl();
328 		case CNL:
329 		case CNLBL:
330 			return;
331 	}
332 	ppbra(cp->cmdelim == '{' ? "{" : "(*");
333 	cmf = cp->cml->cml;
334 	ppid(cmf->cmtext);
335 	for (cml = cmf->cml; cml != cmf; cml = cml->cml) {
336 		align(cp);
337 		oneline(cmf->cmcol, cml);
338 	}
339 	ppket(cp->cmdelim == '{' ? "}" : "*)");
340 }
341 
342 /*
343  * Do the preliminary horizontal and vertical
344  * motions necessary before beginning a comment,
345  * or between lines of a mult-line comment.
346  */
347 align(cp)
348 	register struct comment *cp;
349 {
350 
351 	switch (cp->cmjust) {
352 		case CNL:
353 			ppsnl();
354 			break;
355 		case CNLBL:
356 			ppsnlb();
357 			break;
358 		case CFORM:
359 		case CINCLUD:
360 			ppnl();
361 			break;
362 		case CLMARG:
363 			ppnl();
364 			if (profile)
365 				ppid("\t");
366 			break;
367 		case CALIGN:
368 			ppnl();
369 			indent();
370 			break;
371 		case CTRAIL:
372 			ppspac();
373 			break;
374 		case CRMARG:
375 		case CSRMARG:
376 			pptab();
377 			break;
378 	}
379 }
380 
381 /*
382  * One line of a multi-line comment
383  * Deal with alignment and initial white space trimming.
384  * The "margin" indicates where the first line of the
385  * comment began... don't print stuff in this comment
386  * which came before this.
387  */
388 oneline(margin, cml)
389 	int margin;
390 	struct commline *cml;
391 {
392 	register char *tp;
393 	register int i;
394 
395 	for (i = 8, tp = cml->cmtext; i < margin && *tp; tp++)
396 		switch (*tp) {
397 			case ' ':
398 				i++;
399 				continue;
400 			case '\t':
401 				i += 8;
402 				i &= ~7;
403 				if (i < margin)
404 					continue;
405 				ppop("\t");
406 			default:
407 				goto out;
408 		}
409 out:
410 	ppid(tp);
411 }
412 
413 /*
414  * Flush all comments
415  */
416 flushcm()
417 {
418 
419 	Seqid = 32767;
420 	return(putcm());
421 }
422 
423 #define	BLANKS	((1 << CNL) | (1 << CNLBL) | (1 << CFORM))
424 noblank(i)
425 	int i;
426 {
427 
428 	return ((i & BLANKS) == 0);
429 }
430 
431 int	needform, neednlbl, neednl, needseqid;
432 
433 needtree()
434 {
435 	register struct comment *cp;
436 
437 	needform = neednlbl = neednl = 0;
438 	cp = cmhp;
439 	if (cp == NIL)
440 		return (0);
441 	do {
442 		switch (cp->cmjust) {
443 			case CNL:
444 				neednl++;
445 				goto seq;
446 			case CNLBL:
447 				neednlbl++;
448 				goto seq;
449 			case CFORM:
450 				needform++;
451 seq:
452 				needseqid = cp->cmseqid;
453 				break;
454 			default:
455 				neednl = neednlbl = needform = 0;
456 				return (1);
457 		}
458 		cp = cp->cmnext;
459 	} while (cp != cmhp);
460 	cmhp = NIL;
461 	return (0);
462 }
463 
464 packtree()
465 {
466 	int save;
467 
468 	save = yyseqid;
469 	yyseqid = needseqid;
470 	for (; needform > 0; needform--)
471 		commform();
472 	for (; neednl > 0; neednl--)
473 		commnl();
474 	for (; neednlbl > 0; neednlbl--)
475 		commnlbl();
476 	yyseqid = save;
477 }
478