The MTL611 is a version of the Psion LZ Organiser that is rated as "Intrinsically Safe" so that it can be used in hazardous environments. It was made by Measurement Technology Ltd., and they provided their own version of the manuals to go with it. This is their version of the Programming Manual.
INM611A-1
April 1992
1. Introduction 2. Basic OPL 2.1 The Prog Menu 2.2 Typing in, saving and running a procedure 2.3 Edit, Print, Dir, Copy, Delete 3. Procedures and variables 3.1 Procedure names 3.2 Declaring variables 3.3 Operations upon variables 3.4 Communication of variables 4. Loops and branches 4.1 The DO/UNTIL loop 4.2 The WHILE/ENDWH loop 4.3 BREAK 4.4 Labels and jumps 4.5 Branches 4.6 Endless loops 5. Operators 5.1 Operators 5.2 Operator precedence 5.3 Using brackets 5.4 Precedence of integer and floating point values 5.5 Logical Expressions q6. Handling data files 6.1 Creating a data file 6.2 Adding records to a file 6.3 Changing the current record 6.4 Opening a file 6.5 Changing the current file 7. Handling any type of file 7.1 Examples 7.2 Diary files 8. Error handling 8.1 Common errors 8.2 Run-time errors 8.3 Error trapping 9. Example programs 9.1 Days (version 1) 9.2 Days (version 2) 9.3 Dice 9.4 Mortgage calculator 9.5 Chase game 9.6 Data file handling procedures 9.7 Telephone logging (data file handling) 9.8 Diary file handling procedure 10. OPL commands and functions 10.1 Summary 10.2 Command syntax 10.3 Function syntax 10.4 List of commands and functions 11. Characters, data and error messages 11.1 Organiser character set 11.2 Technical Data 11.3 Technical Programming 11.4 Error Messages
This Programming manual gives information and procedures to enable users to write applications programs for the MTL611 IS Pocket data terminal, using the organiser Programming Language OPL. The main menu may also be modified to show only relevant operations for that particular application. The manual section headings are self explanatory.
The basic operating information for the MTL611 is given in the MTL Users manual INM611.
OPL is the Organiser Programming Language. It has a set of commands and functions suitable for all kinds of applications - including the manipulation of records in data files. From the Prog menu new programs can be started or old ones continued with. Once programs have been written in OPL, they can be run from within Prog or directly from the main menu or even whilst working on the calculator.
An OPL program consists of one or more procedures each of which is typed in separately. A simple program may consist of just one procedure and a more complex program a main procedure which calls on others.
The most efficient way to use OPL is to write short procedures which can be tested individually. Each one should ideally perform just one specific task. That way, programs which have similar requirements can share one common procedure to do the same job.
This section describes how to write, save and run a simple procedure and covers all the options on the Prog menu.
To enter OPL:
a) select Prog from the main menu, by pressing P
The Prog menu is as shown.
11:32a Edit New Run Print Dir Copy Delete
The options on the Prog menu are:
Edit | To alter an existing procedure. |
New | To type in and save a new procedure. |
Run | Executes an existing procedure. |
Prints out a procedure on an attached printer or computer. | |
Dir | Provides a directory list of procedures. |
Copy | Copies procedures to another device. |
Delete | Deletes procedures. |
There are three stages to producing a new procedure:
(i) Select New and type it in.
(ii) Save it and translate it into a form that the machine can read.
(iv) Run it.
The simple procedure below just clears the screen and displays the date until a key is pressed. The procedure's name is DATE:
DATE: CLS PRINT "TODAY IS",DAY;"/";MONTH GET
The following pages show how to type in, save and run this procedure.
a) Select New from the menu and the screen shows
New A:_
The current device is shown after the word New; in this case it is A: (the internal memory). To work on a pack, press MODE to change the device.
First type the procedure name, which can be up to 8 characters long and must start with a letter.
b) Type in DATE as the name for the first procedure. (Don't type the colon.) Press EXE.
This now opens the OPL Editor. The procedure name is shown with a colon at the end. The cursor is flashing at we end of it.
DATE:_
c) Press EXE to move the cursor down to the next line to begin typing. Typing in the OPL editor is the same as typing in the notepad.
If necessary, refer to section 4.6 Using the keyboard in the MTL Users manual INM611.
Note: In OPL use either upper case or lower case letters in any combination.
d) Type the first line:
CLS
This is a command. When you run the procedure, CLS is an instruction to OPL to clear the screen.
e) Press EXE to start a new line, then type:
PRINT "TODAY IS",DAY;"/";MONTH
Check that the line appears on the screen exactly as it is shown here as even the spaces are important:
(i) PRINT is a command. It makes what follows it print on the display screen. All commands are followed by a space.
(ii) "TODAY IS" is the text to be printed. A piece of text in quotes like this is called a string.
(iii) A comma makes the next item to be printed follow on the same line after a space.
(iv) DAY is a function. It finds out the date. Here it returns it to the print command, which displays it.
(v) A semi-colon makes the next item to be printed follow on the same line without a space.
(vi) "/" is another string of just one character and MONTH is another function.
f) Press EXE to start a new line, and type:
GET
The GET function, waits for a keypress before running the rest of the program. So when running DATE:, the date will remain on the screen until a key is pressed.
a) Make corrections at any time to what has been typed as follows:
(i) Use ←, →, ↑ and ↓ to move around.
(ii) Use DEL to delete the character to the left of the character and hold down SHIFT and press DEL to delete the character under the cursor.
(iii) To insert a new line between two existing ones, press EXE on the first character of the second one.
(iv) To join two lines, press DEL on the first character of the second one.
(v) To delete a line, press ON/CLEAR.
b) If required, press MODE and use four of the options on the editor menu to obtain help:
Find | Locates any search-clue specified (it is necessary to press ON/CLEAR to remove the find prompt) |
Home | Moves the cursor to the top of the procedure file. |
End | Moves the cursor to the bottom of the procedure file. |
Zap | Clears all the lines deleting the whole procedure text so that typing can start again. |
The other options on the OPL editor menu - Tran, Save Quit, and Xtran - are to do with saving and translating the procedure and are explained in the pages which follow.
c) Press ON/CLEAR to remove the editor menu.
when typing the procedure is finished, the following options are available:
(i) Translate it into a form which OPL can run.
(ii) Save it for editing - but do not run it.
(iii) Quit and abandon it.
a) Press MODE to get the editor menu. The first three options are: Tran Save Quit
The diagram illustrates the differences between them with the bold path showing the normal process of translating a new procedure.
Normally Tran is selected so that the procedure can be translated into a form that OPL can run.
a) Select Quit and the prompt message is given: Quit? Y/N
b) Press N to return to the procedure editor (If Y is pressed, everything typed during the editing session is discarded)
a) Select Tran.
The procedure is translated into a form that OPL can run. When the procedure has been translated, the screen displays this prompt: Save A:DATE
The translated procedure can now be saved.
b) Press MODE to change device in order to save on a pack, then EXE to save.
This returns to the Prog menu. When the translated version is saved, the original text version is saved with it. So it can be run and re-edited later.
When a typing error occurs, OPL spots it during translation. For example, if PRONT was typed instead of PRINT or one of the pair of quotation marks round a string was omitted, this message is displayed:
ERROR SYNTAX ERR .................... press SPACE key
c) Press SPACE to return to the editor, with the cursor near the error.
d) Correct it, press MODE, and select Tran again.
When saving a procedure rather than translating it, no error checking is done. The text is simply saved exactly as typed in.
If typing part of a procedure and intending to complete it later, select Save instead of Tran to avoid producing an unnecessary translated version.
The best place to save programs is on device A: or a Rampak. Then, if a procedure takes a couple of versions before it runs properly, each version will not use up space. Note that:
(i) when an edited version is saved on A: or a Rampak, the old version is deleted completely each time the new version is saved or translated.
(ii) On Datapaks, however, the old versions remain there taking up space and cannot be accessed.
When a final version of a procedure has been produced on device A for safe storage copy it to a Datapak.
After successfully translating a procedure, it can be run:
a) From the Prog menu, select Run. The name of the procedure just translated is supplied:
Run A:Date
b) Press EXE to run the procedure.
When DATE: is run, the screen will first clear and then show something like this, depending on the date:
TODAY IS 19/8
The last line of the procedure was GET. This instruction simply waits until a key is pressed before continuing. Therefore, when a key is pressed, the procedure finishes, returning to the Prog menu.
Like Run, the remaining Prog options all require an existing procedure file to be specified.
If still in Prog, the name or the procedure worked on last is supplied for Edit and Print. Either press EXE to accept it, or ↓ to get a list of procedures to select from. For information on selecting from file lists, see Section 5.3 in the MTL Users manual INM611.
The Edit option from the Prog menu allows a return to an old procedure to change it or add to it.
a) Select Edit and press MODE to change device if necessary, then select a procedure file.
After finishing editing the procedure, either:
(i) Press MODE, than EXE to translate and save it.
or if the editing needs to be revised:
(ii)Press MODE then Q to quit and delete this version of the procedure so the original can be edited again.
The Print option is used to print out a listing of a procedure on a printer or personal computer.
a) Select Print then select a procedure file.
If no printer or computer is connected to the organiser, this error message is displayed
DEVICE MISSING
For more details on printing, see Section 11 in the MTL Users manual INM611.
The Dir option on the Prog menu shows the directory or procedures stored on the various devices.
a) Select Dir from the Prog menu. The screen shows:
DIR A:_
If necessary, change device with MODE, then list the procedures with ↓ in the same way as Dir in Utils. See section 9 in the MTL users manual INM611.
The Copy option in the Prog menu is used to make copies of procedures from one device to another.
a) Select Copy from the Prog menu:
Copy Select type .................... Opl Oplobj Opltxt
b) Select the part of the procedure to be copied.
Opl | copies both the text version and the translated object code of the procedure to enable the copy to be edited and run. |
Oplobj | Copies only the translated object code version and editing cannot be carried out. |
Opltxt | Copies only the editable text version and cannot be run until after translation again. |
c) Copy in Prog operates just like Copy in Utils.
Warning: When copying a procedure file, if one with the same name already exists on the destination device, the existing one is deleted - even if the existing one is text only and the one being copied is object only.
Copy cannot be used to rename a procedure. Instead it must be saved under a different name. For example, to rename A:DATE to A:TODAY.
a) Select Edit to edit A:DATE then select Tran.
b) When the Save A:DATE prompt appears, press ON/CLEAR then enter the new name, TODAY and press EXE.
The Delete option allows procedures to be deleted from any of the devices.
a) Select Delete to get the prompt: Delete A:_
If necessary change device with MODE. Select a file or files to be deleted in the same way as in the Utils Delete option.
To insert the name of a procedure in the main menu:
a) On the main menu, press MODE with the cursor marking where the name is to be.
b) Type in the name of the procedure.
c) Select Opl.
When the name is selected the procedure runs.
For example, type in, translate and save a procedure like the one below, then enter its name, ID, in the main menu. When the item ID is selected, the Organiser will be identified.
ID: CLS PRINT "IF FOUND PLEASE RING" PRINT "PAUL SMITH EXT. 998" GET
Sometimes a procedure may need to be stopped while its running. To halt the execution of a procedure.
a) Press ON/CLEAR.
This will pause it indefinitely. (Unless the procedure was waiting for a key, with a function such as GET.)
b) Press Q to quit (or any other key to continue).
If the procedure was run from the main menu, the screen shows:
ERROR ESCAPE IN A:procname .................... press SPACE key
c) Press the SPACE key to return to the main menu.
If the procedure was run from the Prog menu, the screen shows:
ERROR ESCAPE .................... Edit A:procname Y/N
d) Press Y to enter the procedure text to edit it, or press N to return to the Prog menu.
The previous section dealt with the mechanics of using the Prog menu. The next six sections cover the basic concepts of OPL programming. If familiar with programming languages just skim through these sections, or refer instead to the example programs and reference sections which follow.
Procedures generally consist of the four steps shown in this simplified example:
(i) Name | SINE50: |
(ii) Declaration of variables | LOCAL x |
(iii) Operations upon variables | x=SIN(50) |
(iv) Communication of variables | PRINT x |
This section deals with these four steps.
e.g. print:, shares89:, TAXCALC:
(i) They may be up to 8 characters long and can combine numbers and letters. The first character must be a letter.
(ii) They end with a colon, but it is only in certain circumstances that this must be typed in. For example, there is no need to type it in when naming a new procedure, but it must be typed in when calling up a procedure from within another one.
(iii) They may be typed in upper or lowercase letters.
Adding together two numbers in algebra could be written as: "x + y = z".
In OPL this would be written z=x+y, but first x, y and z must be declared as variables, in order to
reserve memory space for them. To do this:
a) Declare the variables in order to reserve 3 spaces in memory, called x, y and z.
LOCAL x, y, z
b) Assign values to x and y.
x=5
y=2
c) Add x and y together and assign the result to z.
z=x+y
A variable is therefore a named region of memory which at the very beginning of the procedure is declared. This informs the Organiser of the intention to use the variable so that it will have space to store the number or text later assigned to it. So in the SINE50 example the line 'LOCAL x' reserves a memory space named x in which the value given to x in the next line can be stored.
There are three kinds of variables identified that are declared by the format of the variable name. The three kinds are:
(i) Floating point variables | e.g. x |
(ii) Integer variables | e.g. x% |
(iii) String variables | e.g. x$ |
All variable names may be up is 8 characters long. The first character must be a letter. The other characters may be letters or numbers but not symbols - except for the identifiers % and $ at the end.
A floating point number is one which has a decimal point and then any number of digits after that point, e.g. 13.567 or 8. or 0.05319 or 6.0
A floating point variable should be declared when the sort of value likely to be assigned to it will be a floating point number.
A floating point variable name does not have any special symbol at the end.
e.g. a, AGE, PROFIT89.
Floating point variables are stored in an accuracy of 12 digits and must be in the range +-9.99999999999E99 to +-1E-99 and 0
An integer is a whole number e.g. 6 or 13 or -3 or 11058
Integer variables should be used wherever floating point numbers are not necessary and speed or space are important integer arithmetic is faster than floating point and it occupies two bytes of memory instead of eight.
An integer variable name ends with a % sign. (The % sign is included in the 8 characters length.)
e.g. a%, AGE%, PROFI89%
Integer variables must be in the range -32768 to -32767.
A string is a sequence of characters, alphabetic, numeric or symbolic, which is treated literally rather than being evaluated. Examples of strings are: "x + y =" and "01-345-2908" and "profit".
A string variable name ends with a $ sign. (The $ sign is included in the 8 characters length.)
e.g. a$, NAME$, MAN6$.
When declaring a string variable, the maximum length of the string expected to be assigned to it must be stated. If it is wanted to enter names up to 15 characters long as the value of NAME$ then declare NAME$(15). The number goes in brackets. The maximum length of a string is 255 characters.
Variables must be declared immediately after the procedure name. All 3 types may be listed together in any order, but they must be separated by commas as shown:
LOCAL x,y,a%,NAME$(15),YEAR3%
To declare variables use either the LOCAL or the GLOBAL command as follows:
LOCAL x,a%,list$(8)
or
GLOBAL x,a%,list$(8)
LOCAL and GLOBAL define the range the variables are to be active in. The basic difference is that:
(i) Local variables are limited to the procedure in which they are declared.
(ii) Global variables can also be used in any procedures called by the procedure in which they are declared.
An OPL program can be made up or more than one procedure. However, each procedure must be separately typed and translated.
In the example below, the fourth line of proca: calls another procedure, procb:. To do this, just type the procedure name (with the colon).
proca: procb: GLOBAL a% a%=a%+4 a%=2 procb: PRINT a%
Declare a% as a global variable so that it can be used in the second procedure. In this example the value printed out when proca: is run is 6.
The only danger with global variables is that mistakes can occur if they accidentally use the same variable name twice. So, use the LOCAL command unless the GLOBAL one is required.
If OPL comes across a variable which isn't declared in that procedure, it assumes it has been declared in a previous procedure. OPL will then report a MISSING EXTERNAL error if it can't find the global variable in a calling procedure.
There are ten floating point variables which are always available. These are the calculator memories m0 to m9. They need not be declared as variables, as they are always in existence.
Values may be assigned to these memories at any time in any procedure. They can then be accessed in the calculator.
It may be necessary to declare a large number of similar variables at the beginning of a program. For this reason, OPL has array variables.
The idea is simply that, instead of having to declare separately variables a, b, c, d, and e, they can be declared as variables a1 to a5 in operation as follows:
LOCAL a%(5) | (integer variable array) |
LOCAL a(5) | (floating point variable array) |
LOCAL a$(5,8) | (string variable array) |
Numeric array variables may be thought of as a list of numbers, each with the same name but with an index number to differentiate them.
When the array is declared, the number in brackets is the number of elements in it. The following is a simple example assigning values to the elements of an integer array:
procname: GLOBAL num%(4) num%(1)=1 num%(2)=3 num%(3)=5 num%(4)=7 PRINT num%(1)+num%(2)+num%(3)+num%(4)
This example just prints the sum of the four elements of the array num%.
With strings, the number of elements in the array must be declared and the maximum length of the strings.
For example GLOBAL ARRAY$(5,10) allocates memory space tor five strings, each up to ten characters in length, under the names ARRAY$(1) to ARRAY$(5). As yet, each of the variables is empty (is a null string), but enough memory still has to be set aside to contain all of the five strings when full.
Once the variables have been declared, any number of operations on them can be performed. This might be a combination of arithmetic operations, or the variables might be passed to other procedures for them to operate upon them, or use one or the OPL functions. Whatever is done, however, it is necessary to understand how the variables will react according to what type they are and how they have been combined.
For example, a string variable cannot be divided by an integer variable. And if integers and floating point variables are mixed in the same sum one may convert the other into its own type or variable. The following subsections give details of what problems may arise and how to avoid them.
In the procedure below there is a potential mistake in the third line after the name, where the integer variable y% is assigned a floating point valve.
procname: GLOBAL x%, y% x%=7 y%=3.7+x% PRINT y% GET
OPL deals with this in the following way: instead of reporting an error, OPL carries out an automatic type conversion internally on the value assigned to the mismatched variable.
The right hand side of y%=3+x% is evaluated to 10.7. However, the fractional part of the number is dropped before the result is assigned to the left hand side, y%. So, the PRINT statement will display the value 10.
Since OPL does not report this as an error, the onus is on the user to ensure that it does not happen - unless it is wanted to! Therefore always take care when mixing variable types that the answer produced is the one which is expected.
In the procedure below where only floating point variables are used, it can be seen that another type conversion is made, but does not cause the value to change:
procname: GLOBAL a,b,c a=1.2 b=2.7 c=3 PRINT a+b+c
In this procedure, the floating point variable c is given the integer value 3. An automatic type conversion is carried out in such cases. Here the result is converted to 3.0, so the real value of the variable remains the same.
If assigning a floating point number to an integer variable, then the automatic type conversion will generate an integer rounded down. So if for example a%=2.3 then the value of a% will be 2, but a%=2.9 would also give a% the value 2. And if a negative floating point number is assigned to an integer variable, then the number is still rounded down rather than toward zero. So if for example a%=-2.3 then a% will take the value -3. This may not be desirable.
If it is expected that an expression will return a floating point number, then ensure that the correct types of number are used within that expression.
It is possible to control how floating point numbers are rounded when converted. For example, if it is wanted to round floating point numbers to the nearest half (so 2.4 would round to 2.5 and 2.2 to 2) then the following statement could be tried:
r=INT(2*n+0.5)/2
where n is the number to be rounded.
This would produce the wrong result, though. To see why, substitute a trial value, say 3.4 instead of n:
INT(2*3.4+0.5) i.e. INT(7.3).
This returns the integer 7. But 7/2, when rounded down gives the integer 3, not 3.5.
To obtain 3.5 the division must be forced to give a floating point result in this case the simplest way to do this is to divide by the floating point value or 2.0, instead of the integer 2. So the expression:
r=INT(2*n+0.5)/2.0
will give the required result.
There is more about integers and floating point variables in Section 3.2.
If a number is attempted to be allocated to a string variable, an error will be reported There is no automatic type conversion between string and numeric variables. However, OPL does have facilities for forcing conversion of numbers to strings and vice versa. These are the SCI$, FIX$, GEN$, NUM$ and VAL functions.
Adding strings together is as easy as adding numeric variables:
* If a$ is "DOWN" and b$ is "WIND", then the statement c$=a$+b$ means c$ is "DOWNWIND".
Alternatively, c$ could be given the same value with the statement c$="DOWN"+"WIND".
When concatenating strings, the result cannot be longer than the maximum length declared.
Strings can also be split up. This process is known as string slicing.
There are three functions which allow this to be done. They are LEFT$, RIGHT$ and MID$. These allow the left, right or middle portions of a string to be accessed respectively. For example:
(i) If a$="01-234-5782", then b$=LEFT$(a$,2) assigns the variable b$ the string 01.
String slicing operations leave the original string unchanged - i.e. a$ would still have the value 01-234-5782 after b$ had gained the value 01. The exception would be when the left hand side of the expression is the same string as appears in the right hand side. E.g. a$=LEFT$(a$,4) would return a string containing the leftmost four characters of a$ and assign it to a$, thus overwriting the original value.
Note: If it necessary to define a string which includes the quotation mark character (ASCII character 34) then this character must be included twice in the string. So, if you say a$="x""y""z", then the resulting value of a$ will be x"y"z.
In the first example procedure at the beginning of this chapter the statement PRINT x simply takes the value found in the memory space at variable x and prints it on the screen.
Values can also be passed between procedures. In the example In section 3.2.6 the procedure proca: called another procedure procb: which returned the adjusted value of a% back to proca:. The variable a% was declared global to allow this.
The rest of this Section deals with two other ways of communicating values: entering values from the keyboard using the INPUT command, and passing values between procedures using parameters.
Values can be entered from the keyboard using the INPUT command, as in the example below.
This simple procedure just requests the entering of a number. The number entered is assigned to the variable x and is then printed out to the screen with a message:
INPROC: LOCAL x CLS PRINT "ENTER BATCH NUMBER" INPUT x CLS PRINT "BATCH NUMBER",x GET
For full details of the INPUT command, see Section 10.
Values can be passed between procedures using parameters. In the VAT example below, the second procedure VAT1: is followed by a parameter name (p).
The last line if the first procedure PROC1: calls VAT1 with the value of x. The value of x is copied to the parameter p. VAT1: then prints out this value plus VAT at 17.5%.
PROC1: LOCAL x CLS PRINT "ENTER PRICE" INPUT x VAT1:(x)
VAT1:(p) CLS PRINT "PRICE INCLUDING VAT =",p*1.175 GET
(i) Calling a procedure which has parameters means that the first procedure can use local rather than global variables which is sometimes neater.
(ii) Parameters differ from variables in that values cannot be assigned to them. They have an external value passed to them from the calling procedure and it is then illegal to assign another value by saying, in the above example, p=p+1.
(iii) Parameter names are typed in brackets immediately after the colon of the procedure name. Their type is specified as with variables e.g. p for a floating point value, p% for an integer and p$ for a string.
In this similar VAT example the second procedure VAT2: has two parameters.
The value of the price variable, x, is passed to the parameter p1 and the rate of VAT is also a variable, r, which is passed in the parameter p2. VAT2 then prints out the price plus VAT at the rate specified.
PROC2: LOCAL x,r CLS PRINT "ENTER PRICE" INPUT x CLS PRINT "ENTER VAT RATE" INPUT r VAT2:(x,r)
VAT2:(p1,p2) CLS PRINT p1+p2/100*p1 GET
(i) Variable names can be passed, strings in quotes, or actual values to parameters.
(ii) When passing multiple values to multiple parameters, make sure that the order of the values when the procedure is called corresponds to the order of parameters after the procedure name.
For example:
Procedure call - | PROC:("a string",9,3.7) |
Procedure name - | PROC:(p$,p%,p) |
This VAT example differs from the previous two in that control does not end with the second procedure but returns instead to the first.
The RETURN command is used to return the value of x plus VAT at r percent - to be printed out in PROC3:. VAT3: is now just doing the calculation and not printing. This means it can be called by other procedures which need this calculation but do not necessarily need to print it.
PROC3: LOCAL x,r: CLS PRINT "ENTER PRICE" INPUT x CLS PRINT "ENTER VAT RATE" INPUT r CLS PRINT "PRICE INCLUDING VAT =",VAT3:(x,r) GET
VAT3:(p1,p2) RETURN p1+p2/100*p1
(i) Only one value may be returned by the RETURN command.
(ii) The name of a procedure which RETURNs a value must end with the correct identifier e.g. PROC$: for one which returns a string; PROC%: for one which returns an integer; PROC: for one which returns a floating point value (as in this example).
(iii) The RETURN command returns to the point where the procedure was called.
So far programs have only been considered which run in a straight line from start to finish. They consist if a number of instructions which are executed in the order they appear in the program; if an instruction is to be carried out more than once then it must be repeated.
That is clearly very inefficient. A far more efficient method is for the program to be able to loop around a particular part as many times as required, or until a certain condition is met.
There are a number of ways of achieving this in OPL.
The first two are the DO/UNTIL and the WHILE/ENDWH loops. These are known as structures. They operate in a similar way to each other, with one difference:
(i) The DO/UNTIL structure tests for a condition being fulfilled at the end of the loop.
(ii) The WHILE/ENDWH structure tests the condition at the start of the loop.
Up to eight loops can be nested within each other.
This is an example of a DO/UNTIL loop:
a%=10 DO PRINT "A=";a% a%=a%-1 UNTIL a%=0
First 10 is assigned to a%. The loop starts on the next line, with the instruction DO. This says to OPL
"Execute all the following instructions until an UNTIL is reached. If the condition following UNTIL is not met repeat the same set of instructions until it is."
The next line displays "A=" followed by the value of a%. The first time through the loop this is 10.
Next, the value of a% has 1 subtracted from it so that a% is 9. Now comes UNTIL, followed by a condition. The condition is that a% is equal to zero. It isn't yet, so the program returns to DO and the loop is repeated. Now a% decrements to 8, and again the condition fails. This process continues until a% does equal zero.
When a% equals zero the loop finishes and the program continues with the instructions after UNTIL.
There are many more examples of the DO/UNTIL structure in the example programs in section 9.
The WHILE/ENDWH loop is similar, except that the test condition is at the beginning. For example:
a%=10 WHILE a%>0 PRINT "A=";a% a%=a%-1 ENDWH
The WHILE loop is only entered if the condition at the top is true. In this case if a% is greater than 0. In the last example program Section 9, there is a loop which starts:
WHILE FINDW("*1989*birthday")
The loop will only be entered if a string is found corresponding to the search clue. This is because the FINDW function returns 0 if no string is found. In logical terms 0 means false so in that case the WHILE condition would not be fulfilled.
BREAK can be used in conjunction with an IF statement (see 4.5) to break out of a DO or WHILE loop. It jumps to the instruction after the end of the loop
Another command which can direct the program out of a straight sequence is GOTO. This jumps to a label.
In this example, when the program reaches the GOTO. It jumps to the line beginning with the label exit::,
GOTO exit:: PRINT "MISS THIS LINE" PRINT "AND THIS ONE" exit::
Labels end in a double colon.
The label must be in the same procedure as the GOTO, and the jump is not conditional, it always happens.
GOTO is a way of branching, but it is a fairly crude tool and can make procedures difficult to read.
Better is the IF/ELSEIF/ELSE/ENDIF structure. This structure is used to perform one or more instructions IF a condition is met. If the condition is not met, an ELSEIF instruction can be used to test for another condition. Any number of ELSEIF instructions can be held within an IF/ENDIF structure.
After all likely things are catered for by the ELSEIF instructions, other possibilities can be catered for by an ELSE statement, followed at the end by the ENDIF statement. The following is an example:
whatkey: LOCAL g% g%=GET PRINT "THAT KEY IS" IF g%>64 AND g%<91 PRINT "UPPER CASE" ELSEIF g%>96 AND g%<123 PRINT "lower case" ELSE PRINT "NOT A LETTER" ENDIF GET
This just waits for a key to be pressed, and then prints that it is either a lower or upper case letter. (For an explanation of the significance of the numbers 64 and 91, see Section 11). If it is not a letter at all, then that is printed as allowed for by the ELSE statement.
ELSEIF and ELSE statements are optional, but for every IF there must be a corresponding ENDIF.
ESCAPE OFF, GET, KEY and INPUT must be used with caution in loops for the following reasons:
To halt the execution at a procedure, press ON/CLEAR then Q:
(i) If an ESCAPE OFF command has seen used, this disables ON/CLEAR and therefore an escape can only be made by removing the battery and thus losing data.
(ii) If a function such as GET or KEY is used to read a keypress, press ON/CLEAR quickly followed by Q and repeat this very quickly a few times. This may be very difficult to do.
+ | add |
- | subtract |
* | multiply |
/ | divide |
** | raise to a power |
- | unary minus (make negative) |
% | percent |
> | greater than |
>= | greater than or equal to |
< | less than |
<= | less than or equal to |
= | equal to |
<> | not equal to |
AND
OR
NOT
Highest: | ** |
- (Unary minus) NOT | |
* / | |
+ - | |
= > < <> >= <= | |
Lowest: | AND OR |
The percent operator % is rather different as its effect depends on the operator it is combined with. The way % works is described in the calculator section of the operating manual.
An expression such as some presents no problems, as the result is the same whichever addition is
done first. However, it is possible to enforce precedence with brackets. For example:
a+b*c/d
is evaluated in the order: b multiplied by c, then divided by d, then added to a. To perform the addition
and the division before the multiplication, use brackets:
(a+b)*(c/d)
(i) In an expression where all operators have equal precedence, they are evaluated from left to right.
(ii) Powers, however, are evaluated right to left.
Therefore, in the expression:
a%**b%**c%
b% will first be raised to the power of c% and the resulting value will be used as the power of a%.
When in doubt, always use brackets.
Floating point and integer values can be mixed in expressions but be aware how OPL handles the mix:
(i) Floating point variables take priority over integers so in an expression linked by an operator to a floating point number integers will be converted to floating point.
but then
(ii) The result of the right hand side of an expression is converted to whatever type the left hand side is.
For example, the procedure might include the expression:
a%=b%+c
This is handled like this: b% is converted to floating point and added to c. The resulting floating point value is then automatically converted to an integer in order to be assigned to the integer variable a%.
These conversions may produce odd results, so be careful. For example, a%=3.0*(7/2) assigns 9 to a% but a%=(3.0*7)/2 assigns 10 to a%.
The comparison operators and logical operators are based on the idea that a certain situation can be evaluated as either true or false. For example, if a%=6 and b%=8, a%>b% would be false. They are however useful for setting up alternative paths in the procedures as shown in the following example:
IF salary<expenses PRINT "bad" ELSEIF salary>expenses PRINT "good" ENDIF
The fact that the result of these logical expressions is represented by an integer can also be made use of:
(i) True is represented by the integer -1
(ii) False is represented by the integer 0 (zero)
These integers can be returned to a variable or printed out to the screen to confirm whether a particular condition is true or false, of used in an IF statement.
For example, if a procedure results in two sub-totals, a and b, to find out which is the greater, include the statement: PRINT a>b. If zero is displayed, a and b are equal or b is the larger number but if -1 is displayed, 'a>b' is true - a is the larger.
Example | Result | Integer Returned | |
< | a<b | True if a less than b | -1 |
False if a greater than or equal to b | 0 | ||
> | a>b | True if a greater than b | -1 |
False if a less than or equal to b | 0 | ||
<= | a<=b | True if a less than or equal b | -1 |
False if a greater than b | 0 | ||
>= | a>=b | True if a greater than or equal to b | -1 |
False if a less than b | 0 | ||
<> | a<>b | True if a not equal to b | -1 |
False if a equal to b | 0 | ||
= | a=b | True if a equal to b | -1 |
False if a not equal to b | 0 |
These operators can be used with a mixture of floating point or integer values. However, if one side of the comparison is a floating point, and the other is an integer, the integer is converted to a floating point. So if a%=1 and b=1.2, b>a% is true. A mix of string and numeric values cannot be used, so a$<b is invalid.
Few programmers need the following information, so skip the rest of this section if it seems daunting.
The logical operators AND, OR and NOT have different effects depending on whether they are used with floating point numbers or integers:
1. When used with floating point numbers only, the logical operators have the following effects:
Example | Result | Integer Returned |
a AND b | True if both a and b are non-zero | -1 |
False if either a or b are zero | 0 | |
a OR b | True if either a or b are non-zero | -1 |
False if both a and b are zero | 0 | |
NOT a | True if a is zero | -1 |
False if a is non-zero | 0 |
2. When used with integer values only, AND, OR and NOT are bitwise logical operators.
The way the Organiser holds integer numbers internally is as a l6-bit binary code. So, 7 looks like this:
0000000000000111
The Organiser's numerical range is +32767 to -32768. 32767 is the largest number that can be
represented with 15 binary bits. The 16th bit is used for the + or -.
As the operators are bitwise may perform the operation on first the 1st bit, then the 2nd, up to the 16th bit.
AND The statement PRINT 12 AND 10 prints 8. To understand this, write 12 and 10 in binary:
12 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
AND acts on each pair of bits. Thus, working from left to right - discounting the first 12 bits:
1 AND 1 → 1
1 AND 0 → 0
0 AND 1 → 0
0 AND 0 → 0
The result is therefore the binary number 1000, or 8 in decimal.
OR What result would the statement PRINT 12 OR 10 give? Again, write down the numbers in binary and apply the operator to each pair of digits.
1 OR 1 → 1
1 OR 0 → 1
0 OR 1 → 1
0 OR 0 → 0
The result is the binary number 1110, or 14 in decimal.
NOT NOT works on only one number. It returns the one's complement, i.e. it replaces 0s with 1s and 1s with 0s.
So if 7 looks like this: | 0000000000000111 |
NOT 7 will look like this: | 1111111111111000 |
This is the binary representation of -8.
Hint. A quick way of calculating NOT for integers is to add 1 to the original number and reverse its sign. Thus, NOT 23 is -24, NOT 0 is -1 and NOT -1 is 0. The last two results are the same for floating points.
When the SAVE option from the main menu is used records are saved in a file called MAIN. Extra data files can also be created in the Xfiles option. These files and their records can be accessed from OPL. New files can also be created and then manipulated. This section explains how to do it.
Three examples of data file handling programs are given in Section 9.7. It may be found helpful to refer to those programs while reading this section.
The data file MAIN and any extra ones created contain records which are divided into fields. When saving a record from the main menu with the SAVE option, start a new field every time a new line is started by pressing ↓.
In a name and address file, in each record there might be a name field, a telephone number field, and separate fields for each line of the address.
Before starting to enter data into a new data file, the file must be created on one of the devices using New in Xfiles or the CREATE command in OPL.
CREATE in OPL gives more user control because the user specifies how many fields there can be in each record, and what type of data can go in each field. The CREATE command has this syntax:
CREATE "dev:fname",logname,fldnm1,fldnm2
"dev:fname", is the device (A:, B: or C:) which the file is to be on, and then the file name. This all goes in quotes as a string, e.g. "a:clients". This device and the name string can also be assigned to a string variable (e.g. cl$="a:clients") and then the variable name (cl$) used as the parameter. The file name may be up to 8 characters long.
logname is the logical file name. This may be A, B, C or D. This logical file name is used to refer to the file from within the program.
fldnm1, fldnm2 are the field names. There may be up to 16 fields in any record, and these may be given a qualifier, either % or $, to signify integer data or string data respectively. Fields containing floating point data need no qualifier. Field names may be up to 8 characters long including any qualifier used.
An example of a CREATE command might be:
CREATE "a:clients",B,nm$,tel$,ad1$,ad2$,ad3$
When a file has been created, it is automatically open. This means records can be saved to it immediately. It also becomes the current file which means that when one of the commands is used for manipulating records, they operate on this file.
Records are added to a data file field by field. First assign some values to the current held names, then use the APPEND command to add them to the file.
The field names act in a similar way to variables, and can he assigned values and used in INPUT statements. The field name must be used with the logical file name as follows:
INPUT B.name$
or
B.name$="MR Bruno"
where B is the logical file name and name$ is the name of the field. These are separated by a full stop.
When values have been assigned to the fields, add them to the open file with the APPEND command. They are always added as the last record in the data file. If the file is a new one, this will be the first record.
The APPEND command has no parameters - the field values are automatically added to the file in the correct order and format.
If it is attempted to assign a text string to a numeric field name, an error will be reported.
See the example program procedure 2 (insert:) in section 9.6 for an example of adding records to a data file.
At any time while a data file is open the field names currently in use can be used like any other variable - for example, in a PRINT statement, or a string or numeric expression. However, in order to operate on a particular field, the record containing it must be made the current one.
A record must be made current before it is possible to erase it or operate on the fields in it. The current record can be changed by using any of the six commands and functions below.
FIRST | moves to the first record in a file. |
NEXT | moves to the following record in a file. If the end of the file is passed, NEXT does not report an error. The current record will then be null. This condition can be tested for with the EOF function. |
BACK | moves to the previous record in a file. If the current record is the first record in the file then the current record does not change. |
LAST | moves to the last record in the file. |
POSITION | moves to a particular record. For example, the instruction POSITION 3 makes record 3 (the first record is record 1) the current record. To find the current record number use the POS function which returns the number of the current record. |
FIND | moves to the record which contains a search string that is specified. |
The FIND function acts like the main menu Find, but without wild cards. The difference is that whereas the main menu Find prints the record on the screen, this function makes it the current record so that it can be operated on: editing it, erasing it, or just displaying it.
For example, the line
r%=FIND("HOLMES")
would make the first record containing the string "HOLMES" the current record and return the number of that record to the variable r%. If the number returned is zero, the string was not found.
There is another function, FINDW, which is the same as FIND but does allow wild cards. So, to find the first record containing ORDER and 89 use the following instruction:
r%=FINDW("*ORDER*89*")
+ Matches any character
* Matches any group of characters
See the example program procedure 3 (search:) in Section 9.6 as an example of how to find and edit records.
To erase a record, make that record current by use of one of the commands FIRST, NEXT, BACK, LAST, POSITION or FIND and then use the ERASE command. This removes the current record from the file and renumbers the ones that follow.
See the example procedure 5 (erase:) in Section 9.6 as an example of how to find and erase records.
When a data file is created using the CREATE command it is automatically open but it closes again when the program ends. To open the file again in another program, use the OPEN command.
The syntax of the OPEN command is the same as for the CREATE command. The same device and the name must be used as when it was first created, but when opening it in a different program, it can be given a different logical file name and given different field names. For example, a file which was created in one program with the command:
CREATE "c:address",D,name$,num$,add$,add2$
can be opened in another program by the command:
OPEN "c:address",A,a$,b$,c$,d$
Up to four files may be open at any one time, and these may be spread over any of the three devices. Each must be referred to in the program by a different logical name. Therefore if 4 files are open, one is A, one is B, one is C and the other is D.
Before editing or erasing records in the file, all the fields to be operated on in the OPEN command must be included. However, if only searching for strings and display records, it is only necessary to include the first field in the OPEN command, as follows:
OPEN "c:address",A,a$
When a file is created or opened, that file is then automatically the current file and all access is to that file until it is wanted to USE a different one. The USE command makes a file current. The file should be referred to by its logical file name. For example:
USE B
In this example the file with the logical file name B (as specified in the OPEN or CREATE command which opened it) becomes the current file. All access is now to this file until the current file is changed with another USE command, or the OPEN or CREATE commands open another file. If an attempt is made to use a file which has not previously been opened, an error is reported.
Data files close automatically when programs end. However, when accessing a particular file is finished. It can be closed with the CLOSE command which closes the current file.
There may be a need to close a file if already 4 files are open in a program, and it is wanted to open another, or if it is wanted to delete the file. There is a command DELETE for deleting data files, but the file to be deleted must be closed first.
See Section 10.1 for a summary of all the data file handling commands and functions. Then look up each one for more detail.
See the example program procedures given in Sections 9.6, 9.7 and 9.8 for examples of data file handling programs.
Most of the file handling commands and functions are only for data files.
However there are three, COPYW, DELETEW and DIRW$, which operate on any type of file. The type of file must be indicated with these extensions:
Data file and diary file | .ODB (ODB stands for Organiser Data Base.) |
OPL procedure | .OPL |
Notepad file | .NTS |
Comms Link setup file | .COM |
Spreadsheet file | .PLN |
Pager setup file | .PAG |
Diary file from XP or CM | .DIA |
There are also two extra extensions for COPYW only. Use these to copy only one part of an OPL procedure.
OPL procedure (text only) | .OPT |
OPL procedure (object only) | .OPO |
Wild cards can also be used with COPYW, DELETEW and DIRW$. The wild cards are the normal
ones:
+ is any character, * is any group of characters.
COPYW "A:*88.OPL","B:"
Copies all the OPL procedures whose names end in 88 from A: to B:
DELETEW "C:*.NTS"
Deletes all the notepad files on C:
DIRW$("A:R*)
Returns the name of the first file of any type on A: which starts with the letter R.
Diary files are saved as data files. Each entry is a record with this two field format:
1989042712000100 JAMES BIRTHDAY
In this example, the first field carries this information:
1989 | The year |
04 | The month |
27 | The date |
1200 | The start time |
01 | The duration - one 15 minute interval |
00 | The alarm pre-warning time. In this case there is no alarm so it's zero. |
It is possible to open a saved diary file in Xfiles, and then find and update records in it. For example, to find all the annual entries such as birthdays and include the changes from 1989 to 1990. If the diary is then restored and merged with the current one it won't be necessary to put in all the birthday entries again at the end at the year. However, be careful to use the right format, or it won't be possible to restore the diary.
This could also be done in OPL using the data file handling and string handling commands. See the example program in Section 9.8 which carries this out.
This section covers commonly made errors, then error trapping. There is a list of the OPL error messages in Section 11.4.
All programming languages are very particular about the way commands and functions are used, especially in the way program statements are laid out.
Below are a number or errors which are easy to make in OPL. The incorrect statements are in bold and the correct versions are on the right.
Omitting the colon between statements on a multi-statement line:
Incorrect | Correct |
a$="text" PRINT a$ | a$="text" :PRINT a$ |
Omitting the colon after a called procedure name:
Incorrect | Correct |
proc1: GLOBAL a,b,c . . proc2 |
proc1: GLOBAL a,b,c . . proc2: |
Omitting one or more of the colons after a label:
Incorrect | Correct |
proc1: GOTO below: . . below:: |
proc1: GOTO below:: . . below:: |
Omitting the space before the colon between statements on a multi-statement line:
Incorrect | Correct |
proc1: a$=b$:PRINT a$ |
proc1: a$=b$: PRINT a$ |
Passing a floating point value to a procedure which requires an integer - here the procedure proc2:(x%).
Incorrect | Correct |
2*6+proc2:(PI) | 2*6+proc2:(INT(PI)) |
This may also happen when a procedure is called from the calculator. The calculator converts all numbers to floating point, so:
Incorrect | Correct |
Calc:proc2:(3) | Calc:proc2:(INT(3)) |
Passing an integer to a procedure which requires a floating point value - here the procedure proc3:(x)
Incorrect | Correct |
proc1: . . proc3:(2/3) |
proc1: . . proc3:(2.0/3) |
Passing the wrong number or parameters to a procedure - here, the procedure proc4:(x,y)
Incorrect | Correct |
proc1: . . proc4:(3.7) |
proc1: . . proc4:(3.7,2.5) |
OPL only allows numbers between minus 32768 and plus 32767 to be assigned to integer variables, so any expression which exceeds these limits will cause an error:
Incorrect | Correct |
proc1: LOCAL a% a%=100*2468 |
proc1: LOCAL a a=100.0*2468 |
The structures allowed within OPL are DO/UNTIL, WHILE/ENDWH and IF/ELSEIF/ELSE/ENDIF. These may all be nested within one another to up to eight structures deep. Attempting to nest to a greater depth than this will cause an error. Mixing up the three structures e.g. by matching up DO with WHILE, will also cause an error:
Incorrect | Correct |
proc1: . DO . WHILE a<2 |
proc1: . DO . UNTIL a>=2 |
If an error occurs when running a program, the program stops and an error message is displayed.
If running the procedure from the main menu, just press SPACE to return to the menu.
However, if a procedure is being run from the Prog menu, an option is given to edit it. In the following example a call has been made to a procedure called subproc: which does not exist:
MISSING PROC SUBPROC .................... Edit A:MAINPROC Y/N
To edit the procedure press Y. If the source code is available, a return is made to the OPL error to correct the offending line. Press N or ON/CLEAR if no editing is required.
After this, press MODE to get the editor menu, and either translate, save or quit the procedure. If quit is selected, the edits made this session are abandoned.
In the case of the run time errors just described, the program stops to display the error message. There are ways of avoiding this by trapping errors and dealing with them within the program - but they put the user in full control and must be used carefully.
The tools used to control errors are ONERR, TRAP, ERR, ERR$ and RAISE:
(i) ONERR traps any errors which occur and redirects the program to the user's error handler.
(ii) TRAP traps only errors on a particular command.
(iii) ERR and ERR$ identify which error has occurred.
(iv) RAISE generates an error (often used for testing).
ONERR, is used to redirect program control to a label if an error occurs. This is useful if it is wanted to provide a customised error handling routine, such as printing out a message for an error that is anticipated.
(i) ONERR is followed by the label name which ends in two colons.
(ii) The label itself can go anywhere in the same procedure.
In the example that follows, LPRINT is being used to print to an attached printer. Normally, when no printer is connected, the message DEVICE MISSING is displayed. Here a more precise message, CONNECT PRINTER, is supplied by the programmer:
ONERR noprint:: LPRINT "Dear Sir" RETURN noprint:: ONERR OFF IF ERR=230 PRINT "CONNECT PRINTER" :GET ELSE RAISE ERR ENDIF
The first line causes a jump to the label noprint:: if an error occurs. IF no printer is connected, the LPRINT command causes a jump and the message "CONNECT PRINTER" is displayed. If there is one connected, "Dear sir" is printed and the lines after the label are never run, because of the RETURN before it. If an unanticipated error such as the BATTERY TOO LOW error occurs, it is covered by the ELSE statement, and its own message is printed by the RAISE ERR command.
(i) Always cancel ONERR with ONERR OFF as soon as an error has been detected.
(ii) Always allow for unanticipated errors such as the BATTERY TOO LOW error.
Caution:
Notice that the first instruction after the label noprint is ONERR OFF. This is very important because if it isn't done after the ONERR label:: command is used, all subsequent program errors - even in other procedures called - result in the program being directed to the same label. This diagram illustrates how two completely different errors cause a jump to the same label, and cause the same explanatory message to be printed out:
proc1: ONERR label:: .... a=log(-1) .... .... label:: PRINT "Explanation of log error" .... proc2: .... proc3: PRINT 2/3
As all errors go back to the same label unless ONERR OFF is switched, it is very easy to create an endless loop by mistake. If this happens, ON/CLEAR and Q cannot be pressed to break out, as this just makes control go to the label as any other error would. Therefore the only way to break out is to take the battery out of the Organiser and lose everything in the internal memory. To avoid this:
Always include the command ONERR OFF immediately after the label.
TRAP traps errors on a specified command only, so it doesn't need to be cancelled like ONERR does. It can be used with any of the commands listed below
APPEND | BACK | CLOSE |
COPY | COPYW | CREATE |
DELETE | DELETEW | ERASE |
EDIT | FIRST | INPUT |
LAST | NEXT | OPEN |
POSITION | RENAME | UPDATE |
USE |
The TRAP command immediately precedes any of these commands, separated from it by a space - e.g.:
TRAP INPUT a%
When INPUT is used without TRAP and a text string is entered when a number is required, the display just scrolls up and a question mark is shown, prompting for another - valid - entry. When TRAP is put in front of INPUT, the command is executed in the usual way, but if an error occurs the next line of the program is executed as if there had been no error. The next line in the example below is a helpful message.
proc: LOCAL a% start:: PRINT "ENTER AGE", TRAP INPUT a% IF ERR=252 PRINT "NUMBER NOT WORD" GOTO start:: ENDIF
This example also uses the ERR function.
When errors occur in a program, the number or the error is accessible by using the ERR function. This enables an absolute certainty as to which error is being dealt with.
The anticipated error in the lines below is 246 (NO PACK). If 246 occurs when trying no open the MAIN file on pack B: a helpful error message is printed out. However, just in case a different error occurs, the next lines make sure that the standard error message for that error is printed.
TRAP OPEN "B:MAIN",A,a$ IF ERR=246 PRINT "NO PACK IN B:" ELSEIF ERR PRINT ERR$(ERR) ENDIF
The OPL error messages are listed in Section 11.4.
If commands are being used to trap errors and handle them, then at some stage during the development of the program it will be necessary to test the error handling routines. An easy way to do this is with the RAISE command. This can generate an error that might occur when the program is in use, and see if the error handling routine takes care of it in the way anticipated. For example, this statement causes the NO PACK error to be generated:
RAISE 246
This section contains example programs written in OPL. The programs are not intended to demonstrate all the features of OPL, but they should give some useful hints. To find out more about a particular command or function, refer to Section 10.
Each or the procedures must be entered separately, because two procedures cannot be entered in one block. Section 2 explains how to type in, translate, save and run a procedure.
In the listings here, variables are shown in lowercase and commands and functions in uppercase. However, it doesn't matter which are used when entering procedures in the Organiser:
(i) Procedures can be typed in all uppercase, all lowercase or any mixture of the two.
Be careful to type in the necessary spaces:
(i) When there is more than one command or function on a line, it is necessary to separate each one with a space. Also each command or function except for the first must have a colon before it - for example:
CLS :PRINT "hello" :GET
(ii) Put a space between a command and the arguments which follow it - for example:
LOCAL a$
(iii) Don't put a space between a function and the arguments in brackets - for example:
CHR$(16)
(iv) It doesn't matter how many spaces there are at the beginning of a line.
Lines beginning with the command REM are remarks: they are there to explain things. They do not affect the way a procedure runs and they don't have to be included if it is preferred to leave them out.
This procedure works out the number of days a person has been alive. Substitute their date of birth for the one supplied here.
days1: LOCAL birth%,now%,answer% birth%=DAYS(14,6,1957) now%=DAYS(DAY,MONTH,YEAR) answer%=now%-birth% PRINT answer% :GET
variables | |
birth% | is the date of birth. |
now% | is the current date. |
answer% | is the current date minus the date of birth. |
Date functions
All the OPL date functions return values accessed from the Organiser clock and calendar. The function
DAYS returns the number of days since the beginning of the calendar on a particular date.
This procedure is a more flexible one which works out the number or days between any two dates that are inputted. When the procedure is run a prompt is given to enter the day, month and year of the first date and then the second date.
days2: LOCAL d1%,m1%,y1%,d2%,m2%,y2% PRINT "ENTER FIRST DAY" INPUT d1% PRINT "ENTER FIRST MONTH" INPUT m1% PRINT "ENTER FIRST YEAR" INPUT y1% PRINT "ENTER SECOND DAY" INPUT d2% PRINT "ENTER SECOND MONTH" INPUT m2% PRINT "ENTER SECOND YEAR" INPUT y2% PRINT DAYS(d2%,m2%,y2%)-DAYS(d1%,m1%,y1%) GET
variables | |
d1%, m1%, and y1% | are the day month and year of the first date. |
d2%, m2%, and y2% | are the day month and year of the second date. |
This procedure turns the organiser into a dice. When the program is run, a message is displayed saying that the dice is rolling. Then press S to stop it. A random number from one to six is displayed and you choose whether to roll again or not.
dice: LOCAL dice%,key% KSTAT 1 top:: CLS :PRINT "*** DICE ROLLING ***" PRINT "PRESS S TO STOP" DO dice%=(RND*6+1) UNTIL UPPER$(KEY$)="S" CLS PRINT "********* ";dice%;" ********" BEEP 50,100 AT 1,4 :PRINT "ROLL AGAIN Y/N" yorn:: key%=GET IF key%=%Y OR key%=%y GOTO top:: ELSEIF key%=%N OR key%=%n RETURN ELSE GOTO yorn:: ENDIF
variables | |
dice% | is a random number from 1 to 6. |
key% | is the ASCII value of the keypress read by the GET function. |
Random numbers
This is how dice: displays 1, 2, 3, 4, 5 or 6 randomly. The RND function returns a random floating point
number, between 0 and 1 (not including 1). It is then multiplied by 6 and 1 is added (to get numbers
from 1 to 6 instead of from 0 to 5). It is rounded down to a whole number by assigning to the integer
dice%.
Identifying keypresses of Y and N
The ASCII value of the character of the key pressed is returned by the GET function and assigned to
key%. In OPL, the ASCII value of any character is obtained by putting % in front of it, so %Y is the ASCII
value of Y and %N is the ASCII value of N. In case the keyboard was set to lowercase, look for %y and
%n as well.
This program calculates monthly mortgage payments. When run, enter the amount of the loan, the interest rate and the term in years. Then specify the source of the loan by selecting from a menu. The program does not allow for tax relief.
The program is made up to two procedures - mortgage: and q: - a general input routine. Each one must be typed in separately. The input routine could be called by any procedure which needs to prompt the user to enter a floating point number.
1 mortgage: LOCAL num%,loan,x,term,rate,pay,ques$(2) CLS PRINT "EVALUATE MONTHLY" PRINT "MORTGAGE PAYMENT" PAUSE 30 ques$=CHR$(63)+" " REM CHR$(63) is a "?" - See Appendix A loan=q:("ENTER LOAN"+ques$) DO rate=q:("INTEREST RATE % "+ques$) UNTIL rate>0 AND rate<99 DO term=q:("ENTER TERM (YRS)"+ques$) UNTIL term>.5 AND terms<100 num%=MENU("BUILDING-SOCIETY,BANK,OTHER") IF num%=0 : RETURN :ENDIF rate=rate/100 :x=1+11*(num%/2) pay=loan*rate/12/(1-((1+rate/x)**(-x*term))) CLS :PRINT "MONTHLY PAYMENT" PRINT FIX$(pay,2,-8) GET RETURN
2 q:(a$) LOCAL z CLS :PRINT a$,CHR$(16); INPUT z CLS RETURN(z)
variables | |
loan, term, rate and pay | are the amounts of the loan, the term in years, the interest rate and the monthly payments. |
ques$ | is "? ". |
num% | is the number of the menu item chosen. |
x | is a variable used in the calculation at the end. |
z | is the variable used for the values input when q: is running. |
Calling q:
The main procedure mortgage: calls q: three times, passing it a string to be printed out as a prompt. The
text string is passed to q: as a parameter. The values returned are assigned to the variables loan, rate,
and term.
How "?" is printed
The CHR$ function converts the ASCII value 63 to the question mark character.
How the input routine beeps
The CHR$ function converts the value 16 to the beep control character. This is then "printed" out.
The next two procedures make up a game which demonstrates the use of user defined graphics (UDG's). Each procedure must be typed in separately.
The object of the game is to avoid being caught by the pursuers. The movable man can jump up and down: press the X key to jump down and the S key to jump up. At the end of the game the score will be displayed on the screen.
To pause the game, press ON/CLEAR and to restart press it again. To quit the game press ON/CLEAR then Q.
1 game: LOCAL e$(2) LOCAL a%,b%,b1%,c%,c1%,x%,y%,i%,sc% graphic: :CURSOR OFF e$=CHR$(4)+CHR$(6) b%=20 :c%=12 :x%=3 :y%=1 DO CLS :PRINT REPT$(CHRS(158),80) AT x%,y% :PRINT CHR$(7) a%=1 :c%=1+RND*4 DO :c1%=1+RND*4 :UNTIL c%<>c1% DO cnt%=0 DO AT a%,c% :PRINT CHR$(cnt%) IF cnt%=4 :PRINT CHR$(6) :ENDIF AT a%,a1% :PRINT CHR$(cnt%) IF cnt%=4 :PRINT CHR$(6) :ENDIF BEEP b%,10*b% cnt%=cnt%+1 UNTIL cnt%=6 AT a%,c% :PRINT " " :AT a%,c1% :PRINT " " i%=KEY IF i% IF i%=%S OR i%=%s AND y%>1 AT x%,y% :PRINT CHR$(158) y%=y%-1 :AT x%,y% :PRINT CHR$(7) ENDIF IF i%=%X OR i%=%X AND y%<4 AT x%,y% :PRINT CHR$(158) y%=y%+1 :AT x%,y% :PRINT CHR$(7) ENDIF ENDIF a%=a%+1 IF a%=x% AND (c%=y% OR c1%=y%) :REM Hit i%=0 DO AT x%,y% :PRINT CHR$(170+i%) BEEP 10,100+i% i%=i%+1 BEEP 10,100-i% UNTIL i%=30 b%=b%+5 :a%=20 :x%=x%+2 IF x%>20 CLS :PRINT "GAME OVER" PRINT "SCORE:",sc% :PAUSE 40 WHILE KEY :GET :ENDWH :REM Drain buffer GET :RETURN ENDIF ENDIF UNTIL a%=20 sc%=sc%+1 IF b%>12 b%=b%-2 ELSEIF b%<6 IF b1% b%=b%-1 :b1%=0 ELSE b1%=1 ENDIF ELSE b%=b%-1 ENDIF UNTIL 0
2 graphic: UDG 0,0,0,28,30,30,30,28,0 UDG 1,0,0,14,31,30,31,14,0 UDG 2,0,0,7,14,12,14,7,0 UDG 3,0,0,3,7,6,7,3,0 UDG 4,0,0,1,3,3,1,0,0 UDG 5,0,0,0,1,1,1,0,0 UDG 6,0,0,24,16,4,16,24,0 UDG 7,30,14,4,14,30,14,11,25
User defined graphics
The main procedure, game:, calls graphic: which then uses the UDG command 8 times to define the
graphics characters used in the game. The last UDG command is the one which defines the running
man. User defined characters are explained in Section 11.1.
The main procedure below creates a data file called addr on device A:, to contain names, addresses, post codes and telephone numbers. It is followed by four other procedures which allow one to insert, search for, alter and erase records in the file. When the files are run:, a menu giving a choice of these options is displayed.
Each of these five procedures must be typed in separately.
1 files: LOCAL m% IF NOT EXIST("A:addr") CREATE "A:ADDR",A,n$,ad1$,ad2$,ad3$,pc$,tel$ ELSE OPEN "A:ADDR",A,n$,ad1$,ad2$,ad3$,pc$,tel$ ENDIF DO m%=MENU("INSERT,SEARCH,ALTER,ERASE,QUIT") IF m%=1 :insert: ELSEIF m%=2 :search: ELSEIF m%=3 :alter: ELSEIF m%=4 :erase: ENDIF UNTIL m%=0 OR m%=5
2 insert: PRINT "ENTER NAME" :INPUT A.n$ CLS :PRINT "ENTER STREET" :INPUT A.ad1$ CLS :PRINT "ENTER TOWN" :INPUT A.ad2$ CLS :PRINT "ENTER COUNTY" :INPUT A.ad3$ CLS :PRINT "ENTER PCODE" :INPUT A.pc$ CLS :PRINT "ENTER TELNUM" :INPUT A.tel$ APPEND
3 search: LOCAL recnum%,search$(30) top:: FIRST :CLS :PRINT "FIND:"; TRAP INPUT search$ IF ERR=206 CLS :PRINT "NOT FOUND" :PAUSE 20 GOTO top:: ENDIF DO DISP(-1,"") :NEXT :recnum%=FIND(search$) IF recnum%=0 :CLS PRINT " NO MORE ENTRIES" PAUSE 20 :RETURN ENDIF UNTIL 0
4 alter: LOCAL recnum%, search$(30), k% DO FIRST :CLS PRINT "ALTER:"; :TRAP INPUT search$ IF ERR=206 :RETURN :ENDIF recnum%=FIND(search$) IF recnum%=0 CLS :PRINT "NOT FOUND" PAUSE 20 :CONTINUE ENDIF DO CLS :AT 1,2 :PRINT "EDIT Y/N" k%=VIEW(1,A.n$) IF k%=%Y OR k%=%y :CLS EDIT A.n$ :EDIT A.ad1$ EDIT A.ad2$ :EDIT A.ad3$ EDIT A.pc$ :EDIT A.tel$ :UPDATE :RETURN ELSEIF k%=%N OR k%=%n :NEXT :recnum%=FIND(search$) IF recnum%=0 CLS :PRINT "NOT FOUND" :PAUSE 20 :BREAK ENDIF ENDIF UNTIL 0 UNTIL 0
5 erase: LOCAL recnum%,search$(30),k% FIRST :CLA :PRINT "ERASE:"; TRAP INPUT search$ IF ERR=206 :RETURN :ENDIF recnum%=FIND(search$) DO IF recnum%=0 CLS :PRINT "NOT FOUND" :PAUSE 20 :RETURN ENDIF ask:: AT 1,2 :PRINT "ERASE Y/N" k%=VIEW(1,A.n$) IF k%<>%Y AND k%<>%N AND k%<>%y AND k%<>%n GOTO ask:: ELSEIF k%=%Y OR k%=%y ERASE ELSE NEXT :recnum%=FIND(search$) ENDIF UNTIL EOF
variables | |
m% | is the number of the menu item selected |
recnum% | is the record number returned by FIND |
search$ | is the search clue entered |
k% | is the ASCII value of the key pressed whilst the found record is displayed
(%Y is the ASCII value of Y, %N is the ASCII value of N.) |
Creating the data file
The first procedure, files:, creates or opens a file called addr on device A with 6 fields for each record.
The six field names are n$ for the name, ad1$, ad2$, and ad3$ for each line of the address, pc$ for the
post code and tel$ for the phone number. The file is given the logical name A.
Inserting records
Notice how in insert: the 6 fields of the record are input one by one. The field names are used like
variables and preceded by the logical file name (A) and a full stop. Then the APPEND command is used;
this is necessary to actually add the record to the end of the file.
Displaying the current record
When a record containing a particular string has been found by FIND it becomes the current record.
DISP with -1 as the first parameter displays it.
In the procedure alter:, VIEW is used to display just the first field of the record, while deciding whether to edit it. If it is decided to edit, each field is then displayed by the EDIT function, which allows the alteration of what is on the screen.
These three procedures make up a program which allows the logging of telephone calls. It stores their duration with any comments in a data file. It could easily be adapted to record the duration of any other activity
The first procedure displays a menu like this, with a phone UDG and the clock. Because the clock uses UDGs 3, 4, 5, 6, 7 and 1, UDGs 0 and 2 have been used for the phone and the underline:
X 11:19a Logcall Viewcalls
1 logger: LOCAL m% UDG 0,31,21,14,10,31,31,0,31 UDG 2,0,0,0,0,0,0,0,31 PRINT CHR$(0);REPTS(CHR$(2),14) CLOCK(1) DO m%=MENUN(2,"Logcall,Viewcalls") IF m%=1 logcall: ELSE viewcall: ENDIF UNTIL m%=0
2 logcall: LOCAL k%,h%,m%,s%,sec%,start$(8),swof% ESCAPE OFF IF NOT EXIST("A:LOG") CREATE "A:LOG",B,date$,t$,comment$ ELSE OPEN "A:LOG",B,date$,t$,comment$ ENDIF swof%=PEEKB($7C) POKEB $007C,0 :REM no auto turn off B.t$="00:00:00" B.dates=DATIMS start$=RIGHT$(DATIM$,8) h%=0 :m%=0 :s%=0 :sec%=SECOND DO IF sec%<>SECOND BEEP 1,100 sec%=SECOND :s%=s%+1 IF s%=60 :s%=0 :m%=m%+1 IF m%=60 :m%=0 :h%=h%+1 ENDIF ENDIF B.t$=REPT$("0",-(h%<l0))+NUM$(h%,2)+":" B.t$=B.t$+REPT$("0",-(m%<10))+NUM$(m%,2)+":" B.t$=B.t$+REPT$("0",-(s%<10))+NUM$(s%,2) ENDIF AT 1,1 :PRINT "Started:";start$ PRINT "Time:";B.t$ PAUSE -1 :REM save battery k%=KEY IF k%=1 GOTO exit:: ENDIF UNTIL k%=13 PRINT "Comments "+CHR$(63) TRAP INPUT B.comment$ IF ERR=206 GOTO exit:: ENDIF CLS :PRINT "Saving..." :APPEND exit:: CLOSE POKEB $007C,swof% :REM restore auto turn off ESCAPE ON
3 viewcall: LOCAL k% TRAP OPEN "A:LOG",B,date$,t$,comment$ IF ERR :RETURN :ENDIF DO k%=DISP(-1,"") NEXT IF k%=1 RETURN ENDIF UNTIL EOF AT 1,4 :PRINT " NO MORE ENTRIES" PAUSE 25 RETURN
variables | |
k% | is used for the keypresses read by KEY |
sec% | is the actual number of seconds past the minute at the start of the procedure |
s% | is the seconds shown counting up |
m% | is rhe minutes shown counting up |
h% | is the hours shown counting up |
start$ | is the time the call started |
swof% | is the initial setting of auto-switch off |
The data file
A data file called LOG is created on device A with three fields in each record: one for the date, one for
the time which the call took, and one for comments. When the program is run and a call is logged the
date, time and comment are appended to the data file as a record. Select viewcalls to look through all
the appended records. The file A:LOG can also be opened in Xfiles, and a search made for the records
using Find.
How the stopwatch counts up the elapsed time
The actual number of seconds past the minute is read from the system clock by the SECOND function
and assigned to sec% at the start. Then the SECOND function is used again, and if it is no longer equal
to sec% - i.e. when a second has elapsed - 1 is added to s% and sec% is assigned the actual number of
seconds again. Whenever s% is 60, it is reset to 0 and 1 is added to m% and so on.
ESCAPE OFF
Normally ON/CLEAR pauses the execution of a procedure so that Q can he pressed to Quit. At the
start of this procedure ESCAPE OFF is used. This means that ON/CLEAR does not pause the
program, and can thus be read by the KEY and DISP functions and cause a RETURN to the FROG menu
instead of an ESCAPE error.
Displaying the records
When A:LOG is opened in viewcall, the first record is made current and then displayed by DISP with -1 as
the first parameter. Then NEXT is used to make each record current in turn.
If the diary is saved to a file, this program can be used to copy all the birthdays from one year to the next year. It could easily be adapted to deal with other annual entries too.
If the saved diary file called "olddia" is opened, all the records containing 1990 and birthday have the 1990 changed to 1991 and are put into a file called "newdia". The file "newdia" can then be restored into the current diary and the two merged.
Remember to substitute the name of the saved diary for "olddia" when typing the procedure in.
birthday: CREATE "a:newdia",B,date$,text$ OPEN "a:olddia",A,date$,text$ WHILE FINDW("1990*birthday*") PRINT a.text$ b.date$="1991"+MID$(a.date$,5,255) b.text$=a.text$ USE B :APPEND USE A :NEXT ENDWH GET
Diary files
A saved diary file is just like any other data file. However, for more information about the format of records
in diary files, see Section 7.
The following is a summary of the OPL commands and functions that are available. This is followed by an alphabetic list which deals with each command and function in detail.
A * indicates that the instruction can only be used on a model LZ or LZ64 and not on an XP or CM.
Structures | |
DO/UNTIL | Loops until a condition is met |
GOTO label: | Branches to a label |
IF/ELSEIF/ELSE/ENDIF | Acts conditionally |
WHILE/ENDWH | Loops while a condition is met |
BREAK | Exits from a loop |
CONTINUE | Goes to the test condition of a loop |
General commands | |
AT | Positions the cursor |
BEEP | Sounds the buzzer |
CLS | Clears the display |
CURSOR ON/OFF | Sets the cursor |
EDIT | Allows a string to be edited on the screen |
ESCAPE ON/OFF | Allows user to break out of program |
GLOBAL | Declares variables for all procedures called |
INPUT | Allows data to be input |
KSTAT | Sets the keyboard status |
LOCAL | Declares variables for current procedure only |
OFF | Turns the Organiser off |
OFF x% | Turns the Organiser off for a limited time only* |
PAUSE | Pauses the program |
Prints to the screen | |
LPRINT | Prints to an attached printer or computer |
RANDOMIZE | Sets a new sequence of random numbers |
REM | Precedes a programmer's remark |
RETURN | Returns to the calling procedure |
STOP | Exits from OPL |
UDG | Defines a display character (user-defined graphic)* |
Error handling commands | |
ONERR label:: | Goes to label on error |
ONERR OFF | Cancels ONERR label:: |
RAISE | Generates an error |
TRAP | Traps errors on a specified command |
File handling commands | |
APPEND | Adds current field values to current data file |
CLOSE | Closes a data file |
COPY | Copies a data file |
COPYW | Copies any type of file* |
CREATE | Creates a data file |
DELETE | Deletes a data file |
DELETEW | Deletes any type of file* |
ERASE | Erases a record |
FIRST/LAST/NEXT/BACK | Select first/last/next/previous record |
OPEN | Opens a data file |
POSITION | Selects a record by number |
RENAME | Renames a data file |
UPDATE | Updates a record |
USE | Changes current data file |
Memory address commands | |
POKEB | Writes a byte to an address |
POKEW | Writes an integer to two successive addresses |
General functions | |
CHR$ | Returns a character with a specified ASCII code |
CLOCK | Displays the clock* |
FREE | Returns the amount of memory free to work in |
GET | Waits for a keypress. Returns ASCII value of key |
GET$ | Waits for a keypress. Returns the key as a string |
KEY | Returns the ASCII value of the key pressed |
KEY$ | Returns the key pressed as a string |
MENU | Displays a menu |
MENUN | Displays a multi-line menu* |
SPACE | Returns the amount of memory free on a device |
VIEW | Displays a scrolling string on the screen |
Error handling functions | |
ERR | Returns error number |
ERR$ | Returns error message |
File handling functions | |
COUNT | Returns the number of records in a data file |
DIR$ | Returns name of data file |
DIRW$ | Returns name or any type or file* |
DISP | Displays a record |
EOF | Tests for end of data file |
EXIST | Checks to see if a data file name exists |
FIND | Finds a record containing a string |
FINDW | Like FIND but allows the use of wild cards* |
POS | Returns the current record number |
RECSIZE | Returns bytes occupied by the current record |
Numeric functions | |
ABS | Returns the absolute (unsigned) value of a floating point number |
ACOS | Returns the arc cosine of a number* |
ASIN | Returns the arc sine of a number* |
ATAN | Returns the arc tangent of a number |
COS | Returns the cosine of a number |
DEG | Converts from radians to degrees |
EXP | Returns e raised to the power specified |
FLT | Converts an integer into a floating point number |
IABS | Returns the absolute (unsigned) value of an integer |
INT | Returns a rounded down integer number |
INTF | As above, but returns a floating point number |
LN | Returns the natural log of a number |
LOG | Returns the base 10 log of a number |
PI | Returns Pi (3.1415926535...) |
RAD | Converts from degrees to radians |
RND | Returns a random floating point number |
SIN | Returns the sine of a number |
SQR | Returns the square root of a number |
TAN | Returns the tangent of a number |
Numeric list functions* | |
MAX | Returns the greatest item |
MIN | Returns the smallest item |
MEAN | Returns the mean |
STD | Returns the standard deviation |
SUM | Returns the sum |
VAR | Returns the variance |
Number to string conversion functions | |
FIX$ | Converts a number to a fixed point decimal string |
GEN$ | Converts a number to a string |
HEX$ | Converts an integer to a hexadecimal string |
NUM$ | Converts a number to a string in integer format |
SCI$ | Converts a number to a string in scientific format |
Date functions | |
DAYS | Returns the number of days since 01/01/1900 - used to find out the number of days between two dates |
DATIM$ | Returns the date and time as a string |
DAYNAME$ | Converts 1-7 to the day of the week* |
DOW | Returns the day a date falls on as a number 1-7* |
MONTH$ | Converts 1-12 to the month* |
SECOND/MINUTE/HOUR/DAY/MONTH/YEAR | Return information about the current time and date. |
WEEK | Returns the week number a date falls in* |
String handling functions | |
ASC | Returns the ASCII value of the first character of a string |
LEFT$/MID$/RIGHT$ | Select characters from strings according to their position |
LEN | Returns the length of a string |
LOC | Returns the location of a string within a string |
LOWER$/UPPER$ | Convert a string to lower/upper case |
REPT$ | Returns repetitions of a specified string |
VAL | Converts a numeric string to a floating point value |
Memory address functions | |
ADDR | Returns the address of a variable |
PEEKB | Returns the value stored at an address |
PEEKW | Returns the value stored at two consecutive addresses |
Microprocessor functions | |
USR | Passes values to the microprocessor and returns an integer |
USR$ | Passes values to the microprocessor and returns a string |
Most OPL commands require one or more arguments after them. The arguments may be either literal values or variables.
The following method of specifying the syntax of a command is used:
x | Numeric expression, variable or literal. E.g. price or 49.99 |
x% | Integer expression in the range -32768 to +32767, variable or literal. E.g. price% or 50 |
a$ | String expression, variable or literal. E.g. price$ or "49.99" |
dev: | Device (A:, B:, or C:) |
log | Logical file name (A, B, C or D). |
(i) The arguments follow the command after a space and are separated by commas
(ii) Therefore an example of the AT command - which has the syntax:
AT X%,Y%
might be
AT 15,2
(iii) If more than one command or function on one line is required, they must be separated by a
space followed by a colon - for example:
CLS :PRINT "hello"
Functions are used to produce values which can then be assigned to a variable or combined with commands such as PRINT. For example:
The instruction y%=YEAR assigns the integer value 1990 (or whatever the current year is) to the variable y%.
The instruction PRINT YEAR displays the number 1990 on the screen
The method of specifying the syntax is the same as for commands.
To confirm what the return type of the function is by the type of the receiving variable shown in the syntax:
(i) Numeric functions which return a floating point value look like this: f=FUNCTION.
(ii) Numeric functions which return an integer look like this f%=FUNCTION.
(iii) String functions look like this: f$=FUNCTION$.
(iv) The arguments follow the function with no space, separated by commas and enclosed in round brackets ( ).
(v) An example of an instruction including the ABS function which has the syntax, is:
a=ABS(x)
might be
PRINT ABS(-10) or x=ABS(y)
(vi) Commands, functions and arguments can be typed in upper or lower case.
Syntax: a=ABS(x)
Returns the absolute value, i.e. without any sign, of a floating point number. E.g. ABS(-10) is 10.
See also IABS.
Syntax: a=ACOS(x)
Returns the arc cosine of the expression inside the brackets
Returns the address at which the variable inside the brackets is stored in memory. An array can be used as the variable, e.g. A%=ADDR(ARRAY()), but the individual elements of an array cannot be specified.
Syntax: APPEND
Appends the current field values to the end of the current file as a new record. See also UPDATE.
Syntax: a%=ASC(a$)
Returns the ASCII value of the first character of a string expression. E.g. A%=ASC("hello") returns 104. See Section 11.1 for the ASCII codes. If just the ASCII code is needed for one particular character, the % sign can be used. For example, A%=%G returns the ASCII code for the letter G to the variable A%.
Syntax: a=ASIN(x)
Returns the arc sine of the expression inside the brackets.
Syntax: AT x%,y%
Positions the cursor at the screen position specified. x% is the number of characters across the screen in the range 1 to 20, and y% (1, 2, 3 or 4) indicates the top, second, third or bottom line.
Syntax: a=ATAN(x)
Returns the arc tangent of the expression inside the brackets.
Syntax: BACK
Makes the previous record in the current data file the current record. If the current record is the first record in the file then the current record does not change.
Syntax: BEEP x%,y%
Sounds the internal buzzer of the Organiser. The sound duration is x% milliseconds. The frequency of the sound is determined by the equation {Frequency = 921600/(78+2*y%)Hz}.
Alternatively, the control character 16 can be used in conjunction with the PRINT command and the CHR$ function to sound the buzzer, i.e. PRINT CHR$(16)
Syntax: BREAK
Allows program control to break out of a DO/UNTIL or a WHILE/ENDWH loop, and to continue the execution of the program at the instruction following the terminator of the loop (UNTIL or ENDWH).
Syntax: a$=CHR$(x%)
Returns the ASCII character with the value of the expression inside the brackets. This can be used to print characters not available from the keyboard - for example, the instruction PRINT CHRS(63) prints the question mark character. See Section 11.1 for more information.
Syntax: c%=CLOCK(x%)
This function displays the continuously updating clock in the top right-hand corner of the screen. x% can be 0 or 1:
0 Clock not displayed or if CLOCK(1) has been used already, not updated
1 Clock displayed.
Returns the previous status of the clock (0 or 1).
Syntax: CLOSE
Closes the current file. See also OPEN, CREATE, DELETE, USE.
Syntax: CLS
Clears the screen, and returns the cursor to the first character space on the top line.
Syntax: CONTINUE
Returns program control to the test expression of either a DO/UNTIL or a WHILE/ENDWH loop. E.g.:
DO <statement list> IF x=y CONTINUE ENDIF <statement list> UNTIL a=b
In the example, the CONTINUE command will be executed if the expression following the IF statement is true. If this happens, program control will then be transferred to the UNTIL test.
Syntax: | COPY "dev1:fname1","dev2:fname2"
COPY "dev1:fname1","dev2:" COPY "dev1:","dev2:" |
Copies data files from one device to another. There are three variations:
1. In the first example, a data file on one device is copied to a file on another device with a different filename. An example might be:
COPY "A:CLIENTS","B:CLIENT88"
If there is already a file on the destination device with the name fname2, then the records in the file being copied over are appended to it. Otherwise a new file is created with that name and the records written to it.
2. In the second example, the file name on the destination device is taken to be the same as that on the source device.
3. In the third example, all tiles on the source device are copied onto the destination device, and are given the same names on the destination device as they had on the source device.
Syntax: | COPYW "dev1:fname1.ext","dev2:fname2"
COPYW "dev1:fname1.ext","dev2:" COPYW "dev1:*.*","dev2:" |
Copies any type of file from one device to another. The three variations are the same as for COPY except that file extensions are used to indicate the type of file. Wild cards can also be used. If the first name contains wild cards, the second name must only be the device. E.g. to copy all the notepads from B: to C:
COPYW "B:*.NTS","C:"
Either specify an extension or .* on the first name, therefore to copy all files of any type whose names end in 8 from A: to B:
COPYW "A:*8.*","B:"
Extensions are listed in Section 7.
Syntax: c=COS(x)
Returns the cosine of the expression inside the brackets. The expression represents an angle expressed in radians.
Syntax: c%=COUNT
Returns the number of records in the current file. See also POS, POSITION.
Syntax: CREATE "dev:fname",log,fldl,fld2
Creates a data file on device dev:, with the name fname, the logical file name log, and up to 16 fields as specified by fld1, fld2 etc. The logical file name (A, B, C or D) is used to refer to this file within the program. Each new file is automatically OPEN, and up to four may be open at once. An example of the command might be:
CREATE "A:CLIENTS",B,NAME$,PHONE$,ADDRESS$
In this example a data file is created on device A: with the name clients and the logical name B. Each record in this data file can have up to three fields. See also OPEN, CLOSE, DELETE, USE.
Syntax: CURSOR ON or CURSOR OFF
Switches the cursor on or off. The default is CURSOR OFF.
Syntax: d$=DATIM$
Returns the current date and time from the system clock in string format; e.g.
"MON 16 OCT 1989 16:25:30"
See also SECOND, MINUTE, HOUR, DAY, MONTH, YEAR.
Syntax: a%=DAY
Returns the current day of the month (1 to 31).
See also SECOND, MINUTE, HOUR, MONTH, YEAR, DATIM$
Syntax: d$=DAYNAME$(x%)
Converts x%, a number from 1 to 7, to the day of the week.
E.g.: d$=DAYNAME$(1) returns Mon. See also DOW.
Syntax: d=DAYS(day%,month%,year%)
Returns the number of days since 01/01/1900. This can be used to find out the number of days
between two dates by subtracting one result from another. E.g.:
x=DAYS(1,1,1989)
y=DAYS(DAY,MONTH,YEAR)
z=y-x
Syntax: d=DEG(X)
Converts from radians to degrees. Returns the value of the expression in the brackets, an angle measured in radians, as a number of degrees. See also RAD.
Syntax: DELETE "dev:fname"
Deletes a data file with the name fname from device dev:. For example, DELETE "B:CLIENTS" The file must be closed before this command is given. See also CREATE, OPEN, CLOSE, USE.
Syntax: DELETEW "dev:fname.ext"
Deletes any type of file with the name fname and device dev:. The syntax procedure is the same as that
for DELETE except that a file extension must be used to indicate the type of file. Wild cards can also be
used. E.g. to delete all the notepad files on C: DELETEW "C:*.NTS" For details of the file
extension, see Section 7.
Because DELETEW is such a powerful command, all files should be closed when it is used. If they are
not, the command will close them automatically.
Syntax: | d$=DIR$("dev")
d$=DIR$("") |
Returns the name of a data file:
1 DIR$("dev) returns the name of the first data file on the device specified. The device name (A, B, or C) must be in quotation marks and brackets E.g. DIR$("A")
2 Subsequent uses of this function with a null string in the brackets return the names of the following files on the device. When there are no more, a null string is returned
Syntax: d$=DIRW$("dev:fname.ext") d$=DIRW$("")
Returns the name of any type of file. It works in the same way as DIR$, except that a filename and extension must be specified as well as the device. Wild cards can also be used. E.g. To return the name of the first notepad on B: D$=DIRW$("B:*.NTS") See section 7 for file extensions.
Syntax: d%=DISP(x%,a$)
Displays a string or a record, according to the value of x%. The value of x% may be -1, 0 or 1.
-1 a$ is ignored and the current record is displayed with one field on each line of the display. The cursor keys may be used to scroll around the record.
1 a$ is displayed as above. If a$ contains tab characters (ASCII character 9), these divide the string into different fields so the string is displayed on different lines.
0 a$ is ignored and the last displayed string or record is continued. If any key other than the arrow keys is pressed, the number of that key is returned.
No other commands or functions should be used between using DISP with x% equal to 1 or -1 and DISP with x% equal to 0. For example:
A%=DISP(1,A$) WHILE A%<>13 A$=DISP(0,"") ENDWH
This displays A$ until EXE is pressed. Clearly there can be no reason to use any other command or
function which accesses the screen in between the two uses or DISP. Doing so may have unpredictable
results (13 is the code for the EXE key, see Section 11.1 for more details.)
See also VIEW and EDIT.
Syntax: |
DO
<statement list> UNTIL x=y |
The DO command is used to indicate the start of a list of one or more statements which terminate with the UNTIL command. The list of statements will be repeated until the expression after the UNTIL command returns logical true.
Syntax: d%=DOW(day%,month%,year%)
Returns the day of the week of the date specified as a number from 1 to 7 (Monday is 1.)
E.g. D%=DOW(25,12,1990) returns 2, Tuesday.
Syntax: EDIT var$
Displays a string which can be edited on the screen using the cursor keys and DEL. var$ can be a string variable name or a field name.
when editing has been finished, press EXE to return the edited string. If EXE is pressed before any changes have been made, then the same string will be returned as was included inside the brackets. If ON/CLEAR is pressed during editing, the string will be cleared and new text may be typed. However, if the TRAP command is used with this command and ON/CLEAR is pressed twice, the string will be cleared and then control will pass on to the next line of the procedure with the ESCAPE error condition being set. See also DISP and VIEW.
ELSE See IF
ENDIF See IF.
ENDWH See WHILE.
Syntax: e%=EOF
Tests tor the end of file. Any program instruction which tries to read past the last record in a data file will result in the end of file being reached. This can be tested for as follows:
DO <statement list> UNTIL EOF
The EOF function returns -1 (True) if the end of file condition has been reached, or 0 (False).
Syntax: ERASE
Erase the current record in the current file. Following this command, the current record will be the record after the one just deleted. If the erased record was the last record in a file, then following this command, the current record will be null and EOF will return true.
Syntax e%=ERR
Returns the number of the last error which occurred. Section 11.4 gives a list of all the error messages in numeric order. The number returned will be in the range 0 to 255. If 0 is returned, there is no error. See also ERR$, RAISE, ONERR.
Syntax: e$=ERR$(x%)
Returns an error message as a string. x% can either be a number - e.g. E$=ERR$(240), to return the message for error number 240, or ERR - i.e. PRINT ERR$(ERR), to print the message for the last error which occurred. If the number is outside the range 192 to 255. "UNKNOWN ERR" is returned. Section 11.4 gives a list of error messages. See also ERR, ONERR, RAISE.
Syntax: ESCAPE OFF or ESCAPE ON
Disables and enables the ON/CLEAR key. You can normally press ON/CLEAR to pause a running program, and then Q to quit. ESCAPE OFF cancels the use or the ON/CLEAR key to pause. ESCAPE ON lets the ON/CLEAR key pause the program again. This is the normal state.
Warning: If the program enters a loop which has no logical exit, and ESCAPE OFF has been used, it will not be possible to quit the program unless the battery is removed from the MTL611. All data in the RAM of the machine will then be lost.
Syntax: e%=EXIST("dev:fname")
Tests for the existence of a data file called fname on device dev:. Returns logical true if the file exists and logical false otherwise - so EXIST can be used on an IF statement, for example:
IF EXIST("a:clients") <statement list> ENDIF
See also DIR$.
Syntax: e=EXP(x)
Returns the value of the arithmetic constant e (2.71828...) raised to the power of x.
Syntax: f%=FIND(a$)
Searches the current data file for the string inside the brackets. If found, it returns the record number where the string occurs, and makes the record the current record. If the string is not found, zero is returned. See also NEXT.
Syntax: f%=FINDW(a$) Searches the current data file for the string inside the brackets in a similar way to FIND but with wild cards allowed. The difference is that wild cards can be included in the string expression, it must include a * at the beginning and end of the string.
For example, to find a record containing both "Dr" and either "BROWN" or 'BRAUN', the instruction is
F%=FINDW("*DR*BR++N*")
If the instruction was FINDW("DR BROWN"), only eight character records containing only this string would be found.
Syntax: FIRST
Makes the first record in a data file the current record. See also ERASE, NEXT, POSITION, LAST, BACK, POS.
Syntax: f$=FIX$(x,y%,z%)
Returns a string representation of X, with y% decimal places in a field which is z% characters wide. If z% is negative then the string is right justified. So:
FIX$(123456.127,2,9) ="123456.13" FIX$(1,2,-5) =" 1.00"
If the number will not fit in the field width specified then the returned string will contain asterisks. See also GEN$, NUM$, SCI$.
Syntax f=FLT(x%)
Converts the integer expression inside the brackets into a floating point number.
Syntax: f%=FREE
Returns the number of free bytes in the work area. This does not include bytes free on device A: for storing files, but just bytes free for running programs, the current notepad and the current diary etc. See also SPACE.
Syntax: g$=GENS(x,y%)
Returns a string representation of x in a field of width y% characters. GEN$ tries to represent the number as integer, decimal or scientific, in that order. If the value of y% is negative then the result will be right justified. If the number will not fit in the field width specified then the returned string will contain asterisks. See also FIX$, NUM$, SCI$.
Syntax: g%=GET
Waits for a key to be pressed and returns the ASCII value or special code for that key. For example, if the A key is pressed in lower case mode, the integer returned is 97. If the EXE key is pressed, the integer returned is 13. See Section 11.1 for tables of ASCII values and special key codes. See also GET$, KEY, KEY$, PAUSE.
Syntax: g$=GET$
Waits for a key to be pressed and returns that key as a string. For example, if the A key is pressed in lower case mode, the string returned is "a". See also GET, KEY, KEY$.
Syntax: GLOBAL var1,var2%,var3$(length),var4(n)
Used to declare variables which will be available in the current procedure and any procedures below it in the program.
Variable names not ending with a special sign are floating point variables, those ending with a percent sign (%) are integers: those ending with a dollar sign ($) are string variables. String variable names must be followed by the maximum length of the string in brackets.
The last variable in the example above is a floating point array. The number following it in brackets is the number of elements in the array. Array variables may be of any of the three types.
Variable names may be up to 8 alphanumeric characters long, the first of which must be a letter. This length includes the % or $. More than one GLOBAL or LOCAL statement may be used but they must be the first lines in the procedure. See section 3 Procedures and variables for more information. See also LOCAL.
Syntax: GOTO label::
Sends program control to the line containing the label name label::. The label must be in the current procedure, and must end with a double colon. Labels may be up to 8 characters long excluding the colons.
Syntax: h$=HEX$(x%)
Returns the hexadecimal (base 16) version of the integer expression inside the brackets. For example: HEX$(255) will return "FF".
(Hex numbers may be entered by preceding them by a $. So PRINT $FF gives 255.)
Syntax: h%=HOUR
Returns the number of the current hour from the system clock (0 to 23). See also SECOND, MINUTE, DAY, MONTH, YEAR, DATIM$.
Syntax: i%=IABS(x%)
Returns the absolute value, i.e. without any sign, of an integer. E.g. IABS(-10) is 10. See also ABS.
Syntax: |
IF x=y
<statement list> ELSEIF x=z <statement list> ELSE <statement list> ENDIF |
IF statements are immediately followed by an expression. If the result of that expression returns logical true, (non-zero) then the statements following are executed. If the expression returns logical false (zero) then those statements are ignored. The statement must be followed by and ENDIF.
The ELSEIF statement is optional, but if it is included, and the following expression returns true, while none of the previous ones have, then the next list of statements are executed. There may be more than on ELSEIF, each with its own list of statements.
The ELSE statement is optional. If none of the preceding expressions have returned logical true, then the list of statements after the ELSE statement and before the ENDIF statement are executed.
Syntax: |
INPUT var%
INPUT var INPUT var$ INPUT log.field |
Allows data to be input from the keyboard during program execution. There are four variations.
The variable supplied must have been declared previously with a GLOBAL or LOCAL command, or be a field variable of the current file. If inputting to a string variable, then its maximum length cannot be exceeded.
If inappropriate input is entered, e.g. a string when the variable specified was an integer, a "?" is displayed and indicates that another try can be made. However, if the TRAP command is used with INPUT, control passes on to the next line of the procedure with the ESCAPE error condition (no. 206) being set.
Syntax: i%=INT(x)
Returns the integer (i.e. the whole number part) of x. Negative numbers are rounded down, so INT(-5.3) returns -6. Used when the returned value will be in the Organiser's integer range see also INTF.
Syntax: INTF(x)
Used in the same way as the INT function, but the value returned is a floating point number. This may be
needed should an integer calculation exceed the organisers integer range. For example:
PRINT INTF(320000/3)*100
Syntax: k%=KEY
Returns the ASCII value of any key pressed. If no key has been pressed, zero is returned. This command doesn't wait for a key to be pressed. See also PAUSE, GET, GET$, KEY$.
Syntax: k$=KEY$
Returns a string containing the key pressed. If no key has been pressed, a null string is returned. KEY$ does not wait for a key to be pressed. See also KEY, GET, GET$.
Syntax: KSTAT x%
Sets the state of the keyboard to SHIFT mode, CAPS mode etc. x% is a number from 1 to 4:
1 | Alphabetic | - upper case |
2 | Alphabetic | - lower case |
3 | Numeric | - upper case |
4 | Numeric | - lower case |
Syntax: LAST
Makes the last record in a data file the current record. See also ERASE, NEXT, POSITION, FIRST, BACK, POS.
Syntax: b$=LEFT$(a$,x%)
Returns the leftmost x% characters from the string specified by a$. See also RIGHT$, MID,. LEN, LOC.
Syntax: a%=LEN(a$)
Returns the length of the string expression a$.
Syntax: a=LN(x)
Returns the natural (base e) logarithm of the expression inside the brackets. See also LOG.
Syntax: a%=LOC(a$,b$)
Returns the position in a$ where b$ occurs. E.g. LOC("STANDING","AND") would return the value 3 because the substring "AND" starts at the third character of the main string. If b$ does not occur in a$, zero is returned. See also LEFT$, RIGHT$, MID$, LEN.
Syntax: LOCAL var1%,var2,var3$(length),var4(n)
Used to declare variables which will only be available in the current procedure. Other procedures may use the same variable names for other uses. See GLOBAL for more details on declaring variables.
Syntax: a=LOG(x)
Returns the base 10 logarithm of the expression inside the brackets. See also LN.
Syntax: b$=LOWER$(a$)
Converts any uppercase characters in the string expression inside the brackets to lower case and returns the completely lower case string. See also UPPER$.
Syntax: LPRINT x,y%;a$
Prints out to a printer. If there is no printer attached, a DEVICE MISSING error is reported. If the Psion Printer II is attached and this message occurs, try pressing ON/CLEAR on the main menu to load the printer software.
If items to he printed are separated by commas, there is a space between them when printed. If they are
separated by semi-colons, there are no spaces. A final semi-colon makes the next items printed with an
LPRINT command start immediately afterwards. A final comma has the same effect but inserts a space.
Otherwise the next line is used. For example. the instruction:
LPRINT "The year is",YEAR
prints
The year is 1989
The PRINT command operates like LPRINT, but displays on the screen rather than listing to a printer.
Syntax: | m=MAX(item1,item2,item3)
m=MAX(array(),n) |
Returns the greatest of the items in the list. The list can either be a list of items separated by commas, or the elements of a floating point array. For more details of the format of list functions, see MEAN.
Syntax: | m=MEAN(item1,item2,item3)
m=MEAN(array(),n) |
Returns the mean (average) of the items in the list. The list can either be a list of items separated by commas, or the elements of a floating point array.
1. The items in the list can be any mixture of real values and integer and floating point variables.
E.g.: m=MEAN(12,x,y%,3.6)
2. When operating on an array, the two arguments in brackets are the array name, and the number of array elements required to operate on. E.g.: to return the mean of the first 3 elements of an array called arr, m=MEAN(arr(),3) In the example below, 12.5 would be displayed:
LOCAL a(3) a(1)=10 a(2)=15 a(3)=20 PRINT MEAN(a(),2)
Syntax: m%=MENU("menuitem1,menuitem2...")
Displays a menu of items and allows a selection to be made from the menu in the usual way. Returns the number of the item selected (1 to ...). If ON/CLEAR is pressed, 0 is returned.
The menu items are displayed starting on the top line of the screen.
Syntax: m%=MENUN(n%,"menuitem1,menuitem2...")
Displays a menu of items in the same way as MENU. However, the items are displayed differently according to the value of n%.
n%=0 Exactly the same as MENU
n%=1 Displays a one-line menu
n%=2 Displays a multi-line menu starting on the line with the current cursor position. Any test already
displayed on the line above the cursor remains on the screen.
Syntax: m$=MID$(a$,x%,y%)
Returns a string comprising y% characters of a$, starting at the character at position x%. See also LEFT$, RIGHT$, LEN, LOC.
Syntax: | m=MIN(item1,item2,item3)
m=MIN(array(),n) |
Returns the smallest of the items in the list. The list can either be a list of numbers separated by commas, or the elements of a floating point array. For more details of the format of list functions, see MEAN.
Syntax: m%=MINUTE
Returns the current minute number from the system clock (0 to 59). See also SECOND, HOUR, DAY, MONTH, YEAR, DATIM$.
Syntax: m%=MONTH
Returns the current month from the system clock (1 to 12). See also SECOND, MINUTE, HOUR, DAY, YEAR, DATIM$
Syntax: m$=MONTH$(x%)
Converts x%, a number from 1 to 12, to the month.
E.g.: M$=MONTH$(1) returns Jan.
Syntax: NEXT
Makes the next record the current record in the current file. If use of NEXT is continued beyond the end of a file no error is reported but the current record is a null and the EOF function returns true. See also FIRST, LAST, BACK, POSITION, POS.
Syntax: n$=NUMS(x,y%)
Returns a string representation of the floating point number x as an integer in a field y% characters wide. If y% is negative then the string is right justified. If the number will not fit in the field width specified then the returned string will contain asterisks. See also FIX$, GEN$, SCI$.
Syntax: OFF or OFF x%.
Switches off the MTL611. If the ON/CLEAR key is pressed, program execution will start again at the program line following the OFF command. x% is a number from 2 to 1800. If this number is included the machine switches off for that number of seconds only.
Syntax: OPEN "dev:fname",log,fld1,fld2
Opens an existing data file on device dev:, with the logical name log, and with the field names as specified by fld1, fld2 etc. This file may then be referred to within the program by the logical file name (A, B, C or D). Up to 4 files can be open at once. For more details see Section 6.4 Opening a file. See also CREATE, CLOSE, DELETE, USE.
Syntax: ONERR label:: and ONERR OFF
If an error occurs during program execution, the ONERR label:: instruction transfers program control to the line containing the label.
ONERR OFF cancels the ONERR label:: statement, so that any errors occurring below the ONERR OFF statement are no longer referred to the label::. It is advisable to put the command ONERR OFF immediately after the label. See Section 8.3.1.
Syntax: PAUSE x%
Pauses the program according to the value of x%:
0 Waits for a key to be pressed.
<0 Pauses for x% (made positive) twentieths of a second or until a key is pressed.
>0 Pauses for x% twentieths of a second.
So PAUSE 100 would cause the program to pause for five seconds. In the first two cases, the key
pressed is stored in a buffer and it is wise to remove it with the KEY function:
<statement list>
PAUSE 0
KEY
<statement list>
The keypress stored in the buffer from the PAUSE 0 command is taken as the input for KEY.
Syntax: p%=PEEKB(x%)
Returns the value (0 to 255) stored at the address specified by the expression inside the brackets.
Syntax: p%=PEEKW(x%)
Returns the value at the two byte integer stored at addresses x% and x%+1.
Syntax: p=PI
Returns the value of Pi (3.14...).
Syntax: POKEB x%,y%
Writes the number y%, which must be in the range 0 to 255, into the memory address x%, which must
be an integer. Addresses above 32767 are addressed by negative values or hexadecimal numbers.
E.g. $FFFF = -1, which corresponds to address 65535.
Warning: Casual use of this command can result in the loss of all data in the MTL611.
Syntax: POKEW x%,y%
Writes the integer y% into two successive memory addresses, starting with the address x%, with the
most significant byte in the lower address.
Warning: Casual use of this command can result in the loss of all data in the MTL611.
Syntax: p%=POS
Returns the number of the current record in the current data file.
Syntax: POSITION x%
Makes record number x% the current record in the current data file. If x% is greater than the number of
records in the file then the EOF function will return true.
See also FIRST, NEXT, LAST, BACK, POS.
Syntax: PRINT x,y%;a$
Prints numbers or text to the screen.
If items to be printed are separated by commas, there is a space between them when displayed. If they
are separated by semi-colons, there are no spaces. A final semi-colon makes the next items displayed
with a PRINT command start immediately afterwards. A final comma has the same effect but inserts a
space. Otherwise the next line is used. For example, the instruction:
PRINT "The year is",YEAR
displays
The year is 1989
The LPRINT command operates in the same way as the PRINT command except that it prints on a
printer.
Syntax: n=RAD(x)
Converts c from degrees to radians. See also DEG.
Syntax: RAISE x%
Artificially generates an error, even though no such error has occurred. If no ONERR statement has been issued previously then the appropriate message for that error number is displayed. The range of possible internal errors to use as x% is 192 to 255. Refer to section 8 Error handling for more information. A full list of error messages is given in Section 11.4. See also ONERR, ERR, ERR$.
Syntax: RANDOMIZE x
Gives a new seed value to the random number generator, so that a new sequence of random numbers will be initiated. Therefore use RANDOMIZE to use the same sequence of random numbers more than once. See also RND.
Syntax: r%=RECSIZE
Returns the number of bytes occupied by the current record. No record may contain more than 254 characters, so this function may be used to check that a record may have data added to it without overstepping this limit.
Syntax: REM text
The REM statement precedes a remark included to explain how a program works. The Organiser ignores all text after the REM statement up to the end of that line.
Syntax: RENAME "dev:fname1","fname2"
Renames a file on device dev: called fname1 as the file fname2.
Eg. RENAME "B:ADDR","OLDADDR"
Syntax: r$=REPT$(a$,x%)
Returns a string comprising x% repetitions of a$. See also LEFT$, RIGHT$, MID$, UPPER$, LOWER$, LEN, LOC.
Syntax: RETURN or RETURN x
Used on its own, the RETURN command terminates the execution of a procedure and returns control to the point where that procedure was called. Use of this command at the end of a procedure is optional. The RETURN command may also be used to pass a value back to the level from which the procedure was called. The value must be supplied after the RETURN command thus:
RETURN X% or RETURN X or RETURN A$
A procedure may only return one type of value as indicated by the identifier which is the last character of the procedure name. So proc$: can only return a string.
Syntax: r$=RIGHT$(a$,x%)
Returns the rightmost x% characters of a$. See also LEFT$, MID$, REPT$, LEN, LOC.
Syntax: r=RND
Returns a random floating point number in the range 0 (inclusive) to 1 (exclusive).
See also RANDOMIZE.
Syntax: s$=SCI$(x,y%,z%)
Returns a string representation of x in scientific format, to y% decimal places in a field of width of z%
characters.
For example:
SCI$(123456,2,8) = "1.23E+05"
SCI$(1,2,8) = "1.00E+00"
SCI$(123456789,2,-9) = " 1.23E+08"
If the number does not fit in the field width specified then the returned string contains asterisks.
See also FIX$, GEN$, NUM$.
Syntax: s%=SECOND
Returns the current number of seconds from the system clock (0 to 59). See also MINUTE, HOUR, DAY, MONTH, YEAR.
Syntax: s=SIN(x)
Returns the sine of the expression inside the brackets. The expression represents an angle expressed in radians.
Syntax: s=SPACE
Returns the number of free bytes on the current device. There must be a file open on the device first.
See also FREE.
Syntax: s=SQR(x)
Returns the square root of the expression inside the brackets.
Syntax: | s=STD(item1,item2,item3)
s=STD(array(),n) |
Returns the standard deviation of the items in the list. The list can either be a list of items separated by commas, or the elements of a floating point array. For more details of the format of list functions, see MEAN.
Syntax: STOP
Halts execution of the language and returns the Organiser to the point where that program was started. eg, the main menu or the calculator.
Syntax: | s=SUM(item1,item2,item3)
s=SUM(array(),n) |
Returns the sum of the items in the list. The list can either be a list of items separated by commas, or the elements of floating point array. For more details of the format of list functions, see MEAN.
Syntax: t=TAN(x)
Returns the tangent of the expression inside the brackets. The expression represents an angle expressed in radians.
Syntax: TRAP command
TRAP may precede any or these commands:
APPEND/BACK/CLOSE/COPY/COPYW/CREATE/DELETE/DELETEW/ERASE/EDIT/FIRST/INPUT
LAST/NEXT/OPEN/POSITION/RENAME/UPDATE/USE
For example: TRAP FIRST. Any error resulting from the execution of the command will be trapped ~
the next program line will be executed regardless of whether the error would normally have caused
an error message to be displayed.
Syntax: UDG x%,a%,b%,c%,d%,e%,f%,g%,h%
Defines a display character. x% is the number of the character (0-7) and the integers a% to h% define
each line of the character. For example, the instruction:
UDG 7,0,0,0,0,0,0,0,31
Defines UDG 7 as an underline character. See Section 11.1 for a full explanation or this command.
See DO.
Syntax: UPDATE
The current record in the current file is deleted and the current field values are appended as a new record at the and of the file. See also APPEND.
Syntax: u$=UPPER$(a$)
Converts any lower case characters in the string expression inside the brackets to upper case. Returns the completely upper case string. See also LOWER$.
Syntax: USE log
Selects for use the data file with the logical file name log (A, B, C or D), which must previously have been opened with the OPEN or CREATE command. See also OPEN, CLOSE, CREATE, DELETE.
Syntax; u%=USR(x%,y%)
The value of y% is passed to the D register and the value of x% is passed to the PC register of the HD6303X microprocessor. The microprocessor then executes the machine language program starting at the address x%. At the end of the routine, the value in the x register is passed back to the language as an integer. Warning: Casual use of this function can result in the loss of all data in the MTL611. See also USR$, ADDR.
Syntax: u$=USR$(x%,y%)
The value of y% is passed to the D register and the value of x% is passed to the PC register of the
HD6303X microprocessor. The microprocessor then executes the machine language program starting
at the address x%. At the end of the routine, the value in the X register must point to a length-byte
preceded string. This string is then returned.
Warning: Casual use of this command can result in the loss of all data in the MTL611.
See also USR, ADDR.
Syntax: v=VAL(a$)
Returns a floating point number which is the value of the string expression inside the brackets.
E.g., VAL("470.0") would return the value 470.0. The string cannot contain any non-numeric
characters. Scientific notation is allowed, so VAL("1.3E10") would return the value 1.3E10.
Syntax: | v=VAR(item1,item2,item3)
v=VAR(array(),n) |
Returns the variance of the items in the list. The list can either be a list of items separated by commas or the elements of a floating point array. For more details of the format of list functions, see MEAN.
Syntax: v%=VIEW(x%,a$)
Displays a$ on line number x% (1, 2, 3 or 4) on the screen. a$ can be a string, a string variable, or a field
name.
If the text is longer than 20 characters, the display auto-scrolls to the left and pressing the left or right
cursor keys allows you to change the direction of the scroll. Pressing any other key halts the scrolling of
the text and returns the ASCII value of the key pressed. If VIEW is used again with a$ being a null string
then viewing is continued at the point it was interrupted by a key press. See also DISP.
Syntax: w%=WEEK(day%,month%,year%)
Returns the week number of the date specified. The weeks begin on Mondays, so the 1st Monday in January is the beginning of week 1.
Syntax: | WHILE x<>y
<statement list> ENDWH |
This structure is started by the WHILE command which precedes a numeric expression. The subsequent list of statements, which must end with the ENDWH statement, is executed while the expression returns logical true (non-zero). See also DO/UNTIL.
Syntax: y%=YEAR
Returns the current year from the system date (1900 to 2155). See also SECOND, MINUTE, HOUR, DAY, MONTH.
The full character set of the Organiser is shown in the table below and overleaf. The more common characters can obviously just be typed from the keyboard. However, there are others which do not appear on the keys. These are accessed via the OPL CHR$ function.
By supplying the CHR$ function with the appropriate number from the table overleaf. It is possible to print out to the screen or the printer, or assign to string variables, any of the characters shown. For example, to display a question mark the instruction is:
PRINT CHR$(63)
To display a pound sign the instruction is:
PRINT CHR$(156)
To find the ASCII value of any of the characters on the keyboard at any time without looking at the table, type the % sign followed by the character in the calculator. For example if %P is typed in the calculator, the number 80 is returned.
The above table shows the characters which have the ASCII codes 32 to 255. 32 is the space
character.
The codes 0 to 7 are for user-defined characters (see 11.1.5)
The codes 6 to 31 are for control characters (see 11.1.4)
It is often useful to access the ASCII value of a character in a procedure - for example to find out if a user has typed in Y or N.
To do this use the % sign and the character, e.g. %Y. The example below is part of a procedure in which the question is asked whether or not something needs to be erased. If N is typed the program stops. If Y is typed another procedure called erase: is called. If a key other than Y or N is typed the procedure goes to a label in order to give another chance.
PRINT "ERASE Y/N" label:: g%=GET IF g%=%N OR g%=%n :STOP ELSEIF g%=%y OR g%=%Y :erase: ELSE GOTO label:: ENDIF
When functions such as the GET and KEY functions are used. The ASCII code for the character on the key is normally returned. The keys not in the ASCII set return these numbers:
ON/CLEAR | 1 |
MODE | 2 |
↑ | 3 |
↓ | 4 |
← | 5 |
→ | 6 |
SHIFT and DEL | 7 |
DEL | 8 |
EXE | 13 |
For the screen, the numbers 8 to 26 have special uses. They do not produce a visible character, but may be used in conjunction with the PRINT command to produce the effects listed below. For example, the instruction PRINT CHR$(22) clears the 3rd line of the screen.
CHR$(8) | Moves the cursor 1 character to the left. |
CHR$(9) | Moves the cursor to the next tab position. (Position 0 and 10 on the screen.) |
CHR$(10) | Moves the cursor to the next line. |
CHR$(11) | Moves the cursor to the top left "home" position of the display. |
CHR$(12) | Clears the display (equivalent to CLS). |
CHR$(13) | Moves the cursor to the left of the current line. |
CHR$(14) | Clears the top line of the display and moves the cursor to the top left. |
CHR$(15) | Clears the second line at the display and moves the cursor to the start of line. |
CHR$(16) | Sounds the organiser's buzzer. |
CHR$(17) | Refreshes all the lines. |
CHR$(18) | Refreshes the 1st line |
CHR$(19) | Refreshes the 2nd line. |
CHR$(20) | Refreshes the 3rd line. |
CHR$(21) | Refreshes the 4th line. |
CHR$(22) | Clears the 3rd line. |
CHR$(23) | Clears the 4th line. |
CHR$(24) | Prints dots, like the ones below a one-line menu on the 2nd line. (uses UDG 2.) |
CHR$(25) | Prints dots, like the ones above a one-line menu on the 3rd line. (uses UDG 2.) |
CHR$(26) | Clears to the end or line. |
Codes 24 to 26 print a space if running in 2-line mode.
CHRS(27) to CHRS(31) are reserved.
For the screen, the numbers 0 to 7 are reserved for user-defined characters. The UDG command is used to define the pattern of dots which appears when one of these characters is printed with the CHR$ function.
Define each character line-by-line by a series of eight bytes, starting with the top line of the character. (From each of the eight bytes which make up the characters, only the last five bits 16 to 1 are used because the characters are only five dots across.)
To define the running man as character number 1, you would use the instruction below. The first number is the character number and the 8 numbers after represent each line of the character.
UDG 1,30,14,4,14,30,14,11,25
Then the following instruction can be used to display the man:
PRINT CHR$(1)
The screen clock, the symbols in the top left-hand corner, and the dotted lines under and over menus, all use UDGs. Therefore each time they are displayed, they overwrite any UDGs that have been defined which therefore need to be redefined each time they are displayed.
The example shows the UDG numbers taken up by the clock, the symbol and the underline graphics.
02 345671
X 12:45a
Edit New Run
Print Dir Copy
Delete
To display an underlined menu with a symbol and the clock, it is necessary to use UDGs 0 and 2 for the symbol and the underline. The telephone logging program in Section 9.7 gives an example of how to do this.
For the full Specification of the MTL611 see Appendix A in the MTL Users manual INM611
WARNING: The MTL611 must not be taken into a hazardous area unless fitted with accessories approved for use in hazardous areas. See the MTL users manual INM611, Section 2.2.2.
EPROM (Erasable, Programmable, Read Only Memory)
'Mean time to failure' 50 years at temperatures up to 100'C
30 minutes in Psion Formatter clears Datapak. Can be re-formatted up to 100 times
8K Datapak 8192 bytes 16K Datapak 16384 bytes 32K Datapak 32768 bytes 64K Datapak 65536 bytes 128K Datapak 131072 bytes
Battery backed-up RAM.
Format option in Utils clears Rampak.
32768 bytes.
Only batteries that have been approved as intrinsically safe must be fitted to the MTL611. See the MTL Users manual INM611 Section 4 for details. A mains adaptor unit is available for safe area use.
These addresses are used for certain system variables. You access them with PEEKB, PEEKW, POKEB and POKEW. You should only use these commands if you know what you are doing.
Address | Default | Use |
$0069,$006A | ($04) | Horizontal scroll delay counter |
$006B,$006C | ($0A) | Vertical scroll delay counter |
$0077 | ($0E) | Delay before keyboard auto-repeat |
$0078 | ($00) | Keyboard auto-repeat counter |
$007C | non-zero | Auto-switch off flag, 0 disables |
$20CB,$20CC | Frame counter, increments every 50ms | |
$20CD,$20CE | ($012C) | Default number of seconds to auto-switch off |
$00A4 | ($00) | Buzzer mute. Non-zero mutes |
$2099 | ($F5) | Border character round 2-line mode procedure. |
$20C0 | ($01) | Length of key click. 0 is silent |
$20A7 | ($1F) | Sets bits for workday alarms.
The default is $1F - Monday to Friday:
MSB LSB 1 | F 0 0 0 1 | 1 1 1 1 Sun Sat Fri Thu Wed Tue Mon |
The Organiser Model LZ has 64K of ROM and 32K of RAM in the following arrangement.
To get a hexadecimal number in OPL, prefix it with a $ identifier - for example $FF is 255.
The Organiser's CPU (Central Processor Unit) is the HD6303X microprocessor. This advanced processor can be programmed directly, in its own language called machine language or machine code.
Machine language programs run far faster than OPL programs and take up less memory, but they are much more difficult to write and debug. Also, a simple mistake in a machine language program can easily wipe out all of the information stored in the internal memory of the Organiser, as these programs take over full control of the chip at the heart of the machine.
To avoid this, it is wise to save all important data to a pack before testing machine language programs, so that all will not be lost if the machine loses all its data, or 'crashes'.
The error messages are listed in numeric order. If you find it difficult to locate a message because you do not know the number, find what page it's on by looking it up in the index?????. Error trapping is covered in Section 8.3.
Usually occurs when Comms Link or some other external device fails.
Usually occurs when Comms Link or some other external device fails.
The battery is low. Switch off and see Section 4.2 of the MTL Users manual INM611 on how to change the battery.
The range of numbers allowed for integer variables (-32768 to +32767) has been exceeded.
An attempt has been made to write or to read from a file which is not open.
Occurs when an invalid procedure name is given. For instance, in New in Frog or inserted in the main menu.
No record may exceed a total of 254 characters.
An attempt has been made to open a file which is already open, or to delete a file which is open.
The data in a Datapak cannot be read and the pack needs re-formatting.
Occurs when a field variable used does not match any of those in the current file.
The string supplied to the MENU function is loo large and must be shortened.
A procedure has been called which does not exist on any device.
A variable has been encountered which has not been declared in a calling procedure as a global variable and has not been declared in the current procedure as a local or global variable.
An incorrect number of arguments has been supplied to a procedure.
The ON/CLEAR key followed by Q has been pressed during program execution, halting that program.
Any file must contain at least one and not more than sixteen fields. Occurs when an attempt is made to exceed these limits.
An attempt has been made to assign a value to a procedure parameter.
An illegal logical name has been used: i.e., not A, B, C or D.
A comma has been omitted from a list of items which should be separated by commas throughout.
An attempt has been made to GOTO a label which does not exist in the current procedure.
Structures within a procedure have been nested too deeply. The limit is 8.
An IF/ENDIF, WHILE/ENDWH or DO/UNTIL structure has been incorrectly nested.
The file, procedure or variable name given is already in existence on the current device.
An array has been declared with an illegal number of elements, eg GLOBAL name$(0,15).
A variable has been declared incorrectly - eg GLOBAL name$(300) where the length of the string exceeds the maximum allowed.
An externally created program file has been introduced which does not have a valid procedure name as its first line.
A number which cannot be evaluated properly has been used.
A non-valid character such as ? or @ has been included in a calculation string or an expression.
A string has been produced which exceeds the space allocated with the GLOBAL or LOCAL
commands.eg:
LOCAL a$(10)
A$="123455789ABCDEF"
Occurs when quotation marks are not paired up correctly.
An incorrectly formed variable name has been used, eg name$$.
The specified file, procedure or variable name exceeds the maximum number of characters allowed: eight characters including the $ or % qualifier.
A value has been assigned to a variable of the wrong type, eg. a$=12 or a="text", or a procedure parameter has been given a value of the wrong type.
An out of range subscript has been specified for an array variable. eg a(0) or a(10) when the array a() has been declared as having 9 elements.
An illegal number or type of arguments has been supplied to a function. eg LOG(1,2).
Brackets have not been paired up correctly.
A syntax error has been detected during the translation of a procedure.
A program or peripheral pack has been removed during its verification by the Organiser or the pack has become corrupted.
An attempt has been made to access a device which is not present, eg a printer. When no printer is connected, the LPRINT command will produce this error.
Occurs if an illegal operation is requested of a device.
An attempt has been made to copy a pack which is copy-protected.
Only 110 data files are allowed on each device. An attempt has been made to create a file which exceeds this limit.
An attempt has been made to access a file which does not exist on the specified device.
An attempt has been made to create a file or procedure under a name which already exists on that device.
A file name has been specified which does not conform to the rules. (Max 8 characters, alphanumeric starting with a letter.)
Occurs only when running machine language programs.
Occurs when an attempt is made to read past the end of a data file.
An attempt has been made to write to a full Datapak.
A pack not supported by the MTL611 has been fitted to one of the devices.
Datapak needs formatting as data remnants are still present.
Occurs when calling operating system machine language routines or when a pack is changed in the middle of a COPY.
A device name other man A, B or C has been used.
An attempt has been made to write to a program pack. These may be read from, but not written to.
The Organiser cannot write data to one of the Datapaks. Try re-fitting it. Also occurs when an attempt is made to format a Datapak rather than a Rampak in the Utils Format option.
There is no Datapak fitted to the device named in an instruction such as CREATE, OPEN etc, or a pack has been removed during pack access.
The wrong type of argument has been passed in a function or a user's procedure. e.g. LOG(-1)
Will only occur when users machine language program destroys the Organiser's stack.
As 248.
Only occurs when calling operating system machine language routines.
An attempt has been made to divide by zero.
A non-numeric string has been passed to the VAL function.
A number has exceeded the exponent limit of + or - 99.
Either the internal memory of the machine is fully occupied by programs, diary entries and data files or the current program has used up all available memory.
Seen only when running machine language routines which access internal buffer space.