The ScriptEase LanguageThis chapter is an introduction to and a description of the ScriptEase programming language.ScriptEase provides the most powerful and advanced form of JavaScript available today. Whereas other flavors of JavaScipt are embedded in web browsers and restricted to scripts that have been transmitted along with HTML documents, the ScriptEase processor allows you to run scripts locally, so you can use ScriptEase to write full fledged programs. In addition, ScriptEase has added commands and directives that increase and extend its power without interfering with the operation of standard JavaScript. These enhancements include preprocessor directives such as #include and #define, the switch/case statement, and the built-in Buffer object. Program StructureComputers, 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 five major steps:
while( ThereAreUncalledNamesOnTheList() != false){ name=GetNameFromTheList(); CallthePerson(name); LeaveTheMessage(); }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 parentheses, 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 CharactersCharacters 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.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 statements are equivalent to each other: x=a+b x = a+ b x = a + b x = a + bA 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. CommentsComments help bridge the gap between computer language and human language. A comment is a section of code that the processor will ignore when running the script. By using comments to explain the code in plain English, you will save yourself a lot of time if you have to go back to it later. 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.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). Comments may not be nested inside each other, i.e., comments may not contain comments. Here are some examples of comments: // this is a comment line /******************************** *** This is one big comment *** *** block. Isn't it pretty? *** ********************************/ FavoriteAnimal = "dog"; // except for poodles //This line is a comment but this line is not. VariablesA 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. Javascript variable names can be any length within reason. The following naming guidelines must be followed:
Sid Nancy7436 annualReport sid_and_nancy_prepared_the_annualReport aliceThe following variable names are not valid: 1sid 2nancy this&that Sid and Nancy ratsAndCats?The first time a variable is used, it may be declared with the var keyword: var Marie_Antoinette = "doomed queen"Variables created with the var keyword are local to the function in which they are created and are undefined in other functions unless explicitly passed to them. If a variable is created with the var keyword that has the same name as a global variable, the variable name will refer to the created variable while in the function - the global variable must be referred to as a member of the global object, global.variable, e.g. The following words have special meaning to the interpreter, and cannot be used as variable names:
Expressions, Statements, andBlocksAn 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; the semicolon is optional but recommended to improve readability. Each program statement is usually written on a separate line to make the code easy to read.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){ name=GetNameFromTheList(); CallthePerson(name); LeaveTheMessage(); }GetNameFromTheList(), CallthePerson(), and LeaveTheMessage() are 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. Data TypesData is assigned to a variable with an equal sign (=), regardless of the form the data may take:happyVariable = 7; joyfulVariable = "free chocolate"; theWorldIsFlat = true;The first time a variable is used, its type is determined. The example above creates three variables, each of a different type: the first is a number, the second is a string, and the third is a boolean variable. The variable types are described below. For the most part, you won't have to worry about making sure that a variable is of the correct type, since Javascript will automatically convert from one type to another when it needs to. Numbers : the most self explanatory data type, a variable of the type number represents a number. Both integers and numbers with a decimal component are numbers. Strings : A series of characters linked together. A string is written enclosed in quotation marks, e.g. "I am a string." or "344". Note that the string "344" is different from the number 344; one is a set of characters to be printed, while the other is a value that may be used in numerical calculations. ScriptEase automatically converts strings to numbers and vice versa, depending on context. In other words, if you use a number in a `string' context, it will be converted into a string; likewise, if you use a string in a `number' context, it will be converted to a numerical value. Automatic type conversion is discussed in detail on See Automatic Type Conversion . Undefined : If a variable is created and has nothing assigned to it, it is of type "undefined". You cannot do much with an undefined variable; it just takes up space and waits for a value to be assigned to it. When the variable is assigned a value it will be assigned a new type according to its value. Boolean : A variable of type Boolean may only have one of two possible values: true or false. When a Boolean variable is used in a numeric context, it will be converted to 1 if it is true, or 0 if it is false. Null : Null is a special data type that indicates an variable is empty. In other words, the variable in question holds no value. When used in string context, a null variable converts to the string "null"; when used in a numeric context, it converts to 0. Object : An object is a compound data type, consisting of one or more pieces of data (of any type) grouped together; data that are part of an object are called properties of the object. The object data type is equivalent to the structure data type in C and in previous versions of ScriptEase; however, the object data type also allows functions (methods) to be used as object properties. Here are some examples of variables and their corresponding data types:
The typeof operator provides a way to test a variable's type. It looks like this: result = typeof variableAfter this call, the variable `result' will be set to a string that is the variable's type: "undefined", "boolean", "string", "object", "number", etc.
The delete operator delete variable;Strings In ScriptEase version 4.x, strings are their own data type, as opposed to being arrays of bytes as in C and previous versions of ScriptEase. There are some differences and many similarities in the way strings are handled in the two versions of the language. One major difference is that in ScriptEase version 4.x, a string is not null-terminated. Although the null character is a valid string component, the existence of a null character doesn't indicate the end of the string; "\0\0\0" is a valid string.
Escape Sequences for Characters
Single quote strings
Back-quote strings For example, here are two ways to describe the same file name: "c:\\autoexec.bat"// traditional C method `c:\autoexec.bat`// alternative ScriptEase methodBackquote strings are not supported in most versions of JavaScript, so if you are planning to port your script to some other JavaScript processor, you should not use them.
Long Strings -- Using + to join (concatenate) strings proverb = "A rolling stone " + "gathers no moss."will create the variable proberb and assign it the string "A rolling stone gathers no moss." If you try to concatenate a string with a number, the number will be converted into a string: newstring = 4 + "get it";This bit of code creates the string variable newstring and assigns it the string "4get it". This is the standard way of creating long strings in JavaScript; with ScriptEase, the `+' symbol is optional. For example, the following: 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."creates a long string containing the entire bad joke.
Clib.sprintf()
Mathematical Operators
Basic Arithmetic
4 * 7 - 5 * 3;// 28 - 15 = 13has the same meaning, due to the order of precedence, as: (4 * 7) - (5 * 3);// 28 - 15 = 13but has a different meaning than: 4 * (7 - 5) * 3;// 4 * 2 * 3 = 8 * 3 = 24which is still different from: 4 * (7 - (5 * 3));// 4 * (7 - 15) = 4 * -8 = -32Even though parentheses may not be necessary, their use is recommended. They make your scripts a lot easier to understand.
Assignment Arithmetic
If you just want to add one (1) to a variable, you can use 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 in itself a 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:
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.
Logical operators compare two values and evalute whether the resulting expression is 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). An expression that does a comparison is called a conditional expression. 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. The logical operators are usually used with statements that will perform different actions based on how the conditional expression evaluates. 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){ ...you guessed the number!... }The if statement, used in the example above, is described in the next section of this manual. This is a very simple example, but it illustrates how logical operators can be used to make decisions in ScriptEase. The logical operators are:
Flow Decisions:Loops, Conditions, and Switches
if statement if ( goo < 10 ) { Clib.printf("goo is smaller than 10\n"); } Clib.printf("Print this, regardless of goo's value.")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. In ScriptEase code, it looks like this: if ( goo < 10 ) { Clib.printf("goo is smaller than 10\n"); } else { Clib.printf("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. The following code demonstrates the if, else, and else if statements: if ( goo < 10 ) { Clib.printf("goo is less than 10\n"); if ( goo < 0 ) { Clib.printf("negative goo is less than 10\n"); } } else if ( goo > 10 ) { Clib.printf("goo is greater than 10\n"); } else { Clib.printf("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){ DoSomething() }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 jumps over the block of code associated with the while statement and continues execution. The first example in this chapter uses a while statement: while( ThereAreUncalledNamesOnTheList() != false){ name=GetNameFromTheList(); CallthePerson(name); LeaveTheMessage(); }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 { value++; ProcessData(value); } while( value < 100 );The code used to demonstrate the while statement could also be written this way: do { name=GetNameFromTheList(); CallthePerson(name); LeaveTheMessage(); while (name != TheLastNameOnTheList());Of course, if there are no names on the list, the script will run into problems!
for statement for ( initialization; conditional; loop_expression ){ statement }The initialization is performed first. Then the conditional is tested. If the conditional is true (or if there is no conditional expression), the statement is executed. Then the loop_expression is executed, and the loop begins again, testing the conditional and executing the code following it if it is true. If the conditional is false then the statement will not be executed and the program continues with the next line of code after the statement. For example, the following code will print out the numbers from 0 to 9: for (x=0; x<10; x++){ Clib.printf(x); }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() ; ){ name=GetNameFromTheList(); CallthePerson(name); LeaveTheMessage(); }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 (this is not recommended!): for(;;) { //the code in this block will repeat forever, //unless the program breaks out of the for loop }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: for(;;){ break; }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 switch( switch_variable ) { case value1: statement1 break; case value2: statement2 break; case value3: statement3 break; case value4: statement4 break; case value5: statement5 break; ... default: default_statement break; }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... break; case `B': printf("B");//handle `B' accounts... break; case `C': printf("C");//handle `C' accounts... break; default: printf("nvalid account number entered.\n"); break; }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.
goto and labels goto LABEL;where LABEL is an identifier followed by a colon (:). beginning: 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 ?: test_expression ? expression_if_true : expression_if_falseFirst, 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 printf("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; else MaxNum = Num1is equivalent to this conditional operator code: MaxNum = ( Num1 < Num2 ) ? Num2 : Num1 ;Functions A function is an independent section of code that receives information from a program and performs some action on 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 whether it returns a value back to the statement that called it. Clib.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. In the case of Clib.printf(), people rarely look at the return value. 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. The computer will interpret a=DoubleNumberAndDivideByFive(number)as a=(number*2)/5This 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 be used as 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 are 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 .jsh files. These functions must be explicitly included in your script to use them; see the description of the #include statement. 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 included in the processor or the .jsh files.
Function definition function FunctionName(Parameter1,Parameter2,Parameter3) { statements... return result; }A call is made to a function in this format: FunctionName(Value1,Value2,Value3)A 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.
Function return statement DoubleAndDivideBy5(a) { return (a*2)/5 }Here is an example of a script using the above function: a = DoubleAndDivideBy5(10); a = DoubleAndDivideBy5(20); Clib.printf(a + b);This script will print out the value "12". Some functions don't return anything, and therefore don't have return statements. These functions are called void functions. Void functions return no value to the calling code. A function that just prints out a message, for example, is a void function: GreetingFunction() { Clib.printf("Hello and welcome to ScriptEase!");Passing variables to functions ScriptEase uses different methods to pass variables to functions, depending on the type of variable being passed. This ensures that the information gets to the function in the most complete and logical way. Strings, numbers, and boolean variables are passed by value. The value of the variable is passed to the function; if the function changes the value, the changes will not be visible outside of the function where the change took place. Objects are passed by reference. When ScriptEase passes an object, instead of passing the value of the object (i.e., the values of each of its properties and methods), it passes a reference to the object, indicating where in the computer's memory the values of the object's properties are stored. If you make a change in one of the objects values, that change will be reflected throughout the script.
Function Example num1 = 4; num2 = 6; // use the standard method of multiplying numbers Clib.printf("%d times %d is %d.\n",num1,num2,num1*num2); // now call our function to do the same thing Clib.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). function Multiply(i,j) { total = 0; for ( count = 0; count < j; count++ ) total += i; return(total); // caller will receive this value }When executed, this code will return two identical strings, "4 times 6 is 24." This example demonstrates several features of functions. Notice that in calling Clib.printf() the parameter "num1*num2" is not passed to Clib.printf(), but the result of "num1*num2" is. Likewise, "Multiply(num1, num2)" is not a parameter to Clib.printf(); instead, Clib.printf() receives the return value of Multiply() as its parameter.
Function properties -- arguments[] The most useful aspect of this property is that it allows you to have functions with an indefinite number of arguments. Here is an example of a function that takes however many arguments you pass it and returns the sum of all of them: function SumAll() { total = 0; for (ssk = 0; ssk<SumAll.arguments.length; ssk++){ total += SumAll.arguments[ssk]; } return total; }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. Be aware that recursion has its limits; if a function calls itself too many times the script will run out of memory and abort. 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 ); }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 Clib.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 to the file you will get all kinds of errors, because the file was never opened. 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 = Clib.fopen("myfile.txt", "r"); //check to make sure that null has not been returned: if (null == (fp = Clib.fopen("myfile.txt", "r"))){ ErrorMsg("Clib.fopen returned null"); }You will still have to abort the script in this case, but at least you know why.
cfunction keyword In a function declared with the cfunction keyword, there is no data conversion between numbers and strings. Instead of being treated as a special data type, strings are considered to be an array of bytes (i.e. numbers). The first character of the string is assigned to string[0], the second to string[1], and so on until the end of the string. The last character of a string is always '\0', which defines the end of the string. If you assign a variable to a string, defining the string in double quotes, this character will automatically be appended to the end of the string. To assign a string to a variable without appending the '\0' character, put the string in single quotes. This is most often done with single characters. For example, if boy = "m"; girl = 'm';the variable boy is an array: boy[0] = 'm' and boy[1] = '\0'. The variable girl is a character, containing the letter 'm'. Internally, characters are converted to numbers according to the ASCII standard. You can change the contents of strings (or parts of them) by assigning a new character value a character's array member. For example: string = "file" string[0] = 'b'This snippet of code creates a string containing the word "bile". There is no automatic type conversion in functions defined with the cfunction keyword. If you try to add a number to a string, instead of converting the number to a string and concatenating the two, the starting point of the string will be shifted forward by the number of characters in number. For example, the statement: "This is a test" + 3would evaluate to "This is a test3" in a standard function. In a cfunction, however, this statement would evaluate to "s is a test". The starting point of the string has been shifted by three, so that string[0] is now 's' instead of 'T'. The `T', `h', and `i' of the original string will be found at indices [-3], [-2], and [-1], respectively. The methods and properties normally available to strings are available to strings in cfunctions. Variables passed to cfunctions are passed by reference. If you have two variables: George = "one" Martha = "one"and you compare them with the `==' operator, the comparison will evaluate as false, not true as you might expect. This is because while George and Martha have the same value, they are not the same variable, and therefore are not equal to each other. In functions declared with the function keyword, variables are compared by value, so the actual values of George and Martha are compared. In this case the result of the comparison is true. Variable Scope Variables in ScriptEase may be either global or local. Most variables are local: they only have meaning within the function in which they were created. If you want to use the variable in some other function, you must explicitly pass the variable to that function. Note that two identically-named local variables in different functions are not the same variable (unless, of course, one function passed the variable to the other). 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. Global variables, on the other hand, are visible to all functions in a script. There are two ways to make a global variable: you can declare it outside of any function, or you can assign it to the global object when you create it. The example below demonstrates the difference between global and local variables. foo is a global variable created outside of any function, while roo is a global variable created inside of a function (note that the name of the global object is not capitalized). goo is the name for two different local variables, each with a different value and each valid only within the function where they were created. foo=8 function Afunction() { goo = 6; Clib.printf(goo + foo); global.roo = 10; } function Anotherfunction() { goo = 8; Clib.printf(goo + foo); Clib.printf(roo) }It is possible to have local and global variables with the same name. In this case, the var keyword must be used to define the local variable. The global variable may still be referenced as a property of the Global object (Global.variable, e.g.), but the variable name used by itself will refer to the local variable. Objects Variables that are parts of objects are called properties of the object. To refer to a property of an object, you use both the name of the object and the name of its property, separated by the `.' operator. Any valid variable name may be used as a property name. For example, if you had a rectangle object with height and width properities, you would assign their values like this: rectangle.height = 4 rectangle.width = 6If the properties do not exist, they will be created. Properties that have not had values assigned to them are of the special value `undefined'. Objects do not need to be explicitly created in ScriptEase. However, for compatibility with JavaScript ScriptEase provides the `new' operator, which creates a new object. For example, the code block = new Object();creates an object called block with no members. Predefining Objects The constructor function uses the special `this' keyword to initialize its values. For example, to create a rectangle object with width and height properties as in the example above, you would use a constructor function like this: function Rectangle(width, height) { this.width = width; this.height = height; }Once you have created the constructor function, you can use it to create instances of the object: LASS="Code-in-Body"> joe = new Rectangle(3,4) sally = new Rectangle(5,3);This will create two rectangle objects, one named joe with a width of 3 and a height of 4, and one named sally with a width of 5 and a height of 3. The values passed as parameters are assigned to the properties of the newly created object. This particular example creates a class of `Rectangle' objects; each copy of the Rectangle object is called an instance of the object. All of the instances of a class share the same properties, although a particular instance of the class may have additional properties unique to it. Methods - assigning functions to objects Like a constructor function, a method refers to its variables with the `this' operator. Here is an example of a method that computes the area of a rectangle: function rectangle_area() { this.width * this.height }Because there are no parameters passed to it, this function is meaningless unless it is called from an object. It needs to have an object to provide values for this.width and this.height. A method is assigned to an object like this: joe.area = rectangle_area;The function will now use the values for height and width that were defined when we created the rectangle object joe. Methods may also be defined as part of an object's constructor function. For example, the following code: function rectangle_area() { this.width * this.height } function Rectangle(width, height) { this.width = width; this.height = height; this.area = rectangle_area; }creates an object class `Rectangle' with the rectangle_area method included as one of its properties. The method is available to any instance of the class: joe = Rectangle(3,4) sally = Rectangle(5,3); area1 = joe.area area2 = sally.areaThis code will set the variable area1's value to 12 (3 * 4) and area2's value to 15 (5 * 3)
Object prototypes When the two Rectangles joe and sally were created in the previous section, they were each assigned an area method. Memory was allocated for this function twice, even though the method is exactly the same in each instance. This redundant memory waste can be avoided by putting the shared function (or property) in the object's prototype. Then all instances of the object will use the same function instead of each using their own copy of it. This ensures that all instances of the object use the same mechanism for their methods and conserves the amount of memory needed to run your script. Here is how we'd create the Rectangle object with the area method in a prototype: function rectangle_area() { this.width * this.height } function Rectangle(width, height) { this.width = width; this.height = height; } Rectangle.prototype.area = rectangle_area;You can now access the rectangle_area method as a property of any Rectangle object: area1 = joe.area; area2 = sally.area;You can add methods and data to an object's prototype at any time. The object class must be defined, but there don't have to create an instance of the object before assigning it prototype values. If you assign a method or data to an object prototype, all instances of that object will be updated to include the prototype. If you try to write to an property variable that is assigned through a prototype, a new variable will be created for the newly assigned value. This value will be used for the value of this instance of the object's property; all other instances of the object will still refer to the prototype for their values. If for the sake of example we assume that joe is a special Rectangle, whose area is equal to three times its width plus half its height, we can modify joe like this: joe.area = joe_area; function joe_area() { return (this.width * 3) + (this.height/2); }This creates a value (in this case, a function) for joe.area that supercedes the prototype value. Sally.area will still be the default value defined by the prototype; joe will use the new definition for its area method.
for...in for (property in object){ DoSomething(object.property) }where object is a the name of an object previously defined in the script. Using the for...in statement in this way, the statement block will execute once for every property of the object. For each iteration of the loop, `property' contains the name of one of the properties of object and may be accessed with `object.property'. Note that properties marked with the DontEnum attribute won't be counted in the for...in statement.
with with (Clib){ srand(); xxx = rand() % 5; sprintf(string, "The number is %d", xxx); }The Clib methods srand(), rand(), and sprintf() in the sample above will all be called as if they had been written with the prefixed "Clib." All code in the block following the with statement is treated as if the methods associated with the with object were global functions. Global functions are still treated normally, i.e. you don't need to prefix global. to them unless you are distinguishing between two like-named functions common to both objects. If you were to jump to another part of the code from within the with statement, the with statement would no longer apply. In other words, the with statement only applies to the code within the block, regardless of how the processor accesses or leaves the block. If you want to include two objects in the with filter, do it like this: with (Math) with (Clib){ ... }Arrays An array is a special kind of object. Instead of refering to its properties with their name and the `.' operator, an array uses a numeric or string identifier, called an index, to identify them. The index follows the array name in brackets. Array elements do not all need to be of the same data type. The following are all valid arrays: array[0] = "fish"; array["seven"] = "fowl"; array[foo] = "creeping things" array[goo + 1] = "etc."The variables foo and goo must represent numbers or strings. Arrays allow you to use a variable as an object's property identifier. The variable will then be interpreted and the corresponding value applied to the array. For example: age[0] = "ten" age[1] = "not ten"; if (yourAge == 10) ckc = 0 else ckc = 1; printf ("You are " + sge[ckc] + " years old.");Since an array is a type of object, you can use array notation to access object properties. For example, if object.red = "apple"; object.yellow = "banana" if (condition == true) indexVariable = "red" else indexVariable = "yellow"; printf(object[indexVariable]);This code will print out "apple" or "banana" depending on whether condition is true or not. Another advantage of arrays is that you can use a number for an identifier, rather than a string. This gives you an easy way to access the members of the array. 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: April[1] = 233; April[2] = 344; April[3] = 155; April[4] = 32; (...)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 April[x]: for(x=1; x<32; x++) { printf("On April " + x + " I ate " + April[x] + " jellybeans.\n" ); }Note that arrays do not have to be continuous. If you went away for January 5th and 6th and ate no jelly beans, your next datum could be January[7] = 539If you then tried to acces the value of January[5] or January[6], you'd get an undefined value back, because these two variables haven't been assigned a value yet. Usually arrays start at index [0], not index [1]. This is consistent with C, C++, and JavaScript.
Creating Arrays anArray = new Object(); array[0] = 5; array[1] = 4; array[2] = 3...You can also use the predifined Array() constructor function. The Array() function may be called in three different ways. If called with no parameters, a = new Array();it creates an empty array, with no elements. This is the equivalent to calling a = new Object();except that the array methods and properties (see below) are only available to arrays created with the Array() constructor. You can also pass a number to the Array() function. This will create an array with a length of the number you passed: b = new Array(31)creates an array with a length of 31. Finally, you can pass a number of elements to the Array() function. This creates an array containing all of the parameters passed. For example: c = new Array(5, 4, 3, 2, 1, "blastoff");creates an array with a length of 6. c[0] is set to 5, c[1] is set to 4, and so on up to c[5], which is set to the string "blast off".
Methods and properties of arrays For example, suppose we had two arrays "ant" and "bee", with the following elements: ant[0] = 3 bee[0] = 88 ant[1] = 4 bee[3] = 99 ant[2] = 5 ant[3] = 6The length property of both ant and bee is equal to 4, even though ant has twice as many elements as bee does. By changing the value of the length property, you can remove array elements. For example, if we change ant.length to 2, ant will only have the first two members; the values stored at the other indices will be lost. If we set bee.length to 2, then bee will consist of two members: bee[0], with a value of 88, and bee[1], with an undefined value.
Array.join a = new Array(3, 5, 6, 3) string = a.join();will set the value of `string' to "3,5,6,3". Likewise a = new Array(3, 5, 6, 3) string = a.join("*/*");creates the string "3*/*5*/*6*/*3".
Array.sort() a = new Array(32, 5, 6, 3) a.sort(); string = a.join();creates a string "3, 32, 5, 6". This is probably not the behavior you want in a sort function. Fortunately, the sort() method allows you to specify a different way to sort the array elements. The name of the function you are using to compare values is passed as the only parameter to sort(). If a compare function is supplied, the array elements are sorted according to the return value of the compare function. If a and b are two elements being compared, then:
If compareFunction(a, b) is less than zero, sort b to a lower index than a. If you want to compare numbers instead of strings, you can use the following function to compare values: function compareNumbers(a, b) { return a - b }Array.reverse The reverse() method switches the order of the elements of an array, so that the last element becomes the first. If you had the following code: array[0] = "ant" array[1] = "bee" array[2] = "wasp" array.reverse()It would produce the following array: array[0] = "wasp" array[1] = "bee" array[2] = "ant"The global object and its properties Global variables are members of the global object. To access global properties, you do not need to use the Object name. For example, to access the isNan function, which tests to see whether a value is equal to the special Not a Number value, you can call either isNAN(value); or global.isNaN(value); eval(expression) This method evaluates whatever is represented by the expression variable. If expression is not a string variable, it will be returned. Calling eval(5) returns the value 5, e.g. If expression is a string variable, the processor tries to interpret the string as if it were Javascript code. If successful, it will return the last variable that it was working with (the return variable, e.g.). If it is not successful, it will return the value undefined.
parseInt Whitespace characters at the beginning of the string are ignored. The first non-whitespace character must be either a digit or a minus sign (-). All numeric characters following the string will be read, up to the first non-numeric character, and the result will be converted into a number, expressed in the base specified by the radix variable. All characters including and following the first non-numeric character are ignored. If the string is unable to be converted to a number, the special value NaN will be returned.
parseFloat(string) escape(string) The escape string takes a string and escapes the special characters so that the string may be used with a URL. All uppercase and lowercase letters, numbers, and the following symbos: @ * + - . / will appear in the string. All other characters will be replaced with their respective UNICODE sequence.
unescape(string)
defined(variable)
undefine(variable)
isNaN(number)
isFinite(number)
Properties and methods of the basic data types The properties and methods of the basic data types are retrieved in the same way as from objects. If you have a string variable called name and you want to know the size of the string, you can access the length property of the string to get this information: x = name.lengthThe following two properties are common to all variables. For the most part, they are used internally by the processor, but you may use them if you wish to.
.toString()
.valueOf()
String properties and methods
String.length string = "No, thank you." printf("%d", string.length)will print out the number 14, the number of characters in the string.
String.charAt()
string.charAt(0); string.charAt(string.length - 1);
String.charCodeAt(index)
String.fromCharCode(char1, char2...)
String.substring()
String.indexOf(substring [, offset])
string.indexOf("a")
Returns the position of the first `a' appearing in the string. String.indexOf() may take an optional second parameter. This parameter is an integer indicating the index where the method is to start searching the string. For example,
String.lastIndexOf(substring [, offset])
String.toUpperCase(), String.toLowerCase()
String.split([substring])
For example, if we wanted to create an array of all of the words in a sentence, we could do it like this:
Number.MAX_VALUE
Number.MIN_VALUE
Number.NaN
Number.POSITIVE_INFINITY
Number.NEGATIVE_INFINITY
The Buffer object newBuffer = new Buffer(size);
newBuffer = new Buffer(string [, offset [,size]][ ,isASCII])
newBuffer = new Buffer(array [,offset [, size]][,signed])
Buffer.size
Buffer.cursor
Buffer.comparableTo(Abuffer)
Buffer.compareEnds(Abuffer)
Buffer.compareStarts()
Buffer.getCursor()
Buffer.getSize()
Buffer.isValidIndex(index)
Buffer.setCursor(offset)
Buffer.setSize()
Buffer.shift()
Buffer.shiftWindow()
Buffer Get Methods
Buffer.getUint32([offset] [, bigEnd])
Buffer.getUNICODEValue([offset] [, bigEnd])
Buffer.getASCIIString([offset [, length]][, bigEnd])
Buffer.setUint32(value [,offset][, bigEnd])
Buffer.setUNICODEValue(value [, offset][, bigEnd]) Buffer.setUNICODEString(value [, offset [, length]] [, bigEnd])
The Math object
Math.LN10
Math.LN2
Math.LOG2E
Math.PI
Math.SQRT1_2
Math.SQRT2
Math.abs(x)
Math.acos(x)
Math.asin(x)
Math.atan(x)
Math.atan2(x, y)
Math.ciel(x)
Math.cos(x)
Math.exp(x)
Math.floor(x)
Math.log(x)
Math.max(x, y)
Math.min(x, y)
Math.pow(x, y)
Math.random()
Math.round(x)
Math.sin(x)
Math.sqrt(x)
Math.tan(x) The Date object
ScriptEase also provides a date object, with built in methods for handling date conversions and extracting data.
To create a date object set to the current date and time, use the new operator (as you would for any object):
The second syntax accepts a string representing the entire date. The time may also be included. The format of a datestring is:
The third and fourth syntaxes are self-explanitory. All of the parameters passed are integers.
year - The year. If the year is in the twentieth century (i.e. 19xx),
you need only supply the final two digits; otherwise four digits must
be supplied.
For example:
The following methods are available to all Date objects:
Date.getDate()
Date.getDay()
Date.getHours()
Date.getMinutes()
Date.getMonth()
Date.getSeconds()
Date.getTime()
Date.getTimezoneOffset()
Date.getYear()
Date.setDate(day_of_month)
Date.setHours(hours)
Date.setMinutes(minutes)
Date.setMonth(month)
Date.setSeconds(seconds)
Date.setTime(milliseconds)
Date.setYear(year)
Date.toGMTString()
Date.toLocaleString() Special Date methods
Date.parse(datestring)This
method takes a string and converts it to a date. The string must be of the following format:
Dynamic objects
.get(property)
.put(property, value)
.canPut(property)
.hasProperty(property)
.delete(property)
.defaultValue(hint) .construct(...)
.call(...)
This example creates an Annoying object that beeps whenever it retrieves the value of a property:
Preprocessor directives
define
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 to #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...
#include
The quote characters (` or ") may be used in place of < and >.To include all of C:\CMM\LIB.JSE
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
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 Clib.sprintf() and Clib.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
http://www.nombas.com/downloads/index.htm.
#ifdef, #elif, #else, #endif
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:
You can get around this problem by defining the separator character differently for each operating system:
Any variables referenced in the initialization section are global.
To execute code when program terminates, see the Clib.atexit() function.
Automatic Type Conversion
You can specify a more stringent conversion by using the ParseInt() and ParseFloat() methods. 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:
One advantage to the main() function is that it receives any parameters included on the command line when the script was first called. The call to the function main() looks like this:
main(argc, argv)
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.
|