1 /* $NetBSD: parse.c,v 1.85 2025/01/07 03:55:00 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.85 2025/01/07 03:55:00 rillig Exp $"); 42 43 #include <stdlib.h> 44 45 #include "indent.h" 46 47 /* Replace the top 2 symbols with the given symbol. */ 48 static void 49 ps_psyms_replace2(parser_symbol psym) 50 { 51 ps.psyms.len--; 52 ps.psyms.sym[ps.psyms.len - 1] = psym; 53 ps.ind_level_follow = ps.psyms.ind_level[ps.psyms.len - 1]; 54 } 55 56 static int 57 left_justify_decl_level(void) 58 { 59 int level = 0; 60 for (size_t i = ps.psyms.len - 2; i > 0; i--) 61 if (ps.psyms.sym[i] == psym_decl) 62 level++; 63 return level; 64 } 65 66 void 67 ps_psyms_push(parser_symbol psym, int ind_level) 68 { 69 if (ps.psyms.len == ps.psyms.cap) { 70 ps.psyms.cap += 16; 71 ps.psyms.sym = nonnull(realloc(ps.psyms.sym, 72 sizeof(ps.psyms.sym[0]) * ps.psyms.cap)); 73 ps.psyms.ind_level = nonnull(realloc(ps.psyms.ind_level, 74 sizeof(ps.psyms.ind_level[0]) * ps.psyms.cap)); 75 } 76 ps.psyms.len++; 77 ps.psyms.sym[ps.psyms.len - 1] = psym; 78 ps.psyms.ind_level[ps.psyms.len - 1] = ind_level; 79 } 80 81 /* 82 * Repeatedly try to reduce the top two symbols on the parse stack to a single 83 * symbol, until no more reductions are possible. 84 */ 85 static void 86 psyms_reduce(void) 87 { 88 again: 89 if (ps.psyms.len >= 2 && ps.psyms.sym[ps.psyms.len - 1] == psym_stmt) { 90 switch (ps.psyms.sym[ps.psyms.len - 2]) { 91 case psym_decl: 92 case psym_stmt: 93 case psym_for_exprs: 94 case psym_if_expr_stmt_else: 95 case psym_switch_expr: 96 case psym_while_expr: 97 ps_psyms_replace2(psym_stmt); 98 goto again; 99 case psym_if_expr: 100 ps_psyms_replace2(psym_if_expr_stmt); 101 goto again; 102 case psym_do: 103 ps_psyms_replace2(psym_do_stmt); 104 goto again; 105 default: 106 return; 107 } 108 } 109 if (ps.psyms.sym[ps.psyms.len - 1] == psym_while_expr && 110 ps.psyms.sym[ps.psyms.len - 2] == psym_do_stmt) { 111 ps.psyms.len -= 2; 112 goto again; 113 } 114 } 115 116 static bool 117 is_lbrace(parser_symbol psym) 118 { 119 return psym == psym_lbrace_block 120 || psym == psym_lbrace_struct 121 || psym == psym_lbrace_union 122 || psym == psym_lbrace_enum; 123 } 124 125 /* 126 * Shift the token onto the parser stack, then try to reduce it by combining it with 127 * previous tokens. 128 */ 129 void 130 parse(parser_symbol psym) 131 { 132 debug_blank_line(); 133 debug_println("parse: %s", psym_name[psym]); 134 135 if (psym != psym_else) { 136 while (ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt) { 137 ps.psyms.sym[ps.psyms.len - 1] = psym_stmt; 138 psyms_reduce(); 139 ps.ind_level = ps.ind_level_follow 140 = ps.psyms.ind_level[ps.psyms.len - 1]; 141 } 142 } 143 144 switch (psym) { 145 146 case psym_lbrace_block: 147 case psym_lbrace_struct: 148 case psym_lbrace_union: 149 case psym_lbrace_enum: 150 ps.break_after_comma = false; 151 if (ps.psyms.sym[ps.psyms.len - 1] == psym_decl 152 || ps.psyms.sym[ps.psyms.len - 1] == psym_stmt) 153 ps.ind_level_follow++; 154 else if (code.len == 0) { 155 /* It is part of a while, for, etc. */ 156 ps.ind_level--; 157 158 /* for a switch, brace should be two levels out from 159 * the code */ 160 if (ps.psyms.sym[ps.psyms.len - 1] == psym_switch_expr 161 && opt.case_indent >= 1.0F) 162 ps.ind_level--; 163 } 164 165 ps_psyms_push(psym, ps.ind_level); 166 ps_psyms_push(psym_stmt, ps.ind_level_follow); 167 break; 168 169 case psym_rbrace: 170 /* stack should have <lbrace> <stmt> or <lbrace> <decl> */ 171 if (!(ps.psyms.len >= 2 172 && is_lbrace(ps.psyms.sym[ps.psyms.len - 2]))) { 173 diag(1, "Statement nesting error"); 174 break; 175 } 176 ps_psyms_replace2(psym_stmt); 177 ps.ind_level = ps.ind_level_follow; 178 break; 179 180 case psym_decl: 181 if (ps.psyms.sym[ps.psyms.len - 1] == psym_decl) 182 break; /* only put one declaration onto stack */ 183 184 ps.break_after_comma = true; 185 ps_psyms_push(psym_decl, ps.ind_level_follow); 186 187 if (opt.left_justify_decl) { 188 ps.ind_level = left_justify_decl_level(); 189 ps.ind_level_follow = ps.ind_level; 190 } 191 break; 192 193 case psym_stmt: 194 ps.break_after_comma = false; 195 ps_psyms_push(psym_stmt, ps.ind_level); 196 break; 197 198 case psym_if_expr: 199 if (ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt_else 200 && opt.else_if_in_same_line) { 201 ps.ind_level_follow = 202 ps.psyms.ind_level[ps.psyms.len - 1]; 203 ps.psyms.len--; 204 } 205 /* FALLTHROUGH */ 206 case psym_do: 207 case psym_for_exprs: 208 ps.ind_level = ps.ind_level_follow; 209 ps.ind_level_follow = ps.ind_level + 1; 210 ps_psyms_push(psym, ps.ind_level); 211 break; 212 213 case psym_else: 214 if (ps.psyms.sym[ps.psyms.len - 1] != psym_if_expr_stmt) { 215 diag(1, "Unmatched 'else'"); 216 break; 217 } 218 ps.ind_level = ps.psyms.ind_level[ps.psyms.len - 1]; 219 ps.ind_level_follow = ps.ind_level + 1; 220 ps.psyms.sym[ps.psyms.len - 1] = psym_if_expr_stmt_else; 221 break; 222 223 case psym_switch_expr: 224 ps_psyms_push(psym_switch_expr, ps.ind_level_follow); 225 ps.ind_level_follow += (int)opt.case_indent + 1; 226 break; 227 228 case psym_while_expr: 229 if (ps.psyms.sym[ps.psyms.len - 1] == psym_do_stmt) { 230 ps.ind_level = ps.psyms.ind_level[ps.psyms.len - 1]; 231 ps.ind_level_follow = ps.ind_level; 232 ps_psyms_push(psym_while_expr, ps.ind_level); 233 } else { 234 ps_psyms_push(psym_while_expr, ps.ind_level_follow); 235 ps.ind_level_follow++; 236 } 237 break; 238 239 default: 240 diag(1, "Unknown code to parser"); 241 return; 242 } 243 244 #if debug 245 static struct buffer before, after; 246 buf_clear(&before); 247 ps_psyms_to_string(&before, &ps); 248 #endif 249 psyms_reduce(); 250 #if debug 251 buf_clear(&after); 252 ps_psyms_to_string(&after, &ps); 253 if (strcmp(before.s, after.s) != 0) { 254 debug_println("psyms before: %s", before.s); 255 debug_println("psyms after: %s", after.s); 256 } else 257 debug_println("psyms: %s", after.s); 258 #endif 259 } 260