1 /*
2     Gri - A language for scientific graphics programming
3     Copyright (C) 2008 Daniel Kelley
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include        <stdio.h>
21 #include        <string.h>
22 #include        <math.h>
23 #include	"extern.hh"
24 #define	TOP	20000		/* max number nested if-s */
25 static int      top = 0;	/* nesting level minus 1 */
26 static bool     got_an_else[TOP];	/* keeps track of duplicate `else' */
27 static bool     skipping[TOP];	/* flag telling that skipping code */
28 static bool     skip_to_end[TOP];	/* set to 1 if part of block done */
29 static bool     inside_if_statement[TOP];
30 static bool     need_to_initialize = true;
31 void            initialize_if_necessary(void);
32 
33 void
initialize_if_necessary()34 initialize_if_necessary()
35 {
36 	if (need_to_initialize) {
37 		for (int i = 0; i < TOP; i++) {
38 			got_an_else[i] = false;
39 			skipping[i] = false;
40 			skip_to_end[i] = false;
41 			inside_if_statement[i] = false;
42 		}
43 		need_to_initialize = false;
44 	}
45 }
46 
47 void
push_if(int flag)48 push_if(int flag)
49 {
50 	initialize_if_necessary();
51 	if (++top >= TOP)
52 		fatal_err("Fatal error: too many nested if-statements (max is 20000).");
53 	got_an_else[top] = false;
54 	skipping[top] = ((!flag) || skipping[top - 1]) ? true : false;
55 	skip_to_end[top] = flag != 0 ? true : false;
56 	inside_if_statement[top] = true;
57 }
58 
59 void
pop_if()60 pop_if()
61 {
62 	initialize_if_necessary();
63 	if (--top < 0) {
64 		warning("Warning - ignoring extra `end if'");
65 		top = 0;
66 	}
67 }
68 
69 bool
skipping_through_if()70 skipping_through_if()
71 {
72 	initialize_if_necessary();
73 	return skipping[top];
74 }
75 
76 /*
77  * handle_if_block - handle `else if' and `else' by setting skip-flags.
78  * RETURN VALUE 1 if the commands `if', `else if' or `else' were detected.
79  */
80 bool
handle_if_block()81 handle_if_block()
82 {
83 	if (((unsigned) superuser()) & FLAG_FLOW) printf("DEBUG: %s:%d handle_if_block()\n",__FILE__,__LINE__);
84 	initialize_if_necessary();
85 	if (!_nword)
86 		return false;
87 	/*
88 	 * Handle `end if'
89 	 */
90 	if (_nword == 2 && !strcmp(_word[0], "end") && !strcmp(_word[1], "if")) {
91 		pop_if();
92 		return true;
93 	}
94 	/*
95 	 * Handle `if'
96 	 */
97 	if (!strcmp(_word[0], "if")) {
98 		if (_nword < 2) {
99 			err("if what?");
100 			return true;
101 		}
102 		double flag;
103 
104 		if (((unsigned) superuser()) & FLAG_FLOW) printf("DEBUG %s:%d DEBUG '%s' ... inside_if= %d    skipping= %d\n",__FILE__,__LINE__,_word[1], inside_if_statement[top], skipping[top]);
105 		if (skipping[top]) {
106 			push_if(false);	// does the value matter??????
107 		} else {
108 			if (!strcmp(_word[1], "!")) {
109 				if (!getdnum(_word[2], &flag)) {
110 					err("if what?");
111 					return true;
112 				}
113 				flag = !flag;
114 			} else if (!getdnum(_word[1], &flag)) {
115 				err("`if' what?");
116 				return true;
117 			}
118 			push_if(floor(0.5 + flag) ? true : false);
119 		}
120 		return true;
121 	}
122 	/*
123 	 * Handle `else' and `else if ...'
124 	 */
125 	if (!strcmp(_word[0], "else")) {
126 		if (!inside_if_statement[top]) {
127 			err("This `else' doesn't match an `if'");
128 			return true;
129 		}
130 		/* `else [...]' */
131 		if (_nword == 1) {
132 			/* `else' */
133 			if (got_an_else[top] && !skipping[top]) {
134 				err("Ignoring duplicate else");
135 				return true;
136 			}
137 			got_an_else[top] = true;
138 			skipping[top] = (skip_to_end[top] || skipping[top - 1]) ? true : false;
139 			return true;
140 		} else if (_nword > 2 && !strcmp(_word[1], "if")) {
141 			if (!inside_if_statement[top]) {
142 				err("This `else if' doesn't match an `if'");
143 				return true;
144 			}
145 			//printf("NOTE: In else if.  skipping[%d]=%d\n",top,skipping[top]);
146 
147 			// Only consider the value if presently skipping
148 			if (skipping[top] == 0) {
149 				skipping[top] = 1;
150 				//printf("ELSE IF Set skipping[%d] to 1\n",top);
151 				return true;
152 			}
153 
154 			// Must figure out rpn expressions (if any) since they
155 			// are ignored for the 'false' part of if blocks, and
156 			// that's what we are in at the moment.
157 			while (substitute_rpn_expressions(_cmdLine, _cmdLineCOPY))
158 				strcpy(_cmdLine, _cmdLineCOPY);
159 			chop_into_words(_cmdLine, _word, &_nword, MAX_nword);
160 			/* `else if #' */
161 			double           tmp;
162 			if (!getdnum(_word[2], &tmp)) {
163 				err("else if ?what?");
164 				return true;
165 			}
166 			if (tmp) {
167 				if (skip_to_end[top]) {
168 					err("skipping second TRUE part of IF");
169 					skipping[top] = true;
170 					return true;
171 				}
172 				skipping[top] = skipping[top - 1];
173 				skip_to_end[top] = true;
174 			} else {
175 				skipping[top] = true;
176 			}
177 			return true;
178 		} else {
179 			err("else ?what?");
180 			return true;
181 		}
182 	}
183 	/* cmd = something to do */
184 	return false;
185 }
186