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