The expression evaluator is due to Mark Morley. Some modifications
have been made, to add the possibility to evaluate objects. It is possible
to use the 4 operators +,-, *, / and parentheses. One can also define and
use variables, and use the usual mathematical functions.
Everything that is not recognized by the interpreter as a command or a program is supposed to be a numerical expression. It is computed and the result is printed on screen. For example
interpreter ->
a=2
2.000000
interpreter ->
b=3
3.000000
interpreter ->
a+b
5.000000
interpreter ->
cos(a)
-0.416147
It is possible to use numerical expressions as arguments of commands
(or command files and programs) (cf. sections 6.4
and 3).
Variables are defined when they are assigned for the first time,
except two predefined variables, e and
pi . If a numerical expression contains a non
defined variable, the result is set to 0. Uppercase and lowercase characters
are distinguished.
It is possible to know which variables are defined and their values by using the command varlist .
Example :
interpreter ->
varlist
a=2.000000
b=3.000000
It is possible to undefine variables by using the command undef.
Example :
interpreter ->
undef a
interpreter ->
varlist
b=3.000000
The command interpreter uses hidden variables, essentially for the names of the dimensions of objects. A hidden variable is simply a variable whith a name whose first character is not printable. So it is not possible to access directly these variables. Inside a program one may use the functions S_convert_int or S_convert_float . Their unique argument is a string of characters. These functions add a non printable character at the beginning of the string, send this new string to the expression evaluator and returns the evaluation of the string. For example
S_convert_float("sq_root_of_2=sqrt(2)");
will create the hidden variable sq_root_of_2 (if it did not exist) and assign the square root of 2 to this variable. It is possible to define and fix hidden variables in the !var section of the initialization file. With the command initvar it is possible to use the values of hidden variables. This command will create (or modify) variables which have the same names as the hidden ones (except of course for the first character that is omitted) and give them the values of the corresponding hidden variables. Subsequent modifications of the visible variables will not affect the values of the hidden ones.
The maximal number of variables that can be defined is 500. It is fixed in the source file interp.h :
#define MAXXVARS
500 /* Max user-defined variables */
The mathematical functions that the expression evaluator knows are
in the array Funcs[] (it is an array
of structures FUNCTION ). This array
must be defined by the user. The total number of functions is
_NBFONC,
which must be set by the user. An array of functions is predefined in the
library, it is called Funcs_interp, and
the number of functions defined in Funcs_interp
is contained is the integer _NBFONC0.
FUNCTION Funcs_interp[]
=
{
/* name, funtion
to call */
{ "sin", 1, sin } ,
/* 0 */
{ "cos", 1, cos } ,
/* 1 */
{ "tan", 1, tan } ,
/* 2 */
{ "asin", 1, asin } , /*
3 */
{ "acos", 1, acos } , /* 4 */
{ "atan", 1, atan } , /* 5 */
{ "sinh", 1, sinh } , /*
6 */
{ "cosh", 1, cosh } , /* 7 */
{ "tanh", 1, tanh } , /* 8 */
{ "exp", 1, exp } ,
/* 9 */
{ "log", 1, log } ,
/* 10 */
{ "log10", 1, log10 } , /* 11 */
{ "sqrt", 1, sqrt } , /*
12 */
{ "floor", 1, floor } , /* 13 */
{ "ceil", 1, ceil } ,
/* 14 */
{ "abs", 1, fabs } , /*
15 */
{ "hypot", 2, hypot } , /* 16 */
{ "deg", 1, deg } ,
/* 17 */
{ "rad", 1, rad } ,
/* 18 */
{ 0 }
/* 19 */
} ;
int _NBFONC0=19;
For example if the program uses only the predefined array of functions, the main source file would look as follows :
. . . . . . .
. . .
FUNCTION
*Funcs;
int
main(int argc, char *argv[])
{
Funcs = Funcs_interp;
_NBFONC = _NBFONC0;
. . . . . . .
The first member of the structure FUNCTION
is the string character that will be used to call the function.
The second member is the number of parameters of the function. It must
be 1 or 2. The third member is the name of the function. It must be a real
function with one or two real arguments. In the preceeding example the
usual mathematical functions are used. It is also possible to put other
functions found in some libraries of special functions, like
cephes
for example, or defined by the user.
The expression evaluator can use the values of the objects defined
by the user. This is explained in the end of section
5.3. For example if the object xxx
is a 2-dimensional array of real numbers, &xxx(2,5)
will be the value of the term [2][5] of
the array represented by xxx .
It is possible also to use expressions such as &xxx(i,2*i+j)
, or even something like &xxx(cos(2*z)+&tt(i,k),exp(u))
. If the indices are incorrect, i.e if the integer parts of the indices
are negative or bigger that the dimensions of the object, the value of
the expression will be zero.
For a complex object, zzz for
example, &zzz(2,5) will be the real
part of the value of the term [2][5] of
the array represented by zzz . Equivalently,
on can use &zzz(2,5).r , and &zzz(2,5).i
will give the imaginary part.
The functions
int
convert_int(char *);
double
convert_float(char *);
of the library can be used to parse numeric arguments. For example if the command Xcom3 corresponding to the function
int Xcom3_cmd(int argc, char* argv[]);
needs an argument which is an integer, the function Xcom3_cmd should contain something like
int
n;
n = convert_int(argv[1]);
The function convert_int will send the string of characters to the expression evaluator and return the integer part of the evaluation of this string. The function convert_float can be used to evaluate real arguments. This allows instructions like
interpreter -> Xcom3 i+2
for example.