parse.c revision 1.69 1 /* $NetBSD: parse.c,v 1.69 2023/06/07 15:46:12 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.69 2023/06/07 15:46:12 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 psyms_reduce_stmt(struct psym_stack *psyms)
53 {
54 switch (psyms->sym[psyms->top - 1]) {
55
56 case psym_stmt:
57 case psym_stmt_list:
58 psyms->sym[--psyms->top] = psym_stmt_list;
59 return true;
60
61 case psym_do:
62 psyms->sym[--psyms->top] = psym_do_stmt;
63 ps.ind_level_follow = psyms->ind_level[psyms->top];
64 return true;
65
66 case psym_if_expr:
67 psyms->sym[--psyms->top] = psym_if_expr_stmt;
68 int i = psyms->top - 1;
69 while (psyms->sym[i] != psym_stmt &&
70 psyms->sym[i] != psym_stmt_list &&
71 psyms->sym[i] != psym_lbrace_block)
72 --i;
73 ps.ind_level_follow = psyms->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 psyms->sym[--psyms->top] = psym_stmt;
85 ps.ind_level_follow = psyms->ind_level[psyms->top];
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.psyms.top - 1; i > 0; i--)
98 if (ps.psyms.sym[i] == psym_decl)
99 level++;
100 return level;
101 }
102
103 static void
104 ps_push(parser_symbol psym)
105 {
106 ps.psyms.sym[++ps.psyms.top] = psym;
107 ps.psyms.ind_level[ps.psyms.top] = ps.ind_level;
108 }
109
110 static void
111 ps_push_follow(parser_symbol psym)
112 {
113 ps.psyms.sym[++ps.psyms.top] = psym;
114 ps.psyms.ind_level[ps.psyms.top] = 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 psyms_reduce(struct psym_stack *psyms)
123 {
124 again:
125 if (psyms->sym[psyms->top] == psym_stmt && psyms_reduce_stmt(psyms))
126 goto again;
127 if (psyms->sym[psyms->top] == psym_while_expr &&
128 psyms->sym[psyms->top - 1] == psym_do_stmt) {
129 psyms->top -= 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 struct psym_stack *psyms = &ps.psyms;
154 if (psym != psym_else) {
155 while (psyms->sym[psyms->top] == psym_if_expr_stmt) {
156 psyms->sym[psyms->top] = psym_stmt;
157 psyms_reduce(&ps.psyms);
158 }
159 }
160
161 switch (psym) {
162
163 case psym_decl:
164 if (psyms->sym[psyms->top] == psym_decl)
165 break; /* only put one declaration onto stack */
166
167 ps.break_after_comma = true;
168 ps_push_follow(psym_decl);
169
170 if (opt.left_justify_decl)
171 ps.ind_level_follow = ps.ind_level = decl_level();
172 break;
173
174 case psym_if_expr:
175 if (psyms->sym[psyms->top] == psym_if_expr_stmt_else
176 && opt.else_if_in_same_line)
177 ps.ind_level_follow = psyms->ind_level[psyms->top--];
178 /* FALLTHROUGH */
179 case psym_do:
180 case psym_for_exprs:
181 ps.ind_level = ps.ind_level_follow++;
182 ps_push(psym);
183 break;
184
185 case psym_lbrace_block:
186 case psym_lbrace_struct:
187 case psym_lbrace_union:
188 case psym_lbrace_enum:
189 ps.break_after_comma = false;
190 if (psyms->sym[psyms->top] == psym_stmt
191 || psyms->sym[psyms->top] == psym_decl
192 || psyms->sym[psyms->top] == psym_stmt_list)
193 ++ps.ind_level_follow; /* it is a random, isolated
194 * stmt group or a declaration
195 */
196 else {
197 if (code.len == 0) {
198 /* it is a group as part of a while, for, etc.
199 */
200 --ps.ind_level;
201
202 /* for a switch, brace should be two levels out
203 * from the code */
204 if (psyms->sym[psyms->top] == psym_switch_expr
205 && opt.case_indent >= 1.0F)
206 --ps.ind_level;
207 }
208 }
209
210 ps_push(psym);
211 ps_push_follow(psym_stmt);
212 break;
213
214 case psym_while_expr:
215 if (psyms->sym[psyms->top] == psym_do_stmt) {
216 ps.ind_level =
217 ps.ind_level_follow = psyms->ind_level[psyms->top];
218 ps_push(psym_while_expr);
219 } else {
220 ps_push_follow(psym_while_expr);
221 ++ps.ind_level_follow;
222 }
223
224 break;
225
226 case psym_else:
227 if (psyms->sym[psyms->top] != psym_if_expr_stmt) {
228 diag(1, "Unmatched 'else'");
229 break;
230 }
231 ps.ind_level = psyms->ind_level[psyms->top];
232 ps.ind_level_follow = ps.ind_level + 1;
233 psyms->sym[psyms->top] = psym_if_expr_stmt_else;
234 break;
235
236 case psym_rbrace:
237 /* stack should have <lbrace> <stmt> or <lbrace> <stmt_list> */
238 if (!(psyms->top > 0
239 && is_lbrace(psyms->sym[psyms->top - 1]))) {
240 diag(1, "Statement nesting error");
241 break;
242 }
243 ps.ind_level = ps.ind_level_follow =
244 psyms->ind_level[--psyms->top];
245 psyms->sym[psyms->top] = psym_stmt;
246 break;
247
248 case psym_switch_expr:
249 ps_push_follow(psym_switch_expr);
250 ps.ind_level_follow += (int)opt.case_indent + 1;
251 break;
252
253 case psym_stmt:
254 ps.break_after_comma = false;
255 ps_push(psym_stmt);
256 break;
257
258 default:
259 diag(1, "Unknown code to parser");
260 return;
261 }
262
263 if (psyms->top >= STACKSIZE - 1)
264 errx(1, "Parser stack overflow");
265
266 debug_parse_stack("before reduction");
267 psyms_reduce(&ps.psyms);
268 debug_parse_stack("after reduction");
269 }
270