home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-src.tgz / tar.out / fsf / octave / src / tree-cmd.cc < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  573 lines

  1. // tree-cmd.cc                                           -*- C++ -*-
  2. /*
  3.  
  4. Copyright (C) 1992, 1993, 1994, 1995 John W. Eaton
  5.  
  6. This file is part of Octave.
  7.  
  8. Octave is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. Octave is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with Octave; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. */
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27.  
  28. #include <iostream.h>
  29.  
  30. // Nonzero means we're breaking out of a loop or function body.
  31. int breaking = 0;
  32.  
  33. // Nonzero means we're jumping to the end of a loop.
  34. int continuing = 0;
  35.  
  36. // Nonzero means we're returning from a function.  Global because it
  37. // is also needed in tree-expr.cc.
  38. int returning = 0;
  39.  
  40. #include "user-prefs.h"
  41. #include "variables.h"
  42. #include "symtab.h"
  43. #include "error.h"
  44. #include "gripes.h"
  45. #include "tree-base.h"
  46. #include "tree-expr.h"
  47. #include "tree-cmd.h"
  48. #include "tree-misc.h"
  49. #include "tree-const.h"
  50. #include "unwind-prot.h"
  51.  
  52. // Decide if it's time to quit a for or while loop.
  53. static int
  54. quit_loop_now (void)
  55. {
  56. // Maybe handle `continue N' someday...
  57.  
  58.   if (continuing)
  59.     continuing--;
  60.  
  61.   int quit = (returning || breaking || continuing);
  62.  
  63.   if (breaking)
  64.     breaking--;
  65.  
  66.   return quit;
  67. }
  68.  
  69. // But first, some extra functions used by the tree classes.
  70.  
  71. // We seem to have no use for this now.  Maybe it will be needed at
  72. // some future date, so here it is.
  73. #if 0
  74.  
  75. // Convert a linked list of trees to a vector of pointers to trees.
  76.  
  77. static tree **
  78. list_to_vector (tree *list, int& len)
  79. {
  80.   len = list->length () + 1;
  81.  
  82.   tree **args = new tree * [len];
  83.  
  84. // args[0] may eventually hold something useful, like the function
  85. // name.
  86.   tree *tmp_list = list;
  87.   for (int k = 1; k < len; k++)
  88.     {
  89.       args[k] = tmp_list;
  90.       tmp_list = tmp_list->next_elem ();
  91.     }
  92.   return args;
  93. }
  94. #endif
  95.  
  96. // Global.
  97.  
  98. tree_global_command::~tree_global_command (void)
  99. {
  100.   delete init_list;
  101. }
  102.  
  103. void
  104. tree_global_command::eval (void)
  105. {
  106.   if (init_list)
  107.     init_list->eval ();
  108.  
  109.   if (error_state > 0)
  110.     ::error ("evaluating global command near line %d, column %d",
  111.          line (), column ());
  112. }
  113.  
  114. void
  115. tree_global_command::print_code (ostream& os)
  116. {
  117.   print_code_indent (os);
  118.  
  119.   os << "global ";
  120.  
  121.   if (init_list)
  122.     init_list->print_code (os);
  123. }
  124.  
  125. // While.
  126.  
  127. tree_while_command::~tree_while_command (void)
  128. {
  129.   delete expr;
  130.   delete list;
  131. }
  132.  
  133. void
  134. tree_while_command::eval (void)
  135. {
  136.   if (error_state)
  137.     return;
  138.  
  139.   for (;;)
  140.     {
  141.       int expr_value = 0;
  142.       if (! expr)
  143.     return;
  144.       tree_constant t1 = expr->eval (0);
  145.  
  146.       if (error_state)
  147.     {
  148.       eval_error ();
  149.       return;
  150.     }
  151.  
  152.       if (t1.rows () == 0 || t1.columns () == 0)
  153.     {
  154.       int flag = user_pref.propagate_empty_matrices;
  155.       if (flag < 0)
  156.         warning ("while: empty matrix used in conditional");
  157.       else if (flag == 0)
  158.         {
  159.           ::error ("empty matrix used in while condition near line\
  160.  %d, column %d", line (), column ()); 
  161.           return;
  162.         }
  163.       t1 = tree_constant (0.0);
  164.     }
  165.       else if (! t1.is_scalar_type ())
  166.     {
  167.       tree_constant t2 = t1.all ();
  168.       t1 = t2.all ();
  169.     }
  170.  
  171.       if (t1.is_real_scalar ())
  172.     expr_value = (int) t1.double_value ();
  173.       else if (t1.is_complex_scalar ())
  174.     expr_value = t1.complex_value () != 0.0;
  175.       else
  176.     {
  177.       ::error ("invalid type used in while condition near line %d,\
  178.  column %d", line (), column ());
  179.       return;
  180.     }
  181.  
  182.       if (expr_value)
  183.     {
  184.       if (list)
  185.         {
  186.           list->eval (1);
  187.           if (error_state)
  188.         {
  189.           eval_error ();
  190.           return;
  191.         }
  192.         }
  193.  
  194.       if (quit_loop_now ())
  195.         break;
  196.     }
  197.       else
  198.     break;
  199.     }
  200. }
  201.  
  202. void
  203. tree_while_command::eval_error (void)
  204. {
  205.   if (error_state > 0)
  206.     ::error ("evaluating while command near line %d, column %d",
  207.          line (), column ());
  208. }
  209.  
  210. void
  211. tree_while_command::print_code (ostream& os)
  212. {
  213.   print_code_indent (os);
  214.  
  215.   os << "while ";
  216.  
  217.   if (expr)
  218.     expr->print_code (os);
  219.  
  220.   print_code_new_line (os);
  221.  
  222.   if (list)
  223.     {
  224.       increment_indent_level ();
  225.       list->print_code (os);
  226.       decrement_indent_level ();
  227.     }
  228.  
  229.   print_code_indent (os);
  230.  
  231.   os << "endwhile";
  232. }
  233.  
  234. // For.
  235.  
  236. tree_for_command::~tree_for_command (void)
  237. {
  238.   delete id;
  239.   delete expr;
  240.   delete list;
  241. }
  242.  
  243. void
  244. tree_for_command::eval (void)
  245. {
  246.   if (error_state || ! expr)
  247.     return;
  248.  
  249.   tree_constant tmp_expr = expr->eval (0);
  250.  
  251.   if (error_state || tmp_expr.is_undefined ())
  252.     {
  253.       eval_error ();
  254.       return;
  255.     }
  256.  
  257.   if (tmp_expr.is_scalar_type ())
  258.     {
  259.       tree_constant *rhs = new tree_constant (tmp_expr);
  260.       int quit = 0;
  261.       do_for_loop_once (rhs, quit);
  262.     }
  263.   else if (tmp_expr.is_matrix_type ())
  264.     {
  265.       Matrix m_tmp;
  266.       ComplexMatrix cm_tmp;
  267.       int nr;
  268.       int steps;
  269.       if (tmp_expr.is_real_matrix ())
  270.     {
  271.       m_tmp = tmp_expr.matrix_value ();
  272.       nr = m_tmp.rows ();
  273.       steps = m_tmp.columns ();
  274.     }
  275.       else
  276.     {
  277.       cm_tmp = tmp_expr.complex_matrix_value ();
  278.       nr = cm_tmp.rows ();
  279.       steps = cm_tmp.columns ();
  280.     }
  281.  
  282.       for (int i = 0; i < steps; i++)
  283.     {
  284.       tree_constant *rhs = 0;
  285.  
  286.       if (nr == 1)
  287.         {
  288.           if (tmp_expr.is_real_matrix ())
  289.         rhs = new tree_constant (m_tmp (0, i));
  290.           else
  291.         rhs = new tree_constant (cm_tmp (0, i));
  292.         }
  293.       else
  294.         {
  295.           if (tmp_expr.is_real_matrix ())
  296.         rhs = new tree_constant (m_tmp.extract (0, i, nr-1, i));
  297.           else
  298.         rhs = new tree_constant (cm_tmp.extract (0, i, nr-1, i));
  299.         }
  300.  
  301.       int quit = 0;
  302.       do_for_loop_once (rhs, quit);
  303.       if (quit)
  304.         break;
  305.     }
  306.     }
  307.   else if (tmp_expr.is_string ())
  308.     {
  309.       gripe_string_invalid ();
  310.     }
  311.   else if (tmp_expr.is_range ())
  312.     {
  313.       Range rng = tmp_expr.range_value ();
  314.  
  315.       int steps = rng.nelem ();
  316.       double b = rng.base ();
  317.       double increment = rng.inc ();
  318.  
  319.       for (int i = 0; i < steps; i++)
  320.     {
  321.       double tmp_val = b + i * increment;
  322.  
  323.       tree_constant *rhs = new tree_constant (tmp_val);
  324.  
  325.       int quit = 0;
  326.       do_for_loop_once (rhs, quit);
  327.       if (quit)
  328.         break;
  329.     }
  330.     }
  331.   else
  332.     {
  333.       ::error ("invalid type in for loop expression near line %d, column %d",
  334.            line (), column ());
  335.     }
  336. }
  337.  
  338. void
  339. tree_for_command::eval_error (void)
  340. {
  341.   if (error_state > 0)
  342.     ::error ("evaluating for command near line %d, column %d",
  343.          line (), column ());
  344. }
  345.  
  346. void
  347. tree_for_command::do_for_loop_once (tree_constant *rhs, int& quit)
  348. {
  349.   quit = 0;
  350.  
  351.   tree_simple_assignment_expression tmp_ass (id, rhs, 1);
  352.  
  353.   tmp_ass.eval (0);
  354.  
  355.   if (error_state)
  356.     {
  357.       eval_error ();
  358.       return;
  359.     }
  360.  
  361.   if (list)
  362.     {
  363.       list->eval (1);
  364.       if (error_state)
  365.     {
  366.       eval_error ();
  367.       quit = 1;
  368.       return;
  369.     }
  370.     }
  371.  
  372.   quit = quit_loop_now ();
  373. }
  374.  
  375. void
  376. tree_for_command::print_code (ostream& os)
  377. {
  378.   print_code_indent (os);
  379.  
  380.   os << "for ";
  381.  
  382.   if (id)
  383.     id->print_code (os);
  384.  
  385.   os << " = ";
  386.  
  387.   if (expr)
  388.     expr->print_code (os);
  389.  
  390.   print_code_new_line (os);
  391.  
  392.   if (list)
  393.     {
  394.       increment_indent_level ();
  395.       list->print_code (os);
  396.       decrement_indent_level ();
  397.     }
  398.  
  399.   print_code_indent (os);
  400.  
  401.   os << "endfor";
  402. }
  403.  
  404. // If.
  405.  
  406. tree_if_command::~tree_if_command (void)
  407. {
  408.   delete list;
  409. }
  410.  
  411. void
  412. tree_if_command::eval (void)
  413. {
  414.   if (list)
  415.     list->eval ();
  416.  
  417.   if (error_state > 0)
  418.     ::error ("evaluating if command near line %d, column %d",
  419.          line (), column ());
  420. }
  421.  
  422. void
  423. tree_if_command::print_code (ostream& os)
  424. {
  425.   print_code_indent (os);
  426.  
  427.   os << "if ";
  428.  
  429.   if (list)
  430.     list->print_code (os);
  431.  
  432.   print_code_indent (os);
  433.  
  434.   os << "endif";
  435. }
  436.  
  437. // Simple exception handling.
  438.  
  439. tree_unwind_protect_command::~tree_unwind_protect_command (void)
  440. {
  441.   delete unwind_protect_code;
  442.   delete cleanup_code;
  443. }
  444.  
  445. static void
  446. do_unwind_protect_cleanup_code (void *ptr)
  447. {
  448.   tree_statement_list *list = (tree_statement_list *) ptr;
  449.  
  450. // We want to run the cleanup code without error_state being set, but
  451. // we need to restore its value, so that any errors encountered in
  452. // the first part of the unwind_protect are not completely ignored.
  453.  
  454.   unwind_protect_int (error_state);
  455.  
  456.   error_state = 0;
  457.  
  458.   if (list)
  459.     list->eval (1);
  460.  
  461. // We don't want to ignore errors that occur in the cleanup code, so
  462. // if an error is encountered there, leave error_state alone.
  463. // Otherwise, set it back to what it was before.
  464.  
  465.   if (error_state)
  466.     discard_unwind_protect ();
  467.   else
  468.     run_unwind_protect ();
  469. }
  470.  
  471. void
  472. tree_unwind_protect_command::eval (void)
  473. {
  474.   add_unwind_protect (do_unwind_protect_cleanup_code, cleanup_code);
  475.  
  476.   if (unwind_protect_code)
  477.     unwind_protect_code->eval (1);
  478.  
  479.   run_unwind_protect ();
  480. }
  481.  
  482. void
  483. tree_unwind_protect_command::print_code (ostream& os)
  484. {
  485.   print_code_indent (os);
  486.  
  487.   os << "unwind_protect";
  488.  
  489.   print_code_new_line (os);
  490.  
  491.   if (unwind_protect_code)
  492.     {
  493.       increment_indent_level ();
  494.       unwind_protect_code->print_code (os);
  495.       decrement_indent_level ();
  496.     }
  497.  
  498.   print_code_indent (os);
  499.  
  500.   os << "cleanup_code";
  501.  
  502.   print_code_new_line (os);
  503.  
  504.   if (cleanup_code)
  505.     {
  506.       increment_indent_level ();
  507.       cleanup_code->print_code (os);
  508.       decrement_indent_level ();
  509.     }
  510.  
  511.   print_code_indent (os);
  512.  
  513.   os << "end_unwind_protect";
  514. }
  515.  
  516. // Break.
  517.  
  518. void
  519. tree_break_command::eval (void)
  520. {
  521.   if (! error_state)
  522.     breaking = 1;
  523. }
  524.  
  525. void
  526. tree_break_command::print_code (ostream& os)
  527. {
  528.   print_code_indent (os);
  529.  
  530.   os << "break";
  531. }
  532.  
  533. // Continue.
  534.  
  535. void
  536. tree_continue_command::eval (void)
  537. {
  538.   if (! error_state)
  539.     continuing = 1;
  540. }
  541.  
  542. void
  543. tree_continue_command::print_code (ostream& os)
  544. {
  545.   print_code_indent (os);
  546.  
  547.   os << "continue";
  548. }
  549.  
  550. // Return.
  551.  
  552. void
  553. tree_return_command::eval (void)
  554. {
  555.   if (! error_state)
  556.     returning = 1;
  557. }
  558.  
  559. void
  560. tree_return_command::print_code (ostream& os)
  561. {
  562.   print_code_indent (os);
  563.  
  564.   os << "return";
  565. }
  566.  
  567. /*
  568. ;;; Local Variables: ***
  569. ;;; mode: C++ ***
  570. ;;; page-delimiter: "^/\\*" ***
  571. ;;; End: ***
  572. */
  573.