User Tools

Site Tools


ugbasic:user:procedures
Translations of this page:


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.

Creating a procedure

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). PROCEDURE and END PROC commands should be placed on their own individual lines, but it is not mandatory.

For example:

 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.

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

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

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

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$]
     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"]

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[]
  
  DEBUG a
  DEBUG 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 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 * 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 os, 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.

Using PARAM

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)

Using RETURN and PARAM

The second 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$]
    DEBUG a$
    DEBUG b$
    DEBUG c$   
    RETURN a$+b$+c$
 END PROC
 
 joinString["ONE","TWO","THREE"]
 DEBUG PARAM$(joinString)

Using RETURN only

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