xref: /dragonfly/usr.bin/indent/parse.c (revision 99dd49c5)
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  * @(#)parse.c	8.1 (Berkeley) 6/6/93
36  * $FreeBSD: src/usr.bin/indent/parse.c,v 1.10 2003/06/15 09:28:17 charnier Exp $
37  * $DragonFly: src/usr.bin/indent/parse.c,v 1.3 2005/04/10 20:55:38 drhodus Exp $
38  */
39 
40 #include <stdio.h>
41 #include "indent_globs.h"
42 #include "indent_codes.h"
43 #include "indent.h"
44 
45 static void reduce(void);
46 
47 void
48 parse(int tk) /* tk: the code for the construct scanned */
49 {
50     int         i;
51 
52 #ifdef debug
53     printf("%2d - %s\n", tk, token);
54 #endif
55 
56     while (ps.p_stack[ps.tos] == ifhead && tk != elselit) {
57 	/* true if we have an if without an else */
58 	ps.p_stack[ps.tos] = stmt;	/* apply the if(..) stmt ::= stmt
59 					 * reduction */
60 	reduce();		/* see if this allows any reduction */
61     }
62 
63 
64     switch (tk) {		/* go on and figure out what to do with the
65 				 * input */
66 
67     case decl:			/* scanned a declaration word */
68 	ps.search_brace = btype_2;
69 	/* indicate that following brace should be on same line */
70 	if (ps.p_stack[ps.tos] != decl) {	/* only put one declaration
71 						 * onto stack */
72 	    break_comma = true;	/* while in declaration, newline should be
73 				 * forced after comma */
74 	    ps.p_stack[++ps.tos] = decl;
75 	    ps.il[ps.tos] = ps.i_l_follow;
76 
77 	    if (ps.ljust_decl) {/* only do if we want left justified
78 				 * declarations */
79 		ps.ind_level = 0;
80 		for (i = ps.tos - 1; i > 0; --i)
81 		    if (ps.p_stack[i] == decl)
82 			++ps.ind_level;	/* indentation is number of
83 					 * declaration levels deep we are */
84 		ps.i_l_follow = ps.ind_level;
85 	    }
86 	}
87 	break;
88 
89     case ifstmt:		/* scanned if (...) */
90 	if (ps.p_stack[ps.tos] == elsehead && ps.else_if)	/* "else if ..." */
91 	    ps.i_l_follow = ps.il[ps.tos];
92     case dolit:		/* 'do' */
93     case forstmt:		/* for (...) */
94 	ps.p_stack[++ps.tos] = tk;
95 	ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
96 	++ps.i_l_follow;	/* subsequent statements should be indented 1 */
97 	ps.search_brace = btype_2;
98 	break;
99 
100     case lbrace:		/* scanned { */
101 	break_comma = false;	/* don't break comma in an initial list */
102 	if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl
103 		|| ps.p_stack[ps.tos] == stmtl)
104 	    ++ps.i_l_follow;	/* it is a random, isolated stmt group or a
105 				 * declaration */
106 	else {
107 	    if (s_code == e_code) {
108 		/*
109 		 * only do this if there is nothing on the line
110 		 */
111 		--ps.ind_level;
112 		/*
113 		 * it is a group as part of a while, for, etc.
114 		 */
115 		if (ps.p_stack[ps.tos] == swstmt && ps.case_indent >= 1)
116 		    --ps.ind_level;
117 		/*
118 		 * for a switch, brace should be two levels out from the code
119 		 */
120 	    }
121 	}
122 
123 	ps.p_stack[++ps.tos] = lbrace;
124 	ps.il[ps.tos] = ps.ind_level;
125 	ps.p_stack[++ps.tos] = stmt;
126 	/* allow null stmt between braces */
127 	ps.il[ps.tos] = ps.i_l_follow;
128 	break;
129 
130     case whilestmt:		/* scanned while (...) */
131 	if (ps.p_stack[ps.tos] == dohead) {
132 	    /* it is matched with do stmt */
133 	    ps.ind_level = ps.i_l_follow = ps.il[ps.tos];
134 	    ps.p_stack[++ps.tos] = whilestmt;
135 	    ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
136 	}
137 	else {			/* it is a while loop */
138 	    ps.p_stack[++ps.tos] = whilestmt;
139 	    ps.il[ps.tos] = ps.i_l_follow;
140 	    ++ps.i_l_follow;
141 	    ps.search_brace = btype_2;
142 	}
143 
144 	break;
145 
146     case elselit:		/* scanned an else */
147 
148 	if (ps.p_stack[ps.tos] != ifhead)
149 	    diag2(1, "Unmatched 'else'");
150 	else {
151 	    ps.ind_level = ps.il[ps.tos];	/* indentation for else should
152 						 * be same as for if */
153 	    ps.i_l_follow = ps.ind_level + 1;	/* everything following should
154 						 * be in 1 level */
155 	    ps.p_stack[ps.tos] = elsehead;
156 	    /* remember if with else */
157 	    ps.search_brace = btype_2 | ps.else_if;
158 	}
159 	break;
160 
161     case rbrace:		/* scanned a } */
162 	/* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
163 	if (ps.p_stack[ps.tos - 1] == lbrace) {
164 	    ps.ind_level = ps.i_l_follow = ps.il[--ps.tos];
165 	    ps.p_stack[ps.tos] = stmt;
166 	}
167 	else
168 	    diag2(1, "Statement nesting error");
169 	break;
170 
171     case swstmt:		/* had switch (...) */
172 	ps.p_stack[++ps.tos] = swstmt;
173 	ps.cstk[ps.tos] = case_ind;
174 	/* save current case indent level */
175 	ps.il[ps.tos] = ps.i_l_follow;
176 	case_ind = ps.i_l_follow + ps.case_indent;	/* cases should be one
177 							 * level down from
178 							 * switch */
179 	ps.i_l_follow += ps.case_indent + 1;	/* statements should be two
180 						 * levels in */
181 	ps.search_brace = btype_2;
182 	break;
183 
184     case semicolon:		/* this indicates a simple stmt */
185 	break_comma = false;	/* turn off flag to break after commas in a
186 				 * declaration */
187 	ps.p_stack[++ps.tos] = stmt;
188 	ps.il[ps.tos] = ps.ind_level;
189 	break;
190 
191     default:			/* this is an error */
192 	diag2(1, "Unknown code to parser");
193 	return;
194 
195 
196     }				/* end of switch */
197 
198     reduce();			/* see if any reduction can be done */
199 
200 #ifdef debug
201     for (i = 1; i <= ps.tos; ++i)
202 	printf("(%d %d)", ps.p_stack[i], ps.il[i]);
203     printf("\n");
204 #endif
205 
206     return;
207 }
208 
209 /*
210  * NAME: reduce
211  *
212  * FUNCTION: Implements the reduce part of the parsing algorithm
213  *
214  * ALGORITHM: The following reductions are done.  Reductions are repeated
215  *	until no more are possible.
216  *
217  * Old TOS		New TOS
218  * <stmt> <stmt>	<stmtl>
219  * <stmtl> <stmt>	<stmtl>
220  * do <stmt>		"dostmt"
221  * if <stmt>		"ifstmt"
222  * switch <stmt>	<stmt>
223  * decl <stmt>		<stmt>
224  * "ifelse" <stmt>	<stmt>
225  * for <stmt>		<stmt>
226  * while <stmt>		<stmt>
227  * "dostmt" while	<stmt>
228  *
229  * On each reduction, ps.i_l_follow (the indentation for the following line)
230  * is set to the indentation level associated with the old TOS.
231  *
232  * PARAMETERS: None
233  *
234  * RETURNS: Nothing
235  *
236  * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos =
237  *
238  * CALLS: None
239  *
240  * CALLED BY: parse
241  *
242  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
243  *
244  */
245 /*----------------------------------------------*\
246 |   REDUCTION PHASE				    |
247 \*----------------------------------------------*/
248 static void
249 reduce(void)
250 {
251     int i;
252 
253     for (;;) {			/* keep looping until there is nothing left to
254 				 * reduce */
255 
256 	switch (ps.p_stack[ps.tos]) {
257 
258 	case stmt:
259 	    switch (ps.p_stack[ps.tos - 1]) {
260 
261 	    case stmt:
262 	    case stmtl:
263 		/* stmtl stmt or stmt stmt */
264 		ps.p_stack[--ps.tos] = stmtl;
265 		break;
266 
267 	    case dolit:	/* <do> <stmt> */
268 		ps.p_stack[--ps.tos] = dohead;
269 		ps.i_l_follow = ps.il[ps.tos];
270 		break;
271 
272 	    case ifstmt:
273 		/* <if> <stmt> */
274 		ps.p_stack[--ps.tos] = ifhead;
275 		for (i = ps.tos - 1;
276 			(
277 			 ps.p_stack[i] != stmt
278 			 &&
279 			 ps.p_stack[i] != stmtl
280 			 &&
281 			 ps.p_stack[i] != lbrace
282 			 );
283 			--i);
284 		ps.i_l_follow = ps.il[i];
285 		/*
286 		 * for the time being, we will assume that there is no else on
287 		 * this if, and set the indentation level accordingly. If an
288 		 * else is scanned, it will be fixed up later
289 		 */
290 		break;
291 
292 	    case swstmt:
293 		/* <switch> <stmt> */
294 		case_ind = ps.cstk[ps.tos - 1];
295 
296 	    case decl:		/* finish of a declaration */
297 	    case elsehead:
298 		/* <<if> <stmt> else> <stmt> */
299 	    case forstmt:
300 		/* <for> <stmt> */
301 	    case whilestmt:
302 		/* <while> <stmt> */
303 		ps.p_stack[--ps.tos] = stmt;
304 		ps.i_l_follow = ps.il[ps.tos];
305 		break;
306 
307 	    default:		/* <anything else> <stmt> */
308 		return;
309 
310 	    }			/* end of section for <stmt> on top of stack */
311 	    break;
312 
313 	case whilestmt:	/* while (...) on top */
314 	    if (ps.p_stack[ps.tos - 1] == dohead) {
315 		/* it is termination of a do while */
316 		ps.tos -= 2;
317 		break;
318 	    }
319 	    else
320 		return;
321 
322 	default:		/* anything else on top */
323 	    return;
324 
325 	}
326     }
327 }
328