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