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