1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1985 Sun Microsystems, Inc. 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)parse.c 8.1 (Berkeley) 6/6/93 34 * $FreeBSD: head/usr.bin/indent/parse.c 337651 2018-08-11 19:20:06Z pstef $ 35 */ 36 37 #include <err.h> 38 #include <stdio.h> 39 #include "indent_globs.h" 40 #include "indent_codes.h" 41 #include "indent.h" 42 43 static void reduce(void); 44 45 void 46 parse(int tk) /* tk: the code for the construct scanned */ 47 { 48 int i; 49 50 #ifdef debug 51 printf("%2d - %s\n", tk, token); 52 #endif 53 54 while (ps.p_stack[ps.tos] == ifhead && tk != elselit) { 55 /* true if we have an if without an else */ 56 ps.p_stack[ps.tos] = stmt; /* apply the if(..) stmt ::= stmt 57 * reduction */ 58 reduce(); /* see if this allows any reduction */ 59 } 60 61 62 switch (tk) { /* go on and figure out what to do with the 63 * input */ 64 65 case decl: /* scanned a declaration word */ 66 ps.search_brace = opt.btype_2; 67 /* indicate that following brace should be on same line */ 68 if (ps.p_stack[ps.tos] != decl) { /* only put one declaration 69 * onto stack */ 70 break_comma = true; /* while in declaration, newline should be 71 * forced after comma */ 72 ps.p_stack[++ps.tos] = decl; 73 ps.il[ps.tos] = ps.i_l_follow; 74 75 if (opt.ljust_decl) {/* only do if we want left justified 76 * declarations */ 77 ps.ind_level = 0; 78 for (i = ps.tos - 1; i > 0; --i) 79 if (ps.p_stack[i] == decl) 80 ++ps.ind_level; /* indentation is number of 81 * declaration levels deep we are */ 82 ps.i_l_follow = ps.ind_level; 83 } 84 } 85 break; 86 87 case ifstmt: /* scanned if (...) */ 88 if (ps.p_stack[ps.tos] == elsehead && opt.else_if) /* "else if ..." */ 89 /* 90 * Note that the stack pointer here is decremented, effectively 91 * reducing "else if" to "if". This saves a lot of stack space 92 * in case of a long "if-else-if ... else-if" sequence. 93 */ 94 ps.i_l_follow = ps.il[ps.tos--]; 95 /* the rest is the same as for dolit and forstmt */ 96 /* FALLTHROUGH */ 97 case dolit: /* 'do' */ 98 case forstmt: /* for (...) */ 99 ps.p_stack[++ps.tos] = tk; 100 ps.il[ps.tos] = ps.ind_level = ps.i_l_follow; 101 ++ps.i_l_follow; /* subsequent statements should be indented 1 */ 102 ps.search_brace = opt.btype_2; 103 break; 104 105 case lbrace: /* scanned { */ 106 break_comma = false; /* don't break comma in an initial list */ 107 if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl 108 || ps.p_stack[ps.tos] == stmtl) 109 ++ps.i_l_follow; /* it is a random, isolated stmt group or a 110 * declaration */ 111 else { 112 if (s_code == e_code) { 113 /* 114 * only do this if there is nothing on the line 115 */ 116 --ps.ind_level; 117 /* 118 * it is a group as part of a while, for, etc. 119 */ 120 if (ps.p_stack[ps.tos] == swstmt && opt.case_indent >= 1) 121 --ps.ind_level; 122 /* 123 * for a switch, brace should be two levels out from the code 124 */ 125 } 126 } 127 128 ps.p_stack[++ps.tos] = lbrace; 129 ps.il[ps.tos] = ps.ind_level; 130 ps.p_stack[++ps.tos] = stmt; 131 /* allow null stmt between braces */ 132 ps.il[ps.tos] = ps.i_l_follow; 133 break; 134 135 case whilestmt: /* scanned while (...) */ 136 if (ps.p_stack[ps.tos] == dohead) { 137 /* it is matched with do stmt */ 138 ps.ind_level = ps.i_l_follow = ps.il[ps.tos]; 139 ps.p_stack[++ps.tos] = whilestmt; 140 ps.il[ps.tos] = ps.ind_level = ps.i_l_follow; 141 } 142 else { /* it is a while loop */ 143 ps.p_stack[++ps.tos] = whilestmt; 144 ps.il[ps.tos] = ps.i_l_follow; 145 ++ps.i_l_follow; 146 ps.search_brace = opt.btype_2; 147 } 148 149 break; 150 151 case elselit: /* scanned an else */ 152 153 if (ps.p_stack[ps.tos] != ifhead) 154 diag2(1, "Unmatched 'else'"); 155 else { 156 ps.ind_level = ps.il[ps.tos]; /* indentation for else should 157 * be same as for if */ 158 ps.i_l_follow = ps.ind_level + 1; /* everything following should 159 * be in 1 level */ 160 ps.p_stack[ps.tos] = elsehead; 161 /* remember if with else */ 162 ps.search_brace = opt.btype_2 | opt.else_if; 163 } 164 break; 165 166 case rbrace: /* scanned a } */ 167 /* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */ 168 if (ps.tos > 0 && ps.p_stack[ps.tos - 1] == lbrace) { 169 ps.ind_level = ps.i_l_follow = ps.il[--ps.tos]; 170 ps.p_stack[ps.tos] = stmt; 171 } 172 else 173 diag2(1, "Statement nesting error"); 174 break; 175 176 case swstmt: /* had switch (...) */ 177 ps.p_stack[++ps.tos] = swstmt; 178 ps.cstk[ps.tos] = case_ind; 179 /* save current case indent level */ 180 ps.il[ps.tos] = ps.i_l_follow; 181 case_ind = ps.i_l_follow + opt.case_indent; /* cases should be one 182 * level down from 183 * switch */ 184 ps.i_l_follow += opt.case_indent + 1; /* statements should be two 185 * levels in */ 186 ps.search_brace = opt.btype_2; 187 break; 188 189 case semicolon: /* this indicates a simple stmt */ 190 break_comma = false; /* turn off flag to break after commas in a 191 * declaration */ 192 ps.p_stack[++ps.tos] = stmt; 193 ps.il[ps.tos] = ps.ind_level; 194 break; 195 196 default: /* this is an error */ 197 diag2(1, "Unknown code to parser"); 198 return; 199 200 201 } /* end of switch */ 202 203 if (ps.tos >= STACKSIZE - 1) 204 errx(1, "Parser stack overflow"); 205 206 reduce(); /* see if any reduction can be done */ 207 208 #ifdef debug 209 for (i = 1; i <= ps.tos; ++i) 210 printf("(%d %d)", ps.p_stack[i], ps.il[i]); 211 printf("\n"); 212 #endif 213 214 return; 215 } 216 217 /* 218 * NAME: reduce 219 * 220 * FUNCTION: Implements the reduce part of the parsing algorithm 221 * 222 * ALGORITHM: The following reductions are done. Reductions are repeated 223 * until no more are possible. 224 * 225 * Old TOS New TOS 226 * <stmt> <stmt> <stmtl> 227 * <stmtl> <stmt> <stmtl> 228 * do <stmt> "dostmt" 229 * if <stmt> "ifstmt" 230 * switch <stmt> <stmt> 231 * decl <stmt> <stmt> 232 * "ifelse" <stmt> <stmt> 233 * for <stmt> <stmt> 234 * while <stmt> <stmt> 235 * "dostmt" while <stmt> 236 * 237 * On each reduction, ps.i_l_follow (the indentation for the following line) 238 * is set to the indentation level associated with the old TOS. 239 * 240 * PARAMETERS: None 241 * 242 * RETURNS: Nothing 243 * 244 * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos = 245 * 246 * CALLS: None 247 * 248 * CALLED BY: parse 249 * 250 * HISTORY: initial coding November 1976 D A Willcox of CAC 251 * 252 */ 253 /*----------------------------------------------*\ 254 | REDUCTION PHASE | 255 \*----------------------------------------------*/ 256 static void 257 reduce(void) 258 { 259 int i; 260 261 for (;;) { /* keep looping until there is nothing left to 262 * reduce */ 263 264 switch (ps.p_stack[ps.tos]) { 265 266 case stmt: 267 switch (ps.p_stack[ps.tos - 1]) { 268 269 case stmt: 270 case stmtl: 271 /* stmtl stmt or stmt stmt */ 272 ps.p_stack[--ps.tos] = stmtl; 273 break; 274 275 case dolit: /* <do> <stmt> */ 276 ps.p_stack[--ps.tos] = dohead; 277 ps.i_l_follow = ps.il[ps.tos]; 278 break; 279 280 case ifstmt: 281 /* <if> <stmt> */ 282 ps.p_stack[--ps.tos] = ifhead; 283 for (i = ps.tos - 1; 284 ( 285 ps.p_stack[i] != stmt 286 && 287 ps.p_stack[i] != stmtl 288 && 289 ps.p_stack[i] != lbrace 290 ); 291 --i); 292 ps.i_l_follow = ps.il[i]; 293 /* 294 * for the time being, we will assume that there is no else on 295 * this if, and set the indentation level accordingly. If an 296 * else is scanned, it will be fixed up later 297 */ 298 break; 299 300 case swstmt: 301 /* <switch> <stmt> */ 302 case_ind = ps.cstk[ps.tos - 1]; 303 /* FALLTHROUGH */ 304 case decl: /* finish of a declaration */ 305 case elsehead: 306 /* <<if> <stmt> else> <stmt> */ 307 case forstmt: 308 /* <for> <stmt> */ 309 case whilestmt: 310 /* <while> <stmt> */ 311 ps.p_stack[--ps.tos] = stmt; 312 ps.i_l_follow = ps.il[ps.tos]; 313 break; 314 315 default: /* <anything else> <stmt> */ 316 return; 317 318 } /* end of section for <stmt> on top of stack */ 319 break; 320 321 case whilestmt: /* while (...) on top */ 322 if (ps.p_stack[ps.tos - 1] == dohead) { 323 /* it is termination of a do while */ 324 ps.tos -= 2; 325 break; 326 } 327 else 328 return; 329 330 default: /* anything else on top */ 331 return; 332 333 } 334 } 335 } 336