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