parse.c revision 1.85 1 /* $NetBSD: parse.c,v 1.85 2025/01/07 03:55:00 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.85 2025/01/07 03:55:00 rillig Exp $");
42
43 #include <stdlib.h>
44
45 #include "indent.h"
46
47 /* Replace the top 2 symbols with the given symbol. */
48 static void
49 ps_psyms_replace2(parser_symbol psym)
50 {
51 ps.psyms.len--;
52 ps.psyms.sym[ps.psyms.len - 1] = psym;
53 ps.ind_level_follow = ps.psyms.ind_level[ps.psyms.len - 1];
54 }
55
56 static int
57 left_justify_decl_level(void)
58 {
59 int level = 0;
60 for (size_t i = ps.psyms.len - 2; i > 0; i--)
61 if (ps.psyms.sym[i] == psym_decl)
62 level++;
63 return level;
64 }
65
66 void
67 ps_psyms_push(parser_symbol psym, int ind_level)
68 {
69 if (ps.psyms.len == ps.psyms.cap) {
70 ps.psyms.cap += 16;
71 ps.psyms.sym = nonnull(realloc(ps.psyms.sym,
72 sizeof(ps.psyms.sym[0]) * ps.psyms.cap));
73 ps.psyms.ind_level = nonnull(realloc(ps.psyms.ind_level,
74 sizeof(ps.psyms.ind_level[0]) * ps.psyms.cap));
75 }
76 ps.psyms.len++;
77 ps.psyms.sym[ps.psyms.len - 1] = psym;
78 ps.psyms.ind_level[ps.psyms.len - 1] = ind_level;
79 }
80
81 /*
82 * Repeatedly try to reduce the top two symbols on the parse stack to a single
83 * symbol, until no more reductions are possible.
84 */
85 static void
86 psyms_reduce(void)
87 {
88 again:
89 if (ps.psyms.len >= 2 && ps.psyms.sym[ps.psyms.len - 1] == psym_stmt) {
90 switch (ps.psyms.sym[ps.psyms.len - 2]) {
91 case psym_decl:
92 case psym_stmt:
93 case psym_for_exprs:
94 case psym_if_expr_stmt_else:
95 case psym_switch_expr:
96 case psym_while_expr:
97 ps_psyms_replace2(psym_stmt);
98 goto again;
99 case psym_if_expr:
100 ps_psyms_replace2(psym_if_expr_stmt);
101 goto again;
102 case psym_do:
103 ps_psyms_replace2(psym_do_stmt);
104 goto again;
105 default:
106 return;
107 }
108 }
109 if (ps.psyms.sym[ps.psyms.len - 1] == psym_while_expr &&
110 ps.psyms.sym[ps.psyms.len - 2] == psym_do_stmt) {
111 ps.psyms.len -= 2;
112 goto again;
113 }
114 }
115
116 static bool
117 is_lbrace(parser_symbol psym)
118 {
119 return psym == psym_lbrace_block
120 || psym == psym_lbrace_struct
121 || psym == psym_lbrace_union
122 || psym == psym_lbrace_enum;
123 }
124
125 /*
126 * Shift the token onto the parser stack, then try to reduce it by combining it with
127 * previous tokens.
128 */
129 void
130 parse(parser_symbol psym)
131 {
132 debug_blank_line();
133 debug_println("parse: %s", psym_name[psym]);
134
135 if (psym != psym_else) {
136 while (ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt) {
137 ps.psyms.sym[ps.psyms.len - 1] = psym_stmt;
138 psyms_reduce();
139 ps.ind_level = ps.ind_level_follow
140 = ps.psyms.ind_level[ps.psyms.len - 1];
141 }
142 }
143
144 switch (psym) {
145
146 case psym_lbrace_block:
147 case psym_lbrace_struct:
148 case psym_lbrace_union:
149 case psym_lbrace_enum:
150 ps.break_after_comma = false;
151 if (ps.psyms.sym[ps.psyms.len - 1] == psym_decl
152 || ps.psyms.sym[ps.psyms.len - 1] == psym_stmt)
153 ps.ind_level_follow++;
154 else if (code.len == 0) {
155 /* It is part of a while, for, etc. */
156 ps.ind_level--;
157
158 /* for a switch, brace should be two levels out from
159 * the code */
160 if (ps.psyms.sym[ps.psyms.len - 1] == psym_switch_expr
161 && opt.case_indent >= 1.0F)
162 ps.ind_level--;
163 }
164
165 ps_psyms_push(psym, ps.ind_level);
166 ps_psyms_push(psym_stmt, ps.ind_level_follow);
167 break;
168
169 case psym_rbrace:
170 /* stack should have <lbrace> <stmt> or <lbrace> <decl> */
171 if (!(ps.psyms.len >= 2
172 && is_lbrace(ps.psyms.sym[ps.psyms.len - 2]))) {
173 diag(1, "Statement nesting error");
174 break;
175 }
176 ps_psyms_replace2(psym_stmt);
177 ps.ind_level = ps.ind_level_follow;
178 break;
179
180 case psym_decl:
181 if (ps.psyms.sym[ps.psyms.len - 1] == psym_decl)
182 break; /* only put one declaration onto stack */
183
184 ps.break_after_comma = true;
185 ps_psyms_push(psym_decl, ps.ind_level_follow);
186
187 if (opt.left_justify_decl) {
188 ps.ind_level = left_justify_decl_level();
189 ps.ind_level_follow = ps.ind_level;
190 }
191 break;
192
193 case psym_stmt:
194 ps.break_after_comma = false;
195 ps_psyms_push(psym_stmt, ps.ind_level);
196 break;
197
198 case psym_if_expr:
199 if (ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt_else
200 && opt.else_if_in_same_line) {
201 ps.ind_level_follow =
202 ps.psyms.ind_level[ps.psyms.len - 1];
203 ps.psyms.len--;
204 }
205 /* FALLTHROUGH */
206 case psym_do:
207 case psym_for_exprs:
208 ps.ind_level = ps.ind_level_follow;
209 ps.ind_level_follow = ps.ind_level + 1;
210 ps_psyms_push(psym, ps.ind_level);
211 break;
212
213 case psym_else:
214 if (ps.psyms.sym[ps.psyms.len - 1] != psym_if_expr_stmt) {
215 diag(1, "Unmatched 'else'");
216 break;
217 }
218 ps.ind_level = ps.psyms.ind_level[ps.psyms.len - 1];
219 ps.ind_level_follow = ps.ind_level + 1;
220 ps.psyms.sym[ps.psyms.len - 1] = psym_if_expr_stmt_else;
221 break;
222
223 case psym_switch_expr:
224 ps_psyms_push(psym_switch_expr, ps.ind_level_follow);
225 ps.ind_level_follow += (int)opt.case_indent + 1;
226 break;
227
228 case psym_while_expr:
229 if (ps.psyms.sym[ps.psyms.len - 1] == psym_do_stmt) {
230 ps.ind_level = ps.psyms.ind_level[ps.psyms.len - 1];
231 ps.ind_level_follow = ps.ind_level;
232 ps_psyms_push(psym_while_expr, ps.ind_level);
233 } else {
234 ps_psyms_push(psym_while_expr, ps.ind_level_follow);
235 ps.ind_level_follow++;
236 }
237 break;
238
239 default:
240 diag(1, "Unknown code to parser");
241 return;
242 }
243
244 #if debug
245 static struct buffer before, after;
246 buf_clear(&before);
247 ps_psyms_to_string(&before, &ps);
248 #endif
249 psyms_reduce();
250 #if debug
251 buf_clear(&after);
252 ps_psyms_to_string(&after, &ps);
253 if (strcmp(before.s, after.s) != 0) {
254 debug_println("psyms before: %s", before.s);
255 debug_println("psyms after: %s", after.s);
256 } else
257 debug_println("psyms: %s", after.s);
258 #endif
259 }
260