The ScriptEase Language

This chapter is an introduction to and a description of the ScriptEase programming language for those unfamiliar with C programming. C programmers should proceed to Chapter 4: ScriptEase vs. C.

This chapter describes the commands and operations of the ScriptEase language. This language is used by all products in Nombas product suite. As you go through this chapter, don't be alarmed by all the different symbols and combinations of characters. As you use them, they become second nature. Don't attempt to memorize everything in this chapter. Think of it more as a reference chapter. Read through it once or twice to familiarize yourself with the terms, then take a look at some of the samples in the next chapter.

Program Structure

Computers, contrary to popular opinion, are not intelligent. They are able to carry out simple calculations (add, subtract, multiply, divide) at a dizzying speed, and make tests to see if a is equal to b , for example, but that's pretty much it. Even though the computer can perform these tasks far more quickly and accurately than humans, it never thinks about what it is doing. A computer cannot make decisions. The closest it can come to thinking is to see if a condition is met and then perform an action based on the results of that condition. If a certain button must be pressed to save the world, the computer won't do it unless it is told to do it, or programmed to do it when a certain number of conditions are met (e.g., if this event happens and that event happens, press the button). It will never realize the world needs saving and press the button on its own.

A computer language is designed to give instructions to computers in a way they can understand, so that they can carry out their programmed task. This means that before you write a program, you must have a good idea how to go about doing the task yourself. As in real life, this is easier (and less daunting) if you break the given task down into smaller, easier to handle sections.

For example, let's suppose you have a list of friends whom you wish to call and leave a message about your weekend plans. This can be broken down into four major steps:

In code, this would look like this:

while( ThereAreUncalledNamesOnTheList() != FALSE){





Now you have a framework for your program, and a clear idea of the sub-tasks that need to be accomplished to achieve your goal. By breaking the task into smaller pieces, it is easy to translate your thoughts into ScriptEase. (In computer terminology, each of these steps is called a function. A function has a name followed by a pair of parenthesis, which may or may not have anything in them).

Another advantage to breaking your task up comes when you need to make changes. If you need to make a change in your main task, you don't need to rewrite the entire program, just the part where the change occurs. For example, if you want to leave a different message the next time you run the program, you only need to change the `LeaveTheMessage()' section of the program.

Whitespace Characters

Characters that govern the spacing of text are called whitespace characters. The white characters are the space, tab, carriage return and newline. Whitespace makes the code more readable for humans, but is ignored by the interpreter, with the following exceptions.

A line ends with a carriage return, and each line is usually a separate statement (a more detailed explanation of statements and lines comes later in this chapter). The following three lines are interpreted identically:


x = a + b

x = a + b

as is:

x = a

+ b

Also, a space indicates the end of a variable name. "a b" represents two variables, "a" and "b"; "ab" represents only one.

Tabs are usually not used in writing code, because tab settings are different for different users and what looks good on one system may look awful on another. Instead of using tabs, use two or three spaces.


Although computer languages are easy for computers to understand, they can get pretty obscure for humans. Comments are used by the programmer to explain to himself and to others what the code does. Comments help bridge the gap between computer language and human language. If a section of code is commented, you know exactly what that section of code does, and why it is there, without having to decipher it. If you need to modify a script at some time in the future, you will thank yourself for placing comments in your program. When the program runs, comments are ignored by the ScriptEase interpreter.

In ScriptEase, two slash characters (//) signal the beginning of the comment; the comment extends to the end of the line. Anything after the two slashes is considered a comment and is ignored by the ScriptEase interpreter. Likewise, anything between a slash-asterisk (/*) and an asterisk-slash (*/) is a comment (this type of comment may extend over many lines). Here are some examples of comments:

// this is a comment line



*** This is one big comment ***

*** block. Isn't it pretty? ***



FavoriteAnimal = "dog"; // I really prefer cats, but I'm allergic


//This line is a comment but

this line is not.

Data Types

The ScriptEase interpreter uses different methods to store the different types of data in memory. It determines the data type of a number by how it is used and by how it appears in the code. There are three basic data types in ScriptEase, as follows:


A character (e.g., `A', `B', `C', `D') or a whole number from 0 to 255


A whole number value; this is the most common numeric data type: examples: 0, -1000, 567, 4335600)


floating point numbers; any number containing a decimal point (examples: 0.567, 3.14159, -5.456e-12)

There are times when you will want to explicitly specify the data type of a certain variable. You can do this by declaring the variable equal to zero, and formatting the zero according to how you want your variable cast, e.g.:

variable = 0 //variable is an integer

variable = 0.00 //variable is a float

variable = `\0' //variable is a byte

Here is a list of numbers in various formats and their corresponding data types:


// integer


// integer


// integer in hexadecimal format


// integer


// float


// float


// byte


// byte in octal format

In addition to byte, float and integer, there are two more data types: arrays and structures. These are described more fully later on in this chapter.

Escape Sequences for Characters

Certain bytes (characters) are represented with a multi-character sequence beginning with a backslash (\). There is no need to memorize these characters. It is important, however, to remember that they exist. Many of them are used to format output. These special combinations of characters are called escape sequences, and have the following meanings:


Audible bell








Carriage return




Vertical tab


Single quote


Double quote


Backslash character


Octal number (e.g., `\033' is escape character, `\0' is null character)


Hex number (e.g., `\x1B' is escape)

Note that these escape sequences cannot be used within back-tick strings (see page 23). Also, any integer value starting with 0 is treated specially. 0 alone signifies octal, 0x specifies hexadecimal.


A variable is a symbol that may be assigned data. Variables are used as places to store and represent information in the program you are writing. ScriptEase variable names can be any length within reason. The following naming guidelines must be followed:

All other characters are legal. The interpreter ignores case, so sid is equivalent to Sid as far as ScriptEase is concerned. The following are valid variable names:






The following variable names are not valid:




Sid and Nancy


Data is assigned to a variable with an equal sign (=). The first time a variable is used, its type is determined.

Count = 1 ; // Count is an integer

Character = `A'; // Character is a byte

interestRate = 7.65; // interestRate is a float

After variables have been assigned, they can be treated as their data type. So, after these statements:

Count = 1; // assign count as the integer 1

Count = Count + 2; // same as: Count = 1 + 2

Count now has a value of 3.

Environment Variables

In previous versions of ScriptEase:Desktop (CEnvi), a variable written entirely in UPPERCASE letters was automatically considered to be an environment variable. This is no longer the case; use the getenv() function to access your operating systems environment variables and the putenv() function to modify them (see the ScriptEase Standard Library chapter for documentation of this function).

If you have scripts in CEnvi that rely on this feature, contact Nombas for a script that will convert your old scripts over to the new format for handling environment variables.

Expressions, Statements, and Blocks

A expression or statement is any sequence of code that performs a computation or takes an action (e.g., "Count=1", "(2+4)*3"). ScriptEase code is executed one statement at a time in the order in which it is read. A semicolon (;) may be put at the end of a statement (this is required in C, and is recommended in ScriptEase to improve readability). Each program statement is usually written on a separate line to make the code easy to read.

Expressions may be grouped to affect the sequence of processing: first all multiplications and divisions are calculated for the expression, and then all additions and subtractions. Expressions inside parentheses are processed first. Notice that:

4 * 7 - 5 * 3; // 28 - 15 = 13

has the same meaning, due to algebraic operator precedence, as:

(4 * 7) - (5 * 3); // 28 - 15 = 13

but has a different meaning than:

4 * (7 - 5) * 3; // 4 * 2 * 3 = 8 * 3 = 24

which is still different from:

4 * (7 - (5 * 3)); // 4 * (7 - 15) = 4 * -8 = -32

Even though parentheses may not be necessary, it's usually a good idea to use them anyway, to avoid any possible confusion for you or the computer.

A block is a group of statements enclosed in curly braces ({}). The braces indicate that the enclosed statements are a group and are to be treated as one statement, containing multiple sub-statements. A block can be used anywhere a statement can be used.

The first example of this chapter has a statement block:

while( ThereAreUncalledNamesOnTheList() == TRUE){





GetNameFromTheList, CallthePerson, and LeaveTheMessage are all grouped together within braces to show that they should be treated as a unit. If the braces were left out, the while statement would only apply to the first line following it. In this case, the program would go through and get every name on the list, and then call only the last one.

The indentation of statements is not necessary, but is recommended for readability.

Mathematical Operators

ScriptEase code usually contains some mathematical operations, such as adding numbers together, multiplying, dividing, etc. These are written as you'd expect, i.e., write "2 + 3" when you want to add two and three. The next few subsections define the mathematical operators used in ScriptEase followed by a line of sample code.

Basic Arithmetic

The arithmetic operators in ScriptEase are pretty standard


assignment: sets a variable's value


addition: adds two numbers


subtraction: subtracts a number






modulo: remainder after division

Here are some examples using variables and arithmetic operators:

i = 2;

// i is 2

i = i + 3;

// i is now (2+3) or 5

i = i - 3;

// i is now (5-3) or 2 again

i = i * 5;

// i is now (2*5) or 10

i = i / 3;

// i is now (10/3) or 3 (the remainder is ignored)

i = 10;


i = i % 3;

// i is now (10%3) or 1

Assignment Arithmetic

Each of the above operators can be combined with the assignment operator (=) as a shortcut for performing the operation with the first variable and then assigning the result to the same variable. Using assignment arithmetic operators, the above code could be simplified as follows:


assignment: sets a variable's value


assign addition: adds number


assign subtraction: subtracts a number


assign multiplication


assign division


assign remainder: remainder after division

Here are some examples using assignment arithmetic

i = 2;

// i is 2

i += 3;

// i is now (2+3) or 5; same as i = i + 3

i -= 3;

// i is now (5-3) or 2 again; same as i = i - 3

i *= 5;

// i is now (2*5) or 10; same as i = i * 5

i /= 3;

// i is now (10/3) or 3; same as i = i / 3

i = 10;


i %= 3;

// i is now (10%3) or 1; same as i = i % 3

Auto-Increment (++) and Auto-Decrement (--)

Other arithmetic shortcuts are the auto-increment (++) and auto-decrement (--) operators. These operators add or subtract 1 (one) from the value to which they are applied. ("i++" is a shortcut for "i += 1", which is itself shortcut for "i = i + 1").

These operators can be used before (prefix) or after (postfix) their variables. If used before, then the variable is altered before it is used in the statement; if used after, then the variable is altered after it is used in the statement. This is demonstrated by the following code:

i = 4;

// i is initialized to 4

j = ++i;

// j is 5, i is 5 (i was incremented before use)

j = i++;

// j is 5, i is 6 (i was incremented after use)

j = --i;

// j is 5, i is 5 (i was decremented before use)

j = i--;

// j is 5, i is 4 (i was decremented after use)

Bit Operators

ScriptEase contains many operators for operating on the binary bits in a byte or an integer. If you're not familiar with binary and hexadecimal numbering, then you may want to skip this section on Bit Operators.


shift left: shift all bits left by value


assignment shift left


i = 0x146

i <<= 2; // shift i (0x146) left 2, so i = 0x518


shift right: shift all bits right by value


assignment shift right


i >>= 3; // shift i (0x518) right 3, so i = 0xA3


bitwise AND


assignment bitwise and


i &= 0x35; // and i (0xA3) with 0x35, so i = 0x21


bitwise OR


assignment bitwise OR


i |= 0xC5; // OR i (0x21) with 0xC4, so i = 0xE5


bitwise XOR: exclusive OR


assignment bitwise XOR


i ^= 0xF329 // XOR i (0xE5) with 0xF329, so i = 0xF3CC


Bitwise complement: (turn 0 bits to 1, and 1 to 0)


i = ~i; // complement i (0xF3CC),

so i = 0xFFFF0C33

Arrays and Strings

An array is a group of individual data elements. Each individual item in the array is called an array element. Elements are distinguished by their offset, an integer in square brackets following the array's name in square brackets. All of the elements of an array must be of the same data type. Arrays are usually associated with a count of something.

For example, suppose you wanted to keep track of how many jelly beans you ate each day, so you can graph your jelly bean consumption at the end of the month. Arrays are ideal for storing this kind of data:

January[1] = 233;

January[2] = 344;

January[3] = 155;

January[4] = 0; (...)

Now you have all your data stored conveniently in one variable. You can find out how many jelly beans you ate on day x by checking the value of January[x].

In the example where we call all of the people on a certain list, it makes sense to use arrays to keep track of the numbers we have called and whom they pertain to. Then you'd have two arrays that look like this:

name[0] = "Mary" number[0] = "555-2383"

name[1] = "Eduardo" number[1] = "555-9331"

name[2] = "Vince" number[2] = "555-4920"

An element of an array is itself a variable, much like any other variable. Any particular element of the array is selected by specifying the element's offset in the array. This offset is an integer in square brackets ( [ ] ). It is important to remember that the first element in an array is found at the 0th offset. For example:

prime[0] = 2;

prime[1] = 3;

prime[2] = 5;

month[0] = "January";

month[1] = "February";

month[2] = "March";

Also, an offset can be a variable (or anything else that evaluates to an integer):

prime[x] = y

A ScriptEase array does not need to be predefined for size or data type, as it does in other languages. Any array theoretically extends from minus infinity to plus infinity (within reasonable computer memory limits). The data type for the array is the type of the data first assigned to it.

If ScriptEase code begins with:

foo[5] = 7;

foo[2] = -100;

foo[-5] = 4;

then foo is an array of integers and the element at index 5 is a 7, at index 2 is -100, and at index -5 is 4. foo[5] can be used in the code anywhere that a variable could be used. Any array elements that are not otherwise defined are equal to zero, so if you asked the computer for the value of foo[3] in the above example, it would return 0.

Array Initialization

Arrays can be initialized by initializing specific elements, as in:

foo[5] = 7;

foo[2] = -100;

foo[-5] = 4;

or by enclosing all the initial statements in curly braces, which will cause the array to start initializing at element 0, as in:

foo = { 0, 0, -100, 0, 0, 7 };


One of the most common uses of arrays is to store lines of text; an array used in this way is called a string. Strings usually have a null byte (`\0') at the end to let the computer know where the string ends. In the preceding example, "Mary" and "555-2383" are both strings. Strings are enclosed in quotes to distinguish them from variables. When you assign a string to a variable

string = "Mary";

you are creating an array called string with five elements:

string[0] = `M'

strng[1] = `a';

string[2] = `r';

string[3] = `y';

string[4] = `\0'

Notice that the first element is at offset 0. This is the default starting place for strings; the string continues until a null character (the 0 in string[4]) is reached. When a string is created, a null character is appended to the end to indicate where it ends.

Escape sequences encountered in strings will be translated into their byte value. So you'll often see strings such as "\aHello world\n" where the `\a' means to beep and the `\n' means to put a newline character at the end of the string.

Single quote strings

You can declare a string with single quotes instead of double quotes. This will create a string without a terminal null character. Single quotes strings are rarely used.

Back-quote strings

ScriptEase provides the back-quote (`), also known as the back-tick or grave accent, as an alternative quote character to indicate that escape sequences are not to be translated. Any characters represented with a backslash followed by a letter (`\n', e.g.) cannot be used in back-tick strings.

For example, here are two ways to describe the same file name:

"c:\\autoexec.bat" // traditional C method

`c:\autoexec.bat` // alternative ScriptEase method

Literal Strings

A literal string is a string within double or back-tick quotes. In some cases (during assignment, comparison, passing to function, returning from function, and case statements), ScriptEase treats literal strings slightly different than other arrays. Literal strings can be treated directly as data, avoiding the string handling routines required of C. If you are familiar with C programming, you may want to read the "Literal Strings" section in the "ScriptEase vs. C" chapter for more information on the special treatment of literal strings.

Long Strings

If you have a lot of text that you want to put into a string, you can do it by putting the strings one after another when you define the string variable. For example:

badJoke = "I was standing in front of an Italian "

"restaurant waiting to get in when this guy came "

"up and asked me, \"Why did the Italians lose the "

"war?\" I told him I had no idea. \"Because they "

"ordered ziti instead of shells,\" he replied."

This creates a long string containing the entire bad joke.

Copying Strings

Because a string is a special compound data form, when you copy string variables you should use the strcpy() function. If you try to use the equality operator, your script will behave erratically.

For example, let's suppose you have the following string,

string = "earwig"

and you wanted to copy it to another string called stringdata. You do this with the strcpy() function as follows (more information on functions appears later in this chapter):

strcpy(stringdata, string);

The statement

stringdata = string

will also copy the string, but not in the way you want. It will make a copy of the variable itself, instead of copying the contents of the variable into another. In effect, this statement says, "set the variable stringdata to refer to the information stored in the same place as the information stored in the variable string." The two variables will refer to the same chunk of memory. They are two different names for the same thing (as opposed to two different variables containing the same thing), so when you change one, you change the other.

Array Arithmetic

When one array is assigned to the other, as in:

foo = "cat";

goo = foo;

both variables define the same array, point to the same place in memory, and start at the same offset 0. In this case, if foo[2] is changed then you will find that goo[2] has also been changed. Integer addition and subtraction can also be performed on arrays. Array addition or subtraction sets where the array is based. By altering the previous code segment to:

foo = "cat";

goo = foo + 1;

goo and foo would now be arrays containing the same data, except that now goo is based one element further, and foo[2] is now the same data as goo[1]. To demonstrate:

foo = "cat";

// foo[0] is `c', foo[1] = `a'

goo = foo + 1;

// goo[0] is `a', goo[-1] = `c'

goo[0] = `u';

// goo[0] is `u', foo[1] = `u', foo is "cut"


// goo[0] is `t', goo[-2] = `c'

goo[-2] = `b'

// goo[0] is `t', foo[0] = `b', foo is "but"

The script TReplace.cmm, analyzed in the next chapter, provides a working example of array arithmetic.

Multi-Dimensional Arrays: Arrays of Arrays

Since an array element is a variable, if the type of that element's variable is itself an array, then you have an array of arrays. A statement such as:

goo[4][2] = 5;

indicates that goo is an array of arrays, and that element 2 of element 4 is the integer 5. The examples in the beginning of the section on strings (e.g., name[0]="Mary") are also examples of multi-dimensional arrays.

Multi-dimensional arrays would come in handy for programming a tic-tac-toe game, for instance. Each row and column of the 3 x 3 board could be represented with a row, column element containing `X', `O', or ` ` (blank) depending on the character at that location. For example, filling the middle row with Xs would be initialized like this:

board[1][0] = `X';

board[1][1] = `X';

board[1][2] = `X';

Since a string is an array of characters, anytime you make an array of strings you are defining an array of arrays. For example,

Weekdays = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};

creates an array of strings so that

Weekdays[0] is set to "Monday"

Weekdays[0][0] is set to `M'

Weekdays[0][1] is set to `o'

Weekdays[0][2] is set to `n'

Weekdays[1] is set to "Tuesday"

Arrays: further discussion and explanations

Arrays are perhaps the most confusing parts of ScriptEase. However, they allow you to do a great deal and are well worth the effort it takes to understand them. They allow you to group different variable values together under a common name. It may help to think of a series of numbered boxes, beginning at 0 and continuing on indefinitely. Each box can hold a different value: box[0] can be 5, box[1] can be 23, box[64] can be 88, etc.

The confusion comes in when you try to use array variables in equations. Generally, if an array name appears with a number in brackets, it is a variable representing whatever is in the array at that point, e.g.

bag = box[64]

will set the value of the variable bag to 88 (or whatever value is held in the array at that point).

If, however, the array name appears without the following brackets and number, it stands for the entire array. This situation is most often encountered with strings. When an array holds a string, each box holds a different letter of the string. For example:

string = "duck lips'

is the same as:

string[0] = `d'

string[1] = `u'

string[2] = `c'

string[3] = `k'

string[4] = ` `

string[5] = `l'

string[6] = `i'

string[7] = `p'

string[8] = `s'

string[9] = `\0'

The variable string represents the entire array. The null character (`\0') marks the end of the string. When a string value is set equal to something in double quotes (e.g., string = "duck lips") a null character is automatically appended as the last member of the string. If the null character is moved, the end of the string (but not of the array) moves with it. If you set

string[4] = `\0'

and then output string to a file using a string function, the file will only receive "duck".

Array arithmetic is a way of changing the starting point of that array. In our row of boxes analogy, this is equivalent to renumbering all the boxes (while keeping them in order). So if we set

fling = string + 1

we are setting fling to be equal to string, only fling[0] is `u'. The d (of duck) is now at fling[-1]. The array still starts at 0; if you output fling to a file, the file will contain "uck lips".


A structure is a collection of named variables that belong together as a whole. Each of the named variables in a structure is called a member of that structure and can be any data type (integer, float, array, another structure, array of structures, etc.). These structure members are associated with the structure by using a period (.) between the structure variable and the member name.

A simple and useful example of a structure is to specify a point on the screen. A point consists of a row and column. You might specify:

place.row = 12; // set to row 12

place.col = 20; // set at column 20

place.row--; // move up one row to row 11

Two structures can be compared for equality or inequality (which compares same-named, defined members of the structure), and they may be assigned, but no other arithmetic operations can be performed on a structure.

Like any other data type, structures can be combined into arrays. The two arrays used for storing phone numbers described at the beginning of the array section could be combined into one using structures:

person[0].name = "Mary"

person[0].number = "555-2383"

person[1].name = "Eduardo"

person[1].number = "555-9331"

person[2].name = "Vince"

person[2].number = "555-4920"

The -> operator

The -> operator is a shortcut for "[0]." Using the structure example above, person->name is equivalent to "Mary."

Logical Operators and Conditional Expressions

A conditional expression is evaluated to be TRUE or FALSE, where FALSE is represented by zero, and TRUE means anything that is not FALSE (i.e., not zero). A variable or any other expression by itself can be TRUE or FALSE (i.e., non-zero or zero). ScriptEase has predefined values for TRUE and FALSE. Think of FALSE as being a variable that contains the value 0, and TRUE as a variable set to non-zero. Note that there can be many values that are evaluated as true; everything, in fact, except 0. Therefore it is safer to compare things to FALSE (with only one possible value) than to TRUE (with many). These expressions can be combined with logic operators to make complex TRUE/FALSE decisions.

As an example, let's suppose you were designing a simple guessing game. The computer thinks of a number between 1 and 100, and you guess what it is. The computer will tell you if you're right or not, and whether your guess is higher or lower than the target number. The script might have a structure similar to the one below (GetTheGuess() is a function that gets your guess).

guess = GetTheGuess(); //get the user input

if (guess > target_number){

...guess is too high...

if (guess < target_number){

...guess is too low...

if (guess == target_number){ guessed the number!...


This is a very simple example, but it illustrates how logical operators can be used to make decisions in ScriptEase.

The logical operators are:


NOT: opposite of decision




!(`D') // FALSE

!(5-5) // TRUE


AND: TRUE if and only if both expressions are true




!(5-5) && 4 // TRUE

0 && (foo+2) // FALSE:

(foo+2) is not evaluated;

(since both expressions must be true for the statement as a whole to be true, if the fist expression is FALSE there is no need to evaluate the second expression, since the whole expression is false)


OR: TRUE if either expression is TRUE



0 || 0.345 // TRUE

!(5-3) || 4 // TRUE

TRUE || FALSE // TRUE: doesn't even check FALSE

TRUE || (4+2) // TRUE: (4+2) is not evaluated

FALSE || (4+2) // TRUE:

FALSE || (4+2) // TRUE: (4+2) is evaluated

(since only one of the expressions in the OR statement needs to be true for the expression to evaluate as true, if the first expression evaluates as true the processor returns TRUE and doesn't bother with evaluating the second)


EQUALITY: TRUE if the values are equal, else FALSE

* DO NOT CONFUSE this with `=' used for assignment *


5 == 5 // TRUE

5 == 6 // FALSE


INEQUALITY: TRUE if the values are not equal, else FALSE


5 != 5 // FALSE

5 != 6 // TRUE




5 < 5 // FALSE

5 < 6 // TRUE




5 > 5 // FALSE

5 > 6 // FALSE

5 > -1 // TRUE




5 <= 5 // TRUE

5 <= 6 // TRUE

5 <= -1 // FALSE




5 >= 5 // TRUE

5 >= 6 // FALSE

5 >= -1 // TRUE

Notice the difference between one equals sign (=), used to state that a variable has a certain value; and two equals signs (==), used to test for equality. If you use one equals sign when you mean two, your script will not function the way you want it to. This is a common pitfall even among experienced programmers. Unfortunately, the two meanings of equals must be kept separate, since there are times where you have to use them both in the same statement and there is no way the computer can differentiate them by context.

Normally, if a logical operator is comparing two variables that are arrays, then the comparison tests whether and how they point to the same data. But if either side of a logical operator is a literal string, then that operation compares the contents of the strings (similar to a comparison by the strcmp() function).

For example:

firstword = "green"

thirdword = "green";

If you compare

firstword == "green" TRUE

thirdword == "green" TRUE

thirdword == firstword FALSE

in the first two examples, you are comparing the contents of the variables, which are equivalent. In the third example, you are comparing the variables themselves. Firstword and thirdword are different variables (although at the moment they both contain the same string), residing in different places in computer memory; so they are not equal to each other.

Flow Decisions: Loops, Conditions, and Switches

This section describes the statements that control the flow of your program. You use these statements to tell your program how to make decisions. You'll notice code sections are often indented, when blocks belong together; this makes the code much easier to read.

if statement

The if statement is the most commonly used mechanism for making decisions in a program. It allows you to test a condition and act on it. If an if statement finds the condition you test to be TRUE, the block or statement of code following it will be executed: If you are hungry, then eat something. This is an example of an if statement.

if ( goo < 10 ) {

printf("goo is smaller than 10\n");


else statement

The else statement is an extension of the if statement. It allows you to tell your program to do something else if the condition in the if statement was found to be FALSE. For example: if you are hungry eat something, else go to the gym. In ScriptEase code, it looks like this.

if ( goo < 10 ) {

sprintf(HTMLstring, "goo is smaller than 10\n");


else {

sprintf(HTMLstring, "goo is not smaller than 10\n");


To make more complex decisions, else can be combined with if to match one out of a number of possible conditions. For example: if you are hungry then eat something, else if you like to go to the gym go to the gym, else go for a walk. The following code illustrates this concept.

if ( goo < 10 ) {

printf(goo is less than 10\n");

if ( goo < 0 ) {

printf("goo is negative; so it's less than 10\n");



else if ( goo > 10 ) {

sprintf("goo is greater than 10\n");


else {

sprintf("goo is 10\n");


while statement

The while is used to execute a particular section of code over and over again until an expression evaluates as FALSE.

while (expression){



When the interpreter comes across a while statement it first tests to see whether the expression is true or not. If it is, it will carry out the statement or block following it (in this case the function DoSomething()). Then it will test the expression again. This loop repeats until the test evaluates to FALSE, whereupon the program continues after the block of code associated with the while statement.

The first example in this chapter uses a while statement:

while( ThereAreUncalledNamesOnTheList() != FALSE){





do {...} while

This is different from the while statement in that the code block is executed at least once, before the test condition is checked.

do {



} while( value < 100 );

The code used to demonstrate the while statement could also be written this way:

do {




} while (name != TheLastNameOnTheList());

Of course, if there are no names on the list, the script will run into problems!

for statement

The for statement is a special looping statement. It allows for more precise control of the number of times a section of code is executed. The for statement takes the following form.

for ( initialization; conditional; loop_expression ){



The initialization is performed first. Then the conditional is tested. If the conditional is TRUE (or if there is no conditional expression) then statement is executed. Then the loop_expression is executed, and so on back to testing the conditional. If the conditional is FALSE then statement is not executed and the program continues beyond statement. The for statement is a shortcut for this form of while:


while ( conditional ) {




None of the statements that appear in the parenthesis following the for statement are mandatory, so the above code demonstrating the while statement would be rewritten this way if you preferred to use a for statement:

for( ; ThereAreUncalledNamesOnTheList() ; ){





Since we aren't keeping track of the number of iterations in the loop, there is no need to have an initialization or loop_expression statement. You can use an empty for statement to create an endless loop:


//the code in this statement block will repeat forever, unless the

//program breaks out of the for loop somehow.


For, do and while statements may be nested inside one another.

break and continue

break and continue are used to control the behavior of the looping statements for, while, and do.

break terminates the innermost loop (for, while, or do). The program resumes execution on the next line following the loop. The break statement is also used at the close of a case statement (see below). This bit of code does nothing but illustrate the break statement:




continue jumps to the test condition in the nearest do or while loop, and jumps to the loop_expression in the nearest for loop (i.e., jumps to the next iteration of the loop).

switch, case, and default

The switch statement is a fancy way of making a decision based on the value of a variable or statement. The switch statement follows this format:

switch( switch_variable ) {

case value1: statement1

case value2: statement2

case value3: statement3

case value4: statement4

case value5: statement5




default: default_statement


switch_variable is evaluated, and then it is compared to all of the values in the case statements (value1, value2, value3, etc...) until a match is found. The statement (or statements) following the matched case are then executed until the end of the switch block is reached or until a break statement exits the switch block. If no match is found, the default: statement is executed if there is one.

For example, suppose you had a series of account numbers, each beginning with a letter that determines what type of account it is. You can use a switch statement to carry out actions depending on that first letter. The same can be accomplished with a series of nested if statements, but that requires a lot more typing and is harder to read.

switch ( key[0] ) {

case `A':

printf("A"); //handle `A' accounts...


case `B':

printf("B"); //handle `B' accounts...


case `C':

printf("C"); //handle `C' accounts...



printf("You have entered an invalid account number.\n");



A common mistake is to omit a break statement. In the preceding example, if the break after the printf("B") statement were omitted the computer would print both "B" and "C", because when a match for a case statement is found, the computer will execute commands until a break statement is encountered.

Normally, if a switch and case statements were referencing array variables, then the comparison would be performed on whether they referenced the same array data. But if either the switch_variable or one of the case values is a literal string, then that comparison of the two strings is made using the contents of the strings (i.e., !strcmp()).

goto and labels

You may jump to any location within a function block (see functions) by using the goto statement. The syntax is:

goto LABEL;

where LABEL is an identifier followed by a colon (:).


a = getche(); //get a value for a


if (a<2)

goto beginning;


printf("%d", a);

gotos should be used sparingly, for they make it difficult to track program flow.

Conditional Operator ?:

The conditional operator is a strange-looking statement that is simply a useful shortcut. It is a limited variation of the IF statement. The syntax is:

test_expression ? expression_if_true : expression_if_false

The entire statement must be on one line.

First, test_expression is evaluated. If test_expression is non-zero (TRUE) then expression_if_true is evaluated and the value of the entire expression replaced by the value of expression_if_true. If test_expression is FALSE, then expression_if_false is evaluated and the value of the entire expression is that of expression_if_false.

For example:

foo = ( 5 < 6 ) ? 100 : 200; // foo is set to 100

sprintf(message, "User's name is %s\n",NULL==name ? "unknown" : name);

To see how the conditional operator is a shortcut, consider that this if/else code to get the maximum of two numbers:

if ( Num1 < Num2 )

MaxNum = Num2;


MaxNum = Num1

is equivalent to this conditional operator code:

MaxNum = ( Num1 < Num2 ) ? Num2 : Num1 ;


printf() is an example of a function: a small, independent unit of code designed to do one task that is a subset of a larger one. In the case of printf, that task is to take data, format it and print it to the screen. Although functions won't be formally defined until the next section, we're going to introduce this one now, so that when we get to the proper definition of functions you will have a better idea of what we're talking about.

printf() Syntax

The printf() function prints a string to the screen (standard output). In its most simple form, it takes the string to be printed as its only parameter.

printf("Hello, world!");

The printf() function returns the number of characters that it printed, so the statement

value = printf("Hello, world!");

sets value to 13, the number of characters in the string "Hello, world!".

printf() takes a template string and one or more variables. It then formats them as text and inserts them into the appropriate places in the string. A printf() statement looks like this:


Template, data1, data2, data3, etc., are all parameters being passed to the function. They may be variables, literal strings, or numerical values.

For example, suppose you had a script with the following variables:

first_name = "Helen"

last_name = "Wheels"

state = "Arizona"

age = 26

crime = "frightens young children"

The following printf() statement

printf("%s %s lives in %s, where she %s. She is %d years old\n", first_name, last_name, state, crime, age)

Would be interpreted as:

"Helen Wheels lives in Arizona, where she frightens young children. She is 26 years old."

"%s %s lives in %s, where she %s. She is %d years old.\n" is the template for the string to be printed. The template is always the first parameter passed to printf(). Whenever a template contains a percent character (%) followed by another character, then instead of putting those characters into the string, sprintf() will substitute the next data item (data1, data2, data3, etc...).

The characters immediately following the percent sign (%) determine how the data will be presented. This example uses two formats: %s, to indicate a string; and %d, to indicate a decimal number. There are many such data formats (see the complete description in chapter 6), but here are a few of the more common ones to start with:


print a percentage sign


print a decimal integer


print a hexadecimal integer


print a character


print a floating-point value


print a floating-point value in scientific format


print a string

There are also special characters that cause unique screen behavior when they are printed, some of which are:


goto beginning of next line


print the quote character


print a backslash

Here are some example printf() statements:

printf("Hello world. This is my %dst ScriptEase program.\n", count);

printf("%c %d %dlips",'I', 8, 6-4);

printf("%d decimal is the same as %X in hexadecimal",n,n);

printf("My name is: %s\n","Mary");

The above statements print out the following strings:

Hello world. This is my 1st ScriptEase program [assuming Count = 1]

I 8 2lips

17 decimal is the same as 11 in hexadecimal [where n=17]

My name is: Mary


If a program you are writing starts to get large and complex, it can be simplified by breaking it up into functions. A function is an independent section of code that receives information from a program and performs some action on it. It may also send a value back to the program that called it.

Once a function has been written, you won't have to think again about how to perform that action; you just call the function and let it handle the work for you. You only need to know what information the function needs to receive (parameters) and the type of information it returns.

printf() is an example of a function, providing an easy way to display formatted text. It receives a template string and variables from the program that called it, prints out the formatted string, and returns the number of characters printed to the program that called it.

Functions can perform actions of any complexity, but are used in statements just like variables. Almost any place where you can use a variable in a statement you can use a function instead. For example, let's suppose you had a function called DoubleAndDivideByFive(number), which takes the variable number , doubles it and divides the result by five (most functions are a little more complex that this). The computer will interpret


just like


This is a simple function, so the value of one method over the other is not clear in this case. But functions can get very complex; instead of "DoubleandDivideByFive()", think "RecalculateBasedOnCurrentInterestRate()."

Any valid variable name may also be a function name. Functions are distinguished from variables by the parenthesis that follow them. Like comments, using descriptive function names helps you keep track of what is going on with your script.

Several sets of built-in functions is included as part of the ScriptEase interpreter. These functions are all described in this manual. They are internal to the interpreter, and may be used at any time. In addition, ScriptEase ships with a number of external libraries or .hmm files. These functions must be explicitly included in your script to use them; see the description of the #include statement on page 40.

ScriptEase allows you to have two functions with the same name. The interpreter will use the function nearest the end of the script; that is, the last function to load is the one that will be executed. This way you can write functions that supersede the ones in the .hmm files.

Function definition

A function takes the following form:




return result;


where the function name is followed by a list of input parameters in parentheses (there can be any number of input parameters and they can be named with any variable names).

A call is made to a function in this format:


So any call to FunctionName() will result in the execution of FunctionName() with the parameters passed, and then be equivalent in the calling code statement to whatever value FunctionName() returns.

If you change the value of a variable passed to a function, it will change the value of the variable throughout the program. If you don't want to have a function change the value of the variables passed to it, make a copy of the variable and make your changes on that. If the variable is a string, you should use the strcpy() function to copy the variable.

Function RETURN Statement

The return statement causes a function to return to the code that initially called the function. The calling code will receive the value that the function returned, and any code in the function following the return statement will be ignored.The value to be returned may be enclosed in parenthesis to increase legibility:

foo1(a,b) // return a times b


return a * b;



foo2(a,b) // return the minimum value of a and b


if ( a < b ){

result = a;



result = b;




Some functions don't return anything, and therefore don't have return statements (or they have return statements but no return value). These functions are called void functions. Void functions return no value to the calling code. These examples demonstrate some void-returning functions:

foo(a,b) // set a = b squared. No return value.


a = b * b;




foo(a,b) // set a = b squared. No return value.


a = b * b;


In a ScriptEase program, these two functions behave identically.

Function Example

This code demonstrates a simple function that multiplies two integers by adding them:

num1 = 4;

num2 = 6;


// use the standard method of multiplying numbers

printf("%d times %d is %d.\n",num1,num2,num1*num2);


// now call our function to do the same thing

printf("%d times %d is %d.\n",num1,num2,Multiply(num1,num2));


// declare a function that multiplies two integers. Notice

// that the integers are defined as i and j, so that's how

// they'll be called in this function, no matter what they

// were named in the calling code. This function will

// return i added to itself j times. (It will fail if j<0).



total = 0;

for ( count = 0; count < j; count++ )

total += i;

return(total); // caller will receive this value


When executed, the above code will return two identical strings, "4 times 6 is 24." This example demonstrates several features of functions. Notice that in calling sprintf() the parameter "num1*num2" is not passed to rsprintf(), but the result of "num1*num2" is. Likewise, "Multiply(num1,num2)" is not a parameter to rsprintf(); instead, rsprintf() receives the return value of Multiply() as its parameter.

Function recursion

A recursive function is a function that calls itself, or calls some other function that then goes back and calls the function that first called it. Recursion is permitted in ScriptEase. Each call into a function is independent of any other call to that function (see section on variable scope). Be aware that recursion has its limits; if a function calls itself too many times the script will run out of memory and abort.

Don't worry if you find recursion a confusing idea; you rarely have to use it. Just remember that a function can call itself if it needs to. For example, the following function, factor(), factors a number. Factoring is an ideal candidate for recursion because it is a repetitive process where the result of one factor is then itself factored according to the same rules.

factor(i) // recursive function to print all factors of i,

{ // and return the number of factors in i

if ( 2 <= i ) {

for ( test = 2; test <= i; test++ ) {

if ( 0 == (i % test) ) {

// found a factor, so print this factor then call

// factor() recursively to find the next factor

return( 1 + factor(i/test) );




// if this point was reached, then factor not found

return( 0 );


The function strcat(), used in the above example, adds one string on to the end of another. In this example, it adds the contents of text to the end of result string.

Error checking for functions

Some functions will return a special value if they failed to do what they are supposed to do. For example, the function fopen() opens or creates a file for a script to read or write to. But suppose that the computer was unable to open the file for some reason. In that case, the fopen function returns NULL.

If you try to read or write from the file you will get all kinds of errors, because the file isn't open. To prevent this from happening, make sure that the fopen didn't return NULL when it opened the file. Instead of just calling fopen like this:

fp = fopen("myfile.txt", "r");

check to make sure that NULL has not been returned:

if (NULL == (fp = fopen("myfile.txt", "r"))){

ErrorMsg("fopen returned NULL");


You will still have to abort the script in this case, but at least you know why. The fopen() function is documented in the ScriptEase Standard Library chapter.

Variable Scope

A ScriptEase variable is either global or local. A global variable is one that is referenced outside of any function, making it visible and accessible to all functions. A local variable is one that is only referenced inside of a function, and so it only has meaning and value within the function where it was created and any function it was explicitly passed to. Note that two identically-named local variables in different functions are not the same variable. Each instance of a recursive function has its own set of local variables. In other words, a variable that is not referenced outside of a function only has meaning (and that meaning is unique) while the code for that function is executing.

In the following sample code, number is the only global variable, the two result variables in Quadruple() and Double() are completely independent, and the result variable in one call to Double() is unique to each call to Double():

number = Quadruple(3);




result = Double(Double(i));






result = j + j;



It is important to give global variables names that are unique and unlikely to be declared elsewhere (like current_interest_rate and corinthian_paranoia_index), so that you don't accidentally use the same variable name as a local variable; this will seriously distort your script results. In general, it is better to use local variables than global ones.

Preprocessor directives

The following ScriptEase statements are collectively called preprocessor directives, since they are processed before the rest of the script and direct the way the script commands are interpreted.

# define

#define is used to replace a token (a variable or a function name) with other characters. The #define statement is executed while the script is being read into the processor, before the script itself, so you'll have all the substitutions in place before the code is read). A #define statement has the following structure:

#define token replacement

This results in all subsequent occurrences of token to be replaced with replacement. For example:

#define NumberOfCountriesInSouthAmerica 13

The define statement increases program legibility and makes it easier to change your code later on. If Bolivia and Peru decide someday to unite, you only have to change the #define statement to bring your program up to speed. Otherwise, you'd have to go through your program looking for 13's, decide which ones refer to the number of countries in South America (as opposed to the 13's representing the Original Colonies of the United States, which stay 13's) and change them all to 12's.

Likewise, if you write screen routines for a 25-line monitor, and then later decide to make it a 50-line monitor, you're better off altering

#define ROW_COUNT 25


#define ROW_COUNT 50

and using ROW_COUNT in your code (or ROW_COUNT-1, ROW_COUNT+2, ROW_COUNT/2, etc...) than if you had to search for every instance of the numbers 25, 24, 26, etc...

The ScriptEase interpreter has a large default list of tokens that have already been #defined, such as TRUE, FALSE, and NULL.


The #include directive lets you include other scripts, and all of the functions contained therein, as a part of the code you are writing. Usually #include lines are placed at the beginning of the script and consist only of the #include statement and the name of the file to be included, for example:

#include <gdi.hmm>

This line will make all of the functions in the library file gdi.hmm available to the program.

The quote characters (` or ") may be used in place of < and >.To include all of C:\CMM\LIB.cmm

#include <c:\CMM\LIB.cmm>

To include lots of little files into one big one program

#include <screen.cmm>

#include <keyboard.cmm>

#include <init.cmm>

#include <comm.cmm>

The ScriptEase interpreter will not include a file more than once, so if a file has already been included, a second (or third) #include statement will have no effect. ScriptEase ships with a number of libraries of pre-written functions you can use. Library files are plain text files (as are all ScriptEase code documents) and have the extension .hmm.

This is all you really need to know about the #include statement. It is almost always used in the form above. In certain circumstances, however, #include may take any of a number of parameters to specify which parts of a file should be included. The #include syntax is:

#include <Name[,Ext[,Label[,BeginCode[,EndCode]]]]>



Name of the file to include


Extension name to add to Name if it doesn't have one


Only include code from Name on lines that begin with this label


Will start including code from Name following the line beginning with this text


Will stop including code when this line is read

The second parameter is used when you want to add an extension to the name library name. For example:

#include <library, .hmm:>

is the same as:

#include <library.htm>

If a library is extremely large and you only want to use a small part of it, your script will run faster if you only #include the parts you need. (ScriptEase libraries are rarely so big enough to cause a noticeable slowdown, so you won't need to use this feature very often). The remaining parameters handle various ways to address this issue.

The third parameter lets you designate parts of libraries with labels. For instance, if a library math.hmm contains a function square that is labeled as follows:

:square square(a)

:square {

:square return(a*a)

:square }

To #include only this script, use the following statement:

#include <math.hmm, NULL, :square>

The fourth and fifth parameters will include sections from a file beginning at a certain line and ending at another. For instance the above library could be marked:








and the desired functions included with the following line:

#include <math.hmm, NULL, NULL, //BEGIN SQUARE, //END SQUARE>

Note that the labels used with the extended form of #include are not enclosed in quotes.

Since these libraries are external to ScriptEase, they are less static than the standard function libraries, and can be easily expanded or modified as the need arises. The most recent versions of .hmm libraries are listed on the Nombas downloads page at


#link is a command to incorporate additional functions into the ScriptEase processor. In practice, it works much like the #include statement with no parameters. However, while #include is used to include text files of ScriptEase code, #link is used to include precompiled extensions or .DLL files. For example, the command

#link "oleautoc"

lets the processor use the functions for OLE automation.

The files which may be included with #link are discussed in another chapter. #link takes no parameters other than the name of the library being linked to.

By keeping these functions in external libraries (instead of incorporating them directly into the ScriptEase processor as is the case with functions like sprintf() and strcat()) the processor is kept to a more manageable size, saving disk space and cutting down on the amount of time it takes a script to run.

Since these libraries are external to ScriptEase, they are less static than the standard function libraries, and can be easily expanded or modified as the need arises. The most recent versions of #link libraries are listed on the Nombas downloads page at

#if, #ifdef, #elif, #else, #endif

There are times when you want to #define one file if certain conditions are true, and #define a different file if the condition tests false. You can do this with the #if statement. #if differs from the regular if statement in that it executes while the code is being read into the processor (as opposed to executing when the code itself is run). #elif is the corresponds to the else if statement, and #else corresponds to the else statement. A #if statement must be closed with a terminating #endif statement.

Another way of looking at this is to think of #if as an if statement to use with #include and #define statements, which are also executed while the code is read. This is frequently used to determine which platform the script is running on, so that it will include the proper files and act appropriately to the operating system.

For example, suppose you had a script that built long path names from directories supplied to it in different variables. If you were working in a DOS-based environment, the backslash character is used to separate directories, so you could indicate the full path of a file as follows:

fullPathOfFile = rsprintf("%s\\%s\\%s\\%s", rootdirectory,

subdirectory1, subdirectory2, filename);

If you ported this script to a UNIX machine, however, you'd run into problems, because UNIX uses the forward slash to separate directories.

You can get around this problem by defining the separator character differently for each operating system:

#if defined(_UNIX_)

#define PathChar `/'

#elif defined(_MAC_)

#define PathChar `:'


#define PathChar `\\'


By putting the separator character in a variable, you can make this script work on any operating system:

fullPathOfFile = rsprintf("%s%c%s%c%s%c%s", rootdirectory, PathChar,

subdirectory1, Pathchar, subdirectory2,

PathChar, filename);

The #ifdef statement is a limited form of the #if statement, equivalent to #if defined(var)... The example above could be rewritten with #ifdef statements like this:

#ifdef (_UNIX_)

#define PathChar `/'

#ifdef (_MAC_)

#define PathChar `:'

#else #define PathChar `\\'



All code that is outside of any function is part of the global initialization function. This code is executed first, before calling any function (unless a function is called from this initialization code).

Any variables referenced in the initialization section are global.

To execute code when program terminates, see the atexit() function.

main( ArgCount, ArgStrings)

After the initialization has been performed, the main() function is called and is given the arguments that the operating system passed to the ScriptEase program. If there is no function main(), the program will end after running through all of the steps in the initialization.

ScriptEase is less picky about the main function than C is. While a C program must have a main() function, in ScriptEase this is not the case. The following two programs do exactly the same thing:









These two programs both set the value of a to 400. There are some differences in the way the variables will be handled, however. In the first example, a and b are global variables, and are available to any function in the program. In the second, a and b are local variables, and are only available to the main function. To make these variables available to any other function, they must be explicitly passed to it.

One advantage to the main() function is that it receives any parameters included on the command line when the script was first called. For example, let's say you wanted to view a document in CmmView.cmm (the text file viewer created in the tutorial section). You can pass the document name to the script when you invoke it from the command line:

SEDOS CmmView document.txt

The call to the function main() looks like this:

main(argc, argv)

The variable argc tells you how many variables were passed, while the variable argv is an array of all of the variables passed. The first variable passed (argv[0]) is the name of the script being called, so if argc = 1 then no variables were passed.

In the example above, argc = 2, argv[0] = "CmmView" and argv[1] is "document.cmm." These behave as any other local variable. If you don't need to pass parameters to main(), it is recommended that your program have a main() function anyway, with no parameters; in this case the parenthesis following the main() may be left empty.

Argc, sometimes referred to as ArgCount, is identical to the global _argc variable. Argv, sometimes referred to as argStrings, is identical to the global _argv variable.