debug.c revision 1.38 1 1.38 rillig /* $NetBSD: debug.c,v 1.38 2023/06/07 15:25:08 rillig Exp $ */
2 1.1 rillig
3 1.1 rillig /*-
4 1.1 rillig * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 1.1 rillig * All rights reserved.
6 1.1 rillig *
7 1.1 rillig * This code is derived from software contributed to The NetBSD Foundation
8 1.1 rillig * by Roland Illig <rillig (at) NetBSD.org>.
9 1.1 rillig *
10 1.1 rillig * Redistribution and use in source and binary forms, with or without
11 1.1 rillig * modification, are permitted provided that the following conditions
12 1.1 rillig * are met:
13 1.1 rillig * 1. Redistributions of source code must retain the above copyright
14 1.1 rillig * notice, this list of conditions and the following disclaimer.
15 1.1 rillig * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 rillig * notice, this list of conditions and the following disclaimer in the
17 1.1 rillig * documentation and/or other materials provided with the distribution.
18 1.1 rillig *
19 1.1 rillig * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 rillig * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 rillig * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 rillig * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 rillig * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 rillig * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 rillig * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 rillig * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 rillig * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 rillig * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 rillig * POSSIBILITY OF SUCH DAMAGE.
30 1.1 rillig */
31 1.1 rillig
32 1.1 rillig #include <sys/cdefs.h>
33 1.38 rillig __RCSID("$NetBSD: debug.c,v 1.38 2023/06/07 15:25:08 rillig Exp $");
34 1.6 rillig
35 1.6 rillig #include <stdarg.h>
36 1.1 rillig
37 1.1 rillig #include "indent.h"
38 1.1 rillig
39 1.1 rillig #ifdef debug
40 1.7 rillig
41 1.11 rillig /*-
42 1.7 rillig * false show only the changes to the parser state
43 1.7 rillig * true show unchanged parts of the parser state as well
44 1.7 rillig */
45 1.7 rillig static bool debug_full_parser_state = true;
46 1.7 rillig
47 1.1 rillig const char *const lsym_name[] = {
48 1.13 rillig "eof",
49 1.13 rillig "preprocessing",
50 1.13 rillig "newline",
51 1.13 rillig "comment",
52 1.26 rillig "lparen",
53 1.26 rillig "lbracket",
54 1.26 rillig "rparen",
55 1.26 rillig "rbracket",
56 1.13 rillig "lbrace",
57 1.13 rillig "rbrace",
58 1.13 rillig "period",
59 1.13 rillig "unary_op",
60 1.13 rillig "binary_op",
61 1.13 rillig "postfix_op",
62 1.13 rillig "question",
63 1.28 rillig "'?:' colon",
64 1.28 rillig "label colon",
65 1.28 rillig "other colon",
66 1.13 rillig "comma",
67 1.13 rillig "semicolon",
68 1.13 rillig "typedef",
69 1.29 rillig "modifier",
70 1.13 rillig "type_outside_parentheses",
71 1.13 rillig "type_in_parentheses",
72 1.13 rillig "tag",
73 1.30 rillig "case",
74 1.30 rillig "default",
75 1.13 rillig "sizeof",
76 1.13 rillig "offsetof",
77 1.13 rillig "word",
78 1.13 rillig "funcname",
79 1.13 rillig "do",
80 1.13 rillig "else",
81 1.13 rillig "for",
82 1.13 rillig "if",
83 1.13 rillig "switch",
84 1.13 rillig "while",
85 1.13 rillig "return",
86 1.1 rillig };
87 1.1 rillig
88 1.1 rillig const char *const psym_name[] = {
89 1.33 rillig "-",
90 1.36 rillig "{block",
91 1.36 rillig "{struct",
92 1.36 rillig "{union",
93 1.36 rillig "{enum",
94 1.36 rillig "}",
95 1.13 rillig "decl",
96 1.13 rillig "stmt",
97 1.13 rillig "stmt_list",
98 1.13 rillig "for_exprs",
99 1.13 rillig "if_expr",
100 1.13 rillig "if_expr_stmt",
101 1.13 rillig "if_expr_stmt_else",
102 1.13 rillig "else",
103 1.13 rillig "switch_expr",
104 1.13 rillig "do",
105 1.13 rillig "do_stmt",
106 1.13 rillig "while_expr",
107 1.1 rillig };
108 1.1 rillig
109 1.9 rillig static const char *const declaration_name[] = {
110 1.13 rillig "no",
111 1.13 rillig "begin",
112 1.13 rillig "end",
113 1.3 rillig };
114 1.3 rillig
115 1.9 rillig const char *const paren_level_cast_name[] = {
116 1.13 rillig "(unknown cast)",
117 1.13 rillig "(maybe cast)",
118 1.13 rillig "(no cast)",
119 1.9 rillig };
120 1.9 rillig
121 1.19 rillig const char *const line_kind_name[] = {
122 1.16 rillig "other",
123 1.20 rillig "blank",
124 1.16 rillig "#if",
125 1.16 rillig "#endif",
126 1.20 rillig "stmt head",
127 1.17 rillig "}",
128 1.18 rillig "block comment",
129 1.27 rillig "case/default",
130 1.16 rillig };
131 1.16 rillig
132 1.35 rillig static const char *const extra_expr_indent_name[] = {
133 1.35 rillig "no",
134 1.35 rillig "yes",
135 1.35 rillig "last",
136 1.35 rillig };
137 1.35 rillig
138 1.21 rillig static const char *const decl_ptr_name[] = {
139 1.21 rillig "start",
140 1.21 rillig "word",
141 1.21 rillig "word *",
142 1.21 rillig "other",
143 1.21 rillig };
144 1.21 rillig
145 1.23 rillig static unsigned wrote_newlines = 1;
146 1.22 rillig
147 1.37 rillig
148 1.6 rillig void
149 1.6 rillig debug_printf(const char *fmt, ...)
150 1.6 rillig {
151 1.13 rillig FILE *f = output == stdout ? stderr : stdout;
152 1.13 rillig va_list ap;
153 1.6 rillig
154 1.13 rillig va_start(ap, fmt);
155 1.13 rillig vfprintf(f, fmt, ap);
156 1.13 rillig va_end(ap);
157 1.22 rillig wrote_newlines = 0;
158 1.6 rillig }
159 1.6 rillig
160 1.6 rillig void
161 1.6 rillig debug_println(const char *fmt, ...)
162 1.6 rillig {
163 1.13 rillig FILE *f = output == stdout ? stderr : stdout;
164 1.13 rillig va_list ap;
165 1.6 rillig
166 1.13 rillig va_start(ap, fmt);
167 1.13 rillig vfprintf(f, fmt, ap);
168 1.13 rillig va_end(ap);
169 1.13 rillig fprintf(f, "\n");
170 1.22 rillig wrote_newlines = fmt[0] == '\0' ? wrote_newlines + 1 : 1;
171 1.22 rillig }
172 1.22 rillig
173 1.22 rillig void
174 1.22 rillig debug_blank_line(void)
175 1.22 rillig {
176 1.22 rillig while (wrote_newlines < 2)
177 1.22 rillig debug_println("");
178 1.6 rillig }
179 1.6 rillig
180 1.6 rillig void
181 1.6 rillig debug_vis_range(const char *prefix, const char *s, size_t len,
182 1.6 rillig const char *suffix)
183 1.6 rillig {
184 1.13 rillig debug_printf("%s", prefix);
185 1.13 rillig for (size_t i = 0; i < len; i++) {
186 1.13 rillig const char *p = s + i;
187 1.13 rillig if (*p == '\\' || *p == '"')
188 1.13 rillig debug_printf("\\%c", *p);
189 1.13 rillig else if (isprint((unsigned char)*p))
190 1.13 rillig debug_printf("%c", *p);
191 1.13 rillig else if (*p == '\n')
192 1.13 rillig debug_printf("\\n");
193 1.13 rillig else if (*p == '\t')
194 1.13 rillig debug_printf("\\t");
195 1.13 rillig else
196 1.13 rillig debug_printf("\\x%02x", (unsigned char)*p);
197 1.13 rillig }
198 1.13 rillig debug_printf("%s", suffix);
199 1.6 rillig }
200 1.6 rillig
201 1.25 rillig void
202 1.1 rillig debug_print_buf(const char *name, const struct buffer *buf)
203 1.1 rillig {
204 1.13 rillig if (buf->len > 0) {
205 1.22 rillig debug_printf(" %s ", name);
206 1.34 rillig debug_vis_range("\"", buf->s, buf->len, "\"");
207 1.13 rillig }
208 1.1 rillig }
209 1.1 rillig
210 1.1 rillig void
211 1.1 rillig debug_buffers(void)
212 1.1 rillig {
213 1.22 rillig debug_print_buf("label", &lab);
214 1.22 rillig debug_print_buf("code", &code);
215 1.22 rillig debug_print_buf("comment", &com);
216 1.22 rillig debug_println("");
217 1.1 rillig }
218 1.1 rillig
219 1.1 rillig #define debug_ps_bool(name) \
220 1.12 rillig if (ps.name != prev_ps.name) \
221 1.36 rillig debug_println(" [%c] ps." #name, \
222 1.36 rillig " -+x"[(prev_ps.name ? 1 : 0) + (ps.name ? 2 : 0)]); \
223 1.1 rillig else if (debug_full_parser_state) \
224 1.36 rillig debug_println(" [%c] ps." #name, ps.name ? 'x' : ' ')
225 1.1 rillig #define debug_ps_int(name) \
226 1.1 rillig if (ps.name != prev_ps.name) \
227 1.36 rillig debug_println(" %3d -> %3d ps." #name, prev_ps.name, ps.name); \
228 1.1 rillig else if (debug_full_parser_state) \
229 1.36 rillig debug_println(" %3d ps." #name, ps.name)
230 1.1 rillig #define debug_ps_enum(name, names) \
231 1.1 rillig if (ps.name != prev_ps.name) \
232 1.36 rillig debug_println(" %3s -> %3s ps." #name, \
233 1.1 rillig (names)[prev_ps.name], (names)[ps.name]); \
234 1.1 rillig else if (debug_full_parser_state) \
235 1.36 rillig debug_println(" %10s ps." #name, (names)[ps.name])
236 1.1 rillig
237 1.1 rillig static bool
238 1.1 rillig ps_paren_has_changed(const struct parser_state *prev_ps)
239 1.1 rillig {
240 1.13 rillig if (prev_ps->nparen != ps.nparen)
241 1.13 rillig return true;
242 1.1 rillig
243 1.15 rillig const paren_level_props *prev = prev_ps->paren, *curr = ps.paren;
244 1.13 rillig for (int i = 0; i < ps.nparen; i++)
245 1.14 rillig if (curr[i].indent != prev[i].indent
246 1.14 rillig || curr[i].cast != prev[i].cast)
247 1.13 rillig return true;
248 1.13 rillig return false;
249 1.1 rillig }
250 1.1 rillig
251 1.1 rillig static void
252 1.1 rillig debug_ps_paren(const struct parser_state *prev_ps)
253 1.1 rillig {
254 1.13 rillig if (!debug_full_parser_state && !ps_paren_has_changed(prev_ps))
255 1.13 rillig return;
256 1.1 rillig
257 1.36 rillig debug_printf(" ps.paren:");
258 1.13 rillig for (int i = 0; i < ps.nparen; i++) {
259 1.13 rillig debug_printf(" %s%d",
260 1.14 rillig paren_level_cast_name[ps.paren[i].cast],
261 1.14 rillig ps.paren[i].indent);
262 1.13 rillig }
263 1.13 rillig if (ps.nparen == 0)
264 1.13 rillig debug_printf(" none");
265 1.13 rillig debug_println("");
266 1.1 rillig }
267 1.1 rillig
268 1.15 rillig static bool
269 1.15 rillig ps_di_stack_has_changed(const struct parser_state *prev_ps)
270 1.15 rillig {
271 1.15 rillig if (prev_ps->decl_level != ps.decl_level)
272 1.15 rillig return true;
273 1.15 rillig for (int i = 0; i < ps.decl_level; i++)
274 1.15 rillig if (prev_ps->di_stack[i] != ps.di_stack[i])
275 1.15 rillig return true;
276 1.15 rillig return false;
277 1.15 rillig }
278 1.15 rillig
279 1.15 rillig static void
280 1.15 rillig debug_ps_di_stack(const struct parser_state *prev_ps)
281 1.15 rillig {
282 1.15 rillig bool changed = ps_di_stack_has_changed(prev_ps);
283 1.15 rillig if (!debug_full_parser_state && !changed)
284 1.15 rillig return;
285 1.15 rillig
286 1.36 rillig debug_printf(" %s ps.di_stack:", changed ? "->" : " ");
287 1.15 rillig for (int i = 0; i < ps.decl_level; i++)
288 1.15 rillig debug_printf(" %d", ps.di_stack[i]);
289 1.15 rillig if (ps.decl_level == 0)
290 1.15 rillig debug_printf(" none");
291 1.15 rillig debug_println("");
292 1.15 rillig }
293 1.15 rillig
294 1.1 rillig void
295 1.22 rillig debug_parser_state(void)
296 1.1 rillig {
297 1.13 rillig static struct parser_state prev_ps;
298 1.1 rillig
299 1.22 rillig debug_blank_line();
300 1.36 rillig debug_println(" ps.prev_lsym = %s",
301 1.36 rillig lsym_name[ps.prev_lsym]);
302 1.35 rillig
303 1.35 rillig debug_println("token classification");
304 1.35 rillig debug_ps_int(quest_level);
305 1.13 rillig debug_ps_bool(is_function_definition);
306 1.13 rillig debug_ps_bool(block_init);
307 1.13 rillig debug_ps_int(block_init_level);
308 1.13 rillig debug_ps_bool(init_or_struct);
309 1.35 rillig debug_ps_bool(decl_on_line);
310 1.35 rillig debug_ps_bool(in_stmt_or_decl);
311 1.35 rillig debug_ps_bool(in_decl);
312 1.35 rillig debug_ps_bool(in_func_def_params);
313 1.35 rillig debug_ps_bool(seen_case);
314 1.35 rillig debug_ps_enum(spaced_expr_psym, psym_name);
315 1.35 rillig debug_ps_enum(lbrace_kind, psym_name);
316 1.13 rillig
317 1.35 rillig debug_println("indentation of statements and declarations");
318 1.13 rillig debug_ps_int(ind_level);
319 1.13 rillig debug_ps_int(ind_level_follow);
320 1.35 rillig debug_ps_bool(in_stmt_cont);
321 1.13 rillig debug_ps_int(decl_level);
322 1.15 rillig debug_ps_di_stack(&prev_ps);
323 1.13 rillig debug_ps_bool(decl_indent_done);
324 1.13 rillig debug_ps_int(decl_ind);
325 1.13 rillig debug_ps_bool(tabs_to_var);
326 1.35 rillig debug_ps_enum(extra_expr_indent, extra_expr_indent_name);
327 1.13 rillig
328 1.35 rillig // The parser symbol stack is printed in debug_parse_stack instead.
329 1.35 rillig
330 1.35 rillig debug_println("spacing inside a statement or declaration");
331 1.35 rillig debug_ps_bool(next_unary);
332 1.35 rillig debug_ps_bool(want_blank);
333 1.35 rillig debug_ps_int(line_start_nparen);
334 1.35 rillig debug_ps_int(nparen);
335 1.35 rillig debug_ps_paren(&prev_ps);
336 1.35 rillig debug_ps_enum(decl_ptr, decl_ptr_name);
337 1.35 rillig
338 1.35 rillig debug_println("horizontal spacing for comments");
339 1.35 rillig debug_ps_int(comment_delta);
340 1.35 rillig debug_ps_int(n_comment_delta);
341 1.35 rillig debug_ps_int(com_ind);
342 1.35 rillig
343 1.35 rillig debug_println("vertical spacing");
344 1.35 rillig debug_ps_bool(break_after_comma);
345 1.35 rillig debug_ps_bool(force_nl);
346 1.35 rillig debug_ps_enum(declaration, declaration_name);
347 1.35 rillig debug_ps_bool(blank_line_after_decl);
348 1.1 rillig
349 1.35 rillig debug_println("comments");
350 1.35 rillig debug_ps_bool(curr_col_1);
351 1.35 rillig debug_ps_bool(next_col_1);
352 1.1 rillig
353 1.22 rillig debug_blank_line();
354 1.1 rillig
355 1.13 rillig prev_ps = ps;
356 1.1 rillig }
357 1.1 rillig
358 1.1 rillig void
359 1.1 rillig debug_parse_stack(const char *situation)
360 1.1 rillig {
361 1.38 rillig debug_printf("parse stack %s:", situation);
362 1.32 rillig for (int i = 0; i <= ps.tos; ++i)
363 1.38 rillig debug_printf(" %d %s", ps.s_ind_level[i], psym_name[ps.s_sym[i]]);
364 1.38 rillig debug_println("");
365 1.1 rillig }
366 1.1 rillig #endif
367