octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

oct2mat script based on parse tree


From: Muthiah Annamalai
Subject: oct2mat script based on parse tree
Date: Tue, 08 Jan 2008 13:21:36 -0600
User-agent: Thunderbird 2.0.0.6 (X11/20071022)

Hello there,

I have a oct2mat  like the one  Paul Kienzle mentions in his
README file based on the AST walker. Utilizing Octave's
parse tree to do the conversion is very helpful and accurate
to a larger degree. Its still a work in progress (my disclaimer).

Large parts of the code are directly derived from Octave
source written by JWE.

This script is essentially to help deploy code to your colleagues
who want to use it on Matlab systems for whatever reason. Primary
development is still expected to be based on an Octave based
environment.

You can invoke the script as,

octave:1> oct2mat("full/path/my_cool_octave_function.m",1)
octave:2> oct2mat("full/path/my_cool_octave_script.m")

and the code is output to stdout, where from you can use some shell
scripts to redirect the output to another matlab directory.

I have attached the files. Im waiting for JWE to accept some
global export patches to access some parser information. Once that is done, I plan to add it to the extras branch of octave-forge.

This code works only on the cvs version of Octave, as a external add-on.

Limitations include

1. Can treat only function files or script files not both.
2. Pollutes your command history, as it pipes out to octave_stdout.
3. Cannot handle a script file with function definitions
4. Doesnot write to a separate directory or file, just all output on
   stdout. So you need to create a driver program.
5. Not sure if it works correctly for all cases.

Best,
-Muthu

/*

Copyright (C) 1992-2007 John W. Eaton

Copyright (C) 2008, Muthiah Annamalai

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 3 of the License, 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, see
<http://www.gnu.org/licenses/>.

*/


#include<string>

#include <cstdio>
#include <cstring>
#include<vector>
#include <set>
#include <string>

#include<iostream>
#include<octave/oct.h>
#include<octave/dynamic-ld.h>
#include<octave/oct-map.h>
#include<octave/oct-stream.h>
#include<octave/parse.h>

#include <octave/file-stat.h>
#include <octave/oct-env.h>
#include <octave/Cell.h>
#include <octave/dirfns.h>
#include <octave/error.h>
#include <octave/lex.h>
#include <octave/load-path.h>
#include <octave/oct-map.h>
#include <octave/oct-obj.h>
#include <octave/ov.h>
#include <octave/ov-usr-fcn.h>
#include <octave/symtab.h>
#include <octave/toplev.h>
#include <octave/unwind-prot.h>
#include <octave/file-ops.h>
#include <octave/utils.h>
#include <octave/pt-all.h>

#include "pt-pr-mat.h"

DEFUN_DLD(oct2mat,args,,
      "converts the given file to matlab compatible script.\
\n Useage: oct2mat(filename)")
{
  /* 
     (copy from parse.y, parse_and_execute_file() function )
     1. Invoke the parser.
     2. Check status, and report errors. Reset parser.
     3. Give AST (global_command) to the tree_print_matlab_code.
     4. Cleanup.
  */
  
  if ( args.length() < 1 ) {
    print_usage();
    error("usage: oct2mat(filename,is_a_function);");
    return octave_value();
  }

  std::string fname = args(0).string_value();
  bool is_a_function = false;

  if ( args.length() >= 2 ) {
    is_a_function = args(1).bool_value();
  }
  

  fname = file_ops::canonicalize_file_name( fname );

  unwind_protect::begin_frame ("oct2mat");

  unwind_protect_bool (reading_script_file);
  unwind_protect_str (curr_fcn_file_full_name);

  reading_script_file = true;
  curr_fcn_file_full_name = fname;

  FILE *f = get_input_from_file (fname, 0);
  
  if ( !f ) {   
    error("cannot open file", fname.c_str());
    return octave_value();
  }
  

  unwind_protect::begin_frame ("oct2mat_parse");

  unwind_protect_ptr (global_command);

  YY_BUFFER_STATE old_buf = current_buffer ();
  YY_BUFFER_STATE new_buf = create_buffer (f);

  unwind_protect::add (restore_input_buffer, old_buf);
  unwind_protect::add (delete_input_buffer, new_buf);

  switch_to_buffer (new_buf);

  unwind_protect_bool (line_editing);
  unwind_protect_bool (get_input_from_eval_string);
  unwind_protect_bool (parser_end_of_input);

  line_editing = false;
  get_input_from_eval_string = false;
  parser_end_of_input = false;


  int retval;

  //  is_function_file( fname )
  if (is_a_function )
    {
      tree_print_matlab_code o2mat(octave_stdout);

      octave_function * fcn = NULL; 
      //works only in 3.0.x+ CVS version
      //fcn = load_fcn_from_file ( fname, "" , "", "", false );
      if ( fcn ) {
        fcn->accept(o2mat);
        octave_stdout<<"\n";
      } else {
        error(" cannot find handle to current parsed function! ");
      }
    } else {
    do
      {
        reset_parser ();

        retval = octave_parse ();

        if (retval == 0)
          {
            tree_print_matlab_code o2mat(octave_stdout);

            if (global_command)
              {
                //handle the user script
                global_command->accept(o2mat);
                octave_stdout<<"\n";
          
                global_command = 0;

                OCTAVE_QUIT;

                bool quit = (tree_return_command::returning
                             || tree_break_command::breaking);

                if (tree_return_command::returning)
                  tree_return_command::returning = 0;

                if (tree_break_command::breaking)
                  tree_break_command::breaking--;

                if (error_state)
                  {
                    error ("near line %d of file `%s'", input_line_number,
                           curr_fcn_file_full_name.c_str ());

                    break;
                  }

                if (quit)
                  break;
              }
            else if (parser_end_of_input)
              {
                break;
              }
            //
            // FIXME: if functions are found in a file middle,
            // generate new output file like Matlab respects, and
            // then create a handle for that.
            //
            //else if ( current_parsed_function() ) {
            //  current_parsed_function()->accept(o2mat);
            //  octave_stdout<<"\n";
            //}
            //else {
            //  octave_stdout << "no matches; possibly function undetected \n";
            //}
          }
        else
          {
            error("parse error!");
            break;
          }
      } while ( retval == 0 );
  }

  unwind_protect::run_frame ("oct2mat_parse");

  unwind_protect::run_frame ("oct2mat");

  //successfully executed the functions.
  return octave_value();
}

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/
## test the various matlab conversion code.
sigma(0) + !alpha(0) 
if ( sigma(0) + !alpha(0)  )
if ( beta(0) || rand(2) ) #must change #-comment to %, and || to |
  disp("hello world"); %must change the " quote to '
endif %change to if

if ( 0 && 1 )
  % all that goo must be changed on rhs of the fprintf statement
  fprintf('hello world %d', SEEK_CUR, __error_text__, SEEK_END, SEEK_SET); 
end

x =  0 && 1 %must be 0 & 1
y = "muthu" || "phd" %must be |
z = (and || they)  && 'and forever lived' 
a = ! died %must be ~
end

must_show_this=1
%comment 

%more comments
#function f () 
a = "muthu"
y = "a b" || "y"
#end
function f ()
 a = "muthu"
 y = "a b" || "y"
end
#function f () 
a = "muthu"
y = "a b" || "y"
#end

function f ()
 a = "muthu"
 y = "a b" || "y"
end
all: conversions.cc pt-pr-mat.cc
        mkoctfile -o oct2mat.oct conversions.cc pt-pr-mat.cc 
/*

Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
              2005, 2006, 2007 John W. Eaton

Copyright (C) 2008, Muthiah Annamalai

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 3 of the License, 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, see
<http://www.gnu.org/licenses/>.

*/

#include <octave/ov.h>
#include <octave/error.h>
#include <octave/comment-list.h>
#include <octave/pt-all.h>

#include "pt-pr-mat.h"

//define this to get debugging messages on.
#define O2M_DBG
#undef O2M_DBG

//
// how I rip code, shamelessly.
//

static std::string
__unary_op_as_string (octave_value::unary_op op)
{
  std::string retval;

  switch (op)
    {
    case octave_value::op_not:
      retval = "~";
      break;

    case octave_value::op_uplus:
      retval = "+";
      break;

    case octave_value::op_uminus:
      retval = "-";
      break;

    case octave_value::op_transpose:
      retval = ".'";
      break;

    case octave_value::op_hermitian:
      retval = "'";
      break;

    case octave_value::op_incr:
      retval = "++";
      break;

    case octave_value::op_decr:
      retval = "--";
      break;

    default:
      retval = "<unknown-unop>";
    }

  return retval;
}

static std::string
__binary_op_as_string (octave_value::binary_op op)
{
  std::string retval;

  switch (op)
    {
    case octave_value::op_add:
      retval = "+";
      break;

    case octave_value::op_sub:
      retval = "-";
      break;

    case octave_value::op_mul:
      retval = "*";
      break;

    case octave_value::op_div:
      retval = "/";
      break;

    case octave_value::op_pow:
      retval = "^";
      break;

    case octave_value::op_ldiv:
      retval = "\\";
      break;

    case octave_value::op_lshift:
      retval = "<<";
      break;

    case octave_value::op_rshift:
      retval = ">>";
      break;

    case octave_value::op_lt:
      retval = "<";
      break;

    case octave_value::op_le:
      retval = "<=";
      break;

    case octave_value::op_eq:
      retval = "==";
      break;

    case octave_value::op_ge:
      retval = ">=";
      break;

    case octave_value::op_gt:
      retval = ">";
      break;

    case octave_value::op_ne:
      retval = "~=";
      break;

    case octave_value::op_el_mul:
      retval = ".*";
      break;

    case octave_value::op_el_div:
      retval = "./";
      break;

    case octave_value::op_el_pow:
      retval = ".^";
      break;

    case octave_value::op_el_ldiv:
      retval = ".\\";
      break;

    case octave_value::op_el_and:
      retval = "&";
      break;

    case octave_value::op_el_or:
      retval = "|";
      break;

    case octave_value::op_struct_ref:
      retval = ".";
      break;

    default:
      retval = "<unknown-binop>";
    }

  return retval;
}

static void do_oct2mat_oper(std::ostream &os, tree_binary_expression &expr)
{
  std::string oprval="<unknown-binary>";

  // debugging
#ifdef O2M_DBG
  os << "address@hidden" << expr.oper() << "address@hidden ";
#endif

  // this converts code into whatever form
  // oct2mat requires.
  if ( expr.is_boolean_expression() )
    {
      const tree_boolean_expression & tbr
        = dynamic_cast<tree_boolean_expression &> (expr);

      oprval="<unknown-bool>";

      switch ( tbr.op_type() )
        {
        case tree_boolean_expression::bool_and:
          oprval = "&";
          break;
          
        case tree_boolean_expression::bool_or:
          oprval = "|";
          break;
          
        defualt:
          oprval = "<unknown-bool>";
        }
    }
  else 
    {
      oprval=__binary_op_as_string(expr.op_type());
    }

  os << " " << oprval << " ";
  return;
}


static void do_oct2mat_oper(std::ostream &os, tree_unary_expression &expr)
{
  std::string oprval="<unknown-unary>";

  //debugging
#ifdef O2M_DBG
  os << "address@hidden" << expr.oper() << "address@hidden ";
#endif

  oprval=__unary_op_as_string(expr.op_type());
  os << " " << oprval << " ";
  return;
}

void
tree_print_matlab_code::visit_anon_fcn_handle (tree_anon_fcn_handle& afh)
{
#ifdef O2M_DBG
  os << "% visiting anon-fcn handle  \n";
#endif

  indent ();

  print_parens (afh, "(");

  os << "@(";

  tree_parameter_list *param_list = afh.parameter_list ();

  if (param_list)
    param_list->accept (*this);

  os << ") ";

  tree_statement_list *body = afh.body ();

  if (body)
    body->accept (*this);

  print_parens (afh, ")");
}

void
tree_print_matlab_code::visit_argument_list (tree_argument_list& lst)
{
#ifdef O2M_DBG
  os << "% visiting argument list  \n";
#endif

  tree_argument_list::iterator p = lst.begin ();

  while (p != lst.end ())
    {
      tree_expression *elt = *p++;

      if (elt)
        {
          elt->accept (*this);

          if (p != lst.end ())
            os << ", ";
        }
    }
}

void
tree_print_matlab_code::visit_binary_expression (tree_binary_expression& expr)
{
#ifdef O2M_DBG
  os << "% visiting binary expression \n";
#endif
  indent();

  print_parens (expr, "(");

  tree_expression *op1 = expr.lhs ();

  if (op1)
    op1->accept (*this);

  do_oct2mat_oper(os,expr);

  tree_expression *op2 = expr.rhs ();

  if (op2)
    op2->accept (*this);

  print_parens (expr, ")");
}

void
tree_print_matlab_code::visit_break_command (tree_break_command&)
{
#ifdef O2M_DBG
  os << "% visiting break cmd  \n";
#endif

  indent ();

  os << "break";
}

void
tree_print_matlab_code::visit_colon_expression (tree_colon_expression& expr)
{

#ifdef O2M_DBG
  os << "% visiting colon expression \n";
#endif

  indent ();

  print_parens (expr, "(");

  tree_expression *op1 = expr.base ();

  if (op1)
    op1->accept (*this);

  // Stupid syntax.

  tree_expression *op3 = expr.increment ();

  if (op3)
    {
      os << ":";
      op3->accept (*this);
    }

  tree_expression *op2 = expr.limit ();

  if (op2)
    {
      os << ":";
      op2->accept (*this);
    }

  print_parens (expr, ")");
}

void
tree_print_matlab_code::visit_continue_command (tree_continue_command&)
{
#ifdef O2M_DBG
  os << "% visiting continue  \n";
#endif

  indent ();

  os << "continue";
}

void
tree_print_matlab_code::visit_decl_command (tree_decl_command& cmd)
{
#ifdef O2M_DBG
  os << "% visiting decl cmd  \n";
#endif

  indent ();

  os << cmd.name () << " ";

  tree_decl_init_list *init_list = cmd.initializer_list ();

  if (init_list)
    init_list->accept (*this);
}

void
tree_print_matlab_code::visit_decl_elt (tree_decl_elt& cmd)
{

#ifdef O2M_DBG
  os << "% visiting decl elt  \n";
#endif

  tree_identifier *id = cmd.ident ();

  if (id)
    id->accept (*this);

  tree_expression *expr = cmd.expression ();

  if (expr)
    {
      os << " = ";

      expr->accept (*this);
    }
}

void
tree_print_matlab_code::visit_decl_init_list (tree_decl_init_list& lst)
{

#ifdef O2M_DBG
  os << "% visiting decl init list  \n";
#endif

  tree_decl_init_list::iterator p = lst.begin ();

  while (p != lst.end ())
    {
      tree_decl_elt *elt = *p++;

      if (elt)
        {
          elt->accept (*this);

          if (p != lst.end ())
            os << ", ";
        }
    }
}


void
tree_print_matlab_code::visit_simple_for_command (tree_simple_for_command& cmd)
{

#ifdef O2M_DBG
  os << "% visiting simple for cmd   \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "for ";

  tree_expression *lhs = cmd.left_hand_side ();

  if (lhs)
    lhs->accept (*this);

  os << " = ";

  tree_expression *expr = cmd.control_expr ();

  if (expr)
    expr->accept (*this);

  newline ();

  tree_statement_list *list = cmd.body ();

  if (list)
    {
      increment_indent_level ();

      list->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.trailing_comment ());

  indent ();

  os << "end";
}

void
tree_print_matlab_code::visit_complex_for_command (tree_complex_for_command& 
cmd)
{

#ifdef O2M_DBG
  os << "% visiting complex for cmd  \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "for [";
  nesting.push ('[');

  tree_argument_list *lhs = cmd.left_hand_side ();

  if (lhs)
    lhs->accept (*this);

  nesting.pop ();
  os << "] = ";

  tree_expression *expr = cmd.control_expr ();

  if (expr)
    expr->accept (*this);

  newline ();

  tree_statement_list *list = cmd.body ();

  if (list)
    {
      increment_indent_level ();

      list->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.trailing_comment ());

  indent ();

  os << "endfor";
}

void
tree_print_matlab_code::visit_octave_user_function (octave_user_function& fcn)
{

#ifdef O2M_DBG
  os << "% visiting  user fcn \n";
#endif

  reset ();

  visit_octave_user_function_header (fcn);

  tree_statement_list *cmd_list = fcn.body ();

  if (cmd_list)
    {
      increment_indent_level ();

      cmd_list->accept (*this);

      decrement_indent_level ();
    }

  visit_octave_user_function_trailer (fcn);
}

void
tree_print_matlab_code::visit_octave_user_function_header 
(octave_user_function& fcn)
{

#ifdef O2M_DBG
  os << "% visiting user fcn header  \n";
#endif

  octave_comment_list *leading_comment = fcn.leading_comment ();

  if (leading_comment)
    {
      print_comment_list (leading_comment);
      newline ();
    }

  indent ();

  os << "function ";

  tree_parameter_list *ret_list = fcn.return_list ();

  if (ret_list)
    {
      bool takes_var_return = fcn.takes_var_return ();

      int len = ret_list->length ();

      if (len > 1 || takes_var_return)
        {
          os << "[";
          nesting.push ('[');
        }

      ret_list->accept (*this);

      if (takes_var_return)
        {
          if (len > 0)
            os << ", ";

          os << "varargout";
        }

      if (len > 1 || takes_var_return)
        {
          nesting.pop ();
          os << "]";
        }

      os << " = ";
    }

  std::string fcn_name = fcn.name ();

  os << (fcn_name.empty () ? std::string ("(empty)") : fcn_name) << " ";

  tree_parameter_list *param_list = fcn.parameter_list ();

  if (param_list)
    {
      bool takes_varargs = fcn.takes_varargs ();

      int len = param_list->length ();

      if (len > 0 || takes_varargs)
        {
          os << "(";
          nesting.push ('(');
        }

      param_list->accept (*this);

      if (takes_varargs)
        {
          if (len > 0)
            os << ", ";

          os << "varargin";
        }

      if (len > 0 || takes_varargs)
        {
          nesting.pop ();
          os << ")";
          newline ();
        }
    }
  else
    {
      os << "()";
      newline ();
    }
}


void
tree_print_matlab_code::visit_octave_user_function_trailer 
(octave_user_function& fcn)
{
#ifdef O2M_DBG
  os << "% visiting user fcn trailer  \n";
#endif

  print_indented_comment (fcn.trailing_comment ());

  indent ();

  os << "% endfunction";

  newline ();
}

void
tree_print_matlab_code::visit_identifier (tree_identifier& id)
{
#ifdef O2M_DBG
  os << "% visiting  identifier \n";
#endif


  indent ();

  print_parens (id, "(");

  std::string nm = id.name ();

  std::map<std::string,std::string>::iterator iter= identifier_lut.find(nm);
  if ( iter != identifier_lut.end() )
    os << iter->second ;
  else
    os << (nm.empty () ? std::string ("(empty)") : nm);
  

  print_parens (id, ")");
}

void
tree_print_matlab_code::visit_if_clause (tree_if_clause& cmd)
{
#ifdef O2M_DBG
  os << "% visiting if clause  \n";
#endif

  tree_expression *expr = cmd.condition ();

  if (expr)
    expr->accept (*this);

  newline ();

  tree_statement_list *list = cmd.commands ();

  if (list)
    {
      increment_indent_level ();

      list->accept (*this);

      decrement_indent_level ();
    }
}

void
tree_print_matlab_code::visit_if_command (tree_if_command& cmd)
{

#ifdef O2M_DBG
  os << "% visiting if cmd  \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "if ";

  tree_if_command_list *list = cmd.cmd_list ();

  if (list)
    list->accept (*this);

  print_indented_comment (cmd.trailing_comment ());

  indent ();

  os << "end";

}

void
tree_print_matlab_code::visit_if_command_list (tree_if_command_list& lst)
{

#ifdef O2M_DBG
  os << "% visiting if cmd list  \n";
#endif

  tree_if_command_list::iterator p = lst.begin ();

  bool first_elt = true;

  while (p != lst.end ())
    {
      tree_if_clause *elt = *p++;

      if (elt)
        {
          if (! first_elt)
            {
              print_indented_comment (elt->leading_comment ());

              indent ();

              if (elt->is_else_clause ())
                os << "else";
              else
                os << "elseif ";
            }

          elt->accept (*this);
        }

      first_elt = false;
    }
}

void
tree_print_matlab_code::visit_index_expression (tree_index_expression& expr)
{

#ifdef O2M_DBG
  os << "% visiting index expression \n";
#endif

  indent ();

  print_parens (expr, "(");

  bool expr_has_parens = false;

  tree_expression *e = expr.expression ();

  if (e)
    {
      e->accept (*this);

      expr_has_parens = e->is_postfix_indexed ();
    }

  std::list<tree_argument_list *> arg_lists = expr.arg_lists ();
  std::string type_tags = expr.type_tags ();
  std::list<string_vector> arg_names = expr.arg_names ();

  int n = type_tags.length ();

  std::list<tree_argument_list *>::iterator p_arg_lists = arg_lists.begin ();
  std::list<string_vector>::iterator p_arg_names = arg_names.begin ();

  for (int i = 0; i < n; i++)
    {
      switch (type_tags[i])
        {
        case '(':
          {
            char nc = nesting.top ();
            if ((nc == '[' || nc == '{') && expr.paren_count () == 0)
              os << "(";
            else
              os << " (";
            nesting.push ('(');

            tree_argument_list *l = *p_arg_lists;
            if (l)
              l->accept (*this);

            nesting.pop ();
            os << ")";
          }
          break;
            
        case '{':
          {
            char nc = nesting.top ();
            if ((nc == '[' || nc == '{') && expr.paren_count () == 0)
              os << "{";
            else
              os << " {";
            // We only care about whitespace inside [] and {} when we
            // are defining matrix and cell objects, not when indexing.
            nesting.push ('(');

            tree_argument_list *l = *p_arg_lists;
            if (l)
              l->accept (*this);

            nesting.pop ();
            os << "}";
          }
          break;
            
        case '.':
          {
            string_vector nm = *p_arg_names;
            assert (nm.length () == 1);
            os << "." << nm(0);
          }
          break;

        default:
          panic_impossible ();
        }

      p_arg_lists++;
      p_arg_names++;
    }

  print_parens (expr, ")");
}

void
tree_print_matlab_code::visit_matrix (tree_matrix& lst)
{

#ifdef O2M_DBG
  os << "% visiting matrix \n";
#endif

  indent ();

  print_parens (lst, "(");

  os << "[";
  nesting.push ('[');

  tree_matrix::iterator p = lst.begin ();

  while (p != lst.end ())
    {
      tree_argument_list *elt = *p++;

      if (elt)
        {
          elt->accept (*this);

          if (p != lst.end ())
            os << "; ";
        }
    }

  nesting.pop ();
  os << "]";

  print_parens (lst, ")");
}

void
tree_print_matlab_code::visit_cell (tree_cell& lst)
{
#ifdef O2M_DBG
  os << "% visiting cell \n";
#endif

  indent ();

  print_parens (lst, "(");

  os << "{";
  nesting.push ('{');

  tree_cell::iterator p = lst.begin ();

  while (p != lst.end ())
    {
      tree_argument_list *elt = *p++;

      if (elt)
        {
          elt->accept (*this);

          if (p != lst.end ())
            os << "; ";
        }
    }

  nesting.pop ();
  os << "}";

  print_parens (lst, ")");
}

void
tree_print_matlab_code::visit_multi_assignment (tree_multi_assignment& expr)
{
#ifdef O2M_DBG
  os << "% visiting muti assignment \n";
#endif

  indent ();

  print_parens (expr, "(");

  tree_argument_list *lhs = expr.left_hand_side ();

  if (lhs)
    {
      int len = lhs->length ();

      if (len > 1)
        {
          os << "[";
          nesting.push ('[');
        }

      lhs->accept (*this);

      if (len > 1)
        {
          nesting.pop ();
          os << "]";
        }
    }

  os << "" << expr.oper() << "";

  tree_expression *rhs = expr.right_hand_side ();

  if (rhs)
    rhs->accept (*this);

  print_parens (expr, ")");
}

void
tree_print_matlab_code::visit_no_op_command (tree_no_op_command& cmd)
{
#ifdef O2M_DBG
  os << "% visiting no_op command \n";
#endif

  indent ();

  os << cmd.original_command ();
}

void
tree_print_matlab_code::visit_constant (tree_constant& val)
{
#ifdef O2M_DBG
  os << "% visiting constant \n";
#endif

  indent ();

  print_parens (val, "(");
  octave_value sval=val.rvalue();
  std::string buf_str;

  if ( sval.is_string() )
    {
      buf_str=sval.string_value();
      // see if you need to escape the string stxt.
      os << "'";
      for( int idx=0; idx < buf_str.length();  ) {
        if ( buf_str[idx] == '"' || buf_str[idx] == '\'' ) {
          os << "\\" ;
          os << buf_str[idx];
        } else if ( buf_str[idx] == '\"' ) {
          os << "'";
        } else {
          os << buf_str[idx];
        }
        idx++;
      }
      os << "'";
    }
  else 
    {
      std::ostringstream buf;
      val.print_raw (buf , true, print_original_text);
      buf_str = buf.str();
      // string-escaped sequence need to be printed out.
      for( int idx=0; idx < buf_str.length();  ) {
        if ( buf_str[idx] == '\\' ) {
          os << buf_str[idx];
          idx++;
          os << buf_str[idx];
        } else if ( buf_str[idx] == '\"' ) {
          os << "'";
        } else {
          os << buf_str[idx];
        }
        idx++;
      }
    }

  print_parens (val, ")");
}

void
tree_print_matlab_code::visit_fcn_handle (tree_fcn_handle& fh)
{
#ifdef O2M_DBG
  os << "% visiting  fcn handle\n";
#endif

  indent ();

  print_parens (fh, "(");

  fh.print_raw (os, true, print_original_text);

  print_parens (fh, ")");
}

void
tree_print_matlab_code::visit_parameter_list (tree_parameter_list& lst)
{
#ifdef O2M_DBG
  os << "% visiting param-list  \n";
#endif

  tree_parameter_list::iterator p = lst.begin ();

  while (p != lst.end ())
    {
      tree_decl_elt *elt = *p++;

      if (elt)
        {
          elt->accept (*this);

          if (p != lst.end ())
            os << ", ";
        }
    }
}

void
tree_print_matlab_code::visit_postfix_expression (tree_postfix_expression& expr)
{

#ifdef O2M_DBG
  os << "visiting postfix expression\n";
#endif

  indent ();

  print_parens (expr, "(");

  tree_expression *e = expr.operand ();

  if (e)
    e->accept (*this);

  do_oct2mat_oper(os,expr);


  print_parens (expr, ")");
}

void
tree_print_matlab_code::visit_prefix_expression (tree_prefix_expression& expr)
{
#ifdef O2M_DBG
  os << "visiting prefix expression\n";
#endif

  indent ();

  print_parens (expr, "(");

  do_oct2mat_oper(os,expr);

  tree_expression *e = expr.operand ();

  if (e)
    e->accept (*this);

  print_parens (expr, ")");
}

void
tree_print_matlab_code::visit_return_command (tree_return_command&)
{
#ifdef O2M_DBG
  os << "% visiting  return command \n";
#endif

  indent ();

  os << "return";
}

void
tree_print_matlab_code::visit_return_list (tree_return_list& lst)
{
#ifdef O2M_DBG
  os << "% visiting return list  \n";
#endif

  tree_return_list::iterator p = lst.begin ();

  while (p != lst.end ())
    {
      tree_index_expression *elt = *p++;

      if (elt)
        {
          elt->accept (*this);

          if (p != lst.end ())
            os << ", ";
        }
    }
}

void
tree_print_matlab_code::visit_simple_assignment (tree_simple_assignment& expr)
{
#ifdef O2M_DBG
  os << "% visiting  simple assignment \n";
#endif

  indent ();

  print_parens (expr, "(");

  tree_expression *lhs = expr.left_hand_side ();

  if (lhs)
    lhs->accept (*this);
  
  // assignment is mostly OK. Just that we need to
  // re-form the += , *= operators by transforming the
  // parse tree.
  os << " " << expr.oper () << " ";
  
  tree_expression *rhs = expr.right_hand_side ();

  if (rhs)
    rhs->accept (*this);

  print_parens (expr, ")");
}

void
tree_print_matlab_code::visit_statement (tree_statement& stmt)
{
#ifdef O2M_DBG
  os << "% visiting  statement \n";
#endif

  print_comment_list (stmt.comment_text ());

  tree_command *cmd = stmt.command ();

  if (cmd)
    {
      cmd->accept (*this);

      if (! stmt.print_result ())
        {
          os << ";";
          newline (" ");
        }
      else
        newline ();
    }
  else
    {
      tree_expression *expr = stmt.expression ();

      if (expr)
        {
          expr->accept (*this);

          if (! stmt.print_result ())
            {
              os << ";";
              newline (" ");
            }
          else
            newline ();
        }
    }
}

void
tree_print_matlab_code::visit_statement_list (tree_statement_list& lst)
{
#ifdef O2M_DBG
  os << "% visiting statement list \n";
#endif

  for (tree_statement_list::iterator p = lst.begin (); p != lst.end (); p++)
    {
      tree_statement *elt = *p;
      std::cerr << "One more stmt \n";
      if (elt)
        elt->accept (*this);
    }
}

void
tree_print_matlab_code::visit_switch_case (tree_switch_case& cs)
{
#ifdef O2M_DBG
  os << "% visiting s/w case  \n";
#endif

  print_comment_list (cs.leading_comment ());

  indent ();

  if (cs.is_default_case ())
    os << "otherwise";
  else
    os << "case ";

  tree_expression *label = cs.case_label ();

  if (label)
    label->accept (*this);

  newline ();

  tree_statement_list *list = cs.commands ();

  if (list)
    {
      increment_indent_level ();

      list->accept (*this);

      newline ();

      decrement_indent_level ();
    }
}

void
tree_print_matlab_code::visit_switch_case_list (tree_switch_case_list& lst)
{
#ifdef O2M_DBG
  os << "% visiting s/w case list  \n";
#endif

  tree_switch_case_list::iterator p = lst.begin ();

  while (p != lst.end ())
    {
      tree_switch_case *elt = *p++;

      if (elt)
        elt->accept (*this);
    }
}

void
tree_print_matlab_code::visit_switch_command (tree_switch_command& cmd)
{
#ifdef O2M_DBG
  os << "% visiting  s/w cmd \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "switch ";

  tree_expression *expr = cmd.switch_value ();

  if (expr)
    expr->accept (*this);

  newline ();

  tree_switch_case_list *list = cmd.case_list ();

  if (list)
    {
      increment_indent_level ();

      list->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.leading_comment ());

  indent ();

  os << "end";
}

void
tree_print_matlab_code::visit_try_catch_command (tree_try_catch_command& cmd)
{
#ifdef O2M_DBG
  os << "% visiting try-catch cmd  \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "try";

  newline ();

  tree_statement_list *try_code = cmd.body ();

  if (try_code)
    {
      increment_indent_level ();

      try_code->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.middle_comment ());

  indent ();

  os << "catch";

  newline ();

  tree_statement_list *catch_code = cmd.cleanup ();

  if (catch_code)
    {
      increment_indent_level ();

      catch_code->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.trailing_comment ());

  indent ();

  os << "end";
}


void
tree_print_matlab_code::visit_unwind_protect_command
  (tree_unwind_protect_command& cmd)
{
#ifdef O2M_DBG
  os << "% visiting unwind-protect-cmd  \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "";

  newline ();

  tree_statement_list *unwind_protect_code = cmd.body ();

  if (unwind_protect_code)
    {
      increment_indent_level ();

      unwind_protect_code->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.middle_comment ());

  indent ();


  os << "";

  newline ();

  tree_statement_list *cleanup_code = cmd.cleanup ();

  if (cleanup_code)
    {
      increment_indent_level ();

      cleanup_code->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.trailing_comment ());

  indent ();

  os << "";
}

void
tree_print_matlab_code::visit_while_command (tree_while_command& cmd)
{
#ifdef O2M_DBG
  os << "% visiting  while cmd \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "while ";

  tree_expression *expr = cmd.condition ();

  if (expr)
    expr->accept (*this);

  newline ();

  tree_statement_list *list = cmd.body ();

  if (list)
    {
      increment_indent_level ();

      list->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.trailing_comment ());

  indent ();

  os << "end";
}

void
tree_print_matlab_code::visit_do_until_command (tree_do_until_command& cmd)
{
#ifdef O2M_DBG
  os << "% visiting  do-until-cmd \n";
#endif

  print_comment_list (cmd.leading_comment ());

  indent ();

  os << "do";

  newline ();

  tree_statement_list *list = cmd.body ();

  if (list)
    {
      increment_indent_level ();

      list->accept (*this);

      decrement_indent_level ();
    }

  print_indented_comment (cmd.trailing_comment ());

  indent ();

  os << "until";

  tree_expression *expr = cmd.condition ();

  if (expr)
    expr->accept (*this);

  newline ();
}

// Each print_code() function should call this before printing
// anything.
//
// This doesn't need to be fast, but isn't there a better way?

void
tree_print_matlab_code::indent (void)
{
  assert (curr_print_indent_level >= 0);

  if (printing_newlines)
    {
      if (beginning_of_line)
        {
          os << prefix;

          for (int i = 0; i < curr_print_indent_level; i++)
            os << " ";

          beginning_of_line = false;
        }
    }
}

// All print_code() functions should use this to print new lines.

void
tree_print_matlab_code::newline (const char *alt_txt)
{
  os << (printing_newlines ? "\n" : alt_txt);

  beginning_of_line = true;
}

// For ressetting print_code state.

void
tree_print_matlab_code::reset (void)
{
  beginning_of_line = true;
  curr_print_indent_level = 0;
  while (nesting.top () != 'n')
    nesting.pop ();
}

void
tree_print_matlab_code::print_parens (const tree_expression& expr, const char 
*txt)
{
  int n = expr.paren_count ();

  for (int i = 0; i < n; i++)
    os << txt;
}


void
tree_print_matlab_code::print_comment_elt (const octave_comment_elt& elt)
{
  bool printed_something = false;

  bool prev_char_was_newline = false;

  std::string comment = elt.text ();

  size_t len = comment.length ();

  size_t i = 0;

  while (i < len && comment[i++] == '\n')
    ; /* Skip leading new lines. */
  i--;

  while (i < len)
    {
      char c = comment[i++];

      if (c == '\n')
        {
          if (prev_char_was_newline)
            os << "%";

          newline ();

          prev_char_was_newline = true;
        }
      else
        {
          if (beginning_of_line)
            {
              printed_something = true;

              indent ();

              os << "%%";

              if (! (isspace (c) || c == '!'))
                os << " ";
            }

          os << static_cast<char> (c);

          prev_char_was_newline = false;
        }
    }

  if (printed_something && ! beginning_of_line)
    newline ();
}

void
tree_print_matlab_code::print_comment_list (octave_comment_list *comment_list)
{
  if (comment_list)
    {
      octave_comment_list::iterator p = comment_list->begin ();

      while (p != comment_list->end ())
        {
          octave_comment_elt elt = *p++;

          print_comment_elt (elt);

          if (p != comment_list->end ())
            newline ();
        }
    }
}

void
tree_print_matlab_code::print_indented_comment (octave_comment_list 
*comment_list)
{
  increment_indent_level ();

  print_comment_list (comment_list);

  decrement_indent_level ();
}

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/
/*

Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005,
              2006, 2007 John W. Eaton

Copyright (C) 2008, Muthiah Annamalai

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 3 of the License, 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, see
<http://www.gnu.org/licenses/>.

*/

#if !defined (octave_tree_print_matlab_code_h)
#define octave_tree_print_matlab_code_h 1

#include <stack>
#include <string>
#include <map>

#include <octave/comment-list.h>
#include <octave/pt-walk.h>

class tree_expression;

// How to print the code that the parse trees represent.
// and just make sure its Matlab compatible, as far as possible.

class
tree_print_matlab_code : public tree_walker
{
public:

  tree_print_matlab_code (std::ostream& os_arg,
                   const std::string& pfx = std::string (),
                   bool pr_orig_txt = true)
    : os (os_arg), prefix (pfx), nesting (),
      print_original_text (pr_orig_txt),
      curr_print_indent_level (0), beginning_of_line (true),
      printing_newlines (true)
  {
    // For "none".
    nesting.push ('n');
    // LUT for identifier swapping.    

    // FIXME: make static
    identifier_lut["SEEK_CUR"]="0";
    identifier_lut["SEEK_END"]="1";
    identifier_lut["SEEK_SET"]="-1";
    identifier_lut["usage"]="error";
    identifier_lut["print_usage"]="error";
    identifier_lut["__error_text__"]="lasterr";
  }

  ~tree_print_matlab_code (void) { }


  void visit_anon_fcn_handle (tree_anon_fcn_handle&);

  void visit_argument_list (tree_argument_list&);

  void visit_binary_expression (tree_binary_expression&);

  void visit_break_command (tree_break_command&);

  void visit_colon_expression (tree_colon_expression&);

  void visit_continue_command (tree_continue_command&);

  void visit_decl_command (tree_decl_command&);

  void visit_decl_elt (tree_decl_elt&);

  void visit_decl_init_list (tree_decl_init_list&);

  void visit_simple_for_command (tree_simple_for_command&);

  void visit_complex_for_command (tree_complex_for_command&);

  void visit_octave_user_function (octave_user_function&);

  void visit_octave_user_function_header (octave_user_function&);

  void visit_octave_user_function_trailer (octave_user_function&);

  void visit_identifier (tree_identifier&);

  void visit_if_clause (tree_if_clause&);

  void visit_if_command (tree_if_command&);

  void visit_if_command_list (tree_if_command_list&);

  void visit_index_expression (tree_index_expression&);

  void visit_matrix (tree_matrix&);

  void visit_cell (tree_cell&);

  void visit_multi_assignment (tree_multi_assignment&);

  void visit_no_op_command (tree_no_op_command&);

  void visit_constant (tree_constant&);

  void visit_fcn_handle (tree_fcn_handle&);

  void visit_parameter_list (tree_parameter_list&);

  void visit_postfix_expression (tree_postfix_expression&);

  void visit_prefix_expression (tree_prefix_expression&);

  void visit_return_command (tree_return_command&);

  void visit_return_list (tree_return_list&);

  void visit_simple_assignment (tree_simple_assignment&);

  void visit_statement (tree_statement&);

  void visit_statement_list (tree_statement_list&);

  void visit_switch_case (tree_switch_case&);

  void visit_switch_case_list (tree_switch_case_list&);

  void visit_switch_command (tree_switch_command&);

  void visit_try_catch_command (tree_try_catch_command&);

  void visit_unwind_protect_command (tree_unwind_protect_command&);

  void visit_while_command (tree_while_command&);

  void visit_do_until_command (tree_do_until_command&);

  void suspend_newline (void) { printing_newlines = false; }

  void resume_newline (void) { printing_newlines = true; }


private:

  std::ostream& os;

  std::string prefix;

  std::stack<char> nesting;

  bool print_original_text;

  // Current indentation.
  int curr_print_indent_level;

  // TRUE means we are at the beginning of a line.
  bool beginning_of_line;

  // TRUE means we are printing newlines and indenting.
  bool printing_newlines;

  void reset_indent_level (void) { curr_print_indent_level = 0; }

  void increment_indent_level (void) { curr_print_indent_level += 2; }

  void decrement_indent_level (void) { curr_print_indent_level -= 2; }

  void newline (const char *alt_txt = ", ");

  void indent (void);

  void reset (void);

  void print_parens (const tree_expression& expr, const char *txt);

  void print_comment_list (octave_comment_list *comment_list);

  void print_comment_elt (const octave_comment_elt& comment_elt);

  void print_indented_comment (octave_comment_list *comment_list);

  tree_print_matlab_code (void);

  // No copying!

  std::map<std::string, std::string> identifier_lut;

  tree_print_matlab_code(const tree_print_matlab_code&);

  tree_print_matlab_code& operator = (const tree_print_matlab_code&);
};

#endif

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/
fcn_file = {{"hello.m",0},{"hello2.m",0},{"hello3.m",1},{"hello4.m",0}};
arrayfun(@(x) oct2mat(x{1},x{2}),fcn_file)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]