parse.c revision 1.68 1 /* $NetBSD: parse.c,v 1.68 2023/06/06 05:11:11 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 #include <sys/cdefs.h>
41 __RCSID("$NetBSD: parse.c,v 1.68 2023/06/06 05:11:11 rillig Exp $");
42
43 #include <err.h>
44
45 #include "indent.h"
46
47 /*
48 * Try to combine the statement on the top of the parse stack with the symbol
49 * directly below it, replacing these two symbols with a single symbol.
50 */
51 static bool
52 reduce_stmt(void)
53 {
54 switch (ps.s_sym[ps.tos - 1]) {
55
56 case psym_stmt:
57 case psym_stmt_list:
58 ps.s_sym[--ps.tos] = psym_stmt_list;
59 return true;
60
61 case psym_do:
62 ps.s_sym[--ps.tos] = psym_do_stmt;
63 ps.ind_level_follow = ps.s_ind_level[ps.tos];
64 return true;
65
66 case psym_if_expr:
67 ps.s_sym[--ps.tos] = psym_if_expr_stmt;
68 int i = ps.tos - 1;
69 while (ps.s_sym[i] != psym_stmt &&
70 ps.s_sym[i] != psym_stmt_list &&
71 ps.s_sym[i] != psym_lbrace_block)
72 --i;
73 ps.ind_level_follow = ps.s_ind_level[i];
74 /* For the time being, assume that there is no 'else' on this
75 * 'if', and set the indentation level accordingly. If an
76 * 'else' is scanned, it will be fixed up later. */
77 return true;
78
79 case psym_switch_expr:
80 case psym_decl:
81 case psym_if_expr_stmt_else:
82 case psym_for_exprs:
83 case psym_while_expr:
84 ps.s_sym[--ps.tos] = psym_stmt;
85 ps.ind_level_follow = ps.s_ind_level[ps.tos];
86 return true;
87
88 default:
89 return false;
90 }
91 }
92
93 static int
94 decl_level(void)
95 {
96 int level = 0;
97 for (int i = ps.tos - 1; i > 0; i--)
98 if (ps.s_sym[i] == psym_decl)
99 level++;
100 return level;
101 }
102
103 static void
104 ps_push(parser_symbol psym)
105 {
106 ps.s_sym[++ps.tos] = psym;
107 ps.s_ind_level[ps.tos] = ps.ind_level;
108 }
109
110 static void
111 ps_push_follow(parser_symbol psym)
112 {
113 ps.s_sym[++ps.tos] = psym;
114 ps.s_ind_level[ps.tos] = ps.ind_level_follow;
115 }
116
117 /*
118 * Repeatedly try to reduce the top two symbols on the parse stack to a single
119 * symbol, until no more reductions are possible.
120 */
121 static void
122 reduce(void)
123 {
124 again:
125 if (ps.s_sym[ps.tos] == psym_stmt && reduce_stmt())
126 goto again;
127 if (ps.s_sym[ps.tos] == psym_while_expr &&
128 ps.s_sym[ps.tos - 1] == psym_do_stmt) {
129 ps.tos -= 2;
130 goto again;
131 }
132 }
133
134 static bool
135 is_lbrace(parser_symbol psym)
136 {
137 return psym == psym_lbrace_block
138 || psym == psym_lbrace_struct
139 || psym == psym_lbrace_union
140 || psym == psym_lbrace_enum;
141 }
142
143 /*
144 * Shift the token onto the parser stack, or reduce it by combining it with
145 * previous tokens.
146 */
147 void
148 parse(parser_symbol psym)
149 {
150 debug_blank_line();
151 debug_println("parse token: %s", psym_name[psym]);
152
153 if (psym != psym_else) {
154 while (ps.s_sym[ps.tos] == psym_if_expr_stmt) {
155 ps.s_sym[ps.tos] = psym_stmt;
156 reduce();
157 }
158 }
159
160 switch (psym) {
161
162 case psym_decl:
163 if (ps.s_sym[ps.tos] == psym_decl)
164 break; /* only put one declaration onto stack */
165
166 ps.break_after_comma = true;
167 ps_push_follow(psym_decl);
168
169 if (opt.left_justify_decl)
170 ps.ind_level_follow = ps.ind_level = decl_level();
171 break;
172
173 case psym_if_expr:
174 if (ps.s_sym[ps.tos] == psym_if_expr_stmt_else
175 && opt.else_if_in_same_line)
176 ps.ind_level_follow = ps.s_ind_level[ps.tos--];
177 /* FALLTHROUGH */
178 case psym_do:
179 case psym_for_exprs:
180 ps.ind_level = ps.ind_level_follow++;
181 ps_push(psym);
182 break;
183
184 case psym_lbrace_block:
185 case psym_lbrace_struct:
186 case psym_lbrace_union:
187 case psym_lbrace_enum:
188 ps.break_after_comma = false;
189 if (ps.s_sym[ps.tos] == psym_stmt
190 || ps.s_sym[ps.tos] == psym_decl
191 || ps.s_sym[ps.tos] == psym_stmt_list)
192 ++ps.ind_level_follow; /* it is a random, isolated
193 * stmt group or a declaration
194 */
195 else {
196 if (code.len == 0) {
197 /* it is a group as part of a while, for, etc.
198 */
199 --ps.ind_level;
200
201 /* for a switch, brace should be two levels out
202 * from the code */
203 if (ps.s_sym[ps.tos] == psym_switch_expr &&
204 opt.case_indent >= 1.0F)
205 --ps.ind_level;
206 }
207 }
208
209 ps_push(psym);
210 ps_push_follow(psym_stmt);
211 break;
212
213 case psym_while_expr:
214 if (ps.s_sym[ps.tos] == psym_do_stmt) {
215 ps.ind_level =
216 ps.ind_level_follow = ps.s_ind_level[ps.tos];
217 ps_push(psym_while_expr);
218 } else {
219 ps_push_follow(psym_while_expr);
220 ++ps.ind_level_follow;
221 }
222
223 break;
224
225 case psym_else:
226 if (ps.s_sym[ps.tos] != psym_if_expr_stmt) {
227 diag(1, "Unmatched 'else'");
228 break;
229 }
230 ps.ind_level = ps.s_ind_level[ps.tos];
231 ps.ind_level_follow = ps.ind_level + 1;
232 ps.s_sym[ps.tos] = psym_if_expr_stmt_else;
233 break;
234
235 case psym_rbrace:
236 /* stack should have <lbrace> <stmt> or <lbrace> <stmt_list> */
237 if (!(ps.tos > 0 && is_lbrace(ps.s_sym[ps.tos - 1]))) {
238 diag(1, "Statement nesting error");
239 break;
240 }
241 ps.ind_level = ps.ind_level_follow = ps.s_ind_level[--ps.tos];
242 ps.s_sym[ps.tos] = psym_stmt;
243 break;
244
245 case psym_switch_expr:
246 ps_push_follow(psym_switch_expr);
247 ps.ind_level_follow += (int)opt.case_indent + 1;
248 break;
249
250 case psym_stmt:
251 ps.break_after_comma = false;
252 ps_push(psym_stmt);
253 break;
254
255 default:
256 diag(1, "Unknown code to parser");
257 return;
258 }
259
260 if (ps.tos >= STACKSIZE - 1)
261 errx(1, "Parser stack overflow");
262
263 debug_parse_stack("before reduction");
264 reduce(); /* see if any reduction can be done */
265 debug_parse_stack("after reduction");
266 }
267