From octave-sources-request at bevo dot che dot wisc dot edu Wed Mar 28 14:50:45 2001 Subject: flagging functions as commands From: Paul Kienzle To: octave-sources at bevo dot che dot wisc dot edu Date: Wed, 28 Mar 2001 06:53:58 +0100 Hi! I wrote a little function which flags a function name as a command by setting the textfun bit in the symbol table. Using this, it is possible to say something like: command("axis") in your .octaverc file, then within octave you can say something like axis off to remove tic marks from the current graph. This works even though axis is a script. My function is not very robust. If you call it twice with the same function it will cause a core dump. Also modifying the function will clear the textfun bit. Implementing "command" as a function is inherently limited. You will not be able to define something as a command at the start of a function and use it as a command within the same function. That's because command operates at runtime, but the script is not run until it is parsed in its entirety. Even with these limitations, judicious use of "command" in your .octaverc will allow you to run more of the freely available m-files intended for matlab in Octave without modification. Supporting this feature properly would require changes to the parser. Unfortunately there is no good solution, since the syntax as it stands is ambiguous. Here are three alternatives: 1) If you make everything a command by default, should rand-1 be interpreted as rand("-1") or as rand()-1? 2) If you flag a function as a command during definition using for example the keyword "text_function" rather than "function", the parser will not know it until the function has been loaded, which may not be the case when you are parsing a particular function. You don't want to try loading all identifiers as functions at parse time since you will not know until run time if the identifier is a variable or a function. 3) If you use a parser directive such as "command axis" to flag an existing function as a command then you will have to use that directive in every script that uses that function as a command since you don't know if it will already have been flagged. Paul Kienzle pkienzle at kienzle dot powernet dot co dot uk command.cc: =========== /* Copyright (C) 2001 Paul Kienzle Modified from variable.cc, Copyright (C) 1996, 1997 John W. Eaton This program 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. */ #include #include #include DEFUN_DLD(command, args, , "-*- texinfo -*-\n\ at deffn {Command} command name @dots{}\n\ Register all the named functions as commands which can be invoked\n\ with a set of string arguments without having to quote them or wrap\n\ them in parentheses. For example\n\ \n\ at example\n\ command axis\n\ at end example\n\ \n\ at noindent\n\ allows you to invoke the script axis.m as at code{axis off} rather than\n\ at code{axis(\"off\")} in order to turn off the axis tic marks.\n\ \n\ Note that this effect is applied at run time, not at parse time. Since\n\ a function is parsed before it is run, you will not be able to convert\n\ a function into a command at the beginning of the script and use it as\n\ a command in the remainder of the script, since the remainder of the\n\ script will already have been parsed assuming the function was not a\n\ command.\n\ \n\ WARNING: DO NOT APPLY THIS MORE THAN ONCE TO THE SAME FUNCTION otherwise\n\ octave crashes. Fixes are welcome.\n\ at end deffn") { #if defined(HAVE_OCTAVE_20) error("command: unavailable for Octave 2.0"); #else int nargin = args.length(); for (int i=0; i < nargin; i++) { std::string fcn_name; if (args(i).is_string()) fcn_name = args(i).string_value(); if (! error_state) { symbol_record *sr = 0; if (! fcn_name.empty ()) { // check for symbol in global context, or create a new one sr = global_sym_tab->lookup (fcn_name, true); // read/reread function file if necessary, but don't execute lookup (sr, false); } if (sr && sr->is_function ()) { octave_function* fn = sr->def().function_value(); if (! error_state) // can't do this step for octave 2.0 sr->define(fn, sr->type()|symbol_record::TEXT_FUNCTION); else warning("command: %s function_value error", fcn_name.c_str()); } else warning("command: %s is not a valid function", fcn_name.c_str()); } else warning("command: expects string values for arg %d", i+1); } #endif return octave_value_list(); } ------------------------------------------------------------- Octave is freely available under the terms of the GNU GPL. Octave's home on the web: http://www.octave.org How to fund new projects: http://www.octave.org/funding.html Subscription information: http://www.octave.org/archive.html -------------------------------------------------------------