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