Home | History | Annotate | Line # | Download | only in indent
parse.c revision 1.78
      1 /*	$NetBSD: parse.c,v 1.78 2023/06/17 22:28:49 rillig Exp $	*/
      2 
      3 /*-
      4  * SPDX-License-Identifier: BSD-4-Clause
      5  *
      6  * Copyright (c) 1985 Sun Microsystems, Inc.
      7  * Copyright (c) 1980, 1993
      8  *	The Regents of the University of California.  All rights reserved.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the University of
     22  *	California, Berkeley and its contributors.
     23  * 4. Neither the name of the University nor the names of its contributors
     24  *    may be used to endorse or promote products derived from this software
     25  *    without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     37  * SUCH DAMAGE.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __RCSID("$NetBSD: parse.c,v 1.78 2023/06/17 22:28:49 rillig Exp $");
     42 
     43 #include <stdlib.h>
     44 
     45 #include "indent.h"
     46 
     47 /*
     48  * Try to combine the statement on the top of the parse stack with the symbol
     49  * directly below it, replacing these two symbols with a single symbol.
     50  */
     51 static bool
     52 psyms_reduce_stmt(void)
     53 {
     54 	struct psym_stack *psyms = &ps.psyms;
     55 	switch (psyms->sym[psyms->len - 2]) {
     56 
     57 	case psym_stmt:
     58 		psyms->sym[psyms->len-- - 2] = psym_stmt;
     59 		return true;
     60 
     61 	case psym_do:
     62 		psyms->sym[psyms->len-- - 2] = psym_do_stmt;
     63 		ps.ind_level_follow = psyms->ind_level[psyms->len - 1];
     64 		return true;
     65 
     66 	case psym_if_expr:
     67 		psyms->sym[psyms->len-- - 2] = psym_if_expr_stmt;
     68 		size_t i = psyms->len - 2;
     69 		while (psyms->sym[i] != psym_stmt &&
     70 		    psyms->sym[i] != psym_lbrace_block)
     71 			i--;
     72 		ps.ind_level_follow = psyms->ind_level[i];
     73 		/* For the time being, assume that there is no 'else' on this
     74 		 * 'if', and set the indentation level accordingly. If an
     75 		 * 'else' is scanned, it will be fixed up later. */
     76 		return true;
     77 
     78 	case psym_switch_expr:
     79 	case psym_decl:
     80 	case psym_if_expr_stmt_else:
     81 	case psym_for_exprs:
     82 	case psym_while_expr:
     83 		psyms->sym[psyms->len-- - 2] = psym_stmt;
     84 		ps.ind_level_follow = psyms->ind_level[psyms->len - 1];
     85 		return true;
     86 
     87 	default:
     88 		return false;
     89 	}
     90 }
     91 
     92 static int
     93 decl_level(void)
     94 {
     95 	int level = 0;
     96 	for (size_t i = ps.psyms.len - 2; i > 0; i--)
     97 		if (ps.psyms.sym[i] == psym_decl)
     98 			level++;
     99 	return level;
    100 }
    101 
    102 void
    103 ps_push(parser_symbol psym, bool follow)
    104 {
    105 	if (ps.psyms.len == ps.psyms.cap) {
    106 		ps.psyms.cap += 16;
    107 		ps.psyms.sym = nonnull(realloc(ps.psyms.sym,
    108 			sizeof(ps.psyms.sym[0]) * ps.psyms.cap));
    109 		ps.psyms.ind_level = nonnull(realloc(ps.psyms.ind_level,
    110 			sizeof(ps.psyms.ind_level[0]) * ps.psyms.cap));
    111 	}
    112 	ps.psyms.len++;
    113 	ps.psyms.sym[ps.psyms.len - 1] = psym;
    114 	ps.psyms.ind_level[ps.psyms.len - 1] =
    115 	    follow ? ps.ind_level_follow : ps.ind_level;
    116 }
    117 
    118 /*
    119  * Repeatedly try to reduce the top two symbols on the parse stack to a single
    120  * symbol, until no more reductions are possible.
    121  */
    122 static void
    123 psyms_reduce(void)
    124 {
    125 	struct psym_stack *psyms = &ps.psyms;
    126 again:
    127 	if (psyms->len >= 2 && psyms->sym[psyms->len - 1] == psym_stmt
    128 	    && psyms_reduce_stmt())
    129 		goto again;
    130 	if (psyms->sym[psyms->len - 1] == psym_while_expr &&
    131 	    psyms->sym[psyms->len - 2] == psym_do_stmt) {
    132 		psyms->len -= 2;
    133 		goto again;
    134 	}
    135 }
    136 
    137 static bool
    138 is_lbrace(parser_symbol psym)
    139 {
    140 	return psym == psym_lbrace_block
    141 	    || psym == psym_lbrace_struct
    142 	    || psym == psym_lbrace_union
    143 	    || psym == psym_lbrace_enum;
    144 }
    145 
    146 /*
    147  * Shift the token onto the parser stack, then try to reduce it by combining it with
    148  * previous tokens.
    149  */
    150 void
    151 parse(parser_symbol psym)
    152 {
    153 	debug_blank_line();
    154 	debug_println("parse token: %s", psym_name[psym]);
    155 
    156 	struct psym_stack *psyms = &ps.psyms;
    157 	if (psym != psym_else) {
    158 		while (psyms->sym[psyms->len - 1] == psym_if_expr_stmt) {
    159 			psyms->sym[psyms->len - 1] = psym_stmt;
    160 			psyms_reduce();
    161 		}
    162 	}
    163 
    164 	switch (psym) {
    165 
    166 	case psym_lbrace_block:
    167 	case psym_lbrace_struct:
    168 	case psym_lbrace_union:
    169 	case psym_lbrace_enum:
    170 		ps.break_after_comma = false;
    171 		if (psyms->sym[psyms->len - 1] == psym_decl
    172 		    || psyms->sym[psyms->len - 1] == psym_stmt)
    173 			ps.ind_level_follow++;
    174 		else if (code.len == 0) {
    175 			/* It is part of a while, for, etc. */
    176 			ps.ind_level--;
    177 
    178 			/* for a switch, brace should be two levels out from
    179 			 * the code */
    180 			if (psyms->sym[psyms->len - 1] == psym_switch_expr
    181 			    && opt.case_indent >= 1.0F)
    182 				ps.ind_level--;
    183 		}
    184 
    185 		ps_push(psym, false);
    186 		ps_push(psym_stmt, true);
    187 		break;
    188 
    189 	case psym_rbrace:
    190 		/* stack should have <lbrace> <stmt> or <lbrace> <decl> */
    191 		if (!(psyms->len >= 2
    192 			&& is_lbrace(psyms->sym[psyms->len - 2]))) {
    193 			diag(1, "Statement nesting error");
    194 			break;
    195 		}
    196 		ps.ind_level = ps.ind_level_follow =
    197 		    psyms->ind_level[psyms->len-- - 2];
    198 		psyms->sym[psyms->len - 1] = psym_stmt;
    199 		break;
    200 
    201 	case psym_decl:
    202 		if (psyms->sym[psyms->len - 1] == psym_decl)
    203 			break;	/* only put one declaration onto stack */
    204 
    205 		ps.break_after_comma = true;
    206 		ps_push(psym_decl, true);
    207 
    208 		if (opt.left_justify_decl)
    209 			ps.ind_level_follow = ps.ind_level = decl_level();
    210 		break;
    211 
    212 	case psym_stmt:
    213 		ps.break_after_comma = false;
    214 		ps_push(psym_stmt, false);
    215 		break;
    216 
    217 	case psym_if_expr:
    218 		if (psyms->sym[psyms->len - 1] == psym_if_expr_stmt_else
    219 		    && opt.else_if_in_same_line)
    220 			ps.ind_level_follow =
    221 			    psyms->ind_level[psyms->len-- - 1];
    222 		/* FALLTHROUGH */
    223 	case psym_do:
    224 	case psym_for_exprs:
    225 		ps.ind_level = ps.ind_level_follow++;
    226 		ps_push(psym, false);
    227 		break;
    228 
    229 	case psym_else:
    230 		if (psyms->sym[psyms->len - 1] != psym_if_expr_stmt) {
    231 			diag(1, "Unmatched 'else'");
    232 			break;
    233 		}
    234 		ps.ind_level = psyms->ind_level[psyms->len - 1];
    235 		ps.ind_level_follow = ps.ind_level + 1;
    236 		psyms->sym[psyms->len - 1] = psym_if_expr_stmt_else;
    237 		break;
    238 
    239 	case psym_switch_expr:
    240 		ps_push(psym_switch_expr, true);
    241 		ps.ind_level_follow += (int)opt.case_indent + 1;
    242 		break;
    243 
    244 	case psym_while_expr:
    245 		if (psyms->sym[psyms->len - 1] == psym_do_stmt) {
    246 			ps.ind_level = ps.ind_level_follow =
    247 			    psyms->ind_level[psyms->len - 1];
    248 			ps_push(psym_while_expr, false);
    249 		} else {
    250 			ps_push(psym_while_expr, true);
    251 			ps.ind_level_follow++;
    252 		}
    253 		break;
    254 
    255 	default:
    256 		diag(1, "Unknown code to parser");
    257 		return;
    258 	}
    259 
    260 	debug_psyms_stack("before reduction");
    261 	psyms_reduce();
    262 	debug_psyms_stack("after reduction");
    263 }
    264