comparison src/pt-cmd.cc @ 2982:20f5cec4f11c

[project @ 1997-05-16 03:29:26 by jwe]
author jwe
date Fri, 16 May 1997 03:30:14 +0000
parents a3556d2adec9
children 6e86256e9c54
comparison
equal deleted inserted replaced
2981:38365813950d 2982:20f5cec4f11c
26 26
27 #ifdef HAVE_CONFIG_H 27 #ifdef HAVE_CONFIG_H
28 #include <config.h> 28 #include <config.h>
29 #endif 29 #endif
30 30
31 #include <iostream.h>
32
33 // Nonzero means we're breaking out of a loop or function body.
34 int breaking = 0;
35
36 // Nonzero means we're jumping to the end of a loop.
37 int continuing = 0;
38
39 // Nonzero means we're returning from a function. Global because it
40 // is also needed in tree-expr.cc.
41 int returning = 0;
42
43 #include "error.h"
44 #include "gripes.h"
45 #include "oct-map.h"
46 #include "oct-lvalue.h"
47 #include "pt-cmd.h" 31 #include "pt-cmd.h"
48 #include "symtab.h"
49 #include "ov.h"
50 #include "pt-exp.h"
51 #include "pt-id.h"
52 #include "pt-indir.h"
53 #include "pt-misc.h"
54 #include "pt-walk.h" 32 #include "pt-walk.h"
55 #include "unwind-prot.h"
56 #include "variables.h"
57
58 // Decide if it's time to quit a for or while loop.
59 static inline bool
60 quit_loop_now (void)
61 {
62 // Maybe handle `continue N' someday...
63
64 if (continuing)
65 continuing--;
66
67 bool quit = (error_state || returning || breaking || continuing);
68
69 if (breaking)
70 breaking--;
71
72 return quit;
73 }
74
75 // Base class for declaration commands (global, static).
76
77 tree_decl_command::~tree_decl_command (void)
78 {
79 delete init_list;
80 }
81
82 void
83 tree_decl_command::accept (tree_walker& tw)
84 {
85 tw.visit_decl_command (*this);
86 }
87
88 // Global.
89
90 static void
91 do_global_init (tree_decl_elt& elt, bool skip_initializer)
92 {
93 tree_identifier *id = elt.ident ();
94
95 if (id)
96 {
97 id->link_to_global ();
98
99 tree_expression *expr = elt.expression ();
100
101 if (expr)
102 {
103 octave_value init_val = expr->rvalue ();
104
105 octave_lvalue ult = id->lvalue ();
106
107 ult.assign (octave_value::asn_eq, init_val);
108 }
109 }
110 }
111
112 void
113 tree_global_command::eval (void)
114 {
115 if (init_list)
116 {
117 init_list->eval (do_global_init, initialized);
118
119 initialized = true;
120 }
121
122 if (error_state > 0)
123 ::error ("evaluating global command near line %d, column %d",
124 line (), column ());
125 }
126
127 // Static.
128
129 static void
130 do_static_init (tree_decl_elt& elt, bool)
131 {
132 tree_identifier *id = elt.ident ();
133
134 if (id)
135 {
136 id->mark_as_static ();
137
138 tree_expression *expr = elt.expression ();
139
140 if (expr)
141 {
142 octave_value init_val = expr->rvalue ();
143
144 octave_lvalue ult = id->lvalue ();
145
146 ult.assign (octave_value::asn_eq, init_val);
147 }
148 }
149 }
150
151 void
152 tree_static_command::eval (void)
153 {
154 // Static variables only need to be marked and initialized once.
155
156 if (init_list && ! initialized)
157 {
158 init_list->eval (do_static_init, initialized);
159
160 initialized = true;
161
162 if (error_state > 0)
163 ::error ("evaluating static command near line %d, column %d",
164 line (), column ());
165 }
166 }
167
168 // While.
169
170 tree_while_command::~tree_while_command (void)
171 {
172 delete expr;
173 delete list;
174 }
175
176 void
177 tree_while_command::eval (void)
178 {
179 if (error_state)
180 return;
181
182 if (! expr)
183 panic_impossible ();
184
185 for (;;)
186 {
187 if (expr->is_logically_true ("while"))
188 {
189 if (list)
190 {
191 list->eval ();
192
193 if (error_state)
194 {
195 eval_error ();
196 return;
197 }
198 }
199
200 if (quit_loop_now ())
201 break;
202 }
203 else
204 break;
205 }
206 }
207
208 void
209 tree_while_command::eval_error (void)
210 {
211 if (error_state > 0)
212 ::error ("evaluating while command near line %d, column %d",
213 line (), column ());
214 }
215
216 void
217 tree_while_command::accept (tree_walker& tw)
218 {
219 tw.visit_while_command (*this);
220 }
221
222 // For.
223
224 tree_simple_for_command::~tree_simple_for_command (void)
225 {
226 delete expr;
227 delete list;
228 }
229
230 inline void
231 tree_simple_for_command::do_for_loop_once (octave_lvalue& ult,
232 const octave_value& rhs,
233 bool& quit)
234 {
235 quit = false;
236
237 ult.assign (octave_value::asn_eq, rhs);
238
239 if (! error_state)
240 {
241 if (list)
242 {
243 list->eval ();
244
245 if (error_state)
246 eval_error ();
247 }
248 }
249 else
250 eval_error ();
251
252 quit = quit_loop_now ();
253 }
254
255 #define DO_LOOP(arg) \
256 do \
257 { \
258 for (int i = 0; i < steps; i++) \
259 { \
260 octave_value val (arg); \
261 \
262 bool quit = false; \
263 \
264 do_for_loop_once (ult, val, quit); \
265 \
266 if (quit) \
267 break; \
268 } \
269 } \
270 while (0)
271
272 void
273 tree_simple_for_command::eval (void)
274 {
275 if (error_state)
276 return;
277
278 octave_value rhs = expr->rvalue ();
279
280 if (error_state || rhs.is_undefined ())
281 {
282 eval_error ();
283 return;
284 }
285
286 octave_lvalue ult = lhs->lvalue ();
287
288 if (error_state)
289 {
290 eval_error ();
291 return;
292 }
293
294 if (rhs.is_scalar_type ())
295 {
296 bool quit = false;
297
298 do_for_loop_once (ult, rhs, quit);
299 }
300 else if (rhs.is_matrix_type ())
301 {
302 Matrix m_tmp;
303 ComplexMatrix cm_tmp;
304
305 int nr;
306 int steps;
307
308 if (rhs.is_real_matrix ())
309 {
310 m_tmp = rhs.matrix_value ();
311 nr = m_tmp.rows ();
312 steps = m_tmp.columns ();
313 }
314 else
315 {
316 cm_tmp = rhs.complex_matrix_value ();
317 nr = cm_tmp.rows ();
318 steps = cm_tmp.columns ();
319 }
320
321 if (rhs.is_real_matrix ())
322 {
323 if (nr == 1)
324 DO_LOOP (m_tmp (0, i));
325 else
326 DO_LOOP (m_tmp.extract (0, i, nr-1, i));
327 }
328 else
329 {
330 if (nr == 1)
331 DO_LOOP (cm_tmp (0, i));
332 else
333 DO_LOOP (cm_tmp.extract (0, i, nr-1, i));
334 }
335 }
336 else if (rhs.is_string ())
337 {
338 gripe_string_invalid ();
339 }
340 else if (rhs.is_range ())
341 {
342 Range rng = rhs.range_value ();
343
344 int steps = rng.nelem ();
345 double b = rng.base ();
346 double increment = rng.inc ();
347
348 for (int i = 0; i < steps; i++)
349 {
350 double tmp_val = b + i * increment;
351
352 octave_value val (tmp_val);
353
354 bool quit = false;
355
356 do_for_loop_once (ult, val, quit);
357
358 if (quit)
359 break;
360 }
361 }
362 else if (rhs.is_map ())
363 {
364 Octave_map tmp_val (rhs.map_value ());
365
366 for (Pix p = tmp_val.first (); p != 0; tmp_val.next (p))
367 {
368 octave_value val = tmp_val.contents (p);
369
370 bool quit = false;
371
372 do_for_loop_once (ult, val, quit);
373
374 if (quit)
375 break;
376 }
377 }
378 else
379 {
380 ::error ("invalid type in for loop expression near line %d, column %d",
381 line (), column ());
382 }
383 }
384
385 void
386 tree_simple_for_command::eval_error (void)
387 {
388 if (error_state > 0)
389 ::error ("evaluating for command near line %d, column %d",
390 line (), column ());
391 }
392
393 void
394 tree_simple_for_command::accept (tree_walker& tw)
395 {
396 tw.visit_simple_for_command (*this);
397 }
398
399 tree_complex_for_command::~tree_complex_for_command (void)
400 {
401 delete expr;
402 delete list;
403 }
404
405 void
406 tree_complex_for_command::do_for_loop_once (octave_lvalue &val_ref,
407 octave_lvalue &key_ref,
408 const octave_value& val,
409 const octave_value& key,
410 bool& quit)
411 {
412 quit = false;
413
414 val_ref.assign (octave_value::asn_eq, val);
415 key_ref.assign (octave_value::asn_eq, key);
416
417 if (! error_state)
418 {
419 if (list)
420 {
421 list->eval ();
422
423 if (error_state)
424 eval_error ();
425 }
426 }
427 else
428 eval_error ();
429
430 quit = quit_loop_now ();
431 }
432
433 void
434 tree_complex_for_command::eval (void)
435 {
436 if (error_state)
437 return;
438
439 octave_value rhs = expr->rvalue ();
440
441 if (error_state || rhs.is_undefined ())
442 {
443 eval_error ();
444 return;
445 }
446
447 if (rhs.is_map ())
448 {
449 // Cycle through structure elements. First element of id_list
450 // is set to value and the second is set to the name of the
451 // structure element.
452
453 Pix p = lhs->first ();
454 tree_expression *elt = lhs->operator () (p);
455 octave_lvalue val_ref = elt->lvalue ();
456
457 lhs->next (p);
458 elt = lhs->operator () (p);
459 octave_lvalue key_ref = elt->lvalue ();
460
461 Octave_map tmp_val (rhs.map_value ());
462
463 for (p = tmp_val.first (); p != 0; tmp_val.next (p))
464 {
465 octave_value key = tmp_val.key (p);
466 octave_value val = tmp_val.contents (p);
467
468 bool quit = false;
469
470 do_for_loop_once (key_ref, val_ref, key, val, quit);
471
472 if (quit)
473 break;
474 }
475 }
476 else
477 error ("in statement `for [X, Y] = VAL', VAL must be a structure");
478 }
479
480 void
481 tree_complex_for_command::eval_error (void)
482 {
483 if (error_state > 0)
484 ::error ("evaluating for command near line %d, column %d",
485 line (), column ());
486 }
487
488 void
489 tree_complex_for_command::accept (tree_walker& tw)
490 {
491 tw.visit_complex_for_command (*this);
492 }
493
494 // If.
495
496 tree_if_command::~tree_if_command (void)
497 {
498 delete list;
499 }
500
501 void
502 tree_if_command::eval (void)
503 {
504 if (list)
505 list->eval ();
506
507 if (error_state > 0)
508 ::error ("evaluating if command near line %d, column %d",
509 line (), column ());
510 }
511
512 void
513 tree_if_command::accept (tree_walker& tw)
514 {
515 tw.visit_if_command (*this);
516 }
517
518 // Switch.
519
520 tree_switch_command::~tree_switch_command (void)
521 {
522 delete expr;
523 delete list;
524 }
525
526 void
527 tree_switch_command::eval (void)
528 {
529 if (expr)
530 {
531 octave_value val = expr->rvalue ();
532
533 if (! error_state)
534 {
535 if (list)
536 list->eval (val);
537
538 if (error_state)
539 eval_error ();
540 }
541 else
542 eval_error ();
543 }
544 else
545 ::error ("missing value in switch command near line %d, column %d",
546 line (), column ());
547 }
548
549 void
550 tree_switch_command::eval_error (void)
551 {
552 ::error ("evaluating switch command near line %d, column %d",
553 line (), column ());
554 }
555
556 void
557 tree_switch_command::accept (tree_walker& tw)
558 {
559 tw.visit_switch_command (*this);
560 }
561
562 // Simple exception handling.
563
564 tree_try_catch_command::~tree_try_catch_command (void)
565 {
566 delete try_code;
567 delete catch_code;
568 }
569
570 static void
571 do_catch_code (void *ptr)
572 {
573 tree_statement_list *list = static_cast<tree_statement_list *> (ptr);
574
575 // Set up for letting the user print any messages from errors that
576 // occurred in the body of the try_catch statement.
577
578 buffer_error_messages = 0;
579 bind_global_error_variable ();
580 add_unwind_protect (clear_global_error_variable, 0);
581
582 // Similarly, if we have seen a return or break statement, allow all
583 // the catch code to run before returning or handling the break.
584 // We don't have to worry about continue statements because they can
585 // only occur in loops.
586
587 unwind_protect_int (returning);
588 returning = 0;
589
590 unwind_protect_int (breaking);
591 breaking = 0;
592
593 if (list)
594 list->eval ();
595
596 // This is the one for breaking. (The unwind_protects are popped
597 // off the stack in the reverse of the order they are pushed on).
598
599 // XXX FIXME XXX -- inside a try-catch, should break work like
600 // a return, or just jump to the end of the try_catch block?
601 // The following code makes it just jump to the end of the block.
602
603 run_unwind_protect ();
604 if (breaking)
605 breaking--;
606
607 // This is the one for returning.
608
609 if (returning)
610 discard_unwind_protect ();
611 else
612 run_unwind_protect ();
613
614 run_unwind_protect ();
615 }
616
617 void
618 tree_try_catch_command::eval (void)
619 {
620 begin_unwind_frame ("tree_try_catch::eval");
621
622 add_unwind_protect (do_catch_code, catch_code);
623
624 if (catch_code)
625 {
626 unwind_protect_int (buffer_error_messages);
627 buffer_error_messages = 1;
628 }
629
630 if (try_code)
631 try_code->eval ();
632
633 if (catch_code && error_state)
634 {
635 error_state = 0;
636 run_unwind_frame ("tree_try_catch::eval");
637 }
638 else
639 {
640 error_state = 0;
641 discard_unwind_frame ("tree_try_catch::eval");
642 }
643 }
644
645 void
646 tree_try_catch_command::accept (tree_walker& tw)
647 {
648 tw.visit_try_catch_command (*this);
649 }
650
651 // Simple exception handling.
652
653 tree_unwind_protect_command::~tree_unwind_protect_command (void)
654 {
655 delete unwind_protect_code;
656 delete cleanup_code;
657 }
658
659 static void
660 do_unwind_protect_cleanup_code (void *ptr)
661 {
662 tree_statement_list *list = static_cast<tree_statement_list *> (ptr);
663
664 // We want to run the cleanup code without error_state being set,
665 // but we need to restore its value, so that any errors encountered
666 // in the first part of the unwind_protect are not completely
667 // ignored.
668
669 unwind_protect_int (error_state);
670 error_state = 0;
671
672 // Similarly, if we have seen a return or break statement, allow all
673 // the cleanup code to run before returning or handling the break.
674 // We don't have to worry about continue statements because they can
675 // only occur in loops.
676
677 unwind_protect_int (returning);
678 returning = 0;
679
680 unwind_protect_int (breaking);
681 breaking = 0;
682
683 if (list)
684 list->eval ();
685
686 // This is the one for breaking. (The unwind_protects are popped
687 // off the stack in the reverse of the order they are pushed on).
688
689 // XXX FIXME XXX -- inside an unwind_protect, should break work like
690 // a return, or just jump to the end of the unwind_protect block?
691 // The following code makes it just jump to the end of the block.
692
693 run_unwind_protect ();
694 if (breaking)
695 breaking--;
696
697 // This is the one for returning.
698
699 if (returning)
700 discard_unwind_protect ();
701 else
702 run_unwind_protect ();
703
704 // We don't want to ignore errors that occur in the cleanup code, so
705 // if an error is encountered there, leave error_state alone.
706 // Otherwise, set it back to what it was before.
707
708 if (error_state)
709 discard_unwind_protect ();
710 else
711 run_unwind_protect ();
712 }
713
714 void
715 tree_unwind_protect_command::eval (void)
716 {
717 add_unwind_protect (do_unwind_protect_cleanup_code, cleanup_code);
718
719 if (unwind_protect_code)
720 unwind_protect_code->eval ();
721
722 run_unwind_protect ();
723 }
724
725 void
726 tree_unwind_protect_command::accept (tree_walker& tw)
727 {
728 tw.visit_unwind_protect_command (*this);
729 }
730 33
731 // No-op. 34 // No-op.
732 35
733 void 36 void
734 tree_no_op_command::accept (tree_walker& tw) 37 tree_no_op_command::accept (tree_walker& tw)
735 { 38 {
736 tw.visit_no_op_command (*this); 39 tw.visit_no_op_command (*this);
737 } 40 }
738 41
739 // Break.
740
741 void
742 tree_break_command::eval (void)
743 {
744 if (! error_state)
745 breaking = 1;
746 }
747
748 void
749 tree_break_command::accept (tree_walker& tw)
750 {
751 tw.visit_break_command (*this);
752 }
753
754 // Continue.
755
756 void
757 tree_continue_command::eval (void)
758 {
759 if (! error_state)
760 continuing = 1;
761 }
762
763 void
764 tree_continue_command::accept (tree_walker& tw)
765 {
766 tw.visit_continue_command (*this);
767 }
768
769 // Return.
770
771 void
772 tree_return_command::eval (void)
773 {
774 if (! error_state)
775 returning = 1;
776 }
777
778 void
779 tree_return_command::accept (tree_walker& tw)
780 {
781 tw.visit_return_command (*this);
782 }
783
784 /* 42 /*
785 ;;; Local Variables: *** 43 ;;; Local Variables: ***
786 ;;; mode: C++ *** 44 ;;; mode: C++ ***
787 ;;; End: *** 45 ;;; End: ***
788 */ 46 */