Chapter 5. PROCEDURES AND UNITS

PROCEDURES AND UNITS

In a procedural programming language, the basic unit of code is the procedure. A procedure is a set of instructions that compute some value or take some action (such as printing or reading a character value). This chapter discusses how HLA implements procedures. It begins by discussing HLA's high-level syntax for procedure declarations and invocations, but it also describes the low-level implementation of procedures at the machine level. At this point, you should be getting comfortable with assembly language programming, so it's time to start presenting "pure" assembly language rather than continuing to rely on HLA's high-level syntax as a crutch.

Most procedural programming languages implement procedures using the call/return mechanism. That is, some code calls a procedure, the procedure does its thing, and then the procedure returns to the caller. The call and return instructions provide the 80x86's procedure invocation mechanism. The calling code calls a procedure with the call instruction and the procedure returns to the caller with the ret instruction. For example, the following 80x86 instruction calls the HLA Standard Library stdout.newln routine:[70]

call stdout.newln;

The stdout.newln procedure prints a newline sequence to the console device and returns control to the instruction immediately following the call stdout.newln; instruction.

Alas, the HLA Standard Library does not supply all the routines you will ever need. Most of the time you'll have to write your own procedures. To do this, you will use HLA's procedure-declaration facilities. A basic HLA procedure declaration takes the following form:

procedure ProcName;
          << Local declarations >>
     begin ProcName;
          << Procedure statements >>
     end ProcName;

Procedure declarations appear in the declaration section of your program. That is, anywhere you can put a static, const, type, or other declaration section, you may place a procedure declaration. In the syntax example above, ProcName represents the name of the procedure you wish to define. This can be any valid (and unique) HLA identifier. Whatever identifier follows the procedure reserved word must also follow the begin and end reserved words in the procedure. As you've probably noticed, a procedure declaration looks a whole lot like an HLA program. In fact, the only difference (so far) is the use of the procedure reserved word rather than the program reserved word.

Here is a concrete example of an HLA procedure declaration. This procedure stores zeros into the 256 double words that EBX points at upon entry into the procedure:

procedure zeroBytes;
begin zeroBytes;

     mov( 0, eax );
     mov( 256, ecx );
     repeat
          mov( eax, [ebx] );
          add( 4, ebx );
          dec( ecx );

     until( @z );  // That is, until ecx=0.

end zeroBytes;

You can use the 80x86 call instruction to call this procedure. When, during program execution, the code falls into the end zeroBytes; statement, the procedure returns to whoever called it and begins executing the first instruction beyond the call instruction. The program in Example 5-1 provides an example of a call to the zeroBytes routine.

As you may have noticed when calling HLA Standard Library procedures, you don't have to use the call instruction to call HLA procedures. There is nothing special about the HLA Standard Library procedures versus your own procedures. Although the formal 80x86 mechanism for calling procedures is to use the call instruction, HLA provides a high-level extension that lets you call a procedure by simply specifying the procedure's name followed by an empty set of parentheses.[71] For example, either of the following statements will call the HLA Standard Library stdout.newln procedure:

call stdout.newln;
stdout.newln();

Likewise, either of the following statements will call the zeroBytes procedure in Example 5-1:

call zeroBytes;
zeroBytes();

The choice of calling mechanism is strictly up to you. Most people, however, find the high-level syntax easier to read.



[70] Normally you would call newln using the high-level newln(); syntax, but the call instruction works as well.

[71] This assumes that the procedure does not have any parameters.