Jaap's Psion II Page

MTL611 Programming Manual

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

MTL611A IS Pocket data terminal

PROGRAMMING MANUAL

(Provisional Manual)


Contents

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


MTL611
IS Pocket data terminal

Programming manual

1. INTRODUCTION

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.


2. BASIC OPL

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.

2.1 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:

EditTo alter an existing procedure.
NewTo type in and save a new procedure.
RunExecutes an existing procedure.
PrintPrints out a procedure on an attached printer or computer.
DirProvides a directory list of procedures.
CopyCopies procedures to another device.
DeleteDeletes procedures.

2.2 Creating, saving and running a procedure

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.

2.2.1 Typing in a new 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.

2.2.2 Editing what has been typed

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:

FindLocates any search-clue specified (it is necessary to press ON/CLEAR to remove the find prompt)
HomeMoves the cursor to the top of the procedure file.
EndMoves the cursor to the bottom of the procedure file.
ZapClears 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.

2.2.3 Saving and translating procedures

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.

Quit

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)

Tran

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.

Syntax errors

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.

Save

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.

Where to save programs

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.

2.2.4 Running a procedure

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.

2.3 Edit, Print, Dir, Copy, Delete

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.

2.3.1 Editing an existing procedure

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.

2.3.2 Printing a procedure

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.

2.3.3 The procedure directory

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.

2.3.4 Copying a procedure

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.
OplobjCopies only the translated object code version and editing cannot be carried out.
OpltxtCopies 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.

2.3.5 Renaming a procedure

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.

2.3.6 Deleting a procedure

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.

2.3.7 Running a procedure from the main menu

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

2.3.8 Pausing and quitting a procedure when it's running

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.


3. PROCEDURES AND VARIABLES

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) NameSINE50:
(ii) Declaration of variablesLOCAL x
(iii) Operations upon variablesx=SIN(50)
(iv) Communication of variablesPRINT x

This section deals with these four steps.

3.1 Procedure names

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.

3.2 Declaring variables

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.

3.2.1 Variable names

There are three kinds of variables identified that are declared by the format of the variable name. The three kinds are:

(i) Floating point variablese.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.

3.2.2 Floating point variables

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

3.2.3 Integer variables

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.

3.2.4 String variables

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.

3.2.5 The LOCAL and GLOBAL commands

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.

3.2.6 Calling procedures

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.

3.2.7 Other variables

Calculator memories

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.

Array variables

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.

3.3 Operations upon variables

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.

3.3.1 Mixing Integers and floating point variables: automatic type conversion

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.

3.3.2 Mixing strings and numbers

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.

3.3.3 Concatenating strings

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.

3.3.4 Slicing strings

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.

3.4 Communication of variables

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.

3.4.1 The INPUT command

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.

3.4.2 Procedure parameters

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.

3.4.3 Multiple parameters

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)

3.4.4 The RETURN command

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.


4. LOOPS AND BRANCHES

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.

4.1 The DO/UNTIL loop

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.

4.2 The WHILE/ENDWH loop

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.

4.3 BREAK

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

4.4 Labels and jumps

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.

4.5 Branches

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.

4.6 Endless Loops

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.


5. OPERATORS

5.1 Operators

Arithmetic operators

+add
-subtract
*multiply
/divide
**raise to a power
-unary minus (make negative)
%percent

Comparison operators

>greater than
>=greater than or equal to
<less than
<=less than or equal to
=equal to
<>not equal to

Logical operators

AND
OR
NOT

5.2 Operator precedence

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.

5.3 Using Brackets

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.

5.4 Precedence of integer and floating point values

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%.

5.5 Logical expressions

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.

ExampleResultInteger 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:

ExampleResultInteger 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.


6. HANDLING DATA FILES

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.

Files, records and fields

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.

6.1 Creating a data file

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.

6.2 Adding records to a 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.

6.2.1 Assigning values to field names

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.

6.2.2 Appending the fields

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.

6.3 Changing the current record

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.

6.3.1 Finding a record

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.

6.3.2 Erasing a record

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.

6.4 Opening a file

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$

6.5 Changing the current file

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.

Closing and deleting a file

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.

More information on data file handling

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.


7. HANDLING ANY TYPE OF FILE

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.

7.1 Examples

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.

7.2 Diary files

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:

1989The year
04The month
27The date
1200The start time
01The duration - one 15 minute interval
00The 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.


8. ERROR HANDLING

This section covers commonly made errors, then error trapping. There is a list of the OPL error messages in Section 11.4.

8.1 Common errors

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.

8.1.1 Punctuation errors

Omitting the colon between statements on a multi-statement line:

IncorrectCorrect
a$="text" PRINT a$ a$="text" :PRINT a$

Omitting the colon after a called procedure name:

IncorrectCorrect
proc1:
GLOBAL a,b,c
.
.
proc2
proc1:
GLOBAL a,b,c
.
.
proc2:

Omitting one or more of the colons after a label:

IncorrectCorrect
proc1:
GOTO below:
.
.
below::
proc1:
GOTO below::
.
.
below::

Omitting the space before the colon between statements on a multi-statement line:

IncorrectCorrect
proc1:
a$=b$:PRINT a$
proc1:
a$=b$: PRINT a$

8.1.2 Parameter errors

Passing a floating point value to a procedure which requires an integer - here the procedure proc2:(x%).

IncorrectCorrect
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:

IncorrectCorrect
Calc:proc2:(3) Calc:proc2:(INT(3))

Passing an integer to a procedure which requires a floating point value - here the procedure proc3:(x)

IncorrectCorrect
proc1:
.
.
proc3:(2/3)
proc1:
.
.
proc3:(2.0/3)

Passing the wrong number or parameters to a procedure - here, the procedure proc4:(x,y)

IncorrectCorrect
proc1:
.
.
proc4:(3.7)
proc1:
.
.
proc4:(3.7,2.5)

8.1.3 Integer size error

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:

IncorrectCorrect
proc1:
LOCAL a%
a%=100*2468
proc1:
LOCAL a
a=100.0*2468

8.1.4 Structure errors

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:

IncorrectCorrect
proc1:
.
DO
.
WHILE a<2
proc1:
.
DO
.
UNTIL a>=2

8.2 Run-time errors

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.

8.3 Error trapping

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).

8.3.1 ONERR label:: and ONERR OFF

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.

ONERR OFF

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

Risks of ONERR label::

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.

8.3.2 TRAP

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.

8.3.3 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.

8.3.4 RAISE

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


9. EXAMPLE PROGRAMS

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.

Uppercase, lowercase

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.

Spaces

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.

Remarks

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.

9.1 Days (version 1)

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.

9.2 Days (Version 2)

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.

9.3 Dice

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.

9.4 Mortgage calculator

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.

9.5 Chase Game

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.

9.6 Data file handling procedures

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.

9.7 Telephone logging (data file handling)

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.

9.8 Diary file handling procedure

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.


10. OPL COMMANDS AND FUNCTIONS

10.1 Summary

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
PRINT 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/YEARReturn 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

10.2 Command syntax

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:

xNumeric 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:)
logLogical 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"

10.3 Function syntax

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.

10.4 List of commands and functions

ABS

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.

ACOS

Syntax: a=ACOS(x)

Returns the arc cosine of the expression inside the brackets

ADDR

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.

APPEND

Syntax: APPEND

Appends the current field values to the end of the current file as a new record. See also UPDATE.

ASC

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%.

ASIN

Syntax: a=ASIN(x)

Returns the arc sine of the expression inside the brackets.

AT

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.

ATAN

Syntax: a=ATAN(x)

Returns the arc tangent of the expression inside the brackets.

BACK

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.

BEEP

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)

BREAK

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).

CHR$

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.

CLOCK

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).

CLOSE

Syntax: CLOSE

Closes the current file. See also OPEN, CREATE, DELETE, USE.

CLS

Syntax: CLS

Clears the screen, and returns the cursor to the first character space on the top line.

CONTINUE

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.

COPY
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.

COPYW
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.

COS

Syntax: c=COS(x)

Returns the cosine of the expression inside the brackets. The expression represents an angle expressed in radians.

COUNT

Syntax: c%=COUNT

Returns the number of records in the current file. See also POS, POSITION.

CREATE

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.

CURSOR ON/OFF

Syntax: CURSOR ON or CURSOR OFF

Switches the cursor on or off. The default is CURSOR OFF.

DATIM$

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.

DAY

Syntax: a%=DAY

Returns the current day of the month (1 to 31).
See also SECOND, MINUTE, HOUR, MONTH, YEAR, DATIM$

DAYNAME$

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.

DAYS

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

DEG

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.

DELETE

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.

DELETEW

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.

DIR$
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

DIRW$

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.

DISP

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.

DO/UNTIL
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.

DOW

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.

EDIT

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.

EOF

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).

ERASE

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.

ERR

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.

ERR$

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.

ESCAPE OFF/ESCAPE ON

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.

EXIST

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$.

EXP

Syntax: e=EXP(x)

Returns the value of the arithmetic constant e (2.71828...) raised to the power of x.

FIND

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.

FINDW

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.

FIRST

Syntax: FIRST

Makes the first record in a data file the current record. See also ERASE, NEXT, POSITION, LAST, BACK, POS.

FIX$

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$.

FLT

Syntax f=FLT(x%)

Converts the integer expression inside the brackets into a floating point number.

FREE

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.

GEN$

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$.

GET

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.

GET$

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$.

GLOBAL

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.

GOTO

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.

HEX$

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.)

HOUR

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$.

IABS

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.

IF/ELSEIF/ELSE/ENDIF
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.

INPUT
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.

INT

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.

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

KEY

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$.

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$.

KSTAT

Syntax: KSTAT x%

Sets the state of the keyboard to SHIFT mode, CAPS mode etc. x% is a number from 1 to 4:

1Alphabetic- upper case
2Alphabetic- lower case
3Numeric- upper case
4Numeric- lower case
LAST

Syntax: LAST

Makes the last record in a data file the current record. See also ERASE, NEXT, POSITION, FIRST, BACK, POS.

LEFT$

Syntax: b$=LEFT$(a$,x%)

Returns the leftmost x% characters from the string specified by a$. See also RIGHT$, MID,. LEN, LOC.

LEN

Syntax: a%=LEN(a$)

Returns the length of the string expression a$.

LN

Syntax: a=LN(x)

Returns the natural (base e) logarithm of the expression inside the brackets. See also LOG.

LOC

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.

LOCAL

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.

LOG

Syntax: a=LOG(x)

Returns the base 10 logarithm of the expression inside the brackets. See also LN.

LOWER$

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$.

LPRINT

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.

MAX
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.

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)

MENU

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.

MENUN

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.

MID$

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.

MIN
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.

MINUTE

Syntax: m%=MINUTE

Returns the current minute number from the system clock (0 to 59). See also SECOND, HOUR, DAY, MONTH, YEAR, DATIM$.

MONTH

Syntax: m%=MONTH

Returns the current month from the system clock (1 to 12). See also SECOND, MINUTE, HOUR, DAY, YEAR, DATIM$

MONTH$

Syntax: m$=MONTH$(x%)

Converts x%, a number from 1 to 12, to the month.
E.g.: M$=MONTH$(1) returns Jan.

NEXT

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.

NUM$

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$.

OFF

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.

OPEN

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.

ONERR

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.

PAUSE

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.

PEEKB

Syntax: p%=PEEKB(x%)

Returns the value (0 to 255) stored at the address specified by the expression inside the brackets.

PEEKW

Syntax: p%=PEEKW(x%)

Returns the value at the two byte integer stored at addresses x% and x%+1.

PI

Syntax: p=PI

Returns the value of Pi (3.14...).

POKEB

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.

POKEW

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.

POS

Syntax: p%=POS

Returns the number of the current record in the current data file.

POSITION

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.

PRINT

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.

RAD

Syntax: n=RAD(x)

Converts c from degrees to radians. See also DEG.

RAISE

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$.

RANDOMIZE

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.

RECSIZE

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.

REM

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.

RENAME

Syntax: RENAME "dev:fname1","fname2"

Renames a file on device dev: called fname1 as the file fname2.
Eg. RENAME "B:ADDR","OLDADDR"

REPT$

Syntax: r$=REPT$(a$,x%)

Returns a string comprising x% repetitions of a$. See also LEFT$, RIGHT$, MID$, UPPER$, LOWER$, LEN, LOC.

RETURN

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.

RIGHT$

Syntax: r$=RIGHT$(a$,x%)

Returns the rightmost x% characters of a$. See also LEFT$, MID$, REPT$, LEN, LOC.

RND

Syntax: r=RND

Returns a random floating point number in the range 0 (inclusive) to 1 (exclusive).
See also RANDOMIZE.

SCI$

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$.

SECOND

Syntax: s%=SECOND

Returns the current number of seconds from the system clock (0 to 59). See also MINUTE, HOUR, DAY, MONTH, YEAR.

SIN

Syntax: s=SIN(x)

Returns the sine of the expression inside the brackets. The expression represents an angle expressed in radians.

SPACE

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.

SQR

Syntax: s=SQR(x)

Returns the square root of the expression inside the brackets.

STD
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.

STOP

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.

SUM
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.

TAN

Syntax: t=TAN(x)

Returns the tangent of the expression inside the brackets. The expression represents an angle expressed in radians.

TRAP

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.

UDG

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.

UNTIL

See DO.

UPDATE

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.

UPPER$

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$.

USE

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.

USR

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.

USR$

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.

VAL

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.

VAR
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.

VIEW

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.

WEEK

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.

WHILE/ENDWH
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.

YEAR

Syntax: y%=YEAR

Returns the current year from the system date (1900 to 2155). See also SECOND, MINUTE, HOUR, DAY, MONTH.


11. CHARACTERS, DATA AND ERROR MESSAGES

11.1 Organiser character set

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.

11.1.1 Printing non-keyboard characters

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)

Finding the ASCII code of a keyboard character

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.

Character Set, part 1
Character Set, part 2

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)

11.1.2 Accessing ASCII values within procedures

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

11.1.3 Codes for special keys

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/CLEAR1
MODE2
3
4
5
6
SHIFT and DEL7
DEL8
EXE13

11.1.4 Control characters

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.

11.1.5 User-defined characters

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.)

UDG

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.

11.2 Technical Data

11.2.1 General

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.

11.2.2 Datapaks

Storage medium

EPROM (Erasable, Programmable, Read Only Memory)

Data retention

'Mean time to failure' 50 years at temperatures up to 100'C

Formatting

30 minutes in Psion Formatter clears Datapak. Can be re-formatted up to 100 times

Memory capacity

8K Datapak 8192 bytes 16K Datapak 16384 bytes 32K Datapak 32768 bytes 64K Datapak 65536 bytes 128K Datapak 131072 bytes

11.2.3 Rampaks

Storage medium

Battery backed-up RAM.

Formatting

Format option in Utils clears Rampak.

Memory capacity

32768 bytes.

11.2.3 Power

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.

11.3 Technical programming

11.3.1 Memory addresses

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

11.3.2 Memory Map

The Organiser Model LZ has 64K of ROM and 32K of RAM in the following arrangement.

Memory map

11.3.3 Hexadecimal numbers

To get a hexadecimal number in OPL, prefix it with a $ identifier - for example $FF is 255.

11.3.4 Machine language programming

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'.

11.4 Error messages

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.

192 DEVICE WRITE ERROR

Usually occurs when Comms Link or some other external device fails.

191 DEVICE READ ERR

Usually occurs when Comms Link or some other external device fails.

194 BATTERY TOO LOW

The battery is low. Switch off and see Section 4.2 of the MTL Users manual INM611 on how to change the battery.

195 INTEGER OVERFLOW

The range of numbers allowed for integer variables (-32768 to +32767) has been exceeded.

196 FILE NOT OPEN

An attempt has been made to write or to read from a file which is not open.

197 BAD PROG NAME

Occurs when an invalid procedure name is given. For instance, in New in Frog or inserted in the main menu.

198 RECORD TOO BIG

No record may exceed a total of 254 characters.

199 FILE IN USE

An attempt has been made to open a file which is already open, or to delete a file which is open.

200 READ PACK ERROR

The data in a Datapak cannot be read and the pack needs re-formatting.

201 FIELD MISMATCH

Occurs when a field variable used does not match any of those in the current file.

202 MENU TOO BIG

The string supplied to the MENU function is loo large and must be shortened.

203 MISSING PROC

A procedure has been called which does not exist on any device.

204 MISSING EXTERNAL

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.

205 ARG COUNT ERR

An incorrect number of arguments has been supplied to a procedure.

206 ESCAPE

The ON/CLEAR key followed by Q has been pressed during program execution, halting that program.

207 BAD FIELD LIST

Any file must contain at least one and not more than sixteen fields. Occurs when an attempt is made to exceed these limits.

208 BAD ASSIGNMENT

An attempt has been made to assign a value to a procedure parameter.

209 BAD LOGICAL NAME

An illegal logical name has been used: i.e., not A, B, C or D.

210 MISSING COMMA

A comma has been omitted from a list of items which should be separated by commas throughout.

211 MISSING LABEL

An attempt has been made to GOTO a label which does not exist in the current procedure.

212 TOO COMPLEX

Structures within a procedure have been nested too deeply. The limit is 8.

213 STRUCTURE ERROR

An IF/ENDIF, WHILE/ENDWH or DO/UNTIL structure has been incorrectly nested.

214 DUPLICATE NAME

The file, procedure or variable name given is already in existence on the current device.

215 BAD ARRAY SIZE

An array has been declared with an illegal number of elements, eg GLOBAL name$(0,15).

216 BAD DECLARATION

A variable has been declared incorrectly - eg GLOBAL name$(300) where the length of the string exceeds the maximum allowed.

217 NO PROC NAME

An externally created program file has been introduced which does not have a valid procedure name as its first line.

218 BAD NUMBER

A number which cannot be evaluated properly has been used.

219 BAD CHARACTER

A non-valid character such as ? or @ has been included in a calculation string or an expression.

220 STRING TOO LONG

A string has been produced which exceeds the space allocated with the GLOBAL or LOCAL commands.eg:
LOCAL a$(10)
A$="123455789ABCDEF"

221 MISMATCHED "

Occurs when quotation marks are not paired up correctly.

222 BAD IDENTIFIER

An incorrectly formed variable name has been used, eg name$$.

223 NAME TOO LONG

The specified file, procedure or variable name exceeds the maximum number of characters allowed: eight characters including the $ or % qualifier.

224 TYPE MISMATCH

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.

225 SUBSCRIPT ERR

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.

226 BAD FN ARGS

An illegal number or type of arguments has been supplied to a function. eg LOG(1,2).

227 MISMATCHED ( )'s

Brackets have not been paired up correctly.

228 SYNTAX ERR

A syntax error has been detected during the translation of a procedure.

229 DEVICE LOAD ERR

A program or peripheral pack has been removed during its verification by the Organiser or the pack has become corrupted.

230 DEVICE MISSING

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.

231 BAD DEVICE CALL

Occurs if an illegal operation is requested of a device.

232 PAK NOT COPYABLE

An attempt has been made to copy a pack which is copy-protected.

233 DIRECTORY FULL

Only 110 data files are allowed on each device. An attempt has been made to create a file which exceeds this limit.

234 FILE NOT FOUND

An attempt has been made to access a file which does not exist on the specified device.

235 FILE EXISTS

An attempt has been made to create a file or procedure under a name which already exists on that device.

236 BAD FILE NAME

A file name has been specified which does not conform to the rules. (Max 8 characters, alphanumeric starting with a letter.)

237 BAD RECORD TYPE

Occurs only when running machine language programs.

238 END OF FILE

Occurs when an attempt is made to read past the end of a data file.

239 PACK FULL

An attempt has been made to write to a full Datapak.

240 UNKNOWN PACK

A pack not supported by the MTL611 has been fitted to one of the devices.

241 PACK NOT BLANK

Datapak needs formatting as data remnants are still present.

242 PACK CHANGED

Occurs when calling operating system machine language routines or when a pack is changed in the middle of a COPY.

243 BAD DEVICE NAME

A device name other man A, B or C has been used.

244 READ ONLY PACK

An attempt has been made to write to a program pack. These may be read from, but not written to.

245 WRITE PACK ERR

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.

246 NO PACK

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.

247 FN ARGUMENT ERR

The wrong type of argument has been passed in a function or a user's procedure. e.g. LOG(-1)

248 STACK UNDERFLOW

Will only occur when users machine language program destroys the Organiser's stack.

249 STACK OVERFLOW

As 248.

250 NUM TO STR ERR

Only occurs when calling operating system machine language routines.

251 DIVIDE BY ZERO

An attempt has been made to divide by zero.

252 STR TO NUM ERR

A non-numeric string has been passed to the VAL function.

253 EXPONENT RANGE

A number has exceeded the exponent limit of + or - 99.

254 OUT OF MEMORY

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.

255 NO ALLOC CELLS

Seen only when running machine language routines which access internal buffer space.