A procedure is a component of a computer program that allows the ugBASIC programmer to tackle one aspect of the program at a time, without becoming distracted or side-tracked by other programming considerations. Procedures can be thought of as programming modules, each with a specific purpose and sphere of operation. This section explains how procedures are created and fully exploited.
A procedure is created in exactly the same way as a normal variable, by giving it a name. The name is then followed
by a list of parameters and the procedure must be ended with an
END PROC command (or
END PROCEDURE, as well).
END PROC commands should be placed on their own individual lines, but it is not mandatory.
PROCEDURE hello DEBUG "HELLO I AM A PROCEDURE!" END PROC
If you try and run that program, nothing will happen. This is because a procedure must be called up by name from inside your program before it can do anything. Now add the following line at the end of that last example, compile and then run it.
PROCEDURE hello DEBUG "HELLO I AM A PROCEDURE!" END PROC hello
There is nothing preventing a procedure from calling itself, but this recursion is limited by the stack space. This space is not modifiable, since it depends on the hardware.
Another way to identify a procedure is to precede it with a
PROC statement. Run the following example:
PROCEDURE hello DEBUG "HEY!" END PROC REM Demonstrate that a procedure is being called not simply a command PROC hello REM The same can be achieved without the PROC hello REM The same can be achieved with the CALL command CALL hello
It is possible to place the procedure definition anywhere in your program. When ugBASIC encounters a procedure statement, the procedure is recognised and a jump is made to the final
END PROC. In this way, there is no risk of executing your procedure by accident.
You should be familiar with the use of
ON for jumping to a
GOSUB routine. It is just as simple to use this structure with procedures. In this case, if a variable holds a particular value, a system is automatically triggered that forces a jump to a named procedure. Of course you can have as many values triggering off as many jumps to different procedures as you want.
ON v PROC procedure1, procedure2
Which is exactly the same as saying:
IF v == 1 THEN procedure1 IF v == 2 THEN procedure2
Normally, procedures will only return to the main program when the
END PROC instruction is reached. But supposing you need to jump out of a procedure instantly.
POP PROC instruction provides you with a fast getaway, if you ever find yourself in need of escape. Try this:
PROCEDURE escape FOR prison = 1 TO 1000000000 IF prison == 10 THEN POP PROC DEBUG "I AM ABANDONED." NEXT END PROC escape DEBUG "I AM FREE!"
The same result can be obtained by using the
EXIT PROC command, with the difference that
EXIT PROC can be extended by using an expression, in order to exit from the procedure on a specific condition:
. PROCEDURE escape FOR prison = 1 TO 1000000000 EXIT PROC IF prison == 10 DEBUG "I AM ABANDONED." NEXT END PROC
To better understand the mechanisms of operation of variables within procedures, it is necessary to understand that the procedures on ugBASIC are “stackless”. What does it mean? It means that it is possible to define a variable local to the function, therefore invisible to the main program or to other functions, but always visible to the function if it is called on itself, and reinitialized. So, all of the variables that are defined inside a procedure work completely separately from any other variables in your programs. We call these variables “local” to the procedure. All local variables are automatically initialized when procedure has started executing, so that in the following example the same value of 1 will always be printed, no matter how many times it is called:
PROCEDURE plus a = a + 1 DEBUG a END PROC
All the variables outside of procedures are known as “global” variables, and they are not affected by any instructions inside a procedure. So it is perfectly possible to have the same variable name referring to different variables, depending on whether or not they are local or global. When the next example is run, it can be seen that the values given to the global variables are different to those of the local variables, even though they have the same name. Because the global variables cannot be accessed from inside the procedure, the procedure assigns a value of zero to them no mater what value they are given globally.
a = 42 b = 84 PROCEDURE example DEBUG a DEBUG b END PROG
To avoid errors, you must treat procedures as separate programs with their own sets of variables and instructions. So it is very bad practice for the ugBASIC programmer to use the same variable names inside and outside a procedure, because you might well be confused into believing that completely different variables were the same, and tracking down mistakes would become a nightmare. To make life easy, there are simple methods to overcome such problems.
One method is to define a list of parameters in a procedure. This creates a group of local variables that can be loaded directly from the main program. For example:
PROCEDURE hello [name$] DEBUG "HELLO " + name$ END PROC REM Load n$ into name$ and enter procedure hello ["WORLD"] REM Load string into name$ and call hello hello ["NICE TO MEET YOU!"] HALT
Note that the values to be loaded into
name$ are entered between square brackets as part of the procedure call. This system works equally well with constants as well as variables, but although you are allowed to transfer integer, real or string variables, you may transfer also arrays using this method. If you need to enter more than one parameter, the variables must be separated by commas, like this:
PROCEDURE twins[a,b] DEBUG a + b END PROC PROCEDURE triplets[ x$, y$, z$ ] DEBUG x$ + y$ + z$ END PROC
Those procedures could be called like this:
twins [6,9] triplets ["XENON","YAK","ZYGOTE"]
There is an alternative method of passing data between a procedure and the main program. When
SHARED is placed inside a procedure definition, it takes a list of local variables separated by commas and transforms them into global variables, which can be directly accessed from the main program. Of course, if you declare any arrays as global using this technique, they must already have been dimensioned in the main program.
Here is an example:
PROCEDURE example SHARED a,b a = b - a b = b + 1 END PROC a = 42 b = 84 example DEBUG a DEBUG b
example can now read and write information to the global variables
b. If you need to share an array, it should be defined without parentesys, as follows:
DIM a(10),b(20),c$(5) ... SHARED a, b, c$
In a very large program, it is often convenient for different procedures to share the same set of global variables. This offers an easy way of transferring large amounts of information between your procedures.
GLOBAL sets up a list of variables that can be accessed from absolutely anywhere in your program. This is a
simplified single command, designed to be used without the need for an explicit SHARED statement in your procedure definitions.
Here is an example:
GLOBAL a, b a = 6 b = 9 PROCEDURE test1 a = a + 1 b = b + 1 END PROC PROCEDURE test2 a = a + b b = b + a END PROC test1 test2 DEBUG a DEBUG b
There is a facility of using strings in procedure definitions. As with disc names, the “wild card” characters
? can also be included. In this case, the
* character is used to mean “match this with any list of characters in the variable name, until the next control character is reached”, and the
? character means “match this with any single character in the variable name”. So the next line would define every variable as global:
Now look at the following example:
That line would declare the following variables as shared:
a, as usual;
v, followed by any other characters, or on its own;
var, followed by any other characters, and ending with the characters
a, followed by any single letter, followed by
os, followed by any other characters.
SHARED should be employed before the first use of the variable. Only strings may be used for this technique.
a$ = "AM*" : GLOBAL a$
In that case, the
a$ variable would be regarded as global, and it would not be taken as a wild card for subsequent use. With ugBASIC, you are able to define global arrays from a procedure, even if the array is not created at root level, as follows:
PROCEDURE variables DIM array(4,4) GLOBAL array END PROC
If you want to return a parameter from inside a procedure, that is to say, if you need to send back a value from a local parameter, you need a way of telling your main program where to find this local variable. There are three different methods.
The first is to use the
PARAM function takes the result of an expression in an END PROC statement, and returns it to the PARAM variable. If the variable you are interested in is a string variable, the $ character is used. Also note how the pairs of square brackets are used in the next two examples:
PROCEDURE joinString[a$,b$,c$] DEBUG a$ DEBUG b$ DEBUG c$ END PROC[a$+b$+c$] joinString["ONE","TWO","THREE"] DEBUG PARAM$(joinString)
The second is to use the
RETURN instruction, that takes the result of an expression and put it into the
PROCEDURE joinString[a$,b$,c$] DEBUG a$ DEBUG b$ DEBUG c$ RETURN a$+b$+c$ END PROC joinString["ONE","TWO","THREE"] DEBUG PARAM$(joinString)
The third is to use the
RETURN instruction only.
PROCEDURE joinString[a$,b$,c$] DEBUG a$ DEBUG b$ DEBUG c$ RETURN a$+b$+c$ END PROC DEBUG joinString["ONE","TWO","THREE"]