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