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