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