2982
|
1 /* |
|
2 |
|
3 Copyright (C) 1996, 1997 John W. Eaton |
|
4 |
|
5 This file is part of Octave. |
|
6 |
|
7 Octave is free software; you can redistribute it and/or modify it |
|
8 under the terms of the GNU General Public License as published by the |
|
9 Free Software Foundation; either version 2, or (at your option) any |
|
10 later version. |
|
11 |
|
12 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
15 for more details. |
|
16 |
|
17 You should have received a copy of the GNU General Public License |
|
18 along with Octave; see the file COPYING. If not, write to the Free |
|
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
20 |
|
21 */ |
|
22 |
|
23 #if defined (__GNUG__) |
|
24 #pragma implementation |
|
25 #endif |
|
26 |
|
27 #ifdef HAVE_CONFIG_H |
|
28 #include <config.h> |
|
29 #endif |
|
30 |
|
31 #include "error.h" |
|
32 #include "gripes.h" |
|
33 #include "oct-map.h" |
|
34 #include "oct-lvalue.h" |
|
35 #include "ov.h" |
|
36 #include "pt-arg-list.h" |
|
37 #include "pt-cmd.h" |
|
38 #include "pt-exp.h" |
2985
|
39 #include "pt-jump.h" |
2982
|
40 #include "pt-loop.h" |
|
41 #include "pt-stmt.h" |
|
42 #include "pt-walk.h" |
|
43 |
|
44 // Decide if it's time to quit a for or while loop. |
|
45 static inline bool |
|
46 quit_loop_now (void) |
|
47 { |
|
48 // Maybe handle `continue N' someday... |
|
49 |
2985
|
50 if (tree_continue_command::continuing) |
|
51 tree_continue_command::continuing--; |
2982
|
52 |
2985
|
53 bool quit = (error_state |
|
54 || tree_return_command::returning |
|
55 || tree_break_command::breaking |
|
56 || tree_continue_command::continuing); |
2982
|
57 |
2985
|
58 if (tree_break_command::breaking) |
|
59 tree_break_command::breaking--; |
2982
|
60 |
|
61 return quit; |
|
62 } |
|
63 |
|
64 // While. |
|
65 |
|
66 tree_while_command::~tree_while_command (void) |
|
67 { |
|
68 delete expr; |
|
69 delete list; |
3665
|
70 delete lead_comm; |
|
71 delete trail_comm; |
2982
|
72 } |
|
73 |
|
74 void |
|
75 tree_while_command::eval (void) |
|
76 { |
|
77 if (error_state) |
|
78 return; |
|
79 |
|
80 if (! expr) |
|
81 panic_impossible (); |
|
82 |
|
83 for (;;) |
|
84 { |
|
85 if (expr->is_logically_true ("while")) |
|
86 { |
|
87 if (list) |
|
88 { |
|
89 list->eval (); |
|
90 |
|
91 if (error_state) |
|
92 { |
|
93 eval_error (); |
|
94 return; |
|
95 } |
|
96 } |
|
97 |
|
98 if (quit_loop_now ()) |
|
99 break; |
|
100 } |
|
101 else |
|
102 break; |
|
103 } |
|
104 } |
|
105 |
|
106 void |
|
107 tree_while_command::eval_error (void) |
|
108 { |
|
109 if (error_state > 0) |
|
110 ::error ("evaluating while command near line %d, column %d", |
|
111 line (), column ()); |
|
112 } |
|
113 |
|
114 void |
|
115 tree_while_command::accept (tree_walker& tw) |
|
116 { |
|
117 tw.visit_while_command (*this); |
|
118 } |
|
119 |
3484
|
120 // Do-Until |
|
121 |
|
122 void |
|
123 tree_do_until_command::eval (void) |
|
124 { |
|
125 if (error_state) |
|
126 return; |
|
127 |
|
128 if (! expr) |
|
129 panic_impossible (); |
|
130 |
|
131 for (;;) |
|
132 { |
|
133 if (list) |
|
134 { |
|
135 list->eval (); |
|
136 |
|
137 if (error_state) |
|
138 { |
|
139 eval_error (); |
|
140 return; |
|
141 } |
|
142 } |
|
143 |
|
144 if (quit_loop_now () || expr->is_logically_true ("do-until")) |
|
145 break; |
|
146 } |
|
147 } |
|
148 |
|
149 void |
|
150 tree_do_until_command::eval_error (void) |
|
151 { |
|
152 if (error_state > 0) |
|
153 ::error ("evaluating do-until command near line %d, column %d", |
|
154 line (), column ()); |
|
155 } |
|
156 |
|
157 void |
|
158 tree_do_until_command::accept (tree_walker& tw) |
|
159 { |
|
160 tw.visit_do_until_command (*this); |
|
161 } |
|
162 |
2982
|
163 // For. |
|
164 |
|
165 tree_simple_for_command::~tree_simple_for_command (void) |
|
166 { |
|
167 delete expr; |
|
168 delete list; |
3665
|
169 delete lead_comm; |
|
170 delete trail_comm; |
2982
|
171 } |
|
172 |
|
173 inline void |
|
174 tree_simple_for_command::do_for_loop_once (octave_lvalue& ult, |
|
175 const octave_value& rhs, |
|
176 bool& quit) |
|
177 { |
|
178 quit = false; |
|
179 |
3538
|
180 ult.assign (octave_value::op_asn_eq, rhs); |
2982
|
181 |
|
182 if (! error_state) |
|
183 { |
|
184 if (list) |
|
185 { |
|
186 list->eval (); |
|
187 |
|
188 if (error_state) |
|
189 eval_error (); |
|
190 } |
|
191 } |
|
192 else |
|
193 eval_error (); |
|
194 |
|
195 quit = quit_loop_now (); |
|
196 } |
|
197 |
|
198 #define DO_LOOP(arg) \ |
|
199 do \ |
|
200 { \ |
|
201 for (int i = 0; i < steps; i++) \ |
|
202 { \ |
|
203 octave_value val (arg); \ |
|
204 \ |
|
205 bool quit = false; \ |
|
206 \ |
|
207 do_for_loop_once (ult, val, quit); \ |
|
208 \ |
|
209 if (quit) \ |
|
210 break; \ |
|
211 } \ |
|
212 } \ |
|
213 while (0) |
|
214 |
|
215 void |
|
216 tree_simple_for_command::eval (void) |
|
217 { |
|
218 if (error_state) |
|
219 return; |
|
220 |
|
221 octave_value rhs = expr->rvalue (); |
|
222 |
|
223 if (error_state || rhs.is_undefined ()) |
|
224 { |
|
225 eval_error (); |
|
226 return; |
|
227 } |
|
228 |
|
229 octave_lvalue ult = lhs->lvalue (); |
|
230 |
|
231 if (error_state) |
|
232 { |
|
233 eval_error (); |
|
234 return; |
|
235 } |
|
236 |
3180
|
237 if (rhs.is_range ()) |
|
238 { |
|
239 Range rng = rhs.range_value (); |
|
240 |
|
241 int steps = rng.nelem (); |
|
242 double b = rng.base (); |
|
243 double increment = rng.inc (); |
|
244 |
|
245 for (int i = 0; i < steps; i++) |
|
246 { |
|
247 double tmp_val = b + i * increment; |
|
248 |
|
249 octave_value val (tmp_val); |
|
250 |
|
251 bool quit = false; |
|
252 |
|
253 do_for_loop_once (ult, val, quit); |
|
254 |
|
255 if (quit) |
|
256 break; |
|
257 } |
|
258 } |
|
259 else if (rhs.is_scalar_type ()) |
2982
|
260 { |
|
261 bool quit = false; |
|
262 |
|
263 do_for_loop_once (ult, rhs, quit); |
|
264 } |
3215
|
265 else if (rhs.is_string ()) |
|
266 { |
|
267 charMatrix chm_tmp = rhs.char_matrix_value (); |
|
268 int nr = chm_tmp.rows (); |
|
269 int steps = chm_tmp.columns (); |
|
270 |
|
271 if (error_state) |
|
272 return; |
|
273 |
|
274 if (nr == 1) |
|
275 DO_LOOP (chm_tmp (0, i)); |
|
276 else |
|
277 { |
|
278 for (int i = 0; i < steps; i++) |
|
279 { |
|
280 octave_value val (chm_tmp.extract (0, i, nr-1, i), true); |
|
281 |
|
282 bool quit = false; |
|
283 |
|
284 do_for_loop_once (ult, val, quit); |
|
285 |
|
286 if (quit) |
|
287 break; |
|
288 } |
|
289 } |
|
290 } |
2982
|
291 else if (rhs.is_matrix_type ()) |
|
292 { |
|
293 Matrix m_tmp; |
|
294 ComplexMatrix cm_tmp; |
|
295 |
|
296 int nr; |
|
297 int steps; |
|
298 |
3215
|
299 if (rhs.is_real_matrix ()) |
2982
|
300 { |
|
301 m_tmp = rhs.matrix_value (); |
|
302 nr = m_tmp.rows (); |
|
303 steps = m_tmp.columns (); |
|
304 } |
|
305 else |
|
306 { |
|
307 cm_tmp = rhs.complex_matrix_value (); |
|
308 nr = cm_tmp.rows (); |
|
309 steps = cm_tmp.columns (); |
|
310 } |
|
311 |
3180
|
312 if (error_state) |
|
313 return; |
|
314 |
3215
|
315 if (rhs.is_real_matrix ()) |
2982
|
316 { |
|
317 if (nr == 1) |
|
318 DO_LOOP (m_tmp (0, i)); |
|
319 else |
|
320 DO_LOOP (m_tmp.extract (0, i, nr-1, i)); |
|
321 } |
|
322 else |
|
323 { |
|
324 if (nr == 1) |
|
325 DO_LOOP (cm_tmp (0, i)); |
|
326 else |
|
327 DO_LOOP (cm_tmp.extract (0, i, nr-1, i)); |
|
328 } |
|
329 } |
|
330 else if (rhs.is_map ()) |
|
331 { |
|
332 Octave_map tmp_val (rhs.map_value ()); |
|
333 |
|
334 for (Pix p = tmp_val.first (); p != 0; tmp_val.next (p)) |
|
335 { |
|
336 octave_value val = tmp_val.contents (p); |
|
337 |
|
338 bool quit = false; |
|
339 |
|
340 do_for_loop_once (ult, val, quit); |
|
341 |
|
342 if (quit) |
|
343 break; |
|
344 } |
|
345 } |
|
346 else |
|
347 { |
|
348 ::error ("invalid type in for loop expression near line %d, column %d", |
|
349 line (), column ()); |
|
350 } |
|
351 } |
|
352 |
|
353 void |
|
354 tree_simple_for_command::eval_error (void) |
|
355 { |
|
356 if (error_state > 0) |
|
357 ::error ("evaluating for command near line %d, column %d", |
|
358 line (), column ()); |
|
359 } |
|
360 |
|
361 void |
|
362 tree_simple_for_command::accept (tree_walker& tw) |
|
363 { |
|
364 tw.visit_simple_for_command (*this); |
|
365 } |
|
366 |
|
367 tree_complex_for_command::~tree_complex_for_command (void) |
|
368 { |
|
369 delete expr; |
|
370 delete list; |
3665
|
371 delete lead_comm; |
|
372 delete trail_comm; |
2982
|
373 } |
|
374 |
|
375 void |
|
376 tree_complex_for_command::do_for_loop_once (octave_lvalue &val_ref, |
|
377 octave_lvalue &key_ref, |
|
378 const octave_value& val, |
|
379 const octave_value& key, |
|
380 bool& quit) |
|
381 { |
|
382 quit = false; |
|
383 |
3538
|
384 val_ref.assign (octave_value::op_asn_eq, val); |
|
385 key_ref.assign (octave_value::op_asn_eq, key); |
2982
|
386 |
|
387 if (! error_state) |
|
388 { |
|
389 if (list) |
|
390 { |
|
391 list->eval (); |
|
392 |
|
393 if (error_state) |
|
394 eval_error (); |
|
395 } |
|
396 } |
|
397 else |
|
398 eval_error (); |
|
399 |
|
400 quit = quit_loop_now (); |
|
401 } |
|
402 |
|
403 void |
|
404 tree_complex_for_command::eval (void) |
|
405 { |
|
406 if (error_state) |
|
407 return; |
|
408 |
|
409 octave_value rhs = expr->rvalue (); |
|
410 |
|
411 if (error_state || rhs.is_undefined ()) |
|
412 { |
|
413 eval_error (); |
|
414 return; |
|
415 } |
|
416 |
|
417 if (rhs.is_map ()) |
|
418 { |
|
419 // Cycle through structure elements. First element of id_list |
|
420 // is set to value and the second is set to the name of the |
|
421 // structure element. |
|
422 |
|
423 Pix p = lhs->first (); |
|
424 tree_expression *elt = lhs->operator () (p); |
|
425 octave_lvalue val_ref = elt->lvalue (); |
|
426 |
|
427 lhs->next (p); |
|
428 elt = lhs->operator () (p); |
|
429 octave_lvalue key_ref = elt->lvalue (); |
|
430 |
|
431 Octave_map tmp_val (rhs.map_value ()); |
|
432 |
|
433 for (p = tmp_val.first (); p != 0; tmp_val.next (p)) |
|
434 { |
|
435 octave_value key = tmp_val.key (p); |
|
436 octave_value val = tmp_val.contents (p); |
|
437 |
|
438 bool quit = false; |
|
439 |
|
440 do_for_loop_once (key_ref, val_ref, key, val, quit); |
|
441 |
|
442 if (quit) |
|
443 break; |
|
444 } |
|
445 } |
|
446 else |
|
447 error ("in statement `for [X, Y] = VAL', VAL must be a structure"); |
|
448 } |
|
449 |
|
450 void |
|
451 tree_complex_for_command::eval_error (void) |
|
452 { |
|
453 if (error_state > 0) |
|
454 ::error ("evaluating for command near line %d, column %d", |
|
455 line (), column ()); |
|
456 } |
|
457 |
|
458 void |
|
459 tree_complex_for_command::accept (tree_walker& tw) |
|
460 { |
|
461 tw.visit_complex_for_command (*this); |
|
462 } |
|
463 |
|
464 /* |
|
465 ;;; Local Variables: *** |
|
466 ;;; mode: C++ *** |
|
467 ;;; End: *** |
|
468 */ |