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 |
5307
|
19 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
20 02110-1301, USA. |
2982
|
21 |
|
22 */ |
|
23 |
|
24 #ifdef HAVE_CONFIG_H |
|
25 #include <config.h> |
|
26 #endif |
|
27 |
4153
|
28 #include "quit.h" |
|
29 |
2982
|
30 #include "error.h" |
|
31 #include "gripes.h" |
|
32 #include "oct-map.h" |
|
33 #include "oct-lvalue.h" |
|
34 #include "ov.h" |
|
35 #include "pt-arg-list.h" |
3770
|
36 #include "pt-bp.h" |
2982
|
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" |
3877
|
43 #include "unwind-prot.h" |
|
44 |
|
45 // TRUE means we are evaluating some kind of looping construct. |
|
46 bool evaluating_looping_command = false; |
2982
|
47 |
|
48 // Decide if it's time to quit a for or while loop. |
|
49 static inline bool |
|
50 quit_loop_now (void) |
|
51 { |
4153
|
52 OCTAVE_QUIT; |
|
53 |
2982
|
54 // Maybe handle `continue N' someday... |
|
55 |
4207
|
56 if (tree_continue_command::continuing) |
|
57 tree_continue_command::continuing--; |
2982
|
58 |
2985
|
59 bool quit = (error_state |
4207
|
60 || tree_return_command::returning |
|
61 || tree_break_command::breaking |
|
62 || tree_continue_command::continuing); |
2982
|
63 |
4207
|
64 if (tree_break_command::breaking) |
|
65 tree_break_command::breaking--; |
2982
|
66 |
|
67 return quit; |
|
68 } |
|
69 |
|
70 // While. |
|
71 |
|
72 tree_while_command::~tree_while_command (void) |
|
73 { |
|
74 delete expr; |
|
75 delete list; |
3665
|
76 delete lead_comm; |
|
77 delete trail_comm; |
2982
|
78 } |
|
79 |
|
80 void |
|
81 tree_while_command::eval (void) |
|
82 { |
|
83 if (error_state) |
|
84 return; |
|
85 |
3877
|
86 unwind_protect::begin_frame ("while_command::eval"); |
|
87 |
|
88 unwind_protect_bool (evaluating_looping_command); |
|
89 |
|
90 evaluating_looping_command = true; |
|
91 |
2982
|
92 if (! expr) |
|
93 panic_impossible (); |
|
94 |
|
95 for (;;) |
|
96 { |
|
97 if (expr->is_logically_true ("while")) |
|
98 { |
|
99 if (list) |
|
100 { |
|
101 list->eval (); |
|
102 |
|
103 if (error_state) |
|
104 { |
|
105 eval_error (); |
3877
|
106 goto cleanup; |
2982
|
107 } |
|
108 } |
|
109 |
|
110 if (quit_loop_now ()) |
|
111 break; |
|
112 } |
|
113 else |
|
114 break; |
|
115 } |
3877
|
116 |
|
117 cleanup: |
|
118 unwind_protect::run_frame ("while_command::eval"); |
2982
|
119 } |
|
120 |
|
121 void |
|
122 tree_while_command::eval_error (void) |
|
123 { |
3965
|
124 ::error ("evaluating while command near line %d, column %d", |
|
125 line (), column ()); |
2982
|
126 } |
|
127 |
5861
|
128 tree_command * |
|
129 tree_while_command::dup (symbol_table *sym_tab) |
|
130 { |
|
131 return new tree_while_command (expr ? expr->dup (sym_tab) : 0, |
|
132 list ? list->dup (sym_tab) : 0, |
|
133 lead_comm ? lead_comm->dup () : 0, |
|
134 trail_comm ? trail_comm->dup (): 0, |
|
135 line (), column ()); |
|
136 } |
|
137 |
2982
|
138 void |
|
139 tree_while_command::accept (tree_walker& tw) |
|
140 { |
|
141 tw.visit_while_command (*this); |
|
142 } |
|
143 |
3484
|
144 // Do-Until |
|
145 |
|
146 void |
|
147 tree_do_until_command::eval (void) |
|
148 { |
|
149 if (error_state) |
|
150 return; |
|
151 |
3877
|
152 unwind_protect::begin_frame ("do_until_command::eval"); |
|
153 |
|
154 unwind_protect_bool (evaluating_looping_command); |
|
155 |
|
156 evaluating_looping_command = true; |
|
157 |
3484
|
158 if (! expr) |
|
159 panic_impossible (); |
|
160 |
|
161 for (;;) |
|
162 { |
3770
|
163 MAYBE_DO_BREAKPOINT; |
|
164 |
3484
|
165 if (list) |
|
166 { |
|
167 list->eval (); |
|
168 |
|
169 if (error_state) |
|
170 { |
|
171 eval_error (); |
3877
|
172 goto cleanup; |
3484
|
173 } |
|
174 } |
|
175 |
|
176 if (quit_loop_now () || expr->is_logically_true ("do-until")) |
|
177 break; |
|
178 } |
3877
|
179 |
|
180 cleanup: |
|
181 unwind_protect::run_frame ("do_until_command::eval"); |
3484
|
182 } |
|
183 |
|
184 void |
|
185 tree_do_until_command::eval_error (void) |
|
186 { |
3965
|
187 ::error ("evaluating do-until command near line %d, column %d", |
|
188 line (), column ()); |
3484
|
189 } |
|
190 |
5861
|
191 tree_command * |
|
192 tree_do_until_command::dup (symbol_table *sym_tab) |
|
193 { |
|
194 return new tree_do_until_command (expr ? expr->dup (sym_tab) : 0, |
|
195 list ? list->dup (sym_tab) : 0, |
|
196 lead_comm ? lead_comm->dup () : 0, |
|
197 trail_comm ? trail_comm->dup (): 0, |
|
198 line (), column ()); |
|
199 } |
|
200 |
3484
|
201 void |
|
202 tree_do_until_command::accept (tree_walker& tw) |
|
203 { |
|
204 tw.visit_do_until_command (*this); |
|
205 } |
|
206 |
2982
|
207 // For. |
|
208 |
|
209 tree_simple_for_command::~tree_simple_for_command (void) |
|
210 { |
|
211 delete expr; |
|
212 delete list; |
3665
|
213 delete lead_comm; |
|
214 delete trail_comm; |
2982
|
215 } |
|
216 |
|
217 inline void |
|
218 tree_simple_for_command::do_for_loop_once (octave_lvalue& ult, |
|
219 const octave_value& rhs, |
|
220 bool& quit) |
|
221 { |
|
222 quit = false; |
|
223 |
3538
|
224 ult.assign (octave_value::op_asn_eq, rhs); |
2982
|
225 |
|
226 if (! error_state) |
|
227 { |
|
228 if (list) |
|
229 { |
|
230 list->eval (); |
|
231 |
|
232 if (error_state) |
|
233 eval_error (); |
|
234 } |
|
235 } |
|
236 else |
|
237 eval_error (); |
|
238 |
|
239 quit = quit_loop_now (); |
|
240 } |
|
241 |
|
242 #define DO_LOOP(arg) \ |
|
243 do \ |
|
244 { \ |
|
245 for (int i = 0; i < steps; i++) \ |
|
246 { \ |
3770
|
247 MAYBE_DO_BREAKPOINT; \ |
|
248 \ |
2982
|
249 octave_value val (arg); \ |
|
250 \ |
|
251 bool quit = false; \ |
|
252 \ |
|
253 do_for_loop_once (ult, val, quit); \ |
|
254 \ |
|
255 if (quit) \ |
|
256 break; \ |
|
257 } \ |
|
258 } \ |
|
259 while (0) |
|
260 |
5570
|
261 #define DO_ND_LOOP(TYPE, ARG) \ |
4911
|
262 do \ |
|
263 { \ |
5570
|
264 octave_idx_type steps = dv(1); \ |
4911
|
265 \ |
5275
|
266 for (octave_idx_type i = 0; i < steps; i++) \ |
4911
|
267 { \ |
|
268 MAYBE_DO_BREAKPOINT; \ |
|
269 \ |
5570
|
270 TYPE tmp; \ |
|
271 \ |
|
272 int nr = ARG.rows (); \ |
|
273 \ |
|
274 tmp.resize (dim_vector (nr, 1)); \ |
|
275 \ |
|
276 for (int j = 0; j < nr; j++) \ |
|
277 tmp.xelem (j) = ARG.xelem (j, i); \ |
|
278 \ |
|
279 octave_value val (tmp); \ |
4911
|
280 \ |
|
281 bool quit = false; \ |
|
282 \ |
|
283 do_for_loop_once (ult, val, quit); \ |
|
284 quit = (i == steps - 1 ? true : quit); \ |
|
285 \ |
|
286 if (quit) \ |
|
287 break; \ |
|
288 \ |
|
289 } \ |
|
290 } \ |
|
291 while (0) |
|
292 |
2982
|
293 void |
|
294 tree_simple_for_command::eval (void) |
|
295 { |
|
296 if (error_state) |
|
297 return; |
|
298 |
3877
|
299 unwind_protect::begin_frame ("simple_for_command::eval"); |
|
300 |
|
301 unwind_protect_bool (evaluating_looping_command); |
|
302 |
|
303 evaluating_looping_command = true; |
|
304 |
2982
|
305 octave_value rhs = expr->rvalue (); |
|
306 |
|
307 if (error_state || rhs.is_undefined ()) |
|
308 { |
|
309 eval_error (); |
3877
|
310 goto cleanup; |
2982
|
311 } |
|
312 |
3877
|
313 { |
|
314 octave_lvalue ult = lhs->lvalue (); |
3180
|
315 |
3877
|
316 if (error_state) |
|
317 { |
|
318 eval_error (); |
|
319 goto cleanup; |
|
320 } |
|
321 |
|
322 if (rhs.is_range ()) |
|
323 { |
|
324 Range rng = rhs.range_value (); |
3180
|
325 |
5275
|
326 octave_idx_type steps = rng.nelem (); |
3877
|
327 double b = rng.base (); |
|
328 double increment = rng.inc (); |
3770
|
329 |
5275
|
330 for (octave_idx_type i = 0; i < steps; i++) |
3877
|
331 { |
|
332 MAYBE_DO_BREAKPOINT; |
3180
|
333 |
3877
|
334 double tmp_val = b + i * increment; |
|
335 |
|
336 octave_value val (tmp_val); |
3180
|
337 |
3877
|
338 bool quit = false; |
3180
|
339 |
3877
|
340 do_for_loop_once (ult, val, quit); |
3180
|
341 |
3877
|
342 if (quit) |
|
343 break; |
|
344 } |
|
345 } |
|
346 else if (rhs.is_scalar_type ()) |
|
347 { |
|
348 bool quit = false; |
|
349 |
|
350 MAYBE_DO_BREAKPOINT; |
2982
|
351 |
3877
|
352 do_for_loop_once (ult, rhs, quit); |
|
353 } |
|
354 else if (rhs.is_string ()) |
|
355 { |
|
356 charMatrix chm_tmp = rhs.char_matrix_value (); |
5275
|
357 octave_idx_type nr = chm_tmp.rows (); |
|
358 octave_idx_type steps = chm_tmp.columns (); |
3215
|
359 |
3877
|
360 if (error_state) |
|
361 goto cleanup; |
3215
|
362 |
3877
|
363 if (nr == 1) |
|
364 DO_LOOP (chm_tmp (0, i)); |
|
365 else |
|
366 { |
5275
|
367 for (octave_idx_type i = 0; i < steps; i++) |
3877
|
368 { |
|
369 MAYBE_DO_BREAKPOINT; |
3770
|
370 |
3877
|
371 octave_value val (chm_tmp.extract (0, i, nr-1, i), true); |
3215
|
372 |
3877
|
373 bool quit = false; |
3215
|
374 |
3877
|
375 do_for_loop_once (ult, val, quit); |
3215
|
376 |
3877
|
377 if (quit) |
|
378 break; |
|
379 } |
|
380 } |
|
381 } |
|
382 else if (rhs.is_matrix_type ()) |
|
383 { |
4911
|
384 NDArray m_tmp; |
|
385 ComplexNDArray cm_tmp; |
|
386 dim_vector dv; |
2982
|
387 |
3998
|
388 if (rhs.is_real_type ()) |
3877
|
389 { |
4911
|
390 m_tmp = rhs.array_value (); |
|
391 dv = m_tmp.dims (); |
3877
|
392 } |
|
393 else |
|
394 { |
4911
|
395 cm_tmp = rhs.complex_array_value (); |
|
396 dv = cm_tmp.dims (); |
3877
|
397 } |
2982
|
398 |
3877
|
399 if (error_state) |
|
400 goto cleanup; |
3180
|
401 |
5775
|
402 // FIXME -- maybe we need a function for this? |
5570
|
403 int ndims = dv.length (); |
|
404 for (int i = 2; i < ndims; i++) |
|
405 dv(1) *= dv(i); |
|
406 |
|
407 if (dv(1) > 0) |
5246
|
408 { |
|
409 if (rhs.is_real_type ()) |
5570
|
410 { |
|
411 if (ndims > 2) |
|
412 m_tmp = m_tmp.reshape (dv); |
|
413 |
|
414 DO_ND_LOOP(NDArray, m_tmp); |
|
415 } |
5246
|
416 else |
5570
|
417 { |
|
418 if (ndims > 2) |
|
419 cm_tmp = cm_tmp.reshape (dv); |
|
420 |
|
421 DO_ND_LOOP(ComplexNDArray, cm_tmp); |
|
422 } |
5246
|
423 } |
3877
|
424 } |
|
425 else if (rhs.is_map ()) |
|
426 { |
|
427 Octave_map tmp_val (rhs.map_value ()); |
2982
|
428 |
4219
|
429 for (Octave_map::iterator p = tmp_val.begin (); |
|
430 p != tmp_val.end (); |
|
431 p++) |
3877
|
432 { |
|
433 MAYBE_DO_BREAKPOINT; |
3770
|
434 |
4513
|
435 Cell val_lst = tmp_val.contents (p); |
4121
|
436 |
|
437 octave_value val |
|
438 = (val_lst.length () == 1) ? val_lst(0) : octave_value (val_lst); |
2982
|
439 |
3877
|
440 bool quit = false; |
2982
|
441 |
3877
|
442 do_for_loop_once (ult, val, quit); |
2982
|
443 |
3877
|
444 if (quit) |
|
445 break; |
|
446 } |
|
447 } |
4911
|
448 else if (rhs.is_cell ()) |
|
449 { |
|
450 Cell c_tmp = rhs.cell_value (); |
5248
|
451 |
4911
|
452 dim_vector dv = c_tmp.dims (); |
5248
|
453 |
5775
|
454 // FIXME -- maybe we need a function for this? |
5570
|
455 int ndims = dv.length (); |
|
456 for (int i = 2; i < ndims; i++) |
|
457 dv(1) *= dv(i); |
|
458 |
|
459 if (dv(1) > 0) |
|
460 { |
|
461 if (ndims > 2) |
|
462 c_tmp = c_tmp.reshape (dv); |
|
463 |
|
464 DO_ND_LOOP(Cell, c_tmp); |
|
465 } |
4911
|
466 } |
3877
|
467 else |
|
468 { |
|
469 ::error ("invalid type in for loop expression near line %d, column %d", |
|
470 line (), column ()); |
|
471 } |
|
472 } |
|
473 |
|
474 cleanup: |
|
475 unwind_protect::run_frame ("simple_for_command::eval"); |
2982
|
476 } |
|
477 |
|
478 void |
|
479 tree_simple_for_command::eval_error (void) |
|
480 { |
3965
|
481 ::error ("evaluating for command near line %d, column %d", |
|
482 line (), column ()); |
2982
|
483 } |
|
484 |
5861
|
485 tree_command * |
|
486 tree_simple_for_command::dup (symbol_table *sym_tab) |
|
487 { |
|
488 return new tree_simple_for_command (lhs ? lhs->dup (sym_tab) : 0, |
|
489 expr ? expr->dup (sym_tab) : 0, |
|
490 list ? list->dup (sym_tab) : 0, |
|
491 lead_comm ? lead_comm->dup () : 0, |
|
492 trail_comm ? trail_comm->dup () : 0, |
|
493 line (), column ()); |
|
494 } |
|
495 |
2982
|
496 void |
|
497 tree_simple_for_command::accept (tree_walker& tw) |
|
498 { |
|
499 tw.visit_simple_for_command (*this); |
|
500 } |
|
501 |
|
502 tree_complex_for_command::~tree_complex_for_command (void) |
|
503 { |
|
504 delete expr; |
|
505 delete list; |
3665
|
506 delete lead_comm; |
|
507 delete trail_comm; |
2982
|
508 } |
|
509 |
|
510 void |
|
511 tree_complex_for_command::do_for_loop_once (octave_lvalue &val_ref, |
|
512 octave_lvalue &key_ref, |
|
513 const octave_value& val, |
|
514 const octave_value& key, |
|
515 bool& quit) |
|
516 { |
|
517 quit = false; |
|
518 |
3538
|
519 val_ref.assign (octave_value::op_asn_eq, val); |
|
520 key_ref.assign (octave_value::op_asn_eq, key); |
2982
|
521 |
|
522 if (! error_state) |
|
523 { |
|
524 if (list) |
|
525 { |
|
526 list->eval (); |
|
527 |
|
528 if (error_state) |
|
529 eval_error (); |
|
530 } |
|
531 } |
|
532 else |
|
533 eval_error (); |
|
534 |
|
535 quit = quit_loop_now (); |
|
536 } |
|
537 |
|
538 void |
|
539 tree_complex_for_command::eval (void) |
|
540 { |
|
541 if (error_state) |
|
542 return; |
|
543 |
3877
|
544 unwind_protect::begin_frame ("complex_for_command::eval"); |
|
545 |
|
546 unwind_protect_bool (evaluating_looping_command); |
|
547 |
|
548 evaluating_looping_command = true; |
|
549 |
2982
|
550 octave_value rhs = expr->rvalue (); |
|
551 |
|
552 if (error_state || rhs.is_undefined ()) |
|
553 { |
|
554 eval_error (); |
3877
|
555 goto cleanup; |
2982
|
556 } |
|
557 |
|
558 if (rhs.is_map ()) |
|
559 { |
|
560 // Cycle through structure elements. First element of id_list |
|
561 // is set to value and the second is set to the name of the |
|
562 // structure element. |
|
563 |
4219
|
564 tree_argument_list::iterator p = lhs->begin (); |
|
565 tree_expression *elt = *p++; |
2982
|
566 octave_lvalue val_ref = elt->lvalue (); |
4219
|
567 elt = *p; |
2982
|
568 octave_lvalue key_ref = elt->lvalue (); |
|
569 |
|
570 Octave_map tmp_val (rhs.map_value ()); |
|
571 |
4300
|
572 for (Octave_map::iterator q = tmp_val.begin (); q != tmp_val.end (); q++) |
2982
|
573 { |
4219
|
574 octave_value key = tmp_val.key (q); |
4121
|
575 |
4513
|
576 Cell val_lst = tmp_val.contents (q); |
4121
|
577 |
5275
|
578 octave_idx_type n = tmp_val.numel (); |
4121
|
579 |
|
580 octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); |
2982
|
581 |
3770
|
582 MAYBE_DO_BREAKPOINT; |
|
583 |
2982
|
584 bool quit = false; |
|
585 |
|
586 do_for_loop_once (key_ref, val_ref, key, val, quit); |
|
587 |
|
588 if (quit) |
|
589 break; |
|
590 } |
|
591 } |
|
592 else |
|
593 error ("in statement `for [X, Y] = VAL', VAL must be a structure"); |
3877
|
594 |
|
595 cleanup: |
|
596 unwind_protect::run_frame ("complex_for_command::eval"); |
2982
|
597 } |
|
598 |
|
599 void |
|
600 tree_complex_for_command::eval_error (void) |
|
601 { |
3965
|
602 ::error ("evaluating for command near line %d, column %d", |
|
603 line (), column ()); |
2982
|
604 } |
|
605 |
5861
|
606 tree_command * |
|
607 tree_complex_for_command::dup (symbol_table *sym_tab) |
|
608 { |
|
609 return new tree_complex_for_command (lhs ? lhs->dup (sym_tab) : 0, |
|
610 expr ? expr->dup (sym_tab) : 0, |
|
611 list ? list->dup (sym_tab) : 0, |
|
612 lead_comm ? lead_comm->dup () : 0, |
|
613 trail_comm ? trail_comm->dup () : 0, |
|
614 line (), column ()); |
|
615 } |
|
616 |
2982
|
617 void |
|
618 tree_complex_for_command::accept (tree_walker& tw) |
|
619 { |
|
620 tw.visit_complex_for_command (*this); |
|
621 } |
|
622 |
|
623 /* |
|
624 ;;; Local Variables: *** |
|
625 ;;; mode: C++ *** |
|
626 ;;; End: *** |
|
627 */ |