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