xref: /minix3/usr.bin/indent/parse.c (revision 97c7d358ea5970ca59196ed90e975115245f9e76)
1 /*	$NetBSD: parse.c,v 1.7 2003/08/07 11:14:09 agc Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
34  * Copyright (c) 1985 Sun Microsystems, Inc.
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. All advertising materials mentioning features or use of this software
46  *    must display the following acknowledgement:
47  *	This product includes software developed by the University of
48  *	California, Berkeley and its contributors.
49  * 4. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  */
65 
66 #include <sys/cdefs.h>
67 #ifndef lint
68 #if 0
69 static char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 6/6/93";
70 #else
71 __RCSID("$NetBSD: parse.c,v 1.7 2003/08/07 11:14:09 agc Exp $");
72 #endif
73 #endif				/* not lint */
74 
75 #include <stdio.h>
76 #include "indent_globs.h"
77 #include "indent_codes.h"
78 
79 /* tk: the code for the construct scanned */
80 void
parse(int tk)81 parse(int tk)
82 {
83 	int     i;
84 
85 #ifdef debug
86 	printf("%2d - %s\n", tk, token);
87 #endif
88 
89 	while (ps.p_stack[ps.tos] == ifhead && tk != elselit) {
90 		/* true if we have an if without an else */
91 		ps.p_stack[ps.tos] = stmt;	/* apply the if(..) stmt ::=
92 						 * stmt reduction */
93 		reduce();	/* see if this allows any reduction */
94 	}
95 
96 
97 	switch (tk) {		/* go on and figure out what to do with the
98 				 * input */
99 
100 	case decl:		/* scanned a declaration word */
101 		ps.search_brace = btype_2;
102 		/* indicate that following brace should be on same line */
103 		if (ps.p_stack[ps.tos] != decl) {	/* only put one
104 							 * declaration onto
105 							 * stack */
106 			break_comma = true;	/* while in declaration,
107 						 * newline should be forced
108 						 * after comma */
109 			ps.p_stack[++ps.tos] = decl;
110 			ps.il[ps.tos] = ps.i_l_follow;
111 
112 			if (ps.ljust_decl) {	/* only do if we want left
113 						 * justified declarations */
114 				ps.ind_level = 0;
115 				for (i = ps.tos - 1; i > 0; --i)
116 					if (ps.p_stack[i] == decl)
117 						++ps.ind_level;	/* indentation is number
118 								 * of declaration levels
119 								 * deep we are */
120 				ps.i_l_follow = ps.ind_level;
121 			}
122 		}
123 		break;
124 
125 	case ifstmt:		/* scanned if (...) */
126 		if (ps.p_stack[ps.tos] == elsehead && ps.else_if)	/* "else if ..." */
127 			ps.i_l_follow = ps.il[ps.tos];
128 	case dolit:		/* 'do' */
129 	case forstmt:		/* for (...) */
130 		ps.p_stack[++ps.tos] = tk;
131 		ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
132 		++ps.i_l_follow;/* subsequent statements should be indented 1 */
133 		ps.search_brace = btype_2;
134 		break;
135 
136 	case lbrace:		/* scanned { */
137 		break_comma = false;	/* don't break comma in an initial
138 					 * list */
139 		if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl
140 		    || ps.p_stack[ps.tos] == stmtl)
141 			++ps.i_l_follow;	/* it is a random, isolated
142 						 * stmt group or a declaration */
143 		else {
144 			if (s_code == e_code) {
145 				/*
146 				 * only do this if there is nothing on the line
147 				 */
148 				--ps.ind_level;
149 				/*
150 				 * it is a group as part of a while, for, etc.
151 				 */
152 				if (ps.p_stack[ps.tos] == swstmt && ps.case_indent >= 1)
153 					--ps.ind_level;
154 				/*
155 				 * for a switch, brace should be two levels out from the code
156 				 */
157 			}
158 		}
159 
160 		ps.p_stack[++ps.tos] = lbrace;
161 		ps.il[ps.tos] = ps.ind_level;
162 		ps.p_stack[++ps.tos] = stmt;
163 		/* allow null stmt between braces */
164 		ps.il[ps.tos] = ps.i_l_follow;
165 		break;
166 
167 	case whilestmt:	/* scanned while (...) */
168 		if (ps.p_stack[ps.tos] == dohead) {
169 			/* it is matched with do stmt */
170 			ps.ind_level = ps.i_l_follow = ps.il[ps.tos];
171 			ps.p_stack[++ps.tos] = whilestmt;
172 			ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
173 		} else {	/* it is a while loop */
174 			ps.p_stack[++ps.tos] = whilestmt;
175 			ps.il[ps.tos] = ps.i_l_follow;
176 			++ps.i_l_follow;
177 			ps.search_brace = btype_2;
178 		}
179 
180 		break;
181 
182 	case elselit:		/* scanned an else */
183 
184 		if (ps.p_stack[ps.tos] != ifhead)
185 			diag(1, "Unmatched 'else'");
186 		else {
187 			ps.ind_level = ps.il[ps.tos];	/* indentation for else
188 							 * should be same as for
189 							 * if */
190 			ps.i_l_follow = ps.ind_level + 1;	/* everything following
191 								 * should be in 1 level */
192 			ps.p_stack[ps.tos] = elsehead;
193 			/* remember if with else */
194 			ps.search_brace = btype_2 | ps.else_if;
195 		}
196 		break;
197 
198 	case rbrace:		/* scanned a } */
199 		/* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
200 		if (ps.p_stack[ps.tos - 1] == lbrace) {
201 			ps.ind_level = ps.i_l_follow = ps.il[--ps.tos];
202 			ps.p_stack[ps.tos] = stmt;
203 		} else
204 			diag(1, "Stmt nesting error.");
205 		break;
206 
207 	case swstmt:		/* had switch (...) */
208 		ps.p_stack[++ps.tos] = swstmt;
209 		ps.cstk[ps.tos] = case_ind;
210 		/* save current case indent level */
211 		ps.il[ps.tos] = ps.i_l_follow;
212 		case_ind = ps.i_l_follow + ps.case_indent;	/* cases should be one
213 								 * level down from
214 								 * switch */
215 		ps.i_l_follow += ps.case_indent + 1;	/* statements should be
216 							 * two levels in */
217 		ps.search_brace = btype_2;
218 		break;
219 
220 	case semicolon:	/* this indicates a simple stmt */
221 		break_comma = false;	/* turn off flag to break after commas
222 					 * in a declaration */
223 		ps.p_stack[++ps.tos] = stmt;
224 		ps.il[ps.tos] = ps.ind_level;
225 		break;
226 
227 	default:		/* this is an error */
228 		diag(1, "Unknown code to parser");
229 		return;
230 
231 
232 	}			/* end of switch */
233 
234 	reduce();		/* see if any reduction can be done */
235 
236 #ifdef debug
237 	for (i = 1; i <= ps.tos; ++i)
238 		printf("(%d %d)", ps.p_stack[i], ps.il[i]);
239 	printf("\n");
240 #endif
241 }
242 /*
243  * NAME: reduce
244  *
245  * FUNCTION: Implements the reduce part of the parsing algorithm
246  *
247  * ALGORITHM: The following reductions are done.  Reductions are repeated
248  *	until no more are possible.
249  *
250  * Old TOS		New TOS
251  * <stmt> <stmt>	<stmtl>
252  * <stmtl> <stmt>	<stmtl>
253  * do <stmt>		"dostmt"
254  * if <stmt>		"ifstmt"
255  * switch <stmt>	<stmt>
256  * decl <stmt>		<stmt>
257  * "ifelse" <stmt>	<stmt>
258  * for <stmt>		<stmt>
259  * while <stmt>		<stmt>
260  * "dostmt" while	<stmt>
261  *
262  * On each reduction, ps.i_l_follow (the indentation for the following line)
263  * is set to the indentation level associated with the old TOS.
264  *
265  * PARAMETERS: None
266  *
267  * RETURNS: Nothing
268  *
269  * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos =
270  *
271  * CALLS: None
272  *
273  * CALLED BY: parse
274  *
275  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
276  *
277  */
278 /*----------------------------------------------*\
279 |   REDUCTION PHASE				    |
280 \*----------------------------------------------*/
281 void
reduce(void)282 reduce(void)
283 {
284 
285 	int     i;
286 
287 	for (;;) {		/* keep looping until there is nothing left to
288 				 * reduce */
289 
290 		switch (ps.p_stack[ps.tos]) {
291 
292 		case stmt:
293 			switch (ps.p_stack[ps.tos - 1]) {
294 
295 			case stmt:
296 			case stmtl:
297 				/* stmtl stmt or stmt stmt */
298 				ps.p_stack[--ps.tos] = stmtl;
299 				break;
300 
301 			case dolit:	/* <do> <stmt> */
302 				ps.p_stack[--ps.tos] = dohead;
303 				ps.i_l_follow = ps.il[ps.tos];
304 				break;
305 
306 			case ifstmt:
307 				/* <if> <stmt> */
308 				ps.p_stack[--ps.tos] = ifhead;
309 				for (i = ps.tos - 1;
310 				    (
311 					ps.p_stack[i] != stmt
312 					&&
313 					ps.p_stack[i] != stmtl
314 					&&
315 					ps.p_stack[i] != lbrace
316 				    );
317 				    --i);
318 				ps.i_l_follow = ps.il[i];
319 				/*
320 				 * for the time being, we will assume that there is no else on
321 				 * this if, and set the indentation level accordingly. If an
322 				 * else is scanned, it will be fixed up later
323 				 */
324 				break;
325 
326 			case swstmt:
327 				/* <switch> <stmt> */
328 				case_ind = ps.cstk[ps.tos - 1];
329 
330 			case decl:	/* finish of a declaration */
331 			case elsehead:
332 				/* <<if> <stmt> else> <stmt> */
333 			case forstmt:
334 				/* <for> <stmt> */
335 			case whilestmt:
336 				/* <while> <stmt> */
337 				ps.p_stack[--ps.tos] = stmt;
338 				ps.i_l_follow = ps.il[ps.tos];
339 				break;
340 
341 			default:	/* <anything else> <stmt> */
342 				return;
343 
344 			}	/* end of section for <stmt> on top of stack */
345 			break;
346 
347 		case whilestmt:/* while (...) on top */
348 			if (ps.p_stack[ps.tos - 1] == dohead) {
349 				/* it is termination of a do while */
350 				ps.p_stack[--ps.tos] = stmt;
351 				break;
352 			} else
353 				return;
354 
355 		default:	/* anything else on top */
356 			return;
357 
358 		}
359 	}
360 }
361