7. Functions

A function is a name for a sequence of statements. You can use functions as a black box. You do not need to know how the function works. For example, to use the sin function you only need to know the name and the interface of the function.

7.1. Function Syntax

In UniScript, a function is easily defined. Example:

def dB(rvSignal)
{
    return 20.0 .* log10(rvSignal);
}

The keyword def is followed by the function name. The function name is followed by a list of comma-separated arguments enclosed in parentheses. In our example, the function name is dB and the argument has the name rvSignal. The function has one statement which returns the result to the caller of the dB function. The function call can look like this:

rvdB = dB(1:100);

The values 1 to 100 will be converted into dB (Decibel) values.

A function in UniScript has the following syntax:

def name (parameter-list)
{
    statements
}

The rules for function names are the same as for variable names. The name must be a sequence of letters, digits and underscores, however, it may not begin with a digit. The length of names is not limited in UniScript, but only the first 80 characters are significant. Case is also significant in names. The name must be distinct from all variables or built in function names. A built in function is a function written in in C, C++ or FORTRAN. They are located in Dynamic Link Libraries (DLLs) and are loaded when UniScript starts.

A list of all built in functions can be received with the function call symbols(SYM_BUILTIN).

The function name is followed by a comma separated parameter list enclosed in parentheses. The parameter list can have between 0 and 32 elements. The shortest form of a function in UniScript is:

def f() { }

The parentheses and the braces are necessary for syntax reasons. When this function is called, it returns the value 0.0.

7.2. Function Parameters and Arguments

Values which are passed to a function are called arguments. Parameters are the names of the arguments. In UniScript, the number of function parameters is limited to 32. Example:

def dB(rvSignal)
{
    return 20.0 .* log10(rvSignal);
}

db(1:100)

The value 1:100 is an argument, rvSignal is the function parameter.

A function can be called with less arguments than the function has parameters. Example:

def Test(a, b, c)
{
    return 1;
}

Test();
Test(1);
Test(1,2);
Test(1,2,3);
Test(1,2,3,4);

Except for the last function call, all of the function calls above are valid.

The number of arguments can be checked inside a function with the function nargsin:

def Test(a, b, c, d, e, f, g)
{
    nArgs = nargsin();
    printf("The function was called with %d out of 7" + ..
           " possible arguments\n", nArgs);
}

Function parameters which have not been passed to the function cannot be accessed. To do so will produce an error message. If the function call is Test(1, 2, 3), the parameters d - g are not available and should not be used.

7.3. Global and Local Variables

Normally, all variables used inside a function are local variables. These variables will be created when the function is called and will be destroyed when the function is finished. Local variables are not known outside the function. A variable can be declared as global to avoid this behavior. Global variables can be accessed from any UniScript function. The global variable must be declared at the beginning of the function in order to access it. Example:

def Test()
{
    global Glob1, Glob2;

    Glob1 = 1;
    Glob2 = 2;
    Local1 = 3;
    Local2 = 4;
    print Glob1, Glob2, Local1, Local2;
}

Glob1 = 5;
Glob2 = 6;
Local1 = 7;
Local2 = 8;
print Global1, Global2, Local1, Local2;
Test();
print Global1, Global2, Local1, Local2;

If you execute this program, it will print the numbers 5, 6, 7, 8. In the function Test(), it will print the numbers 1, 2, 3, 4 and in the last print statement, the numbers 1, 2, 7, 8 will be printed. The function Test() has changed the variables Glob1 and Glob2. The variables Local1 and Local2 were not changed by the program Test().

7.4. The return Statement

The return statement returns values to the calling function and terminates the execution of the called function. The return statement has the following syntax:

return expression;

If the expression is empty, the function returns the value 0.0. A function without a return statement returns the default return value 0.0. Example:

def Test(x)
{
    if ((x % 2) == 0) {
        return "x is divisible by 2 without a remainder";
    }
    return "x is NOT divisible by 2 without a remainder";
}
Test(4)
Test(5)

If the argument of the function Test() is divisible by 2, the first return statement will be executed and the function terminated. Otherwise, the second return statement will be executed.

7.5. Multiple Return Values

All of the functions we have used so far, such as sin, have only one return value. However, functions in UniScript can return multiple values. Example:

If you call the eig function in the form

* m = [4,7;2,5]
* eig(m)
    8.2749 + 0.0000i
    0.7251 + 0.0000i

it returns the eigenvalues of the matrix m. If you call the function in the following form

* <e, v> = eig(m)

it will return 2 variables (the eigenvalue e and the eigenvector v).

The syntax for defining functions that return multiple values is

def <return list> = name(argument list)
{
    statements
}

The return list is a list of variable names separated by commas.

The function nargsout returns the number of values that are expected to return. Return variables which have not been passed to the function cannot be accessed. To do so will produce an error message.

def <a,b,c,d> = Test(e,f,g,h,i)
{
    nArgsIn = nargsin(); nArgsOut = nargsout();
    printf("The function was called with %d out of 5 " + ..
           "possible arguments\n", nArgsIn);
    printf("The function was called with %d out of 4 " + ..
           "possible return variables\n", ..
           nArgsOut);
}

Instead of using multiple return values an object can be returned as shown in the following example (see also UniScript Objects). Example:

def Test(p1, p2)
{
   o = [.]; // Create objekt

   o.a = 123;
   o.b = "Hello";

   return o;
}

Note: The return variables enclosed in angle brackets < > cannot be used in the argument list of the function definition.

Two or more return values should not be used. Instead an object can be returned (see UniScript Objects). Example:

def Test(p1, p2)
{
   o = [.]; // Objekt erzeugen

   o.a = 123;
   o.b = "Hello";

   return o;
}

7.6. Calling Functions from DLL`s

DLL is an abbreviation for Dynamic Link Library. A DLL is a collection of functions created with a compiler. With UniScript, functions located in DLLs can be called directly except when the function’s parameter list contains structures or pointers to functions. In this case, you still have to use a C or FORTRAN compiler to create a DLL to enable UniScript to call this function.

We would like to show you the use of the interface with some examples.

7.6.1. FindWindow

The first example is the function FindWindow(). This function is located in a DLL which belongs to the Windows Operating System. The function can be used to check if a certain program has already been started. Before the function can be used, it must be registered. This means, we have to tell UniScript in which DLL the function is located, what the internal name of the function is and what function parameter and return values the function has. The data types of the parameters are needed so that UniScript can convert the values passed to the function to the correct type.

To register a new function, use RegisterFunction. This function must be called only once for each new function. A good place to invoke the function is the startup file startup.ic.

RegisterFunction("USER32", "FindWindowA", ..
                 "uint", "FindWindow", char* , char*);

The first parameter is the name of the DLL. The function FindWindow() is located in the DLL USER32.DLL in one of the Windows directories. To find the DLL in which a function is located, refer to the Windows Software Development Kits (SDK) documentation. SDK documentation is part of a Windows compiler documentation.

The second parameter is the internal name of the function. The FindWindow() function has the internal name FindWindowA. This information is also found in the SDK documentation.

The third parameter is a string which specifies the data type of the return value. The SDK documentation specifies the data type of the return value as a HWND (handle to a Window). Because the RegisterFunction does not know this data type, we use the data type "uint". An "uint" is an unsigned 32 Bits integer. The data types that can be used for the RegisterFunction are specified in the UniScript Reference.

The fourth parameter is the name of the function you want to call from UniScript. You can specify any name that meets the rules of UniScript function names.

The fifth parameter is a string vector which specifies the data types of the function parameters. The function FindWindow has two parameters.

The first one is a pointer to a string which specifies the internal name of the window, and the second parameter is a pointer to a string which specifies the window title. The internal window name for Excel is, for example, "XLMAIN". For MS-WORD it is "OpusApp" and for UniPlot it is ":UniPlot:".

After we have registered the new function, we are able to call it. When the function returns a value not equal to 0, it means that Excel has already been started. If the return value is 0, Excel has not been started.

// Find the Excel Window. The second parameter
// can be set to 0 (see SDK documentation)
h = FindWindow("XLMAIN", 0);
if (h == 0) {
    // Window not found, i.e. Excel not started
    // Start Excel:
    system("excel", SW_SHOW, TRUE);
}
// at this point Excel is running

7.6.2. DGEMM

The next example is a more complicated call of a mathematical function which is located in the UniScript DLL rs_math.dll. The function evaluates the following term:

C = alpha * A * B + beta * C

alpha and beta are scalar values, A, B and C are vectors or matrices.

The function is only an example to show how FORTRAN functions can be called from UniScript because the term

C = alpha * A * B + beat * C

can also be evaluated directly by UniScript without calling a function. However, it is a good example to show the calling of functions of this kind.

The FORTRAN function has the following form:

SUBROUTINE DGEMM (TRANSA, TRANSB, M, N, K, ALPHA, A,
LDA, B, LDB, BETA, C, LDC)

The function belongs to the BLAS Library (Basic Linear Algebra System).

Functions in DLLs must have a so called C interface which looks like the following:

int dgemm_(char *transa, char *transb, int *m,
           int *n, int *k, double *alpha, double *a,
           int *lda, double *b, int *ldb, double *beta,
           double *c, int *ldc);

The corresponding UniScript registration call for this function has the following form:

RegisterFunction("rs_math.dll", "dgemm_", "int", ..
                 "dgemm", ..
                 "char *transa", "char *transb", "int *m",
                 "int *n", ..
                 "int *k", "double *alpha", "double *a", ..
                 "int *lda", "double *b", "int *ldb", ..
                 "double *beta", "double *c", "int *ldc");

We do not call the _dgemm() function directly because UniScript can only perform a very limited number of error checks when calling external DLL functions.

A faulty function call can lead to a “crash” of UniPlot, a so called “Memory Access Violation”. Under Windows 95/98 it can also lead to a crash of Windows itself so that you have to reboot your computer.

Under Windows NT, the applications run in a protected mode so that such an error will only affect UniPlot. To avoid such a problem, we will write a wrapper function for _dgemm().

To simplify the problem we set alpha to 1 and beta to 0 in our formula:

C = alpha * A * B + beta * C
// C = A * B
def Multiply(a, b)
{
    if (nargsin() != 2) {
        error("number of args");
    }
    if (type(a) != "real" || type(b) != "real") {
        error("type error");
    }
    nra = nr(a);
    nrb = nr(b);
    nca = nc(a);
    ncb = nc(b);
    if (nra != ncb) {
        error("dimensions must match");
    }
    c = zeros(nra, ncb);
    _dgemm("N", "N", nra, ncb, nca, 1.0, ..
          a, nra, b, nrb, 0.0, c, nra);
    return c;
}

The following lines are a test of the new interface and will compare the result with the built in multiplication operator.

a = rand(2, 3);
b = rand(3, 2);
x1 = Multiply(a, b)
x2 = a * b;
print x1-x2;

7.6.3. GetCurrentDirectory, SetCurrentDirectory

We will now write two functions to change directories or return the current working directory respectively.

gwd() (get working directory) should return the current working directory.

cd() (change directory) should change the directory.

The corresponding Windows functions are GetCurrentDirectoryA() and SetCurrentDirectoryA().

GetCurrentDirectoryA() has two parameters. The first parameter specifies the buffer size in which the function will write the directory name.

The second parameter is a pointer to the buffer. The function will not write more characters into the buffer than the first parameter specifies. The function returns the number of actually written characters. The registration of this function looks like the following:

RegisterFunction("KERNEL32", "GetCurrentDirectoryA",..
                 "uint", "__GetCurDir", ["uint", "char*"]);

The registration for SetCurrentDirectory() is:

RegisterFunction("KERNEL32", "SetCurrentDirectoryA",..
                 "uint", "__SetCurDir", "char*");

We will now write the wrappers for these functions:

def gwd()
{
    ss = "012345678901234567890123456789";
    ssBuffer = "";
    for (i in 1:10) ssBuffer = ssBuffer + ss;
    GetCurDir(strlen(ssBuffer), ssBuffer)
    return ssBuffer;
}

The first three lines of the function gwd() will create a buffer for 300 characters which will then be filled by the GetCurrentDirectoryA() function. The function gwd() returns the buffer in the last line.

The function SetCurrentDirectoryA() receives a similar wrapper. The two if statements avoid the problem of the function being called with a wrong number of arguments.

def cd(ssDir)
{
    if (nargsin() != 1) {
        error("usage: cd (ssDir)")
    }
    if (type(ssDir) != "string") {
        error("usage: cd (ssDir)")
    }
    return SetCurDir(ssDir);
}

Finally, we can test the new functions in the command window:

* cd ("c:/")
    1.0000
* cd ()

>>> cd : usage: cd (ssDir)

* gwd()
c:\
* cd("d:/uniplot/script")
    0.0000
* gwd()
c:\
* cd("d:/uniplot/script")
    1.0000
* gwd()
d:\uniplot\script

7.7. COM-Interface

As of Version 3.0 UniScript can access objects that have a so called dispatch interface.

Below are some examples of how the new interface can be used.

7.7.1. Access Excel

In the first example we want data to be inserted into a Microsoft Excel spreadsheet.

First Excel must be started by calling the CreateObject function. CreateObject returns a pointer (a reference) to the Excel instance. The function expects the server name of the program that should be started as the argument. For Excel the server name is "Excel.Application".

xls = CreateObject("Excel.Application")
xls.Visible = 1

The second line (xls.Visible = 1) will make the application visible. To access the methods and properties of an object use a period (.).

In the following example UniScript calls a method (function) to add a new workbook to the existing document:

wb = xls.Workbooks
wb.Add();

You can call both methods in one statement:

xls.Workbooks.Add()

The following lines will fill the sheet:

xls.ActiveSheet.Range("a1").Value = "x"
xls.ActiveSheet.Range("b1").Value = "sin(x)"
x = linspace(0, 2*PI)
y = sin(x)
xls.ActiveSheet.Range("a2:a101").Value = x'
xls.ActiveSheet.Range("b2:b101").Value = y'

7.7.2. Data Base Access

In the following example, we will use Microsoft ADO (ActiveX Data Objects) to access the data of a Microsoft Excel XLSX file like a database table with SQL.

// create an Excel 2007 file with the following content and
// name the sheet Sheet1:
/*
a   b   c
1   2   test1
4   5   test2
3   1   test3
*/

def ado_Excel_Test()
{
   // Must be an XLSX file, slash or double backslash
   ssExcelFile = "c:\\excelfile.xlsx";
   ssSheetName = "Sheet1";

   // HDR=Yes : First row are the column names of the table
   strCnn = "Provider=Microsoft.ACE.OLEDB.12.0;Data " + ...
          "Source=%s;" + ..
             "Extended Properties=\"Excel 12.0 Xml;HDR=Yes;IMEX=1\";"
   strCnn = sprintf(strCnn, ssExcelFile);
   db = db_create("ado");
   if (db.connect(strCnn) == 0) {
      MessageBoxError("Cannot connect: %s", strCnn);
      return ""
   }
   // $-sign is neccessary for the table name
   // return all data
   ssSQL = sprintf("SELECT * FROM [%s$];", ssSheetName);
   smData = db.exec(ssSQL);

   // return all columns and all records where a > 1
   ssSQL = sprintf("SELECT * FROM [%s$] Where a > 1;", ssSheetName);
   smData = db.exec(ssSQL);

   // return column b and c where column a > 1
   ssSQL = sprintf("SELECT b,c FROM [%s$] Where a > 1;", ssSheetName);
   smData = db.exec(ssSQL);

   return smData;
}

In the following example, we will use Microsoft Data Access Objects (DAO) to read data from a Microsoft Excel table. DAO is not available in 64-bit Windows.

dao = CreateObject("Dao.DBEngine.36");
if (dao == 0) {
    error("Cannot create Dao.DBEngine.3.6");
}

ws = dao.CreateWorkspace("", "Admin", "", 2);
ssFile = GetRootDirectory()+ "samples\ole\test.xls"
dbs = ws.OpenDatabase(ssFile, 0, 0, "Excel 8.0;HDR=No;");
m = dbs.OpenRecordset("test$").GetRows(1000);
print m

7.7.3. Variant Matrix

An Excel table can contain different data types. In the example above we wrote the string “x” into the cell A1. We wrote floating point numbers into the cells A2 to A101.

In a data base each column can have a different data type, e.g. the first column is the date, the second column an integer and the third column is a string with 80 characters.

To enable UniScript to deal with data matrices where elements can have different data types we added variant matrices to UniScript.

A variant matrix can contain elements of the following 4 data types:

Type Meaning
real Double precision values with 8 bytes.
complex Complex values. Two double precision values. A complex value has 16 Bytes.
string A string with up to 2 times 31 characters.
object Reference to an ActiveX object.

The following example creates an column vector with 3 real values, one complex value, one string and one object reference.

* xls = CreateObject("Excel.Application");
* v = [ConvertToVariant([1,2,3]), 4+5i, "Hello", xls]'
* v
    1.0000
    2.0000
    3.0000
    4.0000 + 5.0000i
Hello
(0x001B6FC4)

The element access for variant matrices is identical to any other matrix element access in UniScript. Variant matrices cannot be used in calculations. Comparison operators for variant matrices are not supported.

The following statement will therefore create a runtime error:

a = [1, "Hallo"]
b = a
if (a == b) MessageBox("a not equal to b")

To use data from variant matrices in computations, the matrices must be converted to real matrices. This can be performed with the VariantConvert function.

a = [1, "Hallo"]
b = a
print VariantConvert(a[1]) + VariantConvert(b[1])

The inverse function to VariantConvert is ConvertToVariant.

VariantGetType returns a matrix with the type of each element.

The UniScript variant matrix is not identical to the data type Variant of Visual-Basic or the ActiveX interface. The ActiveX variant data type knows the following data types:

Type No. Name Description
0 VT_EMPTY empty.
1 VT_NULL Null.
2 VT_I2 2-byte signed int.
3 VT_I4 4-byte signed int.
4 VT_R4 4-byte real.
5 VT_R8 8-byte real.
6 VT_CY Currency.
7 VT_DATE Date/Time.
8 VT_BSTR Binary string.
10 VT_ERROR SCODE.
11 VT_BOOL Boolean.
17 VT_UI1 Unsigned char.

When UniScript uses a property or a method of the COM interface, UniScript must perform a data type conversion from the UniScript data type to the COM data type.

Data types with the numbers 2, 3, 4, 5, 11, 17 will be converted to the UniScript-real data type (Double precision value). Type number 8 will be converted into a UniScript-String. The types 0, 1, 6, 7 will be converted to a complex number where the real part is the value and the imaginary part is the type number.

Example: An Excel table contains the following data in the first column:

x
1,23

01.01.2000
#DIV/0!
FALSCH

UniScript will return the following vector:

* v = xls.ActiveSheet.Range("a1:a6").Value'
* print v
x
    1.2300
    0.0000 + 0.0000i
36526.0000 + 7.0000i
-2.147e+009 + 10i
    0.0000

Cell A3 is empty. For this element UniScript returns the complex number 0+0i. Cell A4 contains a date. For this element UniScript will return the complex number 36526+7i. To convert the date into an string use DT_Format(real(v[4])). The cell A5 (-2.147e+009 + 10i) contains an error code. This is the Excel error code for the Excel formula =1/0.

7.7.4. UniPlot as an COM Server

UniPlot can be used as an COM server (OLE Server or Automation Server). This means that you can use UniPlot/UniScript functions in other applications. UniPlot uses a dual interface, i.e. UniPlot can be used by script languages like VBScript, JavaScript, Visual Basic for Applications as well as languages like C, C++ or Visual Basic.

The following examples will show you how to use UniPlot with Excel. To try out the examples, you need Excel 97 or Excel 2000.

7.7.5. Setup

To setup the examples, execute the following steps:

  • If UniPlot is running, quit UniPlot.

  • The examples are located in the directory UniPlot\Samples\ole. Copy the UniScript files that begin with AX- into UniPlot Autoload directory.

  • Open the DOS command window.

  • Go to the \UniPlot\Program directory and start UniPlot with the following command:

    uniplot /regserver
    

This will register UniPlot as an OLE-Server.

  • After you are finished evaluating the examples it is recommended to remove the AX-*.ic files from the UniPlot/AutoLoad directory.

7.7.6. Example 1 (AX-Data)

The following example shows how a UniScript Function can be called by Excel and how data can be passed to the function.

To execute the function, do the following:

  • Start UniPlot. Open the UniScript Command window (View=>Command Window).

  • Start Excel. Open the file UniPlot\Samples\Ole\AX-Data.xls. Excel may display a dialogbox with a message saying that the file contains macros. Select the button Activate Macros.

    Arrange the two applications side by side on your monitor.

  • Select some cells in the Excel sheet. You’ll see that the data will be displayed in the UniScript Command window when you change the selection.

How does the data exchange between Excel and UniPlot/UniScript work?

Two scripts have been written. The Visual-Basic for Applications script, which is located in the Excel file UniPlot\Samples\Ole\AX-Data.xls and a UniScript function that you can find in the file UniPlot\AutoLoad\AX-Data.ic. Together these small script programs allow the data exchange between Excel and UniPlot

Lets have a look at the Excel script. To view the program open the Excel file and select Tools=>Macro=>Visual Basic-Editor (Alt+F11).

Dim app As Object

Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
    On Error GoTo Error
    Set app = CreateObject("UniPlot.Application")
    app.Visible = 1
    n = app.Call("AX_DataTest", Target)
Error:
End Sub

The code line Dim app As Object creates a global variable. It was not created inside the function to avoid it being destroyed when the function exits.

The Worksheet_SelectionChange function will be called by Excel when the selection in the table changes. A range object is passed as the first parameter by the name Target.

Set app = CreateObject("UniPlot.Application") creates a reference to a running UniPlot instance. The function is equivalent to the CreateObject function in UniScript.

The app.Visible = 1 statement makes the UniPlot window visible if it was hidden.

The code line n = app.Call("AX_DataTest", Target) calls a UniScript function. The first parameter is a UniScript function name, (in this example AX_DataTest) followed by the function parameters. The number of parameters is limited to 16.

Now lets have a look at the UniScript function AX_DataTest.

The first parameter is the Excel range object. Here we use only the Row and Count property. You will find a complete description of all properties and methods of the range object in the Excel Online help system.

def AX_DataTest(t)
{
    if (t.Rows.Count > 100) {
        print "Rows > 100"
    } else {
        print t.Value
    }
}

7.7.7. Example 2 (AX-Curv)

To run the second example, do the following:

  • If UniPlot is running, quit UniPlot.

  • Start Excel. Open the file :file:` UniPlot\Samples\Ole\AX-Curv.xls`. Excel may display a dialog box with a message saying that the file contains macros. Select the button Activate Macros.

  • The second spreadsheet contains two UniPlot objects each showing one diagram. To send data to the left diagram select the values 1, 4, 2, 2, etc. Data will be sent to the right diagram when the first value is not equal to 1.

    ../../_images/OLE_Excel_Curve.png
    Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
        Dim arr(100) As Double
    
        On Error GoTo Error
    
        Worksheets("Sheet 1").OLEObjects(1).Enabled = True
        Worksheets("Sheet 1").OLEObjects(1).AutoLoad = True
        Worksheets("Sheet 1").OLEObjects(2).Enabled = True
        Worksheets("Sheet 1").OLEObjects(2).AutoLoad = True
    
         hDocLeft = Worksheets(1).OLEObjects(1).Object.Handle
        hDocRight = Worksheets(1).OLEObjects(2).Object.Handle
    
        t1$ = Cells(22, 2).Value
        t2$ = Cells(23, 2).Value
        i = 0
        For Each Cell In Target.Cells
            arr(i) = CDbl(Cell.Value)
            i = i + 1
        Next
        Set app = Worksheets("Sheet 1").OLEObjects(1).Object.Application
        n = app.Call("AX_CurveTest", hDocLeft, hDocRight, arr, i, t1$, t2$)
    Error:
    End Sub
    
def AX_CurveTest(hDoc1, hDoc2, y, n, t1, t2)
{
    if (y[1] == 1.0) {
        hPage = DocGetActivePage(hDoc1);
    } else {
        hPage = DocGetActivePage(hDoc2);
    }
    if (hPage == 0) {
        return 0;
    }
    hLayer = PageGetAllDataLayers(hPage)
    hData = LayerGetAllDatasets(hLayer);
    if (hData == 0) {
        hData = XYCreate("test", 1, 1);
        LayerAddDataset(hLayer, hData);
    }
    if (n > 1) {
        x = 1:n;
        ret = XYSetData(hData, x, y[x]);
    }
    LayerAutoScale(hLayer)
    LayerSetAxisTitle(hLayer, "x", t1)
    LayerSetAxisTitle(hLayer, "y", t2)
    __FF_FieldUpdate(0, hPage, 0, 0, 0);
    PageReplot(hPage);
    return n;
}

7.8. The Debugger

Debugging is the process of correcting or modifying the code in a UniScript function.

../../_images/Debugger.png
  • Open the file UniPlot\Script\do_new.ic.
  • Set the cursor in line 62 (def _DoFileNew()). Press F9 (Toggle-Breakpoint) to set a breakpoint. At the left side a break point simble will be set (red dot).
  • Execute the command File=>New. The execution will stop at the breakpoint and a yellow arrow will be displayed.
  • With F10 to single-step through instructions in the program. With F5 you can run to the next break point.

The UniScript debugger supports the following functions:

Example of debbuging a UniScript function:

F5
Go: Executes code from the current statement until a breakpoint or the end of the program is reached, or until the application pauses for user input.
F9
Set/remove a break point.
Ctrl+F9
Remove all break points.
F10
Step Over: Single-steps through instructions in the program.
F11
Step Into: Single-steps through instructions in the program, and enters each function call that is encountered.
../../_images/DebuggerVarWindow.png

Mostly it is more convenient to display variable contents using tool tips. To display the values place the mouse cursor an a variable and wait until a small window with the value is displayed. If a variable contains more than 20 elements, only the first 20 will be displayed.

7.9. Some Annotations about Functions

  • UniScript allows recursive function calls. A recursive function is one which calls itself either directly or indirectly.

  • In contrast to C, UniScript passes function parameters by reference and not by value. This makes it possible for a function to change the values of a parameter. So be careful and create copies of the parameters:

    // INCORRECT
    def asin(x)
    {
          // WRONG !!!!!!
          x = -1i .* log (1i .* x + sqrt(1 - x .* x));
          if (all(all(real(x) == x))) {
              return real(x);
          } else {
              return x;
          }
     }
     // CORRECT
     def asin(xx)
     {
          x = xx; // Use a copy
          x = -1i .* log (1i .* x + sqrt(1 - x .* x));
          if (all(all(real(x) == x))) {
              return real(x);
          } else {
              return x;
          }
     }
    
  • The function what returns a list of all loaded functions.

  • The UniScript source code file can be loaded with the load function. The function call can be included into the file startup.ic.

  • To reduce the loading time of the UniScript user function, a UniScript library is loaded during the execution of the startup file. The name of the function which loads the library is loadiclib. To create a UniScript library (default name: rs_sl.icl), use the following command:

    saveiclib("c:/uniplot/program/rs_sl.icl")
    

id-618984