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