An object is an array of numbers (integers, real or complex, in simple or double precision) which has a name. A structure will have members which are objects or other structures or variables of the expression evaluator.
The object types are structures of the following type :
typedef struct TYPE_OBJET { int type; int nombre; int nbdim; char **nom_dim; char *nom; char *comment; } obj_typ;
This structure is not supposed to be used by anything except the interpreter itself. The user of the interpreter will have to manipulate objects rather than object types.
type is the type of variables contained in the arrays :
- type 0 is for integers,
- type 1 for real numbers in simple precision,
- type 2 for real numbers in double precision,
- type 3 for complex numbers
in simple precision .
- type 4 for complex numbers in double precision .
- type 5 for complex numbers in simple precision .
- type 6 for complex numbers in double precision .
The way complex numbers are represented is explained in 12. There is an extra possible type : type 7 (undetermined type, cf. 6.5).
nombre is the maximal number of objects of this type that will be allowed.
nbdim is the number of dimensions of the arrays. It is at least 1.
nom_dim[i] will be the name of the i-th dimension of the arrays. When the objects will be created, their dimensions will be fixed using hidden variables having these names which are known by the expression evaluator.
nom is the name of the command of the interpreter that is used to create objects of this type.
comment is a description of the object. It is used only by the command list which gives the list of all the objects that have been created.
An object is a structure of this kind :
typedef struct _OBJET { obj\_typ *typ_obj; char *adresse; int occup; char *nom_obj; int *dim; } obj;
typ_obj is the address of the object type of the object (cf. 6.1).
adresse is the address of the array. It is NULL if the object is not already initialized.
occup is 0 if the object has not been initialized, 1 otherwise. If it is 1, the array is allocated.
nom_obj is the name of the object.
dim[i] is the i-th dimension of the array.
Object types are created in the initialization file (cf. 3.5). This allows objects to be created when the interpreter is running.
The object types that are available when the interpreter is running are contained in the array
obj_typ *Obj_typ;
If the section !def of the initialization file contains for example the following :
!def ; Objects of type 1 (comment line) defobj1 -1 0 2 Objects of type 1 : ndim1_1 ndim1_2 nb1 ; Objects of type 2 (comment line) defobj2 0 2 3 Objects of type 2 : ndim2_1 ndim2_2 ndim2_3 nb2 .
2 object types will be created, Obj_typ[0] and Obj_typ[1].
The objects are contained in the array
obj **Obj;
Obj[i][j] will contain the j-th object of type i. The type 0 corresponds to the first type of objects created in the initialization file, the type 1 to the second type of objects created in the initialization file, and so on.
When the interpreter is running, objects are created using the corresponding command. For instance, in the preceeding example, the command
- interpcom -> defobj2 xxx
will create an object of the second type, whose name is xxx. Of course the dimensions of the arrays must have been defined previously. In the example the hidden variables ndim2_1, ndim2_2 and ndim2_3 (which are the names of the dimensions of the arrays) must have been filled with the appropriate dimensions. The way to do this will be explained later.
In the previous example the function
int obj_create(int argc, char *argv[]);
is the one that is called to create objects. This is the function that implements the command objdef. In the above example, defobj2 is in fact the following program
:defobj2 3 0 0 objdef 1 #1
The 1 after objdef means that the command defobj2 will create objects of type 1 (which is the second type of objects defined in the initialization file). When the initialization file is read, a program of this type is created for each object type. So the command
- interpcom -> defobj2 xxx
is equivalent to this one :
- interpcom -> objdef 1 xxx
but the first one is more explicit. It is possible to define many objects in one command, using arrays of objects. For instance the command
- interpcom -> defobj2 zz[3]
will define 3 objects, zz[1], zz[2] and zz[3]. Note that it is now possible to use the name zz alone for another object.
Now we show how to fix the dimensions of the arrays. This is done using the function
For instance, if ndim2_1 must be 100, one can do as follows :
char h[100]; memset(h, 0, 100); sprintf(h, "ndim2_1=%d", 100); S_convert_int(h, flow_interp);
Then the value of ndim2_1 will be . This means that
indices can be anything between
and
(including these values).
Here flow_interp is a pointer to the flow_data structure used
to describe the current thread (cf. 9.4).
The simplest case is when the objects of type defobj2 have always the same dimension. The variables ndim2_1, ndim2_2 and ndim2_3 are then filled once for all in the beginning of the execution of the interpreter (or when one enters a running mode), or by a command before the creation of the objects. One can also assign values to variables by using the section !var of the initialisation file (cf. 3.3). But in some cases it may be useful to be able to create objects with non constant dimensions. This can be done by creating an extra command of creation of objects. For instance suppose that I want to create the command Def_Obj2 that should be used in the following way :
- interpcom -> Def_Obj2 xxx nn1 nn2 nn3
should create an object of type defobj2 whose name is
xxx, whith dimensions
ndim2_1=nn1, ndim2_2=nn2 and
ndim2_3=nn3. Here nn1, nn2 and nn3 could be
integers or numeric expressions that the expression evaluator can parse. The
command is implemented as follows
int Def_Obj2_cmd(int argc, char *argv[])} { int n1, n2, n3;} char h[100], *k[4];} flow_data *flow_interp; flow_interp = (flow_data *) argv[-1]; n1 = convert_int(argv[2], flow_interp); n2 = convert_int(argv[3], flow_interp); n3 = convert_int(argv[4], flow_interp); sprintf(ndim2_1=%d", n1); S_convert_int(h, flow_interp); memset(h, 0, 100); sprintf(ndim2_2=%d", n2); S_convert_int(h, flow_interp); memset(h, 0, 100); sprintf(ndim2_3=%d", n3); S_convert_int(h, flow_interp); k[0] = (char *) flow_interp; k[1] = ch_copy("objdef"); k[2] = ch_copy("1"); k[3] = ch_copy(argv[1]); obj_create(3, k + 1); free(k[1]); free(k[2]); free(k[3]); return 0; }
Here the function obj_create is called. This means also that we emulate the command objdef described previously. Note that the address of the flow_data structure corresponding to the running thread is argv[-1] (cf. 5.2, 9.4). We need also to pass it to the command objdef that we emulate with the function obj_create.
Of course the function Def_Obj2_cmd could be improved. One should test for instance the positivity of n1, n2 and n3 before calling obj_create. One should also be sure that the name of the object (which is argv[1]) is not already used. This can be done with the function
int sketch_obj(char *, int *, flow_data *);
that will be described later. One could also verify that the creation of the object was successful. If it is not the case, the function obj_create returns -1. If there is a test of the value returned by obj_create, it is no longer necessary to verify if the name of the object has already been used. In the preceeding example the function convert_int is used to parse numeric arguments (cf. 6.3 and 11.2).
Now we show how to access objects which have been created. Suppose that we have a command, called Xcom1, that uses an object of type defobj2. So the command should be used as follows :
- interpcom -> Xcom1 xxx
where the argument xxx is supposed to be the name of an object of type defobj2. The function that implements this command could be as follows :
int Xcom1_cmd(int argc, char *argv[]) { int iw, i0, *dim; double ***A; flow_data *flow_interp; flow_interp = (flow_data *) argv[-1]; iw = sketch_obj_restr(argv[1], &i0, 2, flow_interp); if (iw != 2) { error_mess(3, flow_interp); return 1; } dim = Obj[1][i0].dim; A = (double ***) Obj[1][i0].adresse; /* Here should follow the useful part of the function */ . . . return 0; }
The function
int sketch_obj_restr(char *str, int *i0, int j, flow_data *flow_interp);
works as follows : if str contains the name of an object of
type j-1 it returns j. Otherwise it returns 0. Recall that
the first kind of objects defined in the initialization file has type 0, the
second has type 1, and so on. If the function does not return 0, i0
will be the index of the object of type j-1 that has the given name.
So the object will be Obj[j-1][i0]. This function can be used also
with structures instead of objects; in this case negative values for j
are used (cf. 6.10). In the above example we test if the
string given as argument for the command Xcom1 is the name of an object
defobj2 (i.e an object of type 1). If it is not the function prints an
error message (cf. 3.9) and returns. If the name is correct,
we know that this object is Obj[1][i0]. The member
dim = Obj[1][i0].dim will give
the dimensions of the corresponding array (a 3-dimensional array of double
precision real numbers). The dimensions of this array are dim[0],
dim[1] and dim[2]. The array is
A = (double ***) Obj[1][i0].adresse. It can then be used. Note that the
function
sketch_obj_restr needs to know what is the running thread
and how we can retrieve a pointer to the flow_data structure
corresponding to this thread, as for the preceeding command
Def_Obj2_cmd (cf. 9.4, 5.2).
Another function can be used to extract an object from its name.
int sketch_obj(char *str, int *i0, flow_data *flow_interp);
If str contains the name of an object of type j this function returns j+1, and the object is Obj[j][i0]. The function returns a negative value if str is the name of a structure, and 0 if the name has not been used at all. This function can be used if the type of the object is not known a priori. Otherwise, the function sketch_obj_restr is much faster (especially if many object types are defined).
It is possible to know the value of some element of an object from the interpreter. For instance, recall that objects of type defobj2 are 3-dimensional arrays of double precision real numbers. If xxx is one such object, &xxx(1,2,5) will be interpreted by the expression evaluator as the corresponding term of the array defined by xxx.
Example :
- interpcom -> defobj2 xxx - interpcom -> const xxx 1 - interpcom -> &xxx(1,2,5) 1.000000 - interpcom -> i=2 2.000000} - interpcom -> j=3 3.000000 - interpcom -> x=5.5 - interpcom -> x+&xxx(1,i,i+j)} 6.500000
So values of objects at some points can be passed as arguments to commands. For objects containing complex numbers (type 3,4,5 or 6 of variable), the operator & will return the real part. It is also possible to have the real or imaginary part by using the suffixes .r or .i respectively. For instance, if zzz is an object which is a 2 dimensional array of complex numbers, &zzz(1,2).r and &zzz(1,2).i are respectively the real part and the imaginary part of the term of indices (1,2) of zzz.
Two commands are available to fill objects.
With the first one, setobj, it is possible to impose a value to a given term of an object. For instance, if Obj is a real object (i.e. if it contains integers or real or double precision real numbers) with n dimensions, the instruction
setobj Obj x d1 ... dn
with give the value x to the term (d1,...,dn) of Obj. Here x can be a number or a numerical expression that will be sent to the expression evaluator.
Example :
- interpcom -> defobj2 xxx - interpcom -> setobj xxx 1.5 2 3 4 - interpcom -> &xxx(2,3,4) 1.500000
For a complex object, the two components (real and imaginary, or modulus and phase according to the kind of object) must be given as third and fourth parameters of the command.
With the second command, fillobj, it is possible to fill all the object. For instance, if Obj is a real object (i.e. if it contains integers or real or double precision real numbers) with n dimensions, the instruction
fillobj Obj xxx
will fill the object according to the numerical expression xxx. Here xxx must be an expression depending on the variables xi, for i between 0 and n-1, representing the indices of the object. This expression will be sent to the expression evaluator and can also contain other variables or numerical functions recognized by it.
Example :
- interpcom -> defobj2 xxx - interpcom -> dt=0.001 - interpcom -> fillobj xxx x0*dt*cos(x1*dt+x2*dt)
For complex objects two formulas must be given, one for each component of the terms of the objects.
It is possible to define faster several identical object types with different names using the keyword alias. If the section !def of the initialization file contains for example the following :
!def ; Objects of type 1 (comment line) defobj1 -1 0 2 Objects of type 1 : ndim1_1 ndim1_2 nb1 ; Objects of type 1b (comment line) defobj1_b alias defobj1 Objects of type 1b :
the object type defobj1 will first be created. Then another object type called defobj1_b will be created, which will be identical to defobj1 (i.e. they have the same parameters, except the comment defining it). In this case the definition of defobj1_b needs only three lines : in the first is the name of the command defining the objects of this type, in the second we put the keyword alias followed by the name of a previously defined object type and in the third the comment defining the object type.
It is possible to see in a program if an object type is an alias of another. For this we use the global variable
int *Obj_alias;
If the object type number i is not the alias of another object type, the integer Obj_alias[i] will be equal to i. If this object type is the alias of the object type j then Obj_alias[i] will be equal to j (in this case j is smaller than i). This array can be used for instance if one wants to write commands using object types which are the aliases of one object type.
This is the type 7 of variables for objects. It is suitable to store the user defined data types. For this kind of object there are no dimensions, but one should put at least one for compatibility reasons. For instance, suppose that the user needs to manipulate some kind of data called Data0 (for instance, it could be a structure). Then in the !def section of the initialization file, one could find
; Objects of undetermined type defobj3 -1 7 1 Struc0's : 10 nb_struc0
Here these objects are declared to have 1 dimension, which is 10, but this does not matter. We suppose also that this is the 3rd type of objects that we have in the initialization file. Now the command defobj3 will not create any Data0, but rather some place to store the address of such a data type and a name associated to this address. To really create a Data0 one needs a specific command, say Def_Data0. This command could work as follows :
- interpcom -> Def_Data0 xxx
should create a Data0 whose name is xxx. One could also make a more complicated command, with more arguments such as parameters for the Data0 to be created. The command Def_Data0 can be implemented as follows :
int Def_Data0_cmd(int argc, char *argv[]) { int i0, iw; char *k[3],**e; Data0 *D; flow_data *flow_interp; flow_interp = (flow_data *) argv[-1]; iw = sketch_obj(argv[1], &i0, flow_interp); if (iw != 0) { error_mess(4, flow_interp); return 1; } k[0] = (char *) flow_interp; k[1] = ch_copy("objdef"); k[2] = ch_copy("3"); if (obj_create(3, k + 1) == -1) { error_mess(3, flow_interp); return 1; } D = Data0_create() /* user-supplied function that creates a Data0 */ e = (char**) Obj[2][i0].adresse; e[0] = (char*) D; free(k[1]); free(k[2]); }
Here the function sketch_obj is used to see if the name xxx has not been already used. If it has been used, the error message 4 is printed, and the function exits (this message could be already used name !). Then the object defobj3 is created and associated to the name xxx, using the function obj_create. A new Data0 is then created, and its address is stored in the object.
Some commands manipulating objects are present in the library : const, const_c, const_r, const_th, copy, multiply, substract, svg, restore (cf. 10).
It is possible to destroy objects with the command destroy. For example,
- interpcom -> destroy xxx
will destroy the object xxx (if it exists). If the variable type is known (i.e. the type of variables in this object is between 0 and 6), the corresponding array is freed. When an object is destroyed, the function
void dest_prop(int, int, flow_data *);
will be called. This is useful in particular if the type of variables is 7 (undetermined type, see 6.5). This function should contain the procedure provided by the user to free the corresponding data. This function is not in the library. It must be present in the program that uses the command interpreter. It can be simply
void dest_prop(int typ, int i0, flow_data *flow_interp) { }
The argument flow_interp is the address of the flow_data structure corresponding to the current thread (cf. 9.4). The argument typ is the object type (the first to be defined in the initialization file is 0, the second 1, and so on), i0 is the object number. So the object to free is actually Obj[typ][i0]. In the example of 6.5, we could put the following function
void dest_prop(int typ, int i0, flow_data *flow_interp) { char **e; Data0 *D; if (typ == 2) { e = (char **) Obj[typ][i0].adresse; D = (Data0 *) e[0]; free_Data0(D); /* function supplied by the user to free data of type Data0 */ } }
In more complicated situations a specific command can also be written to destroy some kind of object. In the preceeding example the argument flow_interp is not used, but it may be used in more complicated situations. For instance if the destruction of an object would imply the destruction of another object, the function dest_prop should emulate the command destroy to destroy the associated object, by calling the corresponding function detruit_obj(int argc, char *argv[]) and we need to pass to it the parameter flow_interp (in argv[-1]).
The objects of an array of objects must be destroyed individually.
The function
void init_obj(int, flow_data *);
may be used to destroy all the objects of a given type : it deletes all the objects of the type given in the first argument. The second argument is a pointer to the flow_data structure corresponding to the running thread (cf. 9.4).
It is possible to store objects (not of undetermined type) in the results directory, using the command svg. For instance, if the object XXX1 has been defined, the instruction
- interpcom -> svg XXX1 z.svg
will store the object XXX1 in the file z.svg of the results directory. This is done in binary format. The file z.svg will not only contain the numbers of the array corresponding to XXX1, but also informations concerning this object (the type of the object and its dimensions). The object can be loaded by using the command restore. For instance if the object YYY1 has been defined, of the same type as XXX1 and with the same dimensions, the instruction
- interpcom -> restore YYY1 z.svg
will fill YYY1 with the object stored in z.svg.
The structure types are structures of the following type :
typedef struct TYPE_STRUC { int nb_membres; int *type_mb; char **membre_id; char *nom; char *comment; int nombre; } struc_typ;
This structure is not supposed to be used by anything except the interpreter itself. The user of the interpreter will have to manipulate structures rather than structure types.
nb_membres is the number of members of the structure type.
type_mb contains the types of the members. If the member i is an object of type j, type_mb[i] will be j. If this member is a structure of type j then type_mb[i] will be -j-1. If the member i is a variable of the expression evaluator then type_mb[i] will be 0. Structure types are determined by their order in the initialization file (cf. 3.6). The first to be defined has type 0, the second 1, and so on. An object or structure type must be defined before it appears as a member of another structure type.
membre_id contains the names of the members.
nom is the name of the command of the interpreter that is used to create structures of this type.
comment is a description of the object. It is used only by the command list which gives the list of all the objects and structures that have been created.
An structure is a C-structure of this kind :
typedef struct _STRUC { char *nom_struc; int occup; struc_typ *type; char **nom_mb; } strucb;
nom_struc is the name of the structure.
occup is 0 if the structure has not been initialized, 1 otherwise.
type is the address of the structure type of the structure (cf. 6.8).
nom_mb[i] is the name of the object (or structure) which is the member i of the structure (if this member is not a variable of the expression evaluator). It will be NULL if this member has not been assigned.
Structure types are created in the initialization file (cf. 3.6). This allows structures to be created when the interpreter is running.
The structure types that are available when the interpreter is running are contained in the array
struc_typ *Struc_typ;
If the section !struct of the initialization file contains for example the following :
!struct ; Structures of the first type (comment line) defstruc1 3 member_1 defobj1 member_2 defobj2 member_3 X Structures 1 : -1 nb1 ; Structures of the second type (comment line) defstruc2 3 member_1b defobj1 member_2b defobj2 member_3b defstruc1 Structures 1 : 0 nb2 .
2 structure types will be created, Struc_typ[0] and Struc_typ[1]. If the object types defobj1, defobj2 have been created previously, but no object or structure type called X, the structures defstruc1 have 3 members : an object of type defobj1, an object of type defobj2 and a variable of the expression evaluator. The structures defstruc2 have 3 members : an object of type defobj1, an object of type defobj2 and a structure of type defstruc1.
The structures are contained in the array
strucb **Struc;
Struc[i][j] will contain the j-th structure of type i. The type 0 corresponds to the first type of structures created in the initialization file, the type 1 to the second type of structures created in the initialization file, and so on.
When the interpreter is running, structures are created using the corresponding command. For instance, in the preceeding example, the command
- interpcom -> defstruc1 xxx
will create a structure of the first type, whose name is xxx. It is also possible to create arrays of structures. For example, the command
- interpcom -> defstruc1 zz[3]
will create the structures zz[1],zz[2] and zz[3]. Note that it is now possible to use the name zz for another structure or object. The command assign can be used to fix the members of the structure. The command desassign can be used to free them. With the command desc it is possible to have the description of a structure.
Example :
- interpcom -> defstruc1 xxx - interpcom -> desc xxx member_1 (object defobj1) : (null) member_2 (object defobj2) : (null) member_3 (variable xxx_member_3) : 0 - interpcom -> defobj1 xxx1 - interpcom -> defobj2 xxx2 - interpcom -> assign xxx member_1 xxx1 - interpcom -> assign xxx member_2 xxx2 - interpcom -> desc xxx member_1 (object defobj1) : xxx1 member_2 (object defobj2) : xxx2 member_3 (variable xxx_member_3) : 0 - interpcom -> desassign xxx member_1 - interpcom -> assign xxx member_3 2.5 - interpcom -> desc xxx member_1 (object defobj1) : (null) member_2 (object defobj2) : xxx2 member_3 (variable xxx_member_3) : 2.5
In this example the third member of the structure xxx is a hidden variable of the expression evaluator (cf. 7), called xxx_member_3 (so its name is the name of the structure, followed by a _ and by the name of the member). The command assign is also used here to fix the value of the member. Its value will be the last argument of the command assign. If a member of a structure which is a variable of the expression evaluator is not assigned any value, the corresponding variable remains undefined. In the previous example the function
int struc_create(int argc, char *argv[]);
is the one that is called to create structures. This is the function that implements the command strucdef. In the above example, defstruc1 is in fact the following program
:defstruc1 3 0 0 strucdef 0 #1
The 0 after objdef means that the command defstruc1 will create structures of type 0 (which is the first type of structures defined in the initialization file). When the initialization file is read, a program of this type is created for each structure type. So the command
- interpcom -> defstruc1 xxx
is equivalent to this one :
- interpcom -> strucdef 0 xxx
but the first one is more explicit.
Suppose we want to define the members of a structure together with the structure itself. For instance, we want a command called Def_Struc1 such that
- interpcom -> Def_Struc1 xxx
would create the structure xxx, the objects xxx.memb1, xxx.memb2, of type defobj1, defobj2 respectively, and assign these objects to the members of xxx. The function that implements this comment could be :
int Def_struc1_cmd(int argc, char *argv[]) { char *k[5], h[100]; flow_data *flow_interp; flow_interp = (flow_data *) argv[-1]; /* we create the structure */ k[0] = (char *) flow_interp; k[1] = ch_copy("strucdef"); k[2] = ch_copy("0"); k[3] = argv[1]; if (struc_create(3, k + 1)== -1) { /* creation of the structure */ error_mess(5, flow_interp); return 1; } free(k[0]); /*--------------------------------------*/ /* we create the members of the structure */ memset(h, 0, 100); sprintf(h, "%s.memb1", argv[1]); k[1] = ch_copy("objdef"); k[3] = h; if (obj_create(3, k + 1) == -1) { /* creation of member 1 */ error_mess(5, flow_interp); return 1; } memset(h, 0, 100); sprintf(h, "%s.memb2", argv[1]); k[2][0]= '1'; k[3] = h; if (obj_create(3, k + 1) == -1) { /* creation of member 2 */ error_mess(5, flow_interp); return 1; } /*--------------------------------------*/ /* we assign the objects to the members of the structure */ free(k[1]); k[1] = ch_copy("assign"); free(k[2]); k[2] = argv[1]; k[3] = ch_copy("member_1"); sprintf(h, "%s.memb1", argv[1]); k[4] = h; assign_membre(4, k + 1); k[3][7] = '2'; assign_membre(4, k + 1); free(k[1]); free(k[3]); /*--------------------------------------*/ return 0; }
Here the function assign_membre (which corresponds to the command assign) is used to assign objects to members of a structure (we make a simulation of the command assign...). The function struc_create (which creates structures) returns -1 if it fails (as obj_create does). The preceeding function could be improved : for example, if it is impossible to create a member of the structure, the structure (and already created members) could be destroyed.
Now we show how to access structures which have been created, and their members. Suppose that we have a command, called Xcom1b, that uses a structure of type defstr1. So the command should be used as follows :
- interpcom -> Xcom1b xxx
where the argument xxx is supposed to be the name of a structure of type defstr1. The function that implements this command could be as follows :
int Xcom1b_cmd(int argc, char *argv[]) { int i0, i1, i2, **I; double ***A; flow_data *flow_interp; /* we test if the structure exists */ if (sketch_obj_restr(argv[1], &i0, -1, flow_interp) != -1) { error_mess(5, flow_interp); return 1; } /*-------------------------------------*/ /* we extract the members of the structure */ if (sketch_struc(0, i0, "member1", &i1, flow_interp) == 0) { error_mess(6, flow_interp); return 1; } I = (int **) Obj[0][i1].adresse;} if (sketch_struc(0, i0, "member2", &i2, flow_interp) == 0) { error_mess(6, flow_interp); return 1; } A = (double ***) Obj[1][i2].adresse; /*-------------------------------------*/ /* Here should follow the useful part of the function */ return 0; }
Here the error message 6 could be unassigned member !. The function
int sketch_obj_restr(char *str, int *i0, int j, flow_data *flow_interp);
is used as for objects to find a structure with a given name. If j is a negative number, sketch_obj_restr(str, &i0, j, flow_interp) will return j if str is the name of a structure of type -j-1 with name str. In this case, i0 will contain the number of the structure. So this structure will be Struc[-j-1][i0].
To know the members of a structure it is possible to use it itself, or to use the function
int sketch_struc(int i, int i0, char *memb, int *j, flow_data *flow_interp);
Here sketch_struc(i, i0, memb, &j, flow_interp) will return 0 if memb is not the name of a member of the structure number i0 of type i, or if this structure is not defined. If memb is the name of a member of this structure, and if this member is not assigned, it returns also 0. In the remaining case, if the member is an object of type k, the function returns k+1, j will contain the number of the object, and if it is a structure of type k, the function returns -k-1, j will contain the number of the structure. So the member will be Obj[k][j] or Struc[k][j]. The parameter flow_interp is the address of the flow_data structure corresponding to the running thread (cf. 9.4, 5.2).
It is possible to destroy structures with the command destroy. For instance,
- interpcom -> destroy xxx
will destroy the structure xxx (if it exists).
The structures of an array of structures must be destroyed individually.
The function
may be used to destroy all the structures of a given type : it deletes all the structures of the type given in argument.