ugBASIC User Manual

Procedures

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.

create in / out variables parameters sharing return

Creating a procedure

A procedure is created in exactly the same way as a normal variable, by giving it a name. The name is prefixed by PROCEDURE keyword, then followed by a list of parameters and the procedure itself must be ended with an END PROC command (or END PROCEDURE, as well). PROCEDURE and END PROC commands should be placed on their own individual lines, but it is not mandatory.

For example:

PROCEDURE hello
   PRINT "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
   PRINT "HELLO I AM A PROCEDURE!"
END PROC

hello[]

Another way to identify a procedure is to precede it with a PROC statement. Run the following example:

PROCEDURE hello
   PRINT "HEY!"
END PROC

PROC hello
hello[]
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.

Jumping in and out of a procedure



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.

For example:

ON v PROC procedure1, procedure2

Which is exactly the same as saying:

IF v = 1 THEN
   procedure1[]
ELSE IF v = 2 THEN
   procedure2[]
ENDIF

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.

The 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
      PRINT "I AM ABANDONED."
   NEXT
END PROC

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
      PRINT "I AM ABANDONED."
   NEXT
END PROC

Local and global variables

To better understand the mechanisms of operation of variables within procedures, it is necessary to understand that the procedures on ugBASIC are “stackless”. 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, and they maintain their values from execution to execution. So that in the following example the values 1, 2 and 3 will be printed:

PROCEDURE plus
   a = a + 1
   PRINT a
END PROC

plus[]
plus[]
plus[]

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
   PRINT a
   PRINT b
END PROC

example[]

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.

Parameters passing

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$]
   PRINT "HELLO " + name$
END PROC

hello["WORLD"]
hello["NICE TO MEET YOU!"]

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]
   PRINT a + b
END PROC

PROCEDURE triplets[ x$, y$, z$ ]
   PRINT x$ + y$ + z$
END PROC

hello["WORLD"]
hello["NICE TO MEET YOU!"]

Those procedures could be called like this:

twins [6,9]
triplets ["XENON","YAK","ZYGOTE"]

Sharing variables

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[]

PRINT a
PRINT b

The procedure example can now read and write information to the global variables a and 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 every procedure definitions.

Here is an example:

GLOBAL a, b

a = 6
b = 9
PROCEDURE test
   a = b - a
   b = b + 1
END PROC

PROCEDURE test2
   a = a + b
   b = b + a
END PROC

test1[]
test2[]

PRINT a
PRINT b

There is a facility of using strings in procedure definitions. As with disc names, the “wild card” characters * and ? 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:

GLOBAL "*"

Now look at the following example:

SHARED a,"v*","var*end","a*0s*"

That line would declare the following variables as shared:

  • a, as usual;
  • any variable beginning with the character v, followed by any other characters, or on its own;
  • any variable beginning with the letters var, followed by any other characters, and ending with the characters end;
  • any variable beginning with a, followed by any single letter, followed by 0s, followed by any other characters;
GLOBAL or SHARED should be employed before the first use of the variable. Only strings may be used for this technique.

For example:

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

Returning values from a procedure

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: it 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$]
   PRINT a$
   PRINT b$
   PRINT c$
END PROC[a$+b$+c$]

joinString["ONE","TWO","THREE"]

PRINT PARAM$(joinString)

The second method is to use the RETURN instruction, that takes the result of an expression and put it into the PARAM variable.

PROCEDURE joinString[a$,b$,c$]
   PRINT a$
   PRINT b$
   PRINT c$
   RETURN a$+b$+c$
END PROC

joinString["ONE","TWO","THREE"]

PRINT PARAM$(joinString)

The third method is to use the RETURN instruction only.
PROCEDURE joinString[a$,b$,c$]
   PRINT a$
   PRINT b$
   PRINT c$
   RETURN a$+b$+c$
END PROC

PRINT joinString["ONE","TWO","THREE"]


Any problem?

If you have found a problem, if you think there is a bug or, more simply, you would like something to be improved, write a topic on the official forum, or open an issue on GitHub.

Thank you!