xref: /csrg-svn/usr.bin/indent/parse.c (revision 24456)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)parse.c	5.2 (Berkeley) 08/28/85";
9 #endif not lint
10 
11 /*-
12  *
13  *			  Copyright (C) 1976
14  *				by the
15  *			  Board of Trustees
16  *				of the
17  *			University of Illinois
18  *
19  *			 All rights reserved
20  *
21  *
22  * FILE NAME:
23  *	parse.c
24  *
25  * PURPOSE:
26  *	Contains the routines which keep track of the parse stack.
27  *
28  * GLOBALS:
29  *	ps.p_stack =	The parse stack, set by both routines
30  *	ps.il =		Stack of indentation levels, set by parse
31  *	ps.cstk =		Stack of case statement indentation levels, set by parse
32  *	ps.tos =		Pointer to top of stack, set by both routines.
33  *
34  * FUNCTIONS:
35  *	parse
36  *	reduce
37  */
38 /*-
39  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
40  *
41  * All rights reserved
42  *
43  *
44  * NAME: parse
45  *
46  * FUNCTION: Parse is given one input which is a "maxi token" just scanned
47  * from input.  Maxi tokens are signifigant constructs such as else, {,
48  * do, if (...), etc.  Parse works with reduce to maintain a parse stack
49  * of these constructs.  Parse is responsible for the "shift" portion of
50  * the parse algorithm, and reduce handles the "reduce" portion.
51  *
52  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
53  *
54  */
55 
56 #include "./indent_globs.h";
57 #include "./indent_codes.h";
58 
59 
60 
61 
62 parse(tk)
63     int         tk;		/* the code for the construct scanned */
64 {
65     int         i;
66 
67 #ifdef debug
68     printf("%2d - %s\n", tk, token);
69 #endif
70     while (ps.p_stack[ps.tos] == ifhead && tk != elselit) {
71 	/* true if we have an if without an else */
72 	ps.p_stack[ps.tos] = stmt;	/* apply the if(..) stmt ::= stmt
73 				 * reduction */
74 	reduce();		/* see if this allows any reduction */
75     }
76 
77 
78     switch (tk) {		/* go on and figure out what to do with
79 				 * the input */
80 
81 	case decl: 		/* scanned a declaration word */
82 	    ps.search_brace = btype_2;
83 	    /* indicate that following brace should be on same line */
84 	    if (ps.p_stack[ps.tos] != decl) {	/* only put one declaration onto
85 					 * stack */
86 		break_comma = true;	/* while in declaration, newline
87 					 * should be forced after comma */
88 		ps.p_stack[++ps.tos] = decl;
89 		ps.il[ps.tos] = ps.i_l_follow;
90 
91 		if (ps.ljust_decl) {	/* only do if we want left
92 					 * justified declarations */
93 		    ps.ind_level = 0;
94 		    for (i = ps.tos - 1; i > 0; --i)
95 			if (ps.p_stack[i] == decl)
96 			    ++ps.ind_level;	/* indentation is number
97 						 * of declaration levels
98 						 * deep we are */
99 		    ps.i_l_follow = ps.ind_level;
100 		}
101 	    }
102 	    break;
103 
104 	case ifstmt: 		/* scanned if (...) */
105 	    if (ps.p_stack[ps.tos] == elsehead && ps.else_if)	/* "else if ..." */
106 		ps.i_l_follow = ps.il[ps.tos];
107 	case dolit: 		/* 'do' */
108 	case forstmt: 		/* for (...) */
109 	    ps.p_stack[++ps.tos] = tk;
110 	    ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
111 	    ++ps.i_l_follow;	/* subsequent statements should be
112 				 * indented 1 */
113 	    ps.search_brace = btype_2;
114 	    break;
115 
116 	case lbrace: 		/* scanned { */
117 	    break_comma = false;/* don't break comma in an initial list */
118 	    if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl
119 		    || ps.p_stack[ps.tos] == stmtl)
120 		++ps.i_l_follow;	/* it is a random, isolated stmt group or
121 				 * a declaration */
122 	    else {
123 		if (s_code == e_code) {
124 		    /* only do this if there is nothing on the line */
125 		    --ps.ind_level;
126 		    /* it is a group as part of a while, for, etc. */
127 		    if (ps.p_stack[ps.tos] == swstmt && ps.case_indent)
128 			--ps.ind_level;
129 		    /*
130 		     * for a switch, brace should be two levels out from
131 		     * the code
132 		     */
133 		}
134 	    }
135 
136 	    ps.p_stack[++ps.tos] = lbrace;
137 	    ps.il[ps.tos] = ps.ind_level;
138 	    ps.p_stack[++ps.tos] = stmt;
139 	    /* allow null stmt between braces */
140 	    ps.il[ps.tos] = ps.i_l_follow;
141 	    break;
142 
143 	case whilestmt: 	/* scanned while (...) */
144 	    if (ps.p_stack[ps.tos] == dohead) {
145 		/* it is matched with do stmt */
146 		ps.ind_level = ps.i_l_follow = ps.il[ps.tos];
147 		ps.p_stack[++ps.tos] = whilestmt;
148 		ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
149 	    }
150 	    else {		/* it is a while loop */
151 		ps.p_stack[++ps.tos] = whilestmt;
152 		ps.il[ps.tos] = ps.i_l_follow;
153 		++ps.i_l_follow;
154 		ps.search_brace = btype_2;
155 	    }
156 
157 	    break;
158 
159 	case elselit: 		/* scanned an else */
160 
161 	    if (ps.p_stack[ps.tos] != ifhead)
162 		diag(1,"Unmatched 'else'");
163 	    else {
164 		ps.ind_level = ps.il[ps.tos];		/* indentation for else should be same as for if */
165 		ps.i_l_follow = ps.ind_level + 1;	/* everything following should be in 1 level */
166 		ps.p_stack[ps.tos] = elsehead;
167 		/* remember if with else */
168 		ps.search_brace = btype_2;
169 	    }
170 
171 	    break;
172 
173 	case rbrace: 		/* scanned a } */
174 	    /* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
175 	    if (ps.p_stack[ps.tos - 1] == lbrace) {
176 		ps.ind_level = ps.i_l_follow = ps.il[--ps.tos];
177 		ps.p_stack[ps.tos] = stmt;
178 	    }
179 	    else
180 		diag(1,"Stmt nesting error.");
181 	    break;
182 
183 	case swstmt: 		/* had switch (...) */
184 	    ps.p_stack[++ps.tos] = swstmt;
185 	    ps.cstk[ps.tos] = case_ind;
186 	    /* save current case indent level */
187 	    ps.il[ps.tos] = ps.i_l_follow;
188 	    case_ind = ps.i_l_follow + ps.case_indent;	/* cases should be one
189 							 * level down from
190 							 * switch */
191 	    ps.i_l_follow + = ps.case_indent + 1;	/* statements should be
192 						 * two levels in */
193 	    ps.search_brace = btype_2;
194 	    break;
195 
196 	case semicolon: 	/* this indicates a simple stmt */
197 	    break_comma = false;/* turn off flag to break after commas in
198 				 * a declaration */
199 	    ps.p_stack[++ps.tos] = stmt;
200 	    ps.il[ps.tos] = ps.ind_level;
201 	    break;
202 
203 	default: 		/* this is an error */
204 	    diag(1,"Unknown code to parser");
205 	    return;
206 
207 
208     }				/* end of switch */
209 
210     reduce();			/* see if any reduction can be done */
211 #ifdef debug
212     for (i = 1; i <= ps.tos; ++i)
213 	printf("(%d %d)", ps.p_stack[i], ps.il[i]);
214     printf("\n");
215 #endif
216     return;
217 }
218 /*
219  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
220  *
221  * All rights reserved
222  *
223  *
224  * NAME: reduce
225  *
226  * FUNCTION: Implements the reduce part of the parsing algorithm
227  *
228  * ALGORITHM: The following reductions are done.  Reductions are repeated
229  * until no more are possible.
230  *
231  * Old TOS		New TOS <stmt> <stmt>	<stmtl> <stmtl> <stmt>	<stmtl> do
232  * <stmt>	"dostmt" if <stmt>	"ifstmt" switch <stmt>	<stmt>
233  * decl <stmt>	<stmt> "ifelse" <stmt>	<stmt> for <stmt>	<stmt>
234  * while <stmt>	<stmt> "dostmt" while	<stmt>
235  *
236  * On each reduction, ps.i_l_follow (the indentation for the following line) is
237  * set to the indentation level associated with the old TOS.
238  *
239  * PARAMETERS: None
240  *
241  * RETURNS: Nothing
242  *
243  * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos =
244  *
245  * CALLS: None
246  *
247  * CALLED BY: parse 
248  *
249  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
250  *
251  */
252 /*----------------------------------------------*\
253  * |   REDUCTION PHASE
254 \*----------------------------------------------*/
255 reduce() {
256 
257     register int i;
258 
259     for (;;) {			/* keep looping until there is nothing
260 				 * left to reduce */
261 
262 	switch (ps.p_stack[ps.tos]) {
263 
264 	    case stmt:
265 		switch (ps.p_stack[ps.tos - 1]) {
266 
267 		    case stmt:
268 		    case stmtl:
269 			/* stmtl stmt or stmt stmt */
270 			ps.p_stack[--ps.tos] = stmtl;
271 			break;
272 
273 		    case dolit: /* <do> <stmt> */
274 			ps.p_stack[--ps.tos] = dohead;
275 			ps.i_l_follow = ps.il[ps.tos];
276 			break;
277 
278 		    case ifstmt:
279 			/* <if> <stmt> */
280 			ps.p_stack[--ps.tos] = ifhead;
281 			for (i = ps.tos - 1;
282 				(
283 				    ps.p_stack[i] != stmt
284 				    &&
285 				    ps.p_stack[i] != stmtl
286 				    &&
287 				    ps.p_stack[i] != lbrace
288 				);
289 				--i);
290 			ps.i_l_follow = ps.il[i];
291 			/*
292 			 * for the time being, we will assume that there
293 			 * is no else on this if, and set the indentation
294 			 * level accordingly. If an else is scanned, it
295 			 * will be fixed up later
296 			 */
297 			break;
298 
299 		    case swstmt:
300 			/* <switch> <stmt> */
301 			case_ind = ps.cstk[ps.tos - 1];
302 
303 		    case decl: 	/* finish of a declaration */
304 		    case elsehead:
305 			/* <<if> <stmt> else> <stmt> */
306 		    case forstmt:
307 			/* <for> <stmt> */
308 		    case whilestmt:
309 			/* <while> <stmt> */
310 			ps.p_stack[--ps.tos] = stmt;
311 			ps.i_l_follow = ps.il[ps.tos];
312 			break;
313 
314 		    default: 	/* <anything else> <stmt> */
315 			return;
316 
317 		}		/* end of section for <stmt> on top of
318 				 * 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.p_stack[--ps.tos] = stmt;
325 		    break;
326 		}
327 		else
328 		    return;
329 
330 	    default: 		/* anything else on top */
331 		return;
332 
333 	}
334     }
335 }
336