Scilab Bag Of Tricks: The Scilab-2.5.x IAQ (Infrequently Asked Questions) | ||
---|---|---|
Prev | Chapter 7. Scilab Core | Next |
The interface to Scilab's core is widely undocumented. There are two levels, a lower-level Fortran77-derived, and an interface that resembles Scilab's C-interface (see also Section 7.6). Up to version 2.5 the lower-level API was defined in SCI/routines/interf/stack1.f, but from version 2.5.1 on it is defined in SCI/routines/interf/stack1.h and SCI/routines/interf/stack1.c. This means that the implementation has been ported from Fortran77 to C. The higher-level API is defined in SCI/routines/interf/stack2.h and SCI/routines/interf/stack2.c.
All lower-level functions expect the user-function name in the first parameter, whereas the higher-level functions need a variable of type ParameterStackIndex.
To save the reader frequent lookups in the defining files, we have compiled the most important ones in the following sections: query, access, creation of objects, and miscellaneous functions.
The functions in this group retrieve information about the parameters a function has been called with, and about the properties of objects on the stack.
function CheckRhs (SelfName : in String; MinNumParameter : in Natural; MaxNumParameter : in Natural) return Boolean;
Check the number of actual parameters on the right-hand side to be in the range MinNumParameter : MaxNumParameter. Return True if it is in the range, otherwise raise error 77 associated with SelfName and return False.
Ensure that at least 2, but not more than 5 parameters are passed to the function:
if (.not. checkrhs(fname, 2, 5)) return
We have assumed that fname is set to the function's name.
function CheckLhs (SelfName : in String; MinNumParameter : in Natural; MaxNumParameter : in Natural) return Boolean;
Check the number of output variables, i.e. arguments on the right-hand side to be in the range MinNumParameter : MaxNumParameter. Return True if it is in the range, otherwise raise error 78 associated with SelfName and return False.
Note that it is no error to supply less output parameters than the function actually returns. The extra values are silently discarded. This is true for the case of zero output values, too; then ans gets the first output value. Thus, a function called without any output parameters is assigned an Lhs of 1.
Ensure that there are not more than 2 output parameters, when the function is called:
if (.not. checklhs(fname, 1, 2)) return
We have assumed that fname is set to the function's name.
The functions in this section grant the programmer access to parameters that are stored on the Scilab stack. In general all of these functions work alike: An index to the current (i.e. as on entry of the function) top of the parameter stack, "BasePointer", and an index to the desired argument, "StackPointer", are passed to the API. On return the user gets all necessary information about the argument like sub-type, dimension as well as the indices, "FooIndex" that index into the Scilab heap. The indices act like pointers to the actual contents. This way only meta-data is passed, saving time-consuming copy operations.
function GetMat (SelfName : in String; BasePointer : in ParameterStackAddress; StackPointer : in ParameterStackAddress; IsComplex : out ComplexFlag; Rows : out Natural; Columns : out Natural; RealIndex : out DataStackIndex; ImaginaryIndex : out DataStackIndex) return Boolean;
Retrieve the address(es) and dimensions of a real or complex matrix from the parameter stack. The BasePointer must be set to the parameter stack pointer's value on entry of the calling function. StackPointer points to the desired parameter on the parameter stack. If successful, GetMat returns True, and IsComplex, Rows, Columns, and RealIndex are valid. If IsComplex = ComplexVariable then ImaginaryIndex is valid, too. If the parameter indexed by StackPointer is not a matrix GetMat returns False.
The output parameter IsComplex indicates whether the matrix on the data stack is purely real or complex. In the first case RealIndex points to the matrix, in the second case RealIndex points to the real part of matrix, and ImaginaryIndex points to the imaginary part. In any case Rows and Columns are the number of rows and columns of the matrix.
Fetch the addresses of a possibly complex m-times-n matrix from position top of the parameter stack.
if (.not. getmat(fname, topk, top, iscmpx, m, n, are, aim)) return
It is assumed that fname has been set to the function's name, and topk carries the position of the stack on entry to the calling function.
function GetRMat (SelfName : in String; BasePointer : in ParameterStackAddress; StackPointer : in ParameterStackAddress; Rows : out Natural; Columns : out Natural; RealIndex : out DataStackIndex) return Boolean;
Function GetRMat works like function GetMat, but restricts the accepted matrices to purely real ones.
function GetRVect (SelfName : in String; BasePointer : in ParameterStackAddress; StackPointer : in ParameterStackAddress; Rows : out Natural; Columns : out Natural; RealIndex : out DataStackIndex) return Boolean;
Function GetRVect works like function GetRMat, but restricts the accepted matrices to either single rowed (1-times-N) or single columned (N-times-1).
function GetVect (SelfName : in String; BasePointer : in ParameterStackAddress; StackPointer : in ParameterStackAddress; IsComplex : out ComplexFlag; Rows : out Natural; Columns : out Natural; RealIndex : out DataStackIndex; ImaginaryIndex : out DataStackIndex) return Boolean;
Function GetVect works like function GetMat, but restricts the accepted matrices to either single rowed (1-times-N) or single columned (N-times-1).
function GetScalar (SelfName : in String; BasePointer : in ParameterStackAddress; StackPointer : in ParameterStackAddress; Index : out DataStackIndex) return Boolean;
Retrieve the address and dimensions of a real or complex scalar from the parameter stack. The BasePointer must be set to the parameter stack pointer's value on entry of the calling function. StackPointer points to the desired parameter on the parameter stack. If successful, GetScalar returns True, and Index is valid. If the parameter indexed by StackPointer is not a scalar GetScalar returns False.
type FortranIdentifier is array (1 .. 6) of Character; -- Fortran's 6 char limit -- SimpleFunctionType is just an example type SimpleFunctionType is access function(X : in Float) return Float; type InstallerProcedureType is access procedure(FunctionName : in FortranIdentifier; FunctionEntryPoint : in SimpleFunctionType); function GetExternal (SelfName : in String; BasePointer : in ParameterStackAddress; StackPointer : in ParameterStackAddress; FunctionName : in out FortranIdentifier; IsExternal : out Boolean; Installer : in InstallerProcedureType) return Boolean;
The first three parameters SelfName, BasePointer, and StackPointer work exactly the same as in the other functions, so does the return value. They explanations are not repeated here, see e.g. Section 7.5.2.1.
The fourth parameter, FunctionName is the name of the function to be called. This parameter can designate an external function, i.e. code that has been compiled seperately and then linked to Scilab via, for example link, or the name of a Scilab function that has been defined with function or deff. In any case it is simply the name of the function. On return the IsExternal parameter signals True if the function is a external and False otherwise.
The last parameter is very special. It specifies the installation procedure Installer that manipulates a dispatcher function DispatchFunction. After a call to Installer the dispatcher points to the user function given by FunctionName.
![]() |
The programmer should not issue such a call; it is already done by GetExternal. |
Examples of dispatcher functions, the associated hooks and dispatch tables are e.g. found in SCI/routines/default/FTables.{h,c}. We will discuss dispatch tables in Section 7.3.3.
The GetExternal function relies heavily on various support functions. The supporting function have to be set up previous to the first call. Usually they are installed by the user's extention package unless she/he decides to (ab)use existing dispatcher tables and functions.
package ExternalSupport is procedure InstallProcedure (FunctionName : in FortranIdentifier; FunctionEntryPoint : in SimpleFunctionType); end ExternalSupport;
package body ExternalSupport is with Ada.Characters.Latin_1; type FunctionTableEntry is record FunctionName : FortranIdentifier; FunctionAddress : SimpleFunctionType; end record; type FunctionTableType is array (Positive range <>) of FunctionTableEntry; -- SimpleExample is of type SimpleFunction function SimpleExample(X : Float) return Float; begin return X; end Hook; FunctionTable : FunctionTableType(1 .. 2) := (1 => (FunctionName => "exampl", FunctionAddress => SimpleExample'Access), 2 => (FunctionName => (others => Ada.Characters.Latin_1.NUL), FunctionAddress => null)); DispatchFunction : SimpleFunctionType; -- function Hook is the hard-coded target for all -- internal calls function Hook(X : Float) return Float; begin return DispatchFunction.all(X); end Hook; -- bend hook function to point to FunctionEntryPoint procedure InstallProcedure (FunctionName : in FortranIdentifier; FunctionEntryPoint : in SimpleFunctionType); begin DispatchFunction := SetFunction(FunctionName, FunctionEntryPoint, FunctionTable); end InstallProcedure; end ExternalSupport;
For a self-contained example, see Section 7.3.2.
The object creation functions are mainly used to setup temporary variables for the current procedure or the procedures to be called; they bear a lot of resemblance with the object access functions (see also Section 7.5.2). The difference is that a new object is created and therefore stack space is used.
function CreMat (SelfName : in String; StackPointer : in ParameterStackAddress; WantComplex : in ComplexFlag; Rows : in Natural; Columns : in Natural; RealIndex : out DataStackIndex; ImaginaryIndex : out DataStackIndex) return Boolean;
FIXME: write it
FIXME: Write it!