5.2. Some Groundwork

Before we begin to define the various control constructs, we need to lay a bit more groundwork. First, a word of warning: I won't be using the same syntax for these constructs as you're familiar with from Pascal or C. For example, the Pascal syntax for an IF is:

IF <condition> THEN <statement>

Note

where the statement, of course, may be compound.

The C version is similar:

if ( <condition> ) <statement>

Instead, I'll be using something that looks more like Ada:

IF <condition> <block> ENDIF

In other words, the IF construct has a specific termination symbol. This avoids the dangling-else of Pascal and C and also precludes the need for the brackets {} or begin-end. The syntax I'm showing you here, in fact, is that of the language KISS that I'll be detailing in later chapters . The other constructs will also be slightly different. That shouldn't be a real problem for you. Once you see how it's done, you'll realize that it really doesn't matter so much which specific syntax is involved. Once the syntax is defined, turning it into code is straightforward.

Now, all of the constructs we'll be dealing with here involve transfer of control, which at the assembler-language level means conditional and/or unconditional branches. For example, the simple IF statement

IF <condition> A ENDIF B ....

must get translated into

        Branch if NOT condition to L
        A
L:      B
        …

It's clear, then, that we're going to need some more procedures to help us deal with these branches. I've defined two of them below. Procedure NewLabel generates unique labels. This is done via the simple expedient of calling every label 'Lnn', where nn is a label number starting from zero. Procedure PostLabel just outputs the labels at the proper place.

Here are the two routines:

{ Generate a Unique Label }
function NewLabel: string;
var S: string;
begin
   Str(LCount, S);
   NewLabel := 'L' + S;
   Inc(LCount);
end;

{ Post a Label To Output }
procedure PostLabel(L: string);
begin
   WriteLn(L, ':');
end;

Notice that we've added a new global variable, LCount, so you need to change the VAR declarations at the top of the program to look like this:

var Look  : char;              { Lookahead Character }
    LCount: integer;           { Label Counter }

Also, add the following extra initialization to Init:

   LCount := 0;

Note

Don't forget that, or your labels can look really strange!

At this point I'd also like to show you a new kind of notation. If you compare the form of the IF statement above with the assembler code that must be produced, you can see that there are certain actions associated with each of the keywords in the statement:

IF:First, get the condition and issue the code for it. Then, create a unique label and emit a branch if false.
ENDIF:Emit the label.

These actions can be shown very concisely if we write the syntax this way:

IF
<condition>     { Condition;
                  L = NewLabel;
                  Emit(Branch False to L); }
<block>
ENDIF           { PostLabel(L) }

This is an example of syntax-directed translation. We've been doing it all along … we've just never written it down this way before. The stuff in curly brackets represents the actions to be taken. The nice part about this representation is that it not only shows what we have to recognize, but also the actions we have to perform, and in which order. Once we have this syntax, the code almost writes itself.

About the only thing left to do is to be a bit more specific about what we mean by “Branch if false”.

I'm assuming that there will be code executed for <condition> that will perform Boolean algebra and compute some result. It should also set the condition flags corresponding to that result. Now, the usual convention for a Boolean variable is to let 0000 represent “false,” and anything else (some use FFFF, some 0001) represent “true.

On the 68000 the condition flags are set whenever any data is moved or calculated. If the data is a 0000 (corresponding to a false condition, remember), the zero flag will be set. The code for “Branch on zero” is BEQ. So for our purposes here,

BEQ  <=> Branch if false
BNE  <=> Branch if true

It's the nature of the beast that most of the branches we see will be BEQ's … we'll be branching around the code that's supposed to be executed when the condition is true.