11 Tutorial

11.1 How to use the interpreter


The files that are useful for an application of the command interpreter are the library itself  libinter.a  (or  libint_m.a  for the mini-interpreter) and the file  interp.h  which should be included by each source file where functions of the library are used. One or several initialization files must also be written for each application. In the version 1.2 of the command interpreter the names of the built-in commands must not be put in an initialization file, they are already known by the interpreter. The user is concerned only by the new commands of the application.
 
 
 

11.1.1 The main function and related functions

The interperter is called with the function

void    prog_c (int argc, char * argv[], char * A, char B[], int n);

The  main  function of the program should contain only a call to the function  prog_c , and should be written as follows :

int
main(int argc, char * argv[])

and the parameters  argc  and argv[] are passed to the function prog_c . If the main program has no argument, the interpreter will execute the command given in  the  !init  section of the initialization file (if this section is present) and then the interpreter will wait for new commands. If the   !init  section exists, the greeting message will not be printed. If there is an argument for the main program it will be used as a filename which will be executed as a command file. The program will then run silently (the commands in the file will not be printed) and stop when the command file is finished. This way of using the interpreter can be used for example with programs like Geomview that can use external modules. In this situation, Geomview creates pipes connected to the interpreter output, and interprets this output as graphics .

Before running the interpreter, the function  prog_c  will call the function

void   init_prog (void)

which must be provided by the user, and contains all the initializations required by the program. It may be an empty function.

After the exit command that terminates the execution of the interpreter the function

void   exit_prog (void)

will be called. It must also be written by the user, and must contain at least a call to the function  exit()  to end the program.

As explained in section 2 there are two ways of using the initialization file. The first way is to let the interpreter read it at the beginning of the execution, the second way is to include it in the executable file. In the first way the main function will be like this

int
main(int argc, char * argv[])
{
    prog_c(argc, argv, "interp.ini", NULL, 0);
    return 0;
}

Here  interp.ini  is the name of the initialization file. In the second way the main function will be like this

extern     int   int_nb;
extern     char   int_txt[];

int
main(int argc, char * argv[])
{
    prog_c(argc, argv, NULL, int_txt, int_nb);
    return 0;
}

Here the array  int_txt  and the integer  int_nb  are defined in an auxilliary source file. This source file is produced from a usual initialization file, using the utility
 convert  (in the directory of the same name of the distribution). For example, if the initialization file is  interp.ini  the program convert is used like this

convert   interp.ini   init.c   int_txt   int_nb

This will create the source file  init.c defining int_txt  and int_nb . This source file must then be compiled and linked with the program. It contains the same information as  interp.ini .

The user must also write the function

void   dest_prop (int, int);

(which can be empty) cf.  section 5.4.
 
 
 
 

11.1.2 The definition of command and function names

The user must write a source file containing the arrays of functions which are the commands (cf. section 4). The commands which are implemented in the library need not be redefined. Recall that there is one such array for each section  !func of the initialization file, and the list of all such arrays must be given in the array  proc (cf. section 4). The user must also define the array of structures corresponding to numerical functions known by the expression evaluator (cf.  section 6).
 
 

11.1.3 How to glue several applications in a single program

It is easy to glue several applications of the command interpreter. Here we call application a set of sources that can be linked with the command interpreter library to produce an executable, together with the corresponding initialization files. The global application should contain the sources of the various preceeding applications together with a global initialization file in such a way that the final program contains all the features of the particular ones. It is then possible to add new commands which may use several  features (functions, object types...) of the initial applications.

The initialization file for the glogal application must contain the sections that can appear only once (i.e. the sections  !param,  !rep  and  !init, cf. section 2). These sections must then be removed from the initialization files of the applications. Then the initialization files of the applications must be included in the main one (for example by using sections  !include  (cf.  section  2.11)). It is now necessary to define the array  proc  (cf.  sections 4 and 11.1.2) containing the function lists of each application, in the same order as the order of the corresponding  !func  in the initialization files.

There can be problems with the order of the messages defined in the sections  !message  of the applications. This is why the arguments of the function   error_mess in theses applications should be given in an appropriate way : for example if in some application the message number 32 is to be printed we will use something like

error_mess(32 + __APPLI3)

rather than simply  error_mess(32).  Here  __APPLI3  is a globally defined variable corresponding to the given application to be glued. It will be set in the global application : its value is the number of messages defined in the global initialization file before the  !message  section of the given glued application appears. Of course in the particular application its value is set to 0. The same should be done for the object or structure types defined in the initial applications.
 
 
 

11.1.4 How to modify applications using version 1.1

Before using the version 1.2 of the command interpreter the following modifications must be done :

 - In the section  !func  of the initialization file, suppress all the commands that come from the library.

- In the array  proc[]  containing the functions corresponding to commands, suppress the functions corresponding to the built-in commands.

- Rename the array  proc[]  (proc_b  for example).

- Add the following somewhere :

pfi  *proc[]  =
    proc\_b,
};
 
 
 


11.2 Examples

The directories  test  and test2 contain minimal applications of the command interpreter (i.e. only the commands contained in the library are present). The first directory contains a program using an external initialization file called  interp.ini . In the second directory is a version of the program where the initialization file is contained in the executable. An application of the command interpreter can be based on one of these two test programs (the user has only to add new commands and functions).

The directories  mini/test  and mini/test2  contain the same basic examples for the mini-interpreter (i.e. a smaller version of the interpreter that does not support the complex numbers and objects and structures).

The directory  appli  contains two applications of the full command interpreter. The first one (in appli/appli1) can be used to define and use numerical functions of one real variable. The second (in  appli/appli2) is based on the graphic library  g2  written by Lj. Milanovic and H. Wagner. The directory appli/glue contains the global application obtained by glueing the two preceeding ones.
 
 

11.2.1 Example 1

This is the simplest  main  function for an application of the command interpreter. This application has only the built-in commands.

#include   "interp.h"
FUNCTION   *Funcs;

pfi  *proc[] = { }      /* Here only the basic commands of the interpreter
                                are implemented */

int
main(int argc, char *argv[])
{
    Funcs = Funcs_interp;          /* Default array of functions for */
    _NBFONC = _NBFONC0;       /* the expression evaluator */

    prog_c(argc, argv, "interp.ini", NULL, 0);
            /* the initialization file is interp.ini */

    return 0;
}
 
 

11.2.2 Example 2

Here no initialization file is used, all the information is contained in the program.

#include   "interp.h"
extern  int   int_nb;
extern  char   int_txt[];

pfi  *proc[]  =  { };
FUNCTION   *Funcs;

int
main(int argc, char *argv[])
{
    Funcs = Funcs_interp;
    _NBFONC = _NBFONC0;
    prog_c(argc, argv, NULL, int_txt, int_nb);
    return 0;
}
 
 

11.2.3 Example 3

Here we give the main functions for the applications  funct  and  graph  of the command interpreter.

 For the application  funct :

#include "interp.h"       /* include file for the command interpreter library */
#include "funct.h"       /* include file for the application */

int   _XRANGE_F = 1;
int   _XRANGE_D = 2;
int   _RFUNC_F  = 3;
int   _RFUNC_D  = 4;
int   _CFUNC_F  = 5;
int   _CFUNC_D  = 6;
int   _FOUR_TR  = 7;
int   _BESS_PAR = 8;
int   _FUNC_MESS;   /* 0 */
FUNCTION   *Funcs;

pfi  *proc[] =
{
    proc_func,      /* Array of functions corresponding to the
                             additional commands of the application */
};

int
main(int argc, char *argv[])
{
    Funcs = Funcs\_func;                 /* Here the application
                                                        has its own array of functions
                                                        for the expression evaluator */
    _NBFONC = _NBFONC_FUNC;
    prog_c(argc, argv, "funct.ini", NULL, 0);
    return 0;
}

Here  _XRANGE_F = 1  is used to represent the number of the first type of objects defined in  funct : it will be actually 0, and so on for the other object types (see the source  functcmd.c  to see how these variables are used). _FUNC_MESS  (here 0) is the number of the first message in  funct.


For the application   graph :

#include   "interp.h"
#include   "graph.h"
FUNCTION   *Funcs;
int _GRAPH_MESS = 0;
int _GRAPH_X11  = 1;
int _GRAPH_PS   = 2;
int _GRAPH_COL  = 3;
int _GRAPH_FRAM = 4;
FUNCTION  *Funcs;

pfi  *proc[]=
{
    proc_graph,
};

int
main(int argc, char *argv[])
{
    Funcs = Funcs_interp;
    _NBFONC = _NBFONC0;
    prog_c(argc, argv, "graph.ini", NULL, 0);
    return 0;
}

Here  _GRAPH_X11 = 1  is used to represent the number of the first type of objects defined in  graph : it will be actually 0, and so on for the other object types (see the source  graphcmd.c  to see how these variables are used). _GRAPH\_MESS (here 0) is the number of the first message in  graph.
 
 

11.2.4 Example 4

Here is the  main function for the application  funct_graph  which is obtained by glueing the applications  funct  and  graph.

#include  "interp.h"
#include  "funct.h"
#include  "graph.h"

int   _XRANGE_F   = 1;
int   _XRANGE_D   = 2;
int   _RFUNC_F    = 3;
int   _RFUNC_D    = 4;
int   _CFUNC_F    = 5;
int   _CFUNC_D    = 6;
int   _FOUR_TR    = 7;
int   _BESS_PAR   = 8;
int   _FUNC_MESS  = 0;
int   _GRAPH_MESS = 23;
int   _GRAPH_X11  = 9;
int   _GRAPH_PS   = 10;
int   _GRAPH_COL  = 11;
int   _GRAPH_FRAM = 12;

pfi  *proc[] =
{
    proc_func,
    proc_graph,
};

int
main(int argc, char *argv[])
{
    Funcs = Funcs_func;
    _NBFONC = _NBFONC_FUNC;
    prog_c(argc, argv, "glue.ini", NULL, 0);
    return 0;
}

Here the numbers corresponding to the objects and messages of  graph  are not the same since they are stored after those of  funct. This means also that the inclusion of the initialization file of  funct  is done before that of the initialization file of  graph.
 
 
 
 


Main page
Chapters   1   2   3   4   5   6   7   8    9    10   11