ScriptBasic Samples

by Peter Verhas

Table of Contents

[Contents]

1. Introduction

This document introduces you the ScriptBasic programming language via examples. This documentation was created using

'T:\MyProjects\ScriptBasic\source\scriba.exe' is not recognized as an internal or external command, operable program or batch file.

[Contents]

2. Simple Examples

[Contents]

2.1. Hello Word

This is the simplest ever example that you can ever find in any programming language. It is quite simple in BASIC. The most frequently used statement is the print command. This simply prints its arguments to the standard output, which is usually the screen.

Example hello1.bas :

' The simplest ever ScriptBasic program
PRINT "HELLO!"

Result executing hello1.bas :

The first line of the program is a comment line. Any line starting with an apostrophe or with the keyword REM is a comment line. In the example we used the ' character but anytime if you feel like an old BASIC fan, and want to use the keyword REM feel free to do so.

As you could realize the sample code contains PRINT while the sentence before uses the same keyword in lower case letters. This is no mistake. ScriptBasic just as most BASIC implementations is quite liberal regarding the case of the identifier. You can write any reserved word in lower or upper or even mixed case. Thus print and PRINT are the same just as Print, print or PrInT. (Although I advise that you avoid using weird and unreadable mixed case.) From now on I will use the upper case version of the keywords in most cases.

As you will learn later, not only the keywords, but also the variables and function names are also case insensitive.

Getting back a bit more to the PRINT statement. You will use this statement many times in your programs to display data on the console or to send HTML code to the browser when programming CGI. Therefore it is worth examining the specialties of this statement.

Old BASIC languages allowed quite complex PRINT statements, that used tabbing, spaces between elements and so on. ScriptBasic treats this statement extremely simple. When you print values to the screen (to the standard output to be precise) ScriptBasic prints out the values that are separated by commas and nothing else. If you need spaces between the elements, or new line at the end of the printed line, you have to specify those.

Example hello2.bas :

A = 1
B = 2
' this just prints "12"
PRINT A,B

Result executing hello2.bas :

On the other hand

Example hello3.bas :

A = 1
B = 2
' this just prints "12"
PRINT A," ",B,"\n"
PRINT "This goes onto a new line"

Result executing hello3.bas :

Now that we discussed in detail that PRINT statement prints only what it is told to we break the rule. There is an exception when PRINT statement prints something, which is not explicitly specified.

When you have a PRINT statement without any argument it would just print nothing according to the rules detailed above. Such a statement would be totally useless and therefore ScriptBasic makes an exception for the case. If you have a single PRINT statement on a line and no argument, ScriptBasic will print new line when executing the statement.

Example hello4.bas :

PRINT "HELLO!"
PRINT
PRINT "HELLO AGAIN!"

Result executing hello4.bas :

To express the new line and make your code more readable you can use the keyword PRINTNL without argument. Note however that this keyword can only be used without arguments!

Both the PRINT and the PRINTNL statements can be used to print values to files as you will see it later.

[Contents]

2.2. greet.bas

After you have seen how to write to the screen this is the next step to read from the keyboard. Reading from the keyboard is common in small programs that require complex parameters that do not easily fit on the command line as parameters or want to help the user with screen prints what to enter. Lets see the first example!

Example greet1.bas :

PRINT "What is your name?"
PRINT
LINE INPUT Name$
PRINT "HELLO ",Name$," my deer"

This program prints the string What is your name?> on the screen using the statement @code{PRINT, which should already familiar to you. The next statement prints a new-line, thus the cursor is now below the printed string. At this point the program executes the command LINE INPUT. This command reads from the keyboard (from the standard input to be precise) until the end of the line. In other words the command reads the characters that you type up to and including the new-line character you typed by pressing the line terminating ENTER. Let's see what the result is running this program!

Result executing greet1.bas :

in case your name is Peter and you typed it at keyboard when the program questioned. The command LINE INPUT reads a line from the standard input. This is usually the keyboard. The line is put into a variable, that is named Name$ in our example. Notice that the whole line, including the terminating new-line is put into the variable. This is the reason, why the string my deer gets on the next line and not just after the name.

In case you want to get rid of the string terminating new line you can use the function CHOMP.

Example greet2.bas :

PRINT "What is your name?"
PRINT
LINE INPUT Name$
Name$ = CHOMP(Name$)
PRINT "HELLO ",Name$," my deer"

Result executing greet2.bas :

The function CHOMP removes the trailing new-line characters from the end of a string and returns the string without them. This could be performed using other functions, but this function was designed for the very purpose and thus it is very convenient. If the string does not happen to have a new-line character at the end no harm is done. CHOMP removes the last character only if the character is new-line.

The command LINE INPUT can also be used to read lines from files, but that issue is a bit more complex and will be discussed later.

There is also a function called INPUT, which reads from the standard input or from a file given number of characters (or rather bytes to be precise). This will also be detailed later.

[Contents]

2.3. Using Variables

Variables in ScriptBasic store values. These values can be integer, real or string values. The variables are not bound to any type. A variable can hold one type of value at a time and a different on at other types. That is why ScriptBasic is called type-less. Variables are referenced by their names. These names should start with an alpha character, underscore (_), colon (:), or dollar sign ($) and may continue with these characters and numbers. A variable can have any length and all characters are significant. However variable names, just like any other symbol in ScriptBasic are case insensitive. Thus FOO, Foo, fOO and foo mean the same. The following examples are legal variable names:
A
B2
ThisIsAVariable
This_Is_also:a$variable
$perl_style_variable
a$
main::here

The alpha characters and the : _ and $ characters are equivalent in the sense that their usage does not reflect the type or any other feature of the variable. In BASIC languages string variables are usually denoted with a trailing $ character. ScriptBasic does not require this. You can name any variable as you like and store string, integer or real value in that.

A variable can even be an array that holds several variables indexed. These are discussed in array.

In addition to all possible real, integer and string values there is a special value that a variable can hold and this is undef. An undef value means that the variable does not hold any value, in other words it is undefined. All variables that were not assigned any value are undef. When a variable holds a value and is used in an environment where a different type is expected the value is automatically converted.

Example var.bas :

A = "123"
B = A + 1
PRINT B
PRINT
B = A & B
PRINT B
PRINT

Result executing var.bas :

On the line, where addition is used the string value is automatically converted to numeric and the addition was performed on integer values. The variable B will hold an integer value.

Before second PRINT lines the variable B gets a new value again. The operation in this case is concatenation. Because concatenation is a string operation both arguments are converted to be string. The variable A is already a string so there is no need to convert it. The variable B is an integer. This value, and not the variable itself is converted to string and the values are put together.

Variables in ScriptBasic can be local and global. Global variables can be used anywhere in the program, while local variables are available only in the function or subroutine where they are defined. This will be detailed later when I talk about user defined functions and subroutines.

There is a simple name space management in ScriptBasic that helps to avoid name collisions when more than one programmers work on a project. This is detailed in Modules and Name Spaces. From now on it is enough to note that variables like main::a and modu::var are legal variables.

[Contents]

2.4. Strings

Strings are easily handled in ScriptBasic. A string starts with a " character and stops with another one. For example

A="This is a single line string"
B="Strings may contain \" characters backslash quoted"
C="""Multiline strings should start with three " and
may contain single or double " characters, like "" without backslash"""

Whenever you want to store a string in a variable it is automatically handled. ScriptBasic automatically allocates space to store the string and reuses the memory not needed anymore. You can use single line strings just as well as multi-line strings. Multi-line strings should start and end with three " characters. Strings can contain any character with the code between zero and 255 and can be any length limited by available memory only. In other words ScriptBasic strings are byte-streams or byte strings. You can store arbitrary binary data as string in variables. You can easily type binary data, because any \ character inside a string may be followed by the code of the character. For example you can write

"\32is just a space"

If the first number following the \ character is zero then the code is calculated as octal. There are other characters that can be typed using the \ character. For example:

"\n is a new-lien character"
"\r is a carriage return character"
"\t is a tabulator character"
"\" is a double apostrophe character"
"\\ oh! This is a back-slash character"

Finally there is a very special type of string in ScriptBasic and this is the binary multi-line string. A binary multi-line string should be used to specify binary data that is long and may not fit into a single line if you want to specify it using \000 characters.

To specify a binary multi-line string you have to start your string with the four characters """&. This will instruct the ScriptBasic reader to neglect all new-line characters inside the string unless they are explicitly denoted using \n.

This way you can specify any string and still keep your source code editable with moderated line lengths. For example:

Example string1.bas :

PRINT """&This is a multiline 

string with a single\nnewline in it."""

Result executing string1.bas :

Of course this is not the usual usage of this type of string, but is a more or less readable example.

[Contents]

2.5. Modules and Name Spaces

ScriptBasic does not have real name spaces to separate modules from each other. There are no such things as public and private variables of modules or classes. Whenever you develop a module you have to trust the user of the module that he or she will use the module in the way it is intended and the way you hopefully documented. A programmer should not use the internal variables of a module not because he can not but because he is supposed not to. ScriptBasic name spaces only help the programmers to avoid accidental name collisions. When you develop a module you start it saying

Module MyModule

After this line until the end of the module which is noted by the line

End Module

all lines will belong to the specific module and all global variables will belong to that module.

However all these module and name space handling is done on low level altering the names of the variables and functions. When you start to write a program and you write:

A = 3
print A

you actually use the variable main::A. This is because the default name space is main, and if there is no name space defined in a variable its name is altered so that the variable will belong to the current name space. Try the following:

Example mod1.bas :

A = 3
print main::A

Result executing mod1.bas :

Surprising? Try the following:

Example mod2.bas :

A=5
module boo
A=3
print main::A
end module

Result executing mod2.bas :

This is because main::A is 5, boo::A is 3 and the variable name main::A is not converted to boo::main::A, because it is explicitly denoted to belong to the name space main. Name spaces can be nested. You can write:

Example mod3.bas :

A=1
module boo
 A= 2
 module boo::baa
 A= 3
 print A
 print boo::A
 print main::A
end module
end module

Result executing mod3.bas :

To ease the nesting of modules you can write the same code as

Example mod4.bas :

A=1
module boo
 A= 2
 module ::baa
 A= 3
 print A
 print _::A
 print main::A
end module
end module

When the module name in the module declaration starts with double colon ScriptBasic knows that the module is to be nested into the current module. The variable name _::A means: the variable A of the surrounding name space. This is the same as the operating system directories. You can think of name spaces as directories and variables as files. Whenever you write ../../mydir/file.c a similar construct may say _::_::mynamespace::variable When the parser sees the end module statement it always returns to the previous name space. You can start and close modules many times, ScriptBasic will not complain that the module was already defined. You can even totally neglect the module statement and you can write the above program as

main::A=1
boo::A= 2
boo::baa::A= 3
print boo::baa::A
print boo::A
print main::A

This is a bit less readable. Name spaces can serve another purpose. See the following code:

string = "AF"
hex = 0
while string <> ""
 chr = mid(string,1,1)
 string = mid(string,2)
 hex = hex*16 + asc(chr) - asc("A")
wend
print hex

when you try to compile you will probably get many errors. Why? Because string, chr and hex are predefined functions and can not be used as variable names. What to do then? You can use them as variable names when you specify that they are variables:

::string = "AF"
::hex = 0
while ::string <> ""
 ::chr = mid(::string,1,1)
 ::string = mid(::string,2)
 ::hex = ::hex*16 + asc(::chr) - asc("A")
wend
print ::hex

When you write ::string, ::chr or ::hex ScriptBasic will know that they are variables belonging to the current name space. This is a bit weird, so you better avoid using function names and predefined function names as variable names.

[Contents]

2.6. Array Variables

ScriptBasic can handle arrays. Practically any variable can be an array, just like interger, real or string. Array is a variable type when a variable holds not only one, but many values and these values can be accessed using the variable name and an index value. In ScriptBasic arrays are automatically created. There is no statement like DIM. All you have to do is to use the variable like an array. Array subscripts are written using square brackets. This is usually the convention in PASCAL and in C. Other BASIC languages use normal parentheses to index arrays. However that confuses the reader as well as the parser, because function call looks the same as array access. Therefore ScriptBasic uses the square brackets. There is no limit on the number of indices. You can use many as you like. Also there is no limit on the index values. Positive, negative or zero integers can play the role of an index. Whenever you access an array element or assign a value to that ScriptBasic automatically checks if the referenced array element exists or not and adjusts the array if necessary. For example:

Example array1.bas :

a[1] = 3
a[5]=4
for i=1 to 5
print a[i]
print
next

Result executing array1.bas :

Arrays are handled quite liberal. You are not required to declare the index bounds, you need not declare the number of indices. As a matter of fact you can have different number of indices at different points in the array. For example the following code is also legal:

a[1] = 3
a[5,3]=4
print a[1],"\n",a[5,3]

You can even write:

a[1] = 3
a[5,3,1,6,5,4,3,6,4,3,2222]=4
print a[1],"\n",a[5,3,1,6,5,4,3,6,4,3,2222]

if you wish. But what happens if you write:

Example array2.bas :

a[1] = 3
a[5,3]=4
print a[1],"\n",a[5]

Result executing array2.bas :

or some similar message. What has happened? To understand we have to explain how ScriptBasic stores the arrays. An array in ScriptBasic is stored as a list of C pointers. When a ScriptBasic variable first time used as an array a new array of a single element is created. It has one element assigned to the index that was referenced.

VARIABLE[6] = 555

Later, when other elements are referenced the array is automatically extended. For example if the array was first time referenced using the index 6 and it was accessed second time using the index 11 ScriptBasic automatically extends the array to contain six elements, the elements indexed with the values 6,7,8,9,10 and 11.

VARIABLE[11] = "a string"

This means that an array can consume significant memory even if only a few indices are used. When an array element, letís say index 10 is used with a second index, letís say with 3 a new

VARIABLE[10,3] =6.24E3

one-element array is created. Later this new array is treated the same as the one assigned to the variable itself, and when the element

VARIABLE[10,6] = 55

is set it is enlarged to be able to hold all values between and including indices 3 and 6. When the variable in our example named VARIABLE gets a new value, like

VARIABLE = "NEW VALUE"

the arrays are released automatically. When accessing an array element, which is an array itself ScriptBasic tries to do its best. However the result may not be what you expect. The following program:

Example array3.bas :

a[1]=1
a[5,3]=4
c = a[5]
a[5,3]=2
print a[5,3]," ",c

Result executing array3.bas :

in current version of ScriptBasic, but this may change later. That is because the expression a[5] that we try to assign to the variable c is an array itself. However ScriptBasic does not support the assignment of whole arrays. Therefore ScriptBasic tries to calculate the integer, double or string value that the programmer wanted to assign to c. In other BASIC implementations you have to use the declaration DIM and after that you have the array and you know the index limits of the array. In ScriptBasic there is no limit on the indices. Somehow you still may want to know the smallest and the largest index values used. For the purpose there are two functions named lbound and ubound. For example

Example array4.bas :

a[1] = undef
print lbound(a)," ",ubound(a)
print
a[2,-3] = "whoops"
print lbound(a)," ",ubound(a)
print
print lbound(a[2])," ",ubound(a[2])
print

Result executing array4.bas :

As you can see the argument to these functions can be a variable that has array value or an expression that has an array value. (Such an expression is likely to be an array element, which is an array by itself.)

[Contents]

2.7. Expressions

Up to know you have already seen some simple examples of expression. However before going on it is a wise choice to get into more details regarding them. When you see the example
A = 3

the number 3 on the right hand side is an expression. This is actually the simplest expression ever containing a single integer number. Speaking generally an expression is made of integers, real numbers and strings connected together with operators and groupped using parentheses. You can add numbers, subtract and so on. The operators that you can use are:

^    power, for example 2^3 = 8      (8)
*    multiply                        (7)
/    divide                          (7)
\    integer divide                  (7)
%    modulo operator                 (7)
+    addition                        (6)
-    substraction                    (6)
&    string concatenation            (5)
like string like operator            (4)
=    test equality                   (3)
<    test less-than                  (3)
<=   test less-then-or-equal         (3)
>    test greater-then               (3)
>=   test greater-than-or-equal      (3)
<>   test non-equality               (3)
and  bitwise AND operator            (2)
or   bitwise OR operator             (1)
xor  bitwise XOR operator            (1)

The operators have a precedence value. This value is given in parentheses above. When an expression is evaluated the higher precedence operators are evaluated before the lower precedence operators unless parentheses group the expression different. For example:

Example expression1.bas :

print 2+3*6

Result executing expression1.bas :

This is quite common in most languages. In case of using parentheses:

Example expression2.bas :

print (2+3)*6

Result executing expression2.bas :

Let's see some more complex examples of expressions:

Example expression3.bas :

FOR I=0 TO PI/2.0 STEP PI/20.0
PRINT I & " " & SIN(I) & " " & COS(I) & " " & SIN(I)^2+COS(I)^2
PRINT
NEXT I

Result executing expression3.bas :

The expression following the command PRINT is complex. It contains string concatenation as well as numeric function calls and addition operator and powering operator.

[Contents]

2.8. Conditional Execution

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.9. Loop Constructs

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.10. Functions and Subroutines

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.11. Mathematical Calculations

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.12. File Handling

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.13. Directory Handling

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.14. Packing and Unpacking

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.15. System Functions

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

2.16. Using Extensions

This section is under development. In case you think that you can and want to write this section, please do not hesitate. First contact peter@verhas.com for formatting details and then go ahead.

[Contents]

3. Complex Samples