                         Procedures



        Richard Taylor with a program to allow your

       Spectrum to simulate the BBC's Proc commands.



My program gives the Spectrum all the advantages of proce-

dures and local variables - a BBC Basic nicety. To make the

five new commands offered by the program easy to use, you

simply put them in inconspicuous REM statements, without

having to bother with the hassle of machine code calls. As

you would expect, the program is written in machine code,

about 1.5K of it. [...] You can reload at any time using:

        CLEAR 63764: LOAD ""CODE

  As I said earlier, the new commands are put in Basic REM

statements, with a limit of one command per REM. For a

program to use the new commands, its first line must be

RANDOMIZE USR 63765.



 Procedure commands



For the moment I'll concentrate on the commands directly

connected with procedures: DEFPROC, PROC and ENDPROC. A

procedure is a block of Basic coded preceded by a DEFPROC

and terminated with an ENDPROC. To save the impersonal

approach of calling blocks of code using line numbers,

procedures use the more flexible and friendlier system of

calling blocks of code by a name. Usually the name of a

procedure would be short and give some indication of the

procedure's function.

  You can put spaces in, but the computer ignores them.

You can also put the names in either upper or lower case,

or even a mixture of the two, but it doesn't make any

difference. The same is true of the commands themselves,

although it is wise to put them in upper case to make the

program more readable. Sometimes it's a good idea to high-

light the start and end of procedures in inverse video or

in different colours to make it less difficult to locate

when debugging. The general format of a procedure would be

as follows:

        8000 REM DEFPROC thing

        8010 ........

        8020 ........ Basic code

        8030 ........

        ............

        8200 REM ENDPROC

  That's all very well, but you need some way of actually

calling the procedures, so along comes PROC, the "hi-tech"

equivalent of GO SUB just as ENDPROC is the equivalent of

RETURN. Again, the PROC can be put in a REM statement any-

where in the program. It is followed by the name of the

procedure you want to call, so "PROC thing" calls the pro-

cedure at line 8000. The space in between PROC and the name

is optional. you might wonder how the program knows that

there is a procedure called "thing" if the computer has

never previously executed line 8000. When the RANDOMIZE USR

is used, the machine code looks through every line in the

program.

  If any line has a DEFPROC in it, then it looks up the

procedure's name and what line it's on and stores that

information in a special area of memory. In fact, this

special area of memory is at the start of the variables

area. The machine code sets up a string variable called

@$ and puts any data about procedures and other info in

that string. Since you can't change a @$ variable from

Basic you can't corrupt it - unless you use some vicious

POKEs! However, you can use CLEAR and scrub out all the

variables. The program won't do anything drastic like crash

but just gives an error report. As with GO SUBs you can

nest procedures, but with a limited depth of 255 levels.

  There is one more twist to the story of procedures: the

concept of parameters. When you write a normal Basic

subroutine, it usually has to rely on variables defined

somewhere else in the program to perform its functions.

Although passing numbers to a subroutine in this way is

quite workable, it's certainly not the most elegant of

methods.

  Fortunately, there is a neat way of passing values to a

procedure that works in a similar sort of fashion to the

DEF FN and FN commands of normal Sinclair Basic. Say you

want a procedure called 'print' that puts an X at a certain

line and column on the screen. You would write it like

this:

        8000 REM DEFPROC print(x,y)

        8010 PRINT AT y,x;"X"

        8020 REM ENDPROC

  The contents of the brackets at the end of the DEFPROC

statement define what variables are used by the procedure.

The associated PROC might look something like this:

        20 REM PROC print(10,12)

  When the print procedure is called, the number 10 is

placed in x, and 12 in y. The x and y at line 8000 are

called the formal parameters, the variables that will hold

the values given by the PROC. A procedure can have as many

formal parameters as you like, including none at all - in

which case there's no need for the brackets. The variables

themselves can be of any type normally found in Sinclair

Basic, except for array variables of any sort, but it's

unlikely that you would want to use these for passing

values anyway. Therefore a, ab, a$ and a long named vari-

able are all valid, but a(1,z) and a$(3) are not.

  In the PROC statement you can either use numbers, strings

- enclosed in the usual quotes - or variables - don't mix

these up with the formal variables - but there must be the

same amount of them as in the corresponding DEFPROC and

they must be of the right types. If the first DEFPROC

formal variable is a string then the first PROC expression

must also be a string. You're not allowed to do any mathe-

matics in a PROC statement, so -1, 0.1 and "a" are valid

but 1*2, SIN(0.1) and SR$(1) are not. The following proce-

dure draws a rectangle of a specified size and position.

        8000 REM DEFPROC rectangle(x,y,a,b)

        8010 PLOT x,y

        8020 DRAW a,0: DRAW 0,b

        8030 DRAW -a,0: DRAW 0,-b

        8040 REM ENDPROC



 Four numeric parameters



The procedure has four numeric parameters. The first two

give the position of the rectangle's bottom left corner,

the penultimate one gives the width and the last one the

height. PROC rectangle(88,68,80,40) draws a rectangle of

height 40 and length 80 slap bang in the middle of the

screen.

  The last two commands offered by the program, LOCAL and

RECALL, are concerned with local variables. The concept of

local variables can be difficult and confusing for one to

grasp but, basically, it allows you to have two variables

with the same name but with different values in the com-

puter simultaneously.

  A lot of programming errors are caused by using the same

variable twice for conflicting purposes. These sort of bugs

are often particularly difficult to track down. Such a pro-

blem shouldn't really occur because there are 26 string

variables to choose from, 26 loop control variables and an

infinite number of numeric variables. However, some vari-

ables tend to get used a lot more than others. For instance

a,b,c,d for numerics, a$,b$,c$ for strings and i and n for

loop controls. Programmers seem to have an unexplainable

aversion to using k, w, and the like.

  What the LOCAL command does is make a second copy of

certain variables and store them in its safe cubby hole at

the start of the variables area. Then with another command

the second copy can be miraculously recalled. The point of

the whole exercise is that if you use a new variable in a

procedure then you can localise it before you actually get

down to using it so that when you unlocalise when you're

finished you can be sure that it's got its original value

back again. Another part of the program won't even know

that you've been secretly tampering with some of its

variables.

  The LOCAL command is followed by one or more variable

names, separated by commas. These are the names of the

variables that you want localised. The command that does

all the unlocalising business in a procedure is our previ-

ously introduced friend, ENDPROC. As well as returning

control to the line after the calling PROC, ENDPROC also

unlocalises all variables that were localised in that

particular procedure. For instance:

        8000 REM DEFPROC useless

        8010 REM LOCAL a,a$

        8020 LET a=1

        8030 LET a$="This procedure doesn't do anything"

        8040 REM ENDPROC

does nothing because the two variables a and a$ changed by

the procedure are localised so that when the procedure is

terminated they are changed back to their original values.

Mind you, that's only true if a and a$ were defined when

the procedure was called. If they weren't then the LOCAL

command would have great difficulty in localising them -

it wouldn't stop with an error though - and ENDPROC would

have as much difficulty delocalising them; with the result

that ENDPROC allows the variables to retain their values as

defined in the procedure.

  There is one loophole to all this: you might want to lo-

calise the formal parameters of the procedure. The problem

is that you can't, because by the time the computer reaches

the first line of your procedure the formal variables have

already been changed. To save such hassles, before the

values of formal variables are changed the computer auto-

matically localises them. Therefore, don't try and return

values in one of the formal parameters of a procedure - it

will only end in disaster.

  The last command to be discussed is RECALL. RECALL is a

lonely command; it doesn't have any arguments after it.

RECALL is much like an ENDPROC, except it doesn't do the

'return from procedure' bit. What it does do is unlocalise

all previously localised variables in a procedure. If you

have a great desire to do so, for some obscure reason, you

can localise variables outside of a procedure using a

combination of LOCAL and RECALL commands.

  The program adds a number of new error reports to

Sinclair Basic. They are produced in much the same way as

normal errors, with the exception that they are not prece-

ded by an alphanumeric code. The line where the computer

stops because of an error is not always where the error

actually is. For instance, if the computer stops with

'Syntax error' on a PROC line then the error might lie with

the associated DEFPROC. Below is a full list of all the new

reports and their possible reasons for being produced.



'Invalid procedure name'  - You've tried to give a proce-

                            dure name that doesn't consist

                            of just letters.

'Data area cleared'       - You've used a CLEAR statement

                            and erased the program's safe

                            cubby hole at the start of the

                            variables area.

'DEFPROC not found'       - You've used PROC with the name

                            of a procedure that doesn't

                            exist.

'Return stack full'       - You can 'only' nest procedures

                            up to a limit of 255 levels.

                            This is the error you'll get if

                            you exceed that limit. This

                            will only normally happen if

                            you manage to write a procedure

                            that calls itself, either

                            directly or indirectly.

'ENDPROC without DEFPROC' - The computer has come across an

                            ENDPROC and it wasn't executing

                            a procedure at the time. [Note:

                            this also happens if you stray

                            into a procedure using normal

                            Basic commands, for example if

                            you put all your procedures at

                            the start of the program and

                            forget to jump over them.]

'PROC parameter error'    - There's either a different

                            number of parameters between

                            the associated PROC and DEFPROC

                            or some of them aren't of the

                            right type.

'RECALL without LOCAL'    - You've tried to use RECALL

                            outside of a procedure without

                            previously using LOCAL.

'Syntax error'            - This can be caused because of a

                            variety of reasons, such as

                            missing out a comma or bracket.



The program can also produce normal Basic errors, most

notably error C - "Nonsense in BASIC" and 2 - "Variable

not found".

  Listing 2 gives a simple demonstration of procedures as

applied to a real, if very simple, application. The appli-

cation I'm talking about is a program that allows you to

draw lines around the screen using the cursor keys.