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