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 { |
3538
|
222 ult.assign (octave_value::op_asn_eq, rhs); |
2982
|
223 |
|
224 if (! error_state) |
|
225 { |
|
226 if (list) |
|
227 { |
|
228 list->eval (); |
|
229 |
|
230 if (error_state) |
|
231 eval_error (); |
|
232 } |
|
233 } |
|
234 else |
|
235 eval_error (); |
|
236 |
|
237 quit = quit_loop_now (); |
|
238 } |
|
239 |
6602
|
240 #define DO_ND_LOOP(MTYPE, TYPE, CONV, ARG) \ |
2982
|
241 do \ |
|
242 { \ |
6602
|
243 dim_vector dv = ARG.dims (); \ |
2982
|
244 \ |
6602
|
245 bool quit = false; \ |
|
246 \ |
|
247 TYPE *atmp = ARG.fortran_vec (); \ |
|
248 \ |
5570
|
249 octave_idx_type steps = dv(1); \ |
4911
|
250 \ |
6602
|
251 octave_idx_type nrows = dv(0); \ |
|
252 \ |
|
253 int ndims = dv.length (); \ |
|
254 if (ndims > 2) \ |
|
255 { \ |
|
256 for (int i = 2; i < ndims; i++) \ |
|
257 steps *= dv(i); \ |
|
258 dv(1) = steps; \ |
|
259 dv.resize (2); \ |
|
260 } \ |
4911
|
261 \ |
6602
|
262 if (steps > 0) \ |
|
263 { \ |
|
264 if (nrows == 0) \ |
|
265 { \ |
|
266 octave_value val (MTYPE (dim_vector (0, 1))); \ |
|
267 \ |
|
268 for (octave_idx_type i = 0; i < steps; i++) \ |
|
269 { \ |
|
270 MAYBE_DO_BREAKPOINT; \ |
5570
|
271 \ |
6602
|
272 do_for_loop_once (ult, val, quit); \ |
5570
|
273 \ |
6602
|
274 if (quit) \ |
|
275 break; \ |
|
276 } \ |
|
277 } \ |
|
278 else if (nrows == 1) \ |
|
279 { \ |
|
280 for (octave_idx_type i = 0; i < steps; i++) \ |
|
281 { \ |
|
282 MAYBE_DO_BREAKPOINT; \ |
5570
|
283 \ |
6602
|
284 octave_value val (CONV (*atmp++)); \ |
|
285 \ |
|
286 do_for_loop_once (ult, val, quit); \ |
5570
|
287 \ |
6602
|
288 if (quit) \ |
|
289 break; \ |
|
290 } \ |
|
291 } \ |
|
292 else \ |
|
293 { \ |
|
294 if (ndims > 2) \ |
|
295 ARG = ARG.reshape (dv); \ |
4911
|
296 \ |
6602
|
297 MTYPE tmp (dim_vector (nrows, 1)); \ |
|
298 \ |
|
299 TYPE *ftmp = tmp.fortran_vec (); \ |
4911
|
300 \ |
6602
|
301 for (octave_idx_type i = 0; i < steps; i++) \ |
|
302 { \ |
|
303 MAYBE_DO_BREAKPOINT; \ |
|
304 \ |
|
305 for (int j = 0; j < nrows; j++) \ |
|
306 ftmp[j] = *atmp++; \ |
|
307 \ |
|
308 octave_value val (tmp); \ |
4911
|
309 \ |
6602
|
310 do_for_loop_once (ult, val, quit); \ |
|
311 quit = (i == steps - 1 ? true : quit); \ |
4911
|
312 \ |
6602
|
313 if (quit) \ |
|
314 break; \ |
|
315 } \ |
|
316 } \ |
|
317 } \ |
4911
|
318 } \ |
|
319 while (0) |
|
320 |
2982
|
321 void |
|
322 tree_simple_for_command::eval (void) |
|
323 { |
|
324 if (error_state) |
|
325 return; |
|
326 |
3877
|
327 unwind_protect::begin_frame ("simple_for_command::eval"); |
|
328 |
|
329 unwind_protect_bool (evaluating_looping_command); |
|
330 |
|
331 evaluating_looping_command = true; |
|
332 |
2982
|
333 octave_value rhs = expr->rvalue (); |
|
334 |
|
335 if (error_state || rhs.is_undefined ()) |
|
336 { |
|
337 eval_error (); |
3877
|
338 goto cleanup; |
2982
|
339 } |
|
340 |
3877
|
341 { |
|
342 octave_lvalue ult = lhs->lvalue (); |
3180
|
343 |
3877
|
344 if (error_state) |
|
345 { |
|
346 eval_error (); |
|
347 goto cleanup; |
|
348 } |
|
349 |
|
350 if (rhs.is_range ()) |
|
351 { |
|
352 Range rng = rhs.range_value (); |
3180
|
353 |
5275
|
354 octave_idx_type steps = rng.nelem (); |
3877
|
355 double b = rng.base (); |
|
356 double increment = rng.inc (); |
6602
|
357 bool quit = false; |
|
358 double tmp_val = b; |
3770
|
359 |
6602
|
360 for (octave_idx_type i = 0; i < steps; i++, tmp_val += increment) |
3877
|
361 { |
|
362 MAYBE_DO_BREAKPOINT; |
3180
|
363 |
3877
|
364 octave_value val (tmp_val); |
3180
|
365 |
3877
|
366 do_for_loop_once (ult, val, quit); |
3180
|
367 |
3877
|
368 if (quit) |
|
369 break; |
|
370 } |
|
371 } |
|
372 else if (rhs.is_scalar_type ()) |
|
373 { |
|
374 bool quit = false; |
|
375 |
|
376 MAYBE_DO_BREAKPOINT; |
2982
|
377 |
3877
|
378 do_for_loop_once (ult, rhs, quit); |
|
379 } |
|
380 else if (rhs.is_string ()) |
|
381 { |
|
382 charMatrix chm_tmp = rhs.char_matrix_value (); |
5275
|
383 octave_idx_type nr = chm_tmp.rows (); |
|
384 octave_idx_type steps = chm_tmp.columns (); |
6602
|
385 bool quit = false; |
3215
|
386 |
3877
|
387 if (error_state) |
|
388 goto cleanup; |
3215
|
389 |
3877
|
390 if (nr == 1) |
6602
|
391 { |
|
392 for (octave_idx_type i = 0; i < steps; i++) |
|
393 { |
|
394 MAYBE_DO_BREAKPOINT; |
|
395 |
|
396 octave_value val (chm_tmp.xelem (0, i)); |
|
397 |
|
398 do_for_loop_once (ult, val, quit); |
|
399 |
|
400 if (quit) |
|
401 break; |
|
402 } |
|
403 } |
3877
|
404 else |
|
405 { |
5275
|
406 for (octave_idx_type i = 0; i < steps; i++) |
3877
|
407 { |
|
408 MAYBE_DO_BREAKPOINT; |
3770
|
409 |
3877
|
410 octave_value val (chm_tmp.extract (0, i, nr-1, i), true); |
3215
|
411 |
3877
|
412 do_for_loop_once (ult, val, quit); |
3215
|
413 |
3877
|
414 if (quit) |
|
415 break; |
|
416 } |
|
417 } |
|
418 } |
|
419 else if (rhs.is_matrix_type ()) |
|
420 { |
3998
|
421 if (rhs.is_real_type ()) |
3877
|
422 { |
6602
|
423 NDArray m_tmp = rhs.array_value (); |
|
424 |
|
425 if (error_state) |
|
426 goto cleanup; |
|
427 |
|
428 DO_ND_LOOP (NDArray, double, , m_tmp); |
3877
|
429 } |
|
430 else |
|
431 { |
6602
|
432 ComplexNDArray cm_tmp = rhs.complex_array_value (); |
5570
|
433 |
6602
|
434 if (error_state) |
|
435 goto cleanup; |
5570
|
436 |
6602
|
437 DO_ND_LOOP (ComplexNDArray, Complex, , cm_tmp); |
5246
|
438 } |
3877
|
439 } |
|
440 else if (rhs.is_map ()) |
|
441 { |
|
442 Octave_map tmp_val (rhs.map_value ()); |
2982
|
443 |
6602
|
444 bool quit = false; |
|
445 |
4219
|
446 for (Octave_map::iterator p = tmp_val.begin (); |
|
447 p != tmp_val.end (); |
|
448 p++) |
3877
|
449 { |
|
450 MAYBE_DO_BREAKPOINT; |
3770
|
451 |
4513
|
452 Cell val_lst = tmp_val.contents (p); |
4121
|
453 |
|
454 octave_value val |
|
455 = (val_lst.length () == 1) ? val_lst(0) : octave_value (val_lst); |
2982
|
456 |
3877
|
457 do_for_loop_once (ult, val, quit); |
2982
|
458 |
3877
|
459 if (quit) |
|
460 break; |
|
461 } |
|
462 } |
4911
|
463 else if (rhs.is_cell ()) |
|
464 { |
|
465 Cell c_tmp = rhs.cell_value (); |
5248
|
466 |
6602
|
467 DO_ND_LOOP (Cell, octave_value, Cell, c_tmp); |
4911
|
468 } |
3877
|
469 else |
|
470 { |
|
471 ::error ("invalid type in for loop expression near line %d, column %d", |
|
472 line (), column ()); |
|
473 } |
|
474 } |
|
475 |
|
476 cleanup: |
|
477 unwind_protect::run_frame ("simple_for_command::eval"); |
2982
|
478 } |
|
479 |
|
480 void |
|
481 tree_simple_for_command::eval_error (void) |
|
482 { |
3965
|
483 ::error ("evaluating for command near line %d, column %d", |
|
484 line (), column ()); |
2982
|
485 } |
|
486 |
5861
|
487 tree_command * |
|
488 tree_simple_for_command::dup (symbol_table *sym_tab) |
|
489 { |
|
490 return new tree_simple_for_command (lhs ? lhs->dup (sym_tab) : 0, |
|
491 expr ? expr->dup (sym_tab) : 0, |
|
492 list ? list->dup (sym_tab) : 0, |
|
493 lead_comm ? lead_comm->dup () : 0, |
|
494 trail_comm ? trail_comm->dup () : 0, |
|
495 line (), column ()); |
|
496 } |
|
497 |
2982
|
498 void |
|
499 tree_simple_for_command::accept (tree_walker& tw) |
|
500 { |
|
501 tw.visit_simple_for_command (*this); |
|
502 } |
|
503 |
|
504 tree_complex_for_command::~tree_complex_for_command (void) |
|
505 { |
|
506 delete expr; |
|
507 delete list; |
3665
|
508 delete lead_comm; |
|
509 delete trail_comm; |
2982
|
510 } |
|
511 |
|
512 void |
|
513 tree_complex_for_command::do_for_loop_once (octave_lvalue &val_ref, |
|
514 octave_lvalue &key_ref, |
|
515 const octave_value& val, |
|
516 const octave_value& key, |
|
517 bool& quit) |
|
518 { |
|
519 quit = false; |
|
520 |
3538
|
521 val_ref.assign (octave_value::op_asn_eq, val); |
|
522 key_ref.assign (octave_value::op_asn_eq, key); |
2982
|
523 |
|
524 if (! error_state) |
|
525 { |
|
526 if (list) |
|
527 { |
|
528 list->eval (); |
|
529 |
|
530 if (error_state) |
|
531 eval_error (); |
|
532 } |
|
533 } |
|
534 else |
|
535 eval_error (); |
|
536 |
|
537 quit = quit_loop_now (); |
|
538 } |
|
539 |
|
540 void |
|
541 tree_complex_for_command::eval (void) |
|
542 { |
|
543 if (error_state) |
|
544 return; |
|
545 |
3877
|
546 unwind_protect::begin_frame ("complex_for_command::eval"); |
|
547 |
|
548 unwind_protect_bool (evaluating_looping_command); |
|
549 |
|
550 evaluating_looping_command = true; |
|
551 |
2982
|
552 octave_value rhs = expr->rvalue (); |
|
553 |
|
554 if (error_state || rhs.is_undefined ()) |
|
555 { |
|
556 eval_error (); |
3877
|
557 goto cleanup; |
2982
|
558 } |
|
559 |
|
560 if (rhs.is_map ()) |
|
561 { |
|
562 // Cycle through structure elements. First element of id_list |
|
563 // is set to value and the second is set to the name of the |
|
564 // structure element. |
|
565 |
4219
|
566 tree_argument_list::iterator p = lhs->begin (); |
|
567 tree_expression *elt = *p++; |
2982
|
568 octave_lvalue val_ref = elt->lvalue (); |
4219
|
569 elt = *p; |
2982
|
570 octave_lvalue key_ref = elt->lvalue (); |
|
571 |
|
572 Octave_map tmp_val (rhs.map_value ()); |
|
573 |
4300
|
574 for (Octave_map::iterator q = tmp_val.begin (); q != tmp_val.end (); q++) |
2982
|
575 { |
4219
|
576 octave_value key = tmp_val.key (q); |
4121
|
577 |
4513
|
578 Cell val_lst = tmp_val.contents (q); |
4121
|
579 |
5275
|
580 octave_idx_type n = tmp_val.numel (); |
4121
|
581 |
|
582 octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); |
2982
|
583 |
3770
|
584 MAYBE_DO_BREAKPOINT; |
|
585 |
2982
|
586 bool quit = false; |
|
587 |
|
588 do_for_loop_once (key_ref, val_ref, key, val, quit); |
|
589 |
|
590 if (quit) |
|
591 break; |
|
592 } |
|
593 } |
|
594 else |
|
595 error ("in statement `for [X, Y] = VAL', VAL must be a structure"); |
3877
|
596 |
|
597 cleanup: |
|
598 unwind_protect::run_frame ("complex_for_command::eval"); |
2982
|
599 } |
|
600 |
|
601 void |
|
602 tree_complex_for_command::eval_error (void) |
|
603 { |
3965
|
604 ::error ("evaluating for command near line %d, column %d", |
|
605 line (), column ()); |
2982
|
606 } |
|
607 |
5861
|
608 tree_command * |
|
609 tree_complex_for_command::dup (symbol_table *sym_tab) |
|
610 { |
|
611 return new tree_complex_for_command (lhs ? lhs->dup (sym_tab) : 0, |
|
612 expr ? expr->dup (sym_tab) : 0, |
|
613 list ? list->dup (sym_tab) : 0, |
|
614 lead_comm ? lead_comm->dup () : 0, |
|
615 trail_comm ? trail_comm->dup () : 0, |
|
616 line (), column ()); |
|
617 } |
|
618 |
2982
|
619 void |
|
620 tree_complex_for_command::accept (tree_walker& tw) |
|
621 { |
|
622 tw.visit_complex_for_command (*this); |
|
623 } |
|
624 |
|
625 /* |
|
626 ;;; Local Variables: *** |
|
627 ;;; mode: C++ *** |
|
628 ;;; End: *** |
|
629 */ |