Part 1: A Crash Course in OPL

Published by at

In which we'll introduce you to the language of OPL, give you an idea of what variables and procedures are, how procedures call other procedures, and introduce you to the versatile DO... UNTIL... loop structure and the essential IF...ELSE... ENDIF
Where to Start
To begin, you should obtain a copy of the OPL manual for the Psion Series 5mx range. This is available in a ZIP file in the OPL Devkit. The majority of the language is unchanged from ER5 to ER6, major exceptions are noted in the Porting Guide supplied with the OPL ER6 SDK.

The important chapter is Chapter 15. This gives you the structure of each command, and a short explanation of what it does. You'll use this as a reference a lot during coding, keep it close at hand.

First Steps
Think of OPL as a story in a language that is almost, but not quite, English. It's easily readable by you, and if you translate this OPL code, it is easily read by your Communicator. Think of it as a halfway house between you and the computer.

As with any language, there are ways of speaking, and different elements. English has sentences, paragraphs, nouns, verbs and so on. OPL has it's own elements.

Procedures: Where you hang your Code.
When an OPL program is run, the frst procedure (here called PROC main:) is opened. The lines are then read and processed in the order they are listed, until ENDP is reached, at which point the program ends.

Now within a procedure, you can call another procedure. Do this by simply typing the name of the procedure you want to run next. All procedure names must have a colon after them (that's the two dots above each other).

PROC main:
PROC setup_app:
REM Do something interesting here

So main: is opened, it calls three procedures in order, then reaches ENDP, and the program closes. Note that each procedure must start with PROC <a name>: and end with ENDP on seperate lines. When the end of the first procedure is reached, your OPL program stops. The only way t run other procedures is to call them.

Procedure names cannot have spaces, hence the use of the underscore. You'll see that underscore used a lot as a seperator!

Constants are exactly that. They are things that never change. You can use them so code is easier to read, for example rather than having to type the number 103782376892 every time you need to use it (assuming it is something that appears a lot in your app) you could put...

K_Big_Number%=103782376892 the start of your code, and then each time you need to use the number, use K_Big_Number% instead. By convention, you shuld prefix K_ in front of any contant name.

Once you see some example code, constants should be a lot clearer. One thing to point out now is that there are a lot of default constants. If you have the line...

INCLUDE "Const.oph"

...then these default constanst can all be used. They are detailed in the documentation provided with the OPL Development Kit from Symbian. You should print this out and keep it to hand. it will be useful later!

A variable is somewhere where you can tell your computer to remember a piece of information. This is normally a small number, a big number, or a string of letters and numbers. Each of these variables is given a name, and a small sign to indicate what type of information it is. You should also remember these names cannot have a space in them, which is why you'll see so many names with the underscore character in them!

Types of Variables
A small number (called an integer) is followed by a % sign. For example, high_score% is an integer that stores a number referred to as high_score. An integer has to be a whole number (ie you can't have high_score%=2.5, but you can have high_score%=2 or high_score%=3).

A large number is followed by a & sign. For example, big_number& is a large integer that stores a number referred to as big_number. Large integers can be fractions (so you could have high_score&=2.5).

A string of letters and numbers is called (funnilly enough) a string, and is followed by a $ symbol, For example, name$ cold be "ewanspence"

Defining a Variable
Before you can use a variable, you need to have told your program that you are going to use it. Think of it as making a little space to store the number. There are two ways of defining a variable.

A GLOBAL variable is a variable that ANY procedure can use.

A LOCAL procedures is a variable that only that specific procedure can use. When you leave the procedure, the little space for the number is reclaimed. Local variables are good for temporary counters and bits of info that are only needed for a few moments.

The command to set a variable needs to be the first lines of a procedure. Global definitions must be the first lines in your first procedure, and local procedure mus be the first lines in the relevant procedure.

You can put more than one definition on a line. Seperate them with a comma.

PROC main:
GLOBAL high_score%,big_number&


PROC local:
LOCAL name$(20)

You'll note that after defining name$ we have a bracketed number. This tells the computer the maximum length (in characters) the string is going to be. You need to define the length of a string or when you translate the program for your computer, you'll get an error message.

Setting Variables
Variables are easy to set. Simply use the equals sign. For example

name$="rafe blandford"

Setting a variable should be done on a seperate line for each command. Note that when setting a string, you have to use quotation marks. These don't appear as part of the string.

Arrays - Making a bigger Variable
One other tool you have in variables is an array. An array is a 'list of things. For example, if we wanted to have a table of 10 numbers, then instead of

GLOBAL table1%,table2%,table3%

Which would work (but will cause problems later), you can use

GLOBAL table%(10)

Which will create a table of 10 items. The first is called table%(1), then table%(2) and so on.

If you have a string table, then do

GLOBAL name_table$(10,20)

Which is a table of 10 strings, each a maximum of 20 characters long.

So why use name_table%(10) and not table1%,table2%, and so on? Because if you have another variable (eg lookupthisnumber%) then you can refer to name_table%(lookupthisnumber%). This is very useful if you think about it, as we're about to show you.

Loops are a great way to make your program do something over and over again, maybe with a few changes. Look at this code.

PROC loop:
LOCAL foo%
UNTIL foo%=10

Make sure you understand this code. The DO... UNTIL loop is a primary building block of code. Firstly we create a variable to act as a counter. In this case foo%. You'll see me use foo% (and gnu% and zsu%) as a temporary variable name a lot. If you do see it, you can assume it's a counter or another local variable.

Each time round the loop we add one to foo%, then make an entry in an array called table (which must be a Global variable as it's not listed as a local variable).

When foo% reaches ten, then the UNTIL stops the loop, and carries on with the procedure. As there is nothing left to do, ENDP will return the program back to wherever loop: was called.

At many points in your program, you'll have to check something and do seperate commands depending on the outcome. To check things you use the IF command.

IF guess%=1
ELSEIF guess%=2

Again, this is pretty easy to read. If the variable guess%=1, then goto a procedure called guess_right:. If guess%=2, then goto a procedure called guess_close: If guess% is anything else (a sort of catch all for any other condition, which is good programming practice to get into), then goto a procedure called guess_wrong:

The IF... ELSE... ENDIF is the second great building block of computing languages.

Making Sure You Don't Forget
Througout code you'll see lines like this...

REM This routine calculates the cursor position
REM foo_x% represents the temporary x co-ordinate
REM foo_y% represents the temporary y co-ordinate

The power of the REM statement is in the fact it does absolutely nothing! Everything after the REM statement (until the next line of code) is ignored by the computer.

This means you can use it to leave notes for yourself, or to explain a bit of code to someone else who is going to read it. And if you come back to some code 6 months after writing it, wondering what PROC xyz_transposition: does, the REM statement you added will prove invaluable.

So, pretty easy? Of course it is! Although it is a lot to get around, so don't worry if it takes a few weeks to get to grips with it. In the next part, we'll have a look at the Event Core OPL code and see how it works. There's nothing to stop you having a look at it at the moment, and you can't break your machine by experimenting with the code. You'll find you can read and understand quite a bit of it. Some of it, especially the stuff dealing with getting keypresses and events from the keyboard, can be quite daunting... but this is the advantage of having a Core Framework to begin with, rather than a blank canvas!