diff src/pt-exp.cc @ 1741:6ec1465f60f0

[project @ 1996-01-12 11:09:39 by jwe] Initial revision
author jwe
date Fri, 12 Jan 1996 11:09:39 +0000
parents
children a02f140ed897
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pt-exp.cc	Fri Jan 12 11:09:39 1996 +0000
@@ -0,0 +1,910 @@
+// tree-expr2.cc                                          -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993, 1994, 1995 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream.h>
+#include <strstream.h>
+
+#include "defun.h"
+#include "error.h"
+#include "gripes.h"
+#include "help.h"
+#include "input.h"
+#include "oct-obj.h"
+#include "pager.h"
+#include "pt-const.h"
+#include "pt-exp.h"
+#include "pt-fvc.h"
+#include "pt-misc.h"
+#include "pt-mvr.h"
+#include "user-prefs.h"
+#include "utils.h"
+
+// Nonzero means we're returning from a function.
+extern int returning;
+
+// Nonzero means we're breaking out of a loop or function body.
+extern int breaking;
+
+// But first, some extra functions used by the tree classes.
+
+static void
+print_constant (tree_constant& tc, char *name, int print_padding = 1)
+{
+  int pad_after = 0;
+  if (user_pref.print_answer_id_name)
+    {
+      if (print_as_scalar (tc) || print_as_structure (tc))
+	{
+	  ostrstream output_buf;
+	  output_buf << name << " = " << ends;
+	  maybe_page_output (output_buf);
+	}
+      else
+	{
+	  pad_after = 1;
+	  ostrstream output_buf;
+	  output_buf << name << " =\n\n" << ends;
+	  maybe_page_output (output_buf);
+	}
+    }
+
+  tc.eval (1);
+
+  if (print_padding && pad_after)
+    {
+      ostrstream output_buf;
+      output_buf << "\n" << ends;
+      maybe_page_output (output_buf);
+    }
+}
+
+// Prefix expressions.
+
+tree_prefix_expression::~tree_prefix_expression (void)
+{
+  delete id;
+}
+
+tree_constant
+tree_prefix_expression::eval (int print)
+{
+  tree_constant retval;
+
+  if (error_state)
+    return retval;
+
+  if (id)
+    {
+      id->bump_value (etype);
+      if (error_state)
+	eval_error ();
+      else
+	{
+	  retval = id->eval (print);
+	  if (error_state)
+	    {
+	      retval = tree_constant ();
+	      if (error_state)
+		eval_error ();
+	    }
+	}
+    }
+  return retval;
+}
+
+char *
+tree_prefix_expression::oper (void) const
+{
+  static char *op;
+  switch (etype)
+    {
+    case tree_expression::increment:
+      op = "++";
+      break;
+
+    case tree_expression::decrement:
+      op = "--";
+      break;
+
+    default:
+      op = "<unknown>";
+      break;
+    }
+  return op;
+}
+
+void
+tree_prefix_expression::eval_error (void)
+{
+  if (error_state > 0)
+    {
+      char *op = oper ();
+
+      ::error ("evaluating prefix operator `%s' near line %d, column %d",
+	       op, line (), column ());
+    }
+}
+
+void
+tree_prefix_expression::print_code (ostream& os)
+{
+  print_code_indent (os);
+
+  if (in_parens)
+    os << "(";
+
+  os << oper ();
+
+  if (id)
+    id->print_code (os);
+
+  if (in_parens)
+    os << ")";
+}
+
+// Postfix expressions.
+
+tree_postfix_expression::~tree_postfix_expression (void)
+{
+  delete id;
+}
+
+tree_constant
+tree_postfix_expression::eval (int print)
+{
+  tree_constant retval;
+
+  if (error_state)
+    return retval;
+
+  if (id)
+    {
+      retval = id->eval (print);
+      id->bump_value (etype);
+      if (error_state)
+	{
+	  retval = tree_constant ();
+	  if (error_state)
+	    eval_error ();
+	}
+    }
+  return retval;
+}
+
+char *
+tree_postfix_expression::oper (void) const
+{
+  static char *op;
+  switch (etype)
+    {
+    case tree_expression::increment:
+      op = "++";
+      break;
+
+    case tree_expression::decrement:
+      op = "--";
+      break;
+
+    default:
+      op = "<unknown>";
+      break;
+    }
+  return op;
+}
+
+void
+tree_postfix_expression::eval_error (void)
+{
+  if (error_state > 0)
+    {
+      char *op = oper ();
+
+      ::error ("evaluating postfix operator `%s' near line %d, column %d",
+	       op, line (), column ());
+    }
+}
+
+void
+tree_postfix_expression::print_code (ostream& os)
+{
+  print_code_indent (os);
+
+  if (in_parens)
+    os << "(";
+
+  if (id)
+    id->print_code (os);
+
+  os << oper ();
+
+  if (in_parens)
+    os << ")";
+}
+
+// Unary expressions.
+
+tree_constant
+tree_unary_expression::eval (int /* print */)
+{
+  if (error_state)
+    return tree_constant ();
+
+  tree_constant retval;
+
+  switch (etype)
+    {
+    case tree_expression::not:
+    case tree_expression::uminus:
+    case tree_expression::hermitian:
+    case tree_expression::transpose:
+      if (op)
+	{
+	  tree_constant u = op->eval (0);
+	  if (error_state)
+	    eval_error ();
+	  else if (u.is_defined ())
+	    {
+	      retval = do_unary_op (u, etype);
+	      if (error_state)
+		{
+		  retval = tree_constant ();
+		  if (error_state)
+		    eval_error ();
+		}
+	    }
+	}
+      break;
+
+    default:
+      ::error ("unary operator %d not implemented", etype);
+      break;
+    }
+
+  return retval;
+}
+
+char *
+tree_unary_expression::oper (void) const
+{
+  static char *op;
+  switch (etype)
+    {
+    case tree_expression::not:
+      op = "!";
+      break;
+
+    case tree_expression::uminus:
+      op = "-";
+      break;
+
+    case tree_expression::hermitian:
+      op = "'";
+      break;
+
+    case tree_expression::transpose:
+      op = ".'";
+      break;
+
+    default:
+      op = "<unknown>";
+      break;
+    }
+  return op;
+}
+
+void
+tree_unary_expression::eval_error (void)
+{
+  if (error_state > 0)
+    {
+      char *op = oper ();
+
+      ::error ("evaluating unary operator `%s' near line %d, column %d",
+	       op, line (), column ());
+    }
+}
+
+void
+tree_unary_expression::print_code (ostream& os)
+{
+  print_code_indent (os);
+
+  if (in_parens)
+    os << "(";
+
+  switch (etype)
+    {
+    case tree_expression::not:
+    case tree_expression::uminus:
+      os << oper ();
+      if (op)
+	op->print_code (os);
+      break;
+
+    case tree_expression::hermitian:
+    case tree_expression::transpose:
+      if (op)
+	op->print_code (os);
+      os << oper ();
+      break;
+
+    default:
+      os << oper ();
+      if (op)
+	op->print_code (os);
+      break;
+    }
+
+  if (in_parens)
+    os << ")";
+}
+
+// Binary expressions.
+ 
+tree_constant
+tree_binary_expression::eval (int /* print */)
+{
+  if (error_state)
+    return tree_constant ();
+
+  tree_constant retval;
+
+  switch (etype)
+    {
+    case tree_expression::add:
+    case tree_expression::subtract:
+    case tree_expression::multiply:
+    case tree_expression::el_mul:
+    case tree_expression::divide:
+    case tree_expression::el_div:
+    case tree_expression::leftdiv:
+    case tree_expression::el_leftdiv:
+    case tree_expression::power:
+    case tree_expression::elem_pow:
+    case tree_expression::cmp_lt:
+    case tree_expression::cmp_le:
+    case tree_expression::cmp_eq:
+    case tree_expression::cmp_ge:
+    case tree_expression::cmp_gt:
+    case tree_expression::cmp_ne:
+    case tree_expression::and:
+    case tree_expression::or:
+      if (op1)
+	{
+	  tree_constant a = op1->eval (0);
+	  if (error_state)
+	    eval_error ();
+	  else if (a.is_defined () && op2)
+	    {
+	      tree_constant b = op2->eval (0);
+	      if (error_state)
+		eval_error ();
+	      else if (b.is_defined ())
+		{
+		  retval = do_binary_op (a, b, etype);
+		  if (error_state)
+		    {
+		      retval = tree_constant ();
+		      if (error_state)
+			eval_error ();
+		    }
+		}
+	    }
+	}
+      break;
+
+    case tree_expression::and_and:
+    case tree_expression::or_or:
+      {
+	int result = 0;
+	if (op1)
+	  {
+	    tree_constant a = op1->eval (0);
+	    if (error_state)
+	      {
+		eval_error ();
+		break;
+	      }
+
+	    int a_true = a.is_true ();
+	    if (error_state)
+	      {
+		eval_error ();
+		break;
+	      }
+
+	    if (a_true)
+	      {
+		if (etype == tree_expression::or_or)
+		  {
+		    result = 1;
+		    goto done;
+		  }
+	      }
+	    else
+	      {
+		if (etype == tree_expression::and_and)
+		  {
+		    result = 0;
+		    goto done;
+		  }
+	      }
+
+	    if (op2)
+	      {
+		tree_constant b = op2->eval (0);
+		if (error_state)
+		  {
+		    eval_error ();
+		    break;
+		  }
+
+		result = b.is_true ();
+		if (error_state)
+		  {
+		    eval_error ();
+		    break;
+		  }
+	      }
+	  }
+      done:
+	retval = tree_constant ((double) result);
+      }
+      break;
+
+    default:
+      ::error ("binary operator %d not implemented", etype);
+      break;
+    }
+
+  return retval;
+}
+
+char *
+tree_binary_expression::oper (void) const
+{
+  static char *op;
+  switch (etype)
+    {
+    case tree_expression::add:
+      op = "+";
+      break;
+
+    case tree_expression::subtract:
+      op = "-";
+      break;
+
+    case tree_expression::multiply:
+      op = "*";
+      break;
+
+    case tree_expression::el_mul:
+      op = ".*";
+      break;
+
+    case tree_expression::divide:
+      op = "/";
+      break;
+
+    case tree_expression::el_div:
+      op = "./";
+      break;
+
+    case tree_expression::leftdiv:
+      op = "\\";
+      break;
+
+    case tree_expression::el_leftdiv:
+      op = ".\\";
+      break;
+
+    case tree_expression::power:
+      op = "^";
+      break;
+
+    case tree_expression::elem_pow:
+      op = ".^";
+      break;
+
+    case tree_expression::cmp_lt:
+      op = "<";
+      break;
+
+    case tree_expression::cmp_le:
+      op = "<=";
+      break;
+
+    case tree_expression::cmp_eq:
+      op = "==";
+      break;
+
+    case tree_expression::cmp_ge:
+      op = ">=";
+      break;
+
+    case tree_expression::cmp_gt:
+      op = ">";
+      break;
+
+    case tree_expression::cmp_ne:
+      op = "!=";
+      break;
+
+    case tree_expression::and_and:
+      op = "&&";
+      break;
+
+    case tree_expression::or_or:
+      op = "||";
+      break;
+
+    case tree_expression::and:
+      op = "&";
+      break;
+
+    case tree_expression::or:
+      op = "|";
+      break;
+
+    default:
+      op = "<unknown>";
+      break;
+    }
+  return op;
+}
+
+void
+tree_binary_expression::eval_error (void)
+{
+  if (error_state > 0)
+    {
+      char *op = oper ();
+
+      ::error ("evaluating binary operator `%s' near line %d, column %d",
+	     op, line (), column ());
+    }
+}
+
+void
+tree_binary_expression::print_code (ostream& os)
+{
+  print_code_indent (os);
+
+  if (in_parens)
+    os << "(";
+
+  if (op1)
+    op1->print_code (os);
+
+  os << " " << oper () << " ";
+
+  if (op2)
+    op2->print_code (os);
+
+  if (in_parens)
+    os << ")";
+}
+
+// Simple assignment expressions.
+
+tree_simple_assignment_expression::tree_simple_assignment_expression
+  (tree_identifier *i, tree_expression *r, int plhs, int ans_assign,
+   int l, int c)
+    : tree_expression (l, c)
+      {
+	init (plhs, ans_assign);
+	lhs = new tree_indirect_ref (i);
+	rhs = r;
+      }
+
+tree_simple_assignment_expression::tree_simple_assignment_expression
+  (tree_index_expression *idx_expr, tree_expression *r, int plhs,
+   int ans_assign, int l, int c)
+    : tree_expression (l, c)
+      {
+	init (plhs, ans_assign);
+	lhs_idx_expr = idx_expr; // cache this -- we may need to delete it.
+	lhs = idx_expr->ident ();
+	index = idx_expr->arg_list ();
+	rhs = r;
+      }
+
+tree_simple_assignment_expression::~tree_simple_assignment_expression (void)
+{
+  if (! preserve)
+    {
+      if (lhs_idx_expr)
+	delete lhs_idx_expr;
+      else
+	delete lhs;
+    }
+
+  delete rhs;
+}
+
+int
+tree_simple_assignment_expression::left_hand_side_is_identifier_only (void)
+{
+  return lhs->is_identifier_only ();
+}
+
+tree_identifier *
+tree_simple_assignment_expression::left_hand_side_id (void)
+{
+  return lhs->ident ();
+}
+
+tree_constant
+tree_simple_assignment_expression::eval (int print)
+{
+  assert (etype == tree_expression::assignment);
+
+  tree_constant retval;
+
+  if (error_state)
+    return retval;
+
+  if (rhs)
+    {
+      tree_constant rhs_val = rhs->eval (0);
+      if (error_state)
+	{
+	  eval_error ();
+	}
+      else if (rhs_val.is_undefined ())
+	{
+	  error ("value on right hand side of assignment is undefined");
+	  eval_error ();
+	}
+      else if (! index)
+	{
+	  retval = lhs->assign (rhs_val);
+	  if (error_state)
+	    eval_error ();
+	}
+      else
+	{
+	  // Extract the arguments into a simple vector.
+
+	  Octave_object args = index->convert_to_const_vector ();
+
+	  if (error_state)
+	    eval_error ();
+	  else
+	    {
+	      int nargin = args.length ();
+
+	      if (error_state)
+		eval_error ();
+	      else if (nargin > 0)
+		{
+		  retval = lhs->assign (rhs_val, args);
+		  if (error_state)
+		    eval_error ();
+		}
+	    }
+	}
+    }
+
+  if (! error_state && print && retval.is_defined ())
+    print_constant (retval, lhs->name ());
+
+  return retval;
+}
+
+void
+tree_simple_assignment_expression::eval_error (void)
+{
+  if (error_state > 0)
+    {
+      int l = line ();
+      int c = column ();
+      if (l != -1 && c != -1)
+	::error ("evaluating assignment expression near line %d, column %d",
+		 l, c);
+    }
+}
+
+void
+tree_simple_assignment_expression::print_code (ostream& os)
+{
+  print_code_indent (os);
+
+  if (in_parens)
+    os << "(";
+
+  if (! is_ans_assign ())
+    {
+      if (lhs)
+	lhs->print_code (os);
+
+      if (index)
+	{
+	  os << " (";
+	  index->print_code (os);
+	  os << ")";
+	}
+
+      os << " = ";
+    }
+
+  if (rhs)
+    rhs->print_code (os);
+
+  if (in_parens)
+    os << ")";
+}
+
+// Colon expressions.
+
+int
+tree_colon_expression::is_range_constant (void) const
+{
+  int tmp = (op1 && op1->is_constant ()
+	     && op2 && op2->is_constant ());
+
+  return op3 ? (tmp && op3->is_constant ()) : tmp;
+}
+
+tree_colon_expression *
+tree_colon_expression::chain (tree_expression *t)
+{
+  tree_colon_expression *retval = 0;
+  if (! op1 || op3)
+    ::error ("invalid colon expression");
+  else
+    {
+      op3 = op2;	// Stupid syntax.
+      op2 = t;
+
+      retval = this;
+    }
+  return retval;
+}
+
+tree_constant
+tree_colon_expression::eval (int /* print */)
+{
+  tree_constant retval;
+
+  if (error_state || ! op1 || ! op2)
+    return retval;
+
+  tree_constant tmp = op1->eval (0);
+
+  if (tmp.is_undefined ())
+    {
+      eval_error ("invalid null value in colon expression");
+      return retval;
+    }
+
+  double base = tmp.double_value ();
+
+  if (error_state)
+    {
+      error ("colon expression elements must be scalars");
+      eval_error ("evaluating colon expression");
+      return retval;
+    }
+
+  tmp = op2->eval (0);
+
+  if (tmp.is_undefined ())
+    {
+      eval_error ("invalid null value in colon expression");
+      return retval;
+    }
+
+  double limit = tmp.double_value ();
+
+  if (error_state)
+    {
+      error ("colon expression elements must be scalars");
+      eval_error ("evaluating colon expression");
+      return retval;
+    }
+
+  double inc = 1.0;
+  if (op3)
+    {
+      tmp = op3->eval (0);
+
+      if (tmp.is_undefined ())
+	{
+	  eval_error ("invalid null value in colon expression");
+	  return retval;
+	}
+
+      inc = tmp.double_value ();
+
+      if (error_state)
+	{
+	  error ("colon expression elements must be scalars");
+	  eval_error ("evaluating colon expression");
+	  return retval;
+	}
+    }
+
+  retval = tree_constant (base, limit, inc);
+
+  if (error_state)
+    {
+      if (error_state)
+	eval_error ("evaluating colon expression");
+      return tree_constant ();
+    }
+
+  return retval;
+}
+
+void
+tree_colon_expression::eval_error (const char *s)
+{
+  if (error_state > 0)
+    ::error ("%s near line %d column %d", s, line (), column ());
+}
+
+void
+tree_colon_expression::print_code (ostream& os)
+{
+  print_code_indent (os);
+
+  if (in_parens)
+    os << "(";
+
+  if (op1)
+    op1->print_code (os);
+
+  // Stupid syntax.
+
+  if (op3)
+    {
+      os << ":";
+      op3->print_code (os);
+    }
+
+  if (op2)
+    {
+      os << ":";
+      op2->print_code (os);
+    }
+
+  if (in_parens)
+    os << ")";
+}
+
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/