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