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