debug.c revision 1.6
1/* $NetBSD: debug.c,v 1.6 2023/05/15 07:57:22 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.6 2023/05/15 07:57:22 rillig Exp $"); 34 35#include <stdarg.h> 36 37#include "indent.h" 38 39#ifdef debug 40const char *const lsym_name[] = { 41 "eof", 42 "preprocessing", 43 "newline", 44 "form_feed", 45 "comment", 46 "lparen_or_lbracket", 47 "rparen_or_rbracket", 48 "lbrace", 49 "rbrace", 50 "period", 51 "unary_op", 52 "binary_op", 53 "postfix_op", 54 "question", 55 "colon", 56 "comma", 57 "semicolon", 58 "typedef", 59 "storage_class", 60 "type_outside_parentheses", 61 "type_in_parentheses", 62 "tag", 63 "case_label", 64 "sizeof", 65 "offsetof", 66 "word", 67 "funcname", 68 "do", 69 "else", 70 "for", 71 "if", 72 "switch", 73 "while", 74 "return", 75}; 76 77const char *const psym_name[] = { 78 "0", 79 "lbrace", 80 "rbrace", 81 "decl", 82 "stmt", 83 "stmt_list", 84 "for_exprs", 85 "if_expr", 86 "if_expr_stmt", 87 "if_expr_stmt_else", 88 "else", 89 "switch_expr", 90 "do", 91 "do_stmt", 92 "while_expr", 93}; 94 95static const char *declaration_name[] = { 96 "no", 97 "begin", 98 "end", 99}; 100 101static const char *in_enum_name[] = { 102 "no", 103 "enum", 104 "type", 105 "brace", 106}; 107 108static bool debug_full_parser_state = true; 109 110void 111debug_printf(const char *fmt, ...) 112{ 113 FILE *f = output == stdout ? stderr : stdout; 114 va_list ap; 115 116 va_start(ap, fmt); 117 vfprintf(f, fmt, ap); 118 va_end(ap); 119} 120 121void 122debug_println(const char *fmt, ...) 123{ 124 FILE *f = output == stdout ? stderr : stdout; 125 va_list ap; 126 127 va_start(ap, fmt); 128 vfprintf(f, fmt, ap); 129 va_end(ap); 130 fprintf(f, "\n"); 131} 132 133void 134debug_vis_range(const char *prefix, const char *s, size_t len, 135 const char *suffix) 136{ 137 debug_printf("%s", prefix); 138 for (size_t i = 0; i < len; i++) { 139 const char *p = s + i; 140 if (*p == '\\' || *p == '"') 141 debug_printf("\\%c", *p); 142 else if (isprint((unsigned char)*p)) 143 debug_printf("%c", *p); 144 else if (*p == '\n') 145 debug_printf("\\n"); 146 else if (*p == '\t') 147 debug_printf("\\t"); 148 else 149 debug_printf("\\x%02x", (unsigned char)*p); 150 } 151 debug_printf("%s", suffix); 152} 153 154static void 155debug_print_buf(const char *name, const struct buffer *buf) 156{ 157 if (buf->len > 0) { 158 debug_printf("%s ", name); 159 debug_vis_range("\"", buf->st, buf->len, "\"\n"); 160 } 161} 162 163void 164debug_buffers(void) 165{ 166 if (lab.len > 0) { 167 debug_printf(" label "); 168 debug_vis_range("\"", lab.st, lab.len, "\""); 169 } 170 if (code.len > 0) { 171 debug_printf(" code "); 172 debug_vis_range("\"", code.st, code.len, "\""); 173 } 174 if (com.len > 0) { 175 debug_printf(" comment "); 176 debug_vis_range("\"", com.st, com.len, "\""); 177 } 178} 179 180#define debug_ps_bool(name) \ 181 if (ps.name != prev_ps.name) \ 182 debug_println("[%c] -> [%c] ps." #name, \ 183 prev_ps.name ? 'x' : ' ', ps.name ? 'x' : ' '); \ 184 else if (debug_full_parser_state) \ 185 debug_println(" [%c] ps." #name, ps.name ? 'x' : ' ') 186#define debug_ps_int(name) \ 187 if (ps.name != prev_ps.name) \ 188 debug_println("%3d -> %3d ps." #name, prev_ps.name, ps.name); \ 189 else if (debug_full_parser_state) \ 190 debug_println(" %3d ps." #name, ps.name) 191#define debug_ps_enum(name, names) \ 192 if (ps.name != prev_ps.name) \ 193 debug_println("%3s -> %3s ps." #name, \ 194 (names)[prev_ps.name], (names)[ps.name]); \ 195 else if (debug_full_parser_state) \ 196 debug_println("%10s ps." #name, (names)[ps.name]) 197 198static bool 199ps_paren_has_changed(const struct parser_state *prev_ps) 200{ 201 const paren_level_props *prev = prev_ps->paren, *curr = ps.paren; 202 203 if (prev_ps->nparen != ps.nparen) 204 return true; 205 206 for (int i = 0; i < ps.nparen; i++) { 207 if (curr[i].indent != prev[i].indent || 208 curr[i].maybe_cast != prev[i].maybe_cast || 209 curr[i].no_cast != prev[i].no_cast) 210 return true; 211 } 212 return false; 213} 214 215static void 216debug_ps_paren(const struct parser_state *prev_ps) 217{ 218 if (!debug_full_parser_state && !ps_paren_has_changed(prev_ps)) 219 return; 220 221 debug_printf(" ps.paren:"); 222 for (int i = 0; i < ps.nparen; i++) { 223 const paren_level_props *props = ps.paren + i; 224 const char *cast = props->no_cast ? "(no cast)" 225 : props->maybe_cast ? "(cast)" 226 : ""; 227 debug_printf(" %s%d", cast, props->indent); 228 } 229 if (ps.nparen == 0) 230 debug_printf(" none"); 231 debug_println(""); 232} 233 234void 235debug_parser_state(lexer_symbol lsym) 236{ 237 static struct parser_state prev_ps; 238 239 debug_println(""); 240 debug_printf("line %d: %s", line_no, lsym_name[lsym]); 241 debug_vis_range(" \"", token.st, token.len, "\"\n"); 242 243 debug_print_buf("label", &lab); 244 debug_print_buf("code", &code); 245 debug_print_buf("comment", &com); 246 247 debug_println(" ps.prev_token = %s", lsym_name[ps.prev_token]); 248 debug_ps_bool(curr_col_1); 249 debug_ps_bool(next_col_1); 250 debug_ps_bool(next_unary); 251 debug_ps_bool(is_function_definition); 252 debug_ps_bool(want_blank); 253 debug_ps_bool(force_nl); 254 debug_ps_int(line_start_nparen); 255 debug_ps_int(nparen); 256 debug_ps_paren(&prev_ps); 257 258 debug_ps_int(comment_delta); 259 debug_ps_int(n_comment_delta); 260 debug_ps_int(com_ind); 261 262 debug_ps_bool(block_init); 263 debug_ps_int(block_init_level); 264 debug_ps_bool(init_or_struct); 265 266 debug_ps_int(ind_level); 267 debug_ps_int(ind_level_follow); 268 269 debug_ps_int(decl_level); 270 debug_ps_bool(decl_on_line); 271 debug_ps_bool(in_decl); 272 debug_ps_enum(declaration, declaration_name); 273 debug_ps_bool(blank_line_after_decl); 274 debug_ps_bool(in_func_def_params); 275 debug_ps_enum(in_enum, in_enum_name); 276 debug_ps_bool(decl_indent_done); 277 debug_ps_int(decl_ind); 278 // No debug output for di_stack. 279 debug_ps_bool(tabs_to_var); 280 281 debug_ps_bool(in_stmt_or_decl); 282 debug_ps_bool(in_stmt_cont); 283 debug_ps_bool(is_case_label); 284 debug_ps_bool(seen_case); 285 286 // The debug output for the parser symbols is done in 'parse' instead. 287 288 debug_ps_enum(spaced_expr_psym, psym_name); 289 debug_ps_int(quest_level); 290 291 prev_ps = ps; 292} 293 294void 295debug_parse_stack(const char *situation) 296{ 297 printf("parse stack %s:", situation); 298 for (int i = 1; i <= ps.tos; ++i) 299 printf(" %s %d", psym_name[ps.s_sym[i]], ps.s_ind_level[i]); 300 if (ps.tos == 0) 301 printf(" empty"); 302 printf("\n"); 303} 304#endif 305