1 /* $NetBSD: debug.c,v 1.70 2023/06/27 04:41:23 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.70 2023/06/27 04:41:23 rillig Exp $"); 34 35 #include <stdarg.h> 36 #include <string.h> 37 38 #include "indent.h" 39 40 #ifdef debug 41 42 static struct { 43 // false show only the changes to the parser state 44 // true show unchanged parts of the parser state as well 45 bool full_parser_state; 46 } config = { 47 .full_parser_state = false, 48 }; 49 50 const char *const lsym_name[] = { 51 "eof", 52 "preprocessing", 53 "newline", 54 "comment", 55 "lparen", 56 "rparen", 57 "lbracket", 58 "rbracket", 59 "lbrace", 60 "rbrace", 61 "period", 62 "unary_op", 63 "sizeof", 64 "offsetof", 65 "postfix_op", 66 "binary_op", 67 "question", 68 "question_colon", 69 "comma", 70 "typedef", 71 "modifier", 72 "tag", 73 "type", 74 "word", 75 "funcname", 76 "label_colon", 77 "other_colon", 78 "semicolon", 79 "case", 80 "default", 81 "do", 82 "else", 83 "for", 84 "if", 85 "switch", 86 "while", 87 "return", 88 }; 89 90 const char *const psym_name[] = { 91 "-", 92 "{block", 93 "{struct", 94 "{union", 95 "{enum", 96 "}", 97 "decl", 98 "stmt", 99 "for_exprs", 100 "if_expr", 101 "if_expr_stmt", 102 "if_expr_stmt_else", 103 "else", 104 "switch_expr", 105 "do", 106 "do_stmt", 107 "while_expr", 108 }; 109 110 static const char *const declaration_name[] = { 111 "no", 112 "begin", 113 "end", 114 }; 115 116 static const char *const badp_name[] = { 117 "none", 118 "seen{", 119 "decl", 120 "seen_decl", 121 "yes", 122 }; 123 124 const char *const paren_level_cast_name[] = { 125 "(unknown cast)", 126 "(maybe cast)", 127 "(no cast)", 128 }; 129 130 const char *const line_kind_name[] = { 131 "other", 132 "blank", 133 "#if", 134 "#endif", 135 "#other", 136 "stmt head", 137 "}", 138 "block comment", 139 "case/default", 140 }; 141 142 static const char *const extra_expr_indent_name[] = { 143 "no", 144 "maybe", 145 "last", 146 }; 147 148 static struct { 149 struct parser_state prev_ps; 150 bool ps_first; 151 const char *heading; 152 unsigned wrote_newlines; 153 } state = { 154 .ps_first = true, 155 .wrote_newlines = 1, 156 }; 157 158 void 159 debug_printf(const char *fmt, ...) 160 { 161 FILE *f = output == stdout ? stderr : stdout; 162 va_list ap; 163 164 if (state.heading != NULL) { 165 fprintf(f, "%s\n", state.heading); 166 state.heading = NULL; 167 } 168 va_start(ap, fmt); 169 vfprintf(f, fmt, ap); 170 va_end(ap); 171 state.wrote_newlines = 0; 172 } 173 174 void 175 debug_println(const char *fmt, ...) 176 { 177 FILE *f = output == stdout ? stderr : stdout; 178 va_list ap; 179 180 if (state.heading != NULL) { 181 fprintf(f, "%s\n", state.heading); 182 state.heading = NULL; 183 state.wrote_newlines = 1; 184 } 185 va_start(ap, fmt); 186 vfprintf(f, fmt, ap); 187 va_end(ap); 188 fprintf(f, "\n"); 189 state.wrote_newlines = fmt[0] == '\0' ? state.wrote_newlines + 1 : 1; 190 } 191 192 void 193 debug_blank_line(void) 194 { 195 while (state.wrote_newlines < 2) 196 debug_println(""); 197 } 198 199 void 200 debug_vis_range(const char *s, size_t len) 201 { 202 debug_printf("\""); 203 for (size_t i = 0; i < len; i++) { 204 const char *p = s + i; 205 if (*p == '\\' || *p == '"') 206 debug_printf("\\%c", *p); 207 else if (isprint((unsigned char)*p)) 208 debug_printf("%c", *p); 209 else if (*p == '\n') 210 debug_printf("\\n"); 211 else if (*p == '\t') 212 debug_printf("\\t"); 213 else 214 debug_printf("\\x%02x", (unsigned char)*p); 215 } 216 debug_printf("\""); 217 } 218 219 void 220 debug_print_buf(const char *name, const struct buffer *buf) 221 { 222 if (buf->len > 0) { 223 debug_printf(" %s ", name); 224 debug_vis_range(buf->s, buf->len); 225 } 226 } 227 228 void 229 debug_buffers(void) 230 { 231 debug_print_buf("label", &lab); 232 debug_print_buf("code", &code); 233 debug_print_buf("comment", &com); 234 debug_blank_line(); 235 } 236 237 static void 238 debug_ps_bool_member(const char *name, bool prev, bool curr) 239 { 240 if (!state.ps_first && curr != prev) { 241 char diff = " -+x"[(prev ? 1 : 0) + (curr ? 2 : 0)]; 242 debug_println(" [%c] ps.%s", diff, name); 243 } else if (config.full_parser_state || state.ps_first) 244 debug_println(" [%c] ps.%s", curr ? 'x' : ' ', name); 245 } 246 247 static void 248 debug_ps_int_member(const char *name, int prev, int curr) 249 { 250 if (!state.ps_first && curr != prev) 251 debug_println(" %3d -> %3d ps.%s", prev, curr, name); 252 else if (config.full_parser_state || state.ps_first) 253 debug_println(" %3d ps.%s", curr, name); 254 } 255 256 static void 257 debug_ps_enum_member(const char *name, const char *prev, const char *curr) 258 { 259 if (!state.ps_first && strcmp(prev, curr) != 0) 260 debug_println(" %3s -> %3s ps.%s", prev, curr, name); 261 else if (config.full_parser_state || state.ps_first) 262 debug_println(" %10s ps.%s", curr, name); 263 } 264 265 static bool 266 paren_stack_equal(const struct paren_stack *a, const struct paren_stack *b) 267 { 268 if (a->len != b->len) 269 return false; 270 271 for (size_t i = 0, n = a->len; i < n; i++) 272 if (a->item[i].indent != b->item[i].indent 273 || a->item[i].cast != b->item[i].cast) 274 return false; 275 return true; 276 } 277 278 static void 279 debug_ps_paren(void) 280 { 281 if (!config.full_parser_state 282 && paren_stack_equal(&state.prev_ps.paren, &ps.paren) 283 && !state.ps_first) 284 return; 285 286 debug_printf(" ps.paren:"); 287 for (size_t i = 0; i < ps.paren.len; i++) { 288 debug_printf(" %s%d", 289 paren_level_cast_name[ps.paren.item[i].cast], 290 ps.paren.item[i].indent); 291 } 292 if (ps.paren.len == 0) 293 debug_printf(" none"); 294 debug_println(""); 295 } 296 297 static bool 298 ps_di_stack_has_changed(void) 299 { 300 if (state.prev_ps.decl_level != ps.decl_level) 301 return true; 302 for (int i = 0; i < ps.decl_level; i++) 303 if (state.prev_ps.di_stack[i] != ps.di_stack[i]) 304 return true; 305 return false; 306 } 307 308 static void 309 debug_ps_di_stack(void) 310 { 311 bool changed = ps_di_stack_has_changed(); 312 if (!config.full_parser_state && !changed && !state.ps_first) 313 return; 314 315 debug_printf(" %s ps.di_stack:", changed ? "->" : " "); 316 for (int i = 0; i < ps.decl_level; i++) 317 debug_printf(" %d", ps.di_stack[i]); 318 if (ps.decl_level == 0) 319 debug_printf(" none"); 320 debug_println(""); 321 } 322 323 #define debug_ps_bool(name) \ 324 debug_ps_bool_member(#name, state.prev_ps.name, ps.name) 325 #define debug_ps_int(name) \ 326 debug_ps_int_member(#name, state.prev_ps.name, ps.name) 327 #define debug_ps_enum(name, names) \ 328 debug_ps_enum_member(#name, (names)[state.prev_ps.name], \ 329 (names)[ps.name]) 330 331 void 332 debug_parser_state(void) 333 { 334 debug_blank_line(); 335 336 state.heading = "token classification"; 337 debug_ps_enum(prev_lsym, lsym_name); 338 debug_ps_bool(in_stmt_or_decl); 339 debug_ps_bool(in_decl); 340 debug_ps_bool(in_typedef_decl); 341 debug_ps_bool(in_var_decl); 342 debug_ps_bool(in_init); 343 debug_ps_int(init_level); 344 debug_ps_bool(line_has_func_def); 345 debug_ps_bool(in_func_def_params); 346 debug_ps_bool(line_has_decl); 347 debug_ps_enum(lbrace_kind, psym_name); 348 debug_ps_enum(spaced_expr_psym, psym_name); 349 debug_ps_bool(seen_case); 350 debug_ps_bool(prev_paren_was_cast); 351 debug_ps_int(quest_level); 352 353 state.heading = "indentation of statements and declarations"; 354 debug_ps_int(ind_level); 355 debug_ps_int(ind_level_follow); 356 debug_ps_bool(line_is_stmt_cont); 357 debug_ps_int(decl_level); 358 debug_ps_di_stack(); 359 debug_ps_bool(decl_indent_done); 360 debug_ps_int(decl_ind); 361 debug_ps_bool(tabs_to_var); 362 debug_ps_enum(extra_expr_indent, extra_expr_indent_name); 363 364 // The parser symbol stack is printed in debug_psyms_stack instead. 365 366 state.heading = "spacing inside a statement or declaration"; 367 debug_ps_bool(next_unary); 368 debug_ps_bool(want_blank); 369 debug_ps_int(ind_paren_level); 370 debug_ps_paren(); 371 372 state.heading = "indentation of comments"; 373 debug_ps_int(comment_ind); 374 debug_ps_int(comment_shift); 375 debug_ps_bool(comment_cont); 376 377 state.heading = "vertical spacing"; 378 debug_ps_bool(break_after_comma); 379 debug_ps_bool(want_newline); 380 debug_ps_enum(declaration, declaration_name); 381 debug_ps_bool(blank_line_after_decl); 382 debug_ps_enum(badp, badp_name); 383 384 state.heading = NULL; 385 debug_blank_line(); 386 387 parser_state_free(&state.prev_ps); 388 parser_state_back_up(&state.prev_ps); 389 state.ps_first = false; 390 } 391 392 void 393 debug_psyms_stack(const char *situation) 394 { 395 debug_printf("parse stack %s:", situation); 396 const struct psym_stack *psyms = &ps.psyms; 397 for (size_t i = 0; i < psyms->len; i++) 398 debug_printf(" %d %s", 399 psyms->ind_level[i], psym_name[psyms->sym[i]]); 400 debug_println(""); 401 } 402 #endif 403