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