debug.c revision 1.30
1/* $NetBSD: debug.c,v 1.30 2023/06/04 12:46:57 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.30 2023/06/04 12:46:57 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 "lbracket", 54 "rparen", 55 "rbracket", 56 "lbrace", 57 "rbrace", 58 "period", 59 "unary_op", 60 "binary_op", 61 "postfix_op", 62 "question", 63 "'?:' colon", 64 "label colon", 65 "other colon", 66 "comma", 67 "semicolon", 68 "typedef", 69 "modifier", 70 "type_outside_parentheses", 71 "type_in_parentheses", 72 "tag", 73 "case", 74 "default", 75 "sizeof", 76 "offsetof", 77 "word", 78 "funcname", 79 "do", 80 "else", 81 "for", 82 "if", 83 "switch", 84 "while", 85 "return", 86}; 87 88const char *const psym_name[] = { 89 "0", 90 "lbrace", 91 "rbrace", 92 "decl", 93 "stmt", 94 "stmt_list", 95 "for_exprs", 96 "if_expr", 97 "if_expr_stmt", 98 "if_expr_stmt_else", 99 "else", 100 "switch_expr", 101 "do", 102 "do_stmt", 103 "while_expr", 104}; 105 106static const char *const declaration_name[] = { 107 "no", 108 "begin", 109 "end", 110}; 111 112static const char *const in_enum_name[] = { 113 "no", 114 "enum", 115 "type", 116 "brace", 117}; 118 119const char *const paren_level_cast_name[] = { 120 "(unknown cast)", 121 "(maybe cast)", 122 "(no cast)", 123}; 124 125const char *const line_kind_name[] = { 126 "other", 127 "blank", 128 "#if", 129 "#endif", 130 "stmt head", 131 "}", 132 "block comment", 133 "case/default", 134}; 135 136static const char *const decl_ptr_name[] = { 137 "start", 138 "word", 139 "word *", 140 "other", 141}; 142 143static unsigned wrote_newlines = 1; 144 145void 146debug_printf(const char *fmt, ...) 147{ 148 FILE *f = output == stdout ? stderr : stdout; 149 va_list ap; 150 151 va_start(ap, fmt); 152 vfprintf(f, fmt, ap); 153 va_end(ap); 154 wrote_newlines = 0; 155} 156 157void 158debug_println(const char *fmt, ...) 159{ 160 FILE *f = output == stdout ? stderr : stdout; 161 va_list ap; 162 163 va_start(ap, fmt); 164 vfprintf(f, fmt, ap); 165 va_end(ap); 166 fprintf(f, "\n"); 167 wrote_newlines = fmt[0] == '\0' ? wrote_newlines + 1 : 1; 168} 169 170void 171debug_blank_line(void) 172{ 173 while (wrote_newlines < 2) 174 debug_println(""); 175} 176 177void 178debug_vis_range(const char *prefix, const char *s, size_t len, 179 const char *suffix) 180{ 181 debug_printf("%s", prefix); 182 for (size_t i = 0; i < len; i++) { 183 const char *p = s + i; 184 if (*p == '\\' || *p == '"') 185 debug_printf("\\%c", *p); 186 else if (isprint((unsigned char)*p)) 187 debug_printf("%c", *p); 188 else if (*p == '\n') 189 debug_printf("\\n"); 190 else if (*p == '\t') 191 debug_printf("\\t"); 192 else 193 debug_printf("\\x%02x", (unsigned char)*p); 194 } 195 debug_printf("%s", suffix); 196} 197 198void 199debug_print_buf(const char *name, const struct buffer *buf) 200{ 201 if (buf->len > 0) { 202 debug_printf(" %s ", name); 203 debug_vis_range("\"", buf->st, buf->len, "\""); 204 } 205} 206 207void 208debug_buffers(void) 209{ 210 debug_print_buf("label", &lab); 211 debug_print_buf("code", &code); 212 debug_print_buf("comment", &com); 213 debug_println(""); 214} 215 216#define debug_ps_bool(name) \ 217 if (ps.name != prev_ps.name) \ 218 debug_println("[%c] -> [%c] ps." #name, \ 219 prev_ps.name ? 'x' : ' ', ps.name ? 'x' : ' '); \ 220 else if (debug_full_parser_state) \ 221 debug_println(" [%c] ps." #name, ps.name ? 'x' : ' ') 222#define debug_ps_int(name) \ 223 if (ps.name != prev_ps.name) \ 224 debug_println("%3d -> %3d ps." #name, prev_ps.name, ps.name); \ 225 else if (debug_full_parser_state) \ 226 debug_println(" %3d ps." #name, ps.name) 227#define debug_ps_enum(name, names) \ 228 if (ps.name != prev_ps.name) \ 229 debug_println("%3s -> %3s ps." #name, \ 230 (names)[prev_ps.name], (names)[ps.name]); \ 231 else if (debug_full_parser_state) \ 232 debug_println("%10s ps." #name, (names)[ps.name]) 233 234static bool 235ps_paren_has_changed(const struct parser_state *prev_ps) 236{ 237 if (prev_ps->nparen != ps.nparen) 238 return true; 239 240 const paren_level_props *prev = prev_ps->paren, *curr = ps.paren; 241 for (int i = 0; i < ps.nparen; i++) 242 if (curr[i].indent != prev[i].indent 243 || curr[i].cast != prev[i].cast) 244 return true; 245 return false; 246} 247 248static void 249debug_ps_paren(const struct parser_state *prev_ps) 250{ 251 if (!debug_full_parser_state && !ps_paren_has_changed(prev_ps)) 252 return; 253 254 debug_printf(" ps.paren:"); 255 for (int i = 0; i < ps.nparen; i++) { 256 debug_printf(" %s%d", 257 paren_level_cast_name[ps.paren[i].cast], 258 ps.paren[i].indent); 259 } 260 if (ps.nparen == 0) 261 debug_printf(" none"); 262 debug_println(""); 263} 264 265static bool 266ps_di_stack_has_changed(const struct parser_state *prev_ps) 267{ 268 if (prev_ps->decl_level != ps.decl_level) 269 return true; 270 for (int i = 0; i < ps.decl_level; i++) 271 if (prev_ps->di_stack[i] != ps.di_stack[i]) 272 return true; 273 return false; 274} 275 276static void 277debug_ps_di_stack(const struct parser_state *prev_ps) 278{ 279 bool changed = ps_di_stack_has_changed(prev_ps); 280 if (!debug_full_parser_state && !changed) 281 return; 282 283 debug_printf(" %s ps.di_stack:", changed ? "->" : " "); 284 for (int i = 0; i < ps.decl_level; i++) 285 debug_printf(" %d", ps.di_stack[i]); 286 if (ps.decl_level == 0) 287 debug_printf(" none"); 288 debug_println(""); 289} 290 291void 292debug_parser_state(void) 293{ 294 static struct parser_state prev_ps; 295 296 debug_blank_line(); 297 debug_println(" ps.prev_token = %s", 298 lsym_name[ps.prev_token]); 299 debug_ps_bool(curr_col_1); 300 debug_ps_bool(next_col_1); 301 debug_ps_bool(next_unary); 302 debug_ps_bool(is_function_definition); 303 debug_ps_bool(want_blank); 304 debug_ps_bool(break_after_comma); 305 debug_ps_bool(force_nl); 306 debug_ps_int(line_start_nparen); 307 debug_ps_int(nparen); 308 debug_ps_paren(&prev_ps); 309 310 debug_ps_int(comment_delta); 311 debug_ps_int(n_comment_delta); 312 debug_ps_int(com_ind); 313 314 debug_ps_bool(block_init); 315 debug_ps_int(block_init_level); 316 debug_ps_bool(init_or_struct); 317 318 debug_ps_int(ind_level); 319 debug_ps_int(ind_level_follow); 320 321 debug_ps_int(decl_level); 322 debug_ps_di_stack(&prev_ps); 323 debug_ps_bool(decl_on_line); 324 debug_ps_bool(in_decl); 325 debug_ps_enum(declaration, declaration_name); 326 debug_ps_bool(blank_line_after_decl); 327 debug_ps_bool(in_func_def_params); 328 debug_ps_enum(in_enum, in_enum_name); 329 debug_ps_enum(decl_ptr, decl_ptr_name); 330 debug_ps_bool(decl_indent_done); 331 debug_ps_int(decl_ind); 332 debug_ps_bool(tabs_to_var); 333 334 debug_ps_bool(in_stmt_or_decl); 335 debug_ps_bool(in_stmt_cont); 336 debug_ps_bool(seen_case); 337 338 // The debug output for the parser symbols is done in 'parse' instead. 339 340 debug_ps_enum(spaced_expr_psym, psym_name); 341 debug_ps_int(quest_level); 342 debug_blank_line(); 343 344 prev_ps = ps; 345} 346 347void 348debug_parse_stack(const char *situation) 349{ 350 printf("parse stack %s:", situation); 351 for (int i = 1; i <= ps.tos; ++i) 352 printf(" %s %d", psym_name[ps.s_sym[i]], ps.s_ind_level[i]); 353 if (ps.tos == 0) 354 printf(" empty"); 355 printf("\n"); 356} 357#endif 358