How to define new expression evaluators

Here is the part of the file `interp.h` that corresponds to
additional expression evaluators :

typedef void (*oper2_expr)(void *, void *, void *); typedef void (*oper1_expr)(void *); typedef int (*oper0_expr)(void *); typedef void (*oper3_expr)(void *, char *); typedef void (*oper4_expr)(void **); typedef char* (*oper5_expr)(void *); typedef void* (*oper6_expr)(void *); typedef void* (*oper)(char *); typedef struct { oper1_expr clear; oper1_expr Zero; oper1_expr neg; oper0_expr iszero; oper2_expr add; oper2_expr sub; oper2_expr mul; oper2_expr pow; oper2_expr div; oper3_expr set; oper4_expr Init; oper5_expr print; oper6_expr copy; oper0_expr sign; int n_oper; char **oper_name; oper *OPER; int n_var; char *desc; } EXPREVAL_GEN; EXPREVAL_GEN *Expreval_ops; typedef struct { char *name; void **value; } Vars_Gen; Vars_Gen **VArs_global_Gen; int *_NBFONC_Gen; typedef struct { char* name; /* Function name */ int args; /* Number of arguments to expect */ void (*func)(void**, void**); /* Pointer to function */ } FUNCTIONGen; extern FUNCTIONGen *Funcs_Gen[]; int NB_expr_eval; /* Number of supplementary evaluators */

Here it is assumed that the numbers we work with are represented by
pointers to `void`. These pointers should actually contain the addresses
of the numbers.

The directory `expr_evals` contains the definition of several expression
evaluators. To each expression evaluator corresponds a `main` file in the
`test/extra ` directory that produces a test program for the `interpcom`
library where this new expression evaluator can be used. The file `main_all` of the `test/extra` directory produces a test program where all
the expression evaluators can be used. The expression evaluators in the
`expr_evals` directory are :

- -
`_dummy.c`: an expression evaluator that uses double precision numbers. It should work just like the ordinary expression evaluator, perhaps more slowly. The reader should look at this file to see how an expression evaluator is implemented.- -
`_mapm.c`: an expression evaluator that uses the library`mapm`(*Mike's Arbitrary Precision Math Library*) by Michael C. Ring This library can be found at`http://tc.umn.edu/~ringx004`. The default precision used here is 50 digits. It is stored in the integer`_mapm_dec_places`(see the file`main_mapm.c`in the`test`directory). It would be possible to create a new command to change this default precision.- -
`_GMP.c`: an expression evaluator that uses the`gmp`library (that can be found at many places, beeing a part of the GNU project). More precisely this expression evaluator uses rational numbers, i.e. quotients of arbitrary big integers. In this expression evaluator some operations will produce nothing (i.e. give a zero result) :`pow`,`sqrt`.- -
`_matrix.c`: an expression evaluator that uses 2X2 matrices. It comes with the command`set_mat`that is used to set the values of a matrix. Example :- interpcom -> a=1 [1.0000000000000000,0.0000000000000000,0.0000000000000000,1.0000000000000000] - interpcom -> set_mat a 1 -2.5 4 2.1 - interpcom -> a [1.0000000000000000,-2.5000000000000000,4.0000000000000000,2.1000000000000001]

Here also the functions`pow`and`sqrt`are not implemented.

Now we will indicate how new expression evaluators should be implemented.
First of all an `EXPREVAL_GEN` structure must be created, with the
appropriate functions that are listed below. The "numbers" that are used in the
new expression evaluator must be represented by pointers to `void`.

Member `clear` : this number destroys the number represented in its
argument, i.e. it frees the memory used to define this number.

Member `Zero` : this functions gives the value 0 to the number represented
by its argument.

Member `neg` : this function negates the number represented by its argument.

Member `iszero` : this function returns 1 if its argument is the number 0,
and 1 otherwise.

Member `add` : this function adds the two numbers represented by the two
last arguments, and puts the result in the number represented by the first
argument.

Member `sub` : this function substracts the two numbers represented by the
two last arguments, and puts the result in the number represented by the first
argument.

Member `mul` : this function multiplies the two numbers represented by the
two last arguments, and puts the result in the number represented by the first
argument.

Member `pow` : this function computes the power of the number represented by
the second argument to the number represented by the third argument, and puts
the result in the number represented by the first argument.

Member `div` : this function divides the two numbers represented by the
two last arguments, and puts the result in the number represented by the first
argument.

Member `set` : this function gives the value represented by the second
argument to the number represented by the first argument.

Member `Init` : if the argument is `void **s`, this function creates a
new number a puts its address in `s[0]`.

Member `print` : this function returns a character string representing the
number corresponding to its first argument.

Member `copy` : this function returns the address of a new number having
the same value as the number represented by the first argument.

Member `sign` : this function returns the the number having represented by
the first argument (i.e. -1 if the number is negative, 0 if it is 0, and 1 if it
is positive).

The members `n_oper`, `oper_name`, `OPER` and `n_var` are not
yet used and should be respectively `0`, `NULL`, `NULL` and `1`.

The functions used by the new expression evaluator should be put in a `FUNCTIONGen` array (see `_dummy.c`). Each function `F` should be of
type

void func(void **res, void **x)

Here `res` is the address of the result (so the number computed by the
function is represented by `res[0]`), and the other argument represent
the array of arguments of `F`.

Now the function `init_expr_GEN` must be created to indicate which
expression evaluators will be used, and the array `Funcs_Gen` must be
defined and filled with the new corresponding function arrays. This can be done
for instance in the main source file.

For instance, if two new expression evaluators are created, we could write the following :

FUNCTIONGen *Funcs_Gen[] = { Funcs_1, /* array of functions for the first additional expression evaluator */ Funcs_2, /* array of functions for the second additional expression evaluator */ }; void init_expr_GEN(flow_data *flow_interp) { NB_expr_eval = 4; _NBFONC_Gen[0] = _NBFONC_1; Expreval_ops[0] = _exprev_1; _NBFONC_Gen[1] = _NBFONC_2; Expreval_ops[1] = _exprev_2; }

Here `NB_expr_eval` is the total number of expression evaluators (the two
that are defined in the library plus the two supplementary ones). The
`EXPREVAL_GEN` structure corresponding to the first new expression
evaluator is `_exprev_1`, which is put in `Expreval_ops[0]`, the
number of corresponding functions (defined in `Funcs_1`) is `_NBFONC_1`, which is put in `_NBFONC_Gen[0]`, and so on.

The function `init_expr_GEN` can also contain some initializations needed
by the new expression evaluators (see the file `main_all.c` where three
additional expression evaluators are defined).