Legato
Legato

GoFiler Legato Script Reference

 

Legato v 1.5d

Application v 5.25a

  

 

Chapter FourFlow Control

4.1 Introduction to Program Flow Control

4.1.1 Overview

Program flow control refers to the order in which a program executes code. A simple program, such as the one shown below, begins execution at the program entry point (which is in this case implicit) and continues until the program ends:

string s1;

 

s1 = "Hello, World!";

MessageBox(s1);

 

This is an extremely straightforward program. It consists of a variable declaration (s1), assignment of a value to that variable, and a function to display the information. The script ends after the final line of code. A script can be more explicit by defining a start point and an end point:

int main {

string s1;

 

s1 = "Hello, World!";

MessageBox(s1);

return 0;

}

 

These both represent fairly straightforward execution. The script is executed, line by line, until the end of the script is reached. However, a major power in programming is the ability to alter program flow through functions and programmatic constructs. This allows conditional code execution, and therefore flow can be altered for any number of reasons, such as adjusting for user input and error processing.

Some of the most common flow keywords concern conditional execution and loops. In particular, the if, else, while, and for keywords can be used to build complex structures that control program flow. The following is a simple example of a conditional statement nested inside a loop:

int main {

int i;

while (i < 10) {

if (i % 2 == 0) {

MessageBox("%d is an even number less than 10", i);

}

else {

MessageBox("%d is an odd number less than 10", i);

}

i++;

}

return 0;

}

 

In this program, a small loop iterates through integers from 0 to 10. Each time the loop executes, the value of i is checked through the modulus operator to determine if it is divisible by 2. If there is no remainder, the value of i is even, and a message box is used to display that information. If the remainder does not equal zero, the value of i is odd, and a message box is used to display that. The loop iterates until the conditional expression of i less than 10 is met, and then flow leaves the loop and the script completes execution.

Flow control is essential to proper code execution. Legato keywords, constructs, and functions can be used in conjunction to create scripts that react properly to changing input, variable information, and errors and exceptions.

4.1.2 Statement Keywords Versus Functions

Both statement keywords and functions can shift program execution from a particular line of code to a different location within the script. Statement keywords (including if, else, for, do, and while) directly control the flow of execution through conditional statements and loops. Statement keywords cannot return a value, though expressions are often evaluated to a boolean TRUE or FALSE value in conjunction with a statement keyword.

Conversely, functions can return values to the calling routine, but they do not directly control the flow of a script. Script execution jumps to the function when the function is called but returns immediately to the code subsequent to the call once the function has completed.

4.1.3 The Script Engine

As part of flow control, entire scripts can be called, run, held in memory and later released. This is generally the case when a script is ‘hooked’ to a menu function or attached to a Forms View or other edit windows. On the other hand, certain scripts may be transient, running and performing a task and then released.

When a script is run, a Legato Script Engine Class (SEC) is created and the script program and all of its associated files are loaded. Each script run has its own script engine including global variables and resource management.

SECs can live beyond the execution of a script. For example, a script serving as a hook may be loaded and held in memory until the parent application is terminated or the SEC is forcibly retired. This allows a script to initialize and hold global information that can be repeatedly referenced and modified. Further, since the SEC holds the executable version of the assembled script program, it does not have to be loaded and parsed for each parent call into the script which significantly improves performance.

The following outlines the overall SEC structure.

In the diagram above, on the left, is a script file (or a simple pool of text as a script) that is fed to the Preprocessor. The preprocessor’s principal task is to create a map of the overall script program by loading all the included components (including the default SDK header) and skipping any processing according to directives. The result is a combination of “p-code” or program code and symbols. Each user defined symbol, function or variable is stored and later resolved. Once the preprocessor completes, all referenced files are released (they are actually loaded and released in a single step). If the script has been crunched and compressed, it is decompressed prior to processing. Finally, if a security signature is available (or required), it is tested prior to continuing.

On the right is the Execution Engine. Before any of the script code is executed, all global variable declarations are resolved. Depending on how the parent runs the script with the SEC, the engine runs default global code, the entry point, main or a function as specified. The execution engine will continue to run until: (i) the last global line of code is executed (if default entry); (ii) the top level function returns (or top brace is encountered); or, (iii) an exit function is encountered at any point. Upon exit/return, the parent can call the SEC again from any declared function entry point. This allows for very efficient access and repeated access to scripts.

The execution engine references the p-code, global variable pool and program stack which also contains a local variable for each function located on the program stack.

Once SEC is unloaded, the global variable pool is released. Since any open object handles are closed when the variable pool is unloaded, global unclosed handles will remain open until the SEC itself is unloaded.

In a larger sense, multiple SECs can exist and be utilized within the parent application. An SEC can reference numerous external resources including application components and other SECs.

The process essentially starts with some sort of parent action. In the simplest sense, it could be a ‘run’ from the IDE or it could be a menu hook invoked. In a more complex sense, the Parent Actions could be a series of events such as ‘update caret position’ or ‘edit cell’. If the SEC is not set up, then a complete initialization occurs and the Preprocessor is run. If the script is already initialized, then the action runs a function and receives the thread on return.

On a side note, most hooks will reload the script if the source file date and time changes. This allows for progressive debugging while the parent application is running.

Once initialized, the SEC will execute the requested function. The SEC Global Variable Pool is static as well as objects that are allowed by the script to remain open. As part of the SEC then, a large number of application functions and a suite of operating system functions are available to the script. The SEC can then interact with various data sources and modules as defined on the right side of the figure.