5.4. The WHILE Statement

The next type of statement should be easy, since we already have the process down pat. The syntax I've chosen for the WHILE statement is

WHILE <condition> <block> ENDWHILE

I know, I know, we don't really need separate kinds of terminators for each construct … you can see that by the fact that in our one-character version, e is used for all of them. But I also remember many debugging sessions in Pascal, trying to track down a wayward END that the compiler obviously thought I meant to put somewhere else. It's been my experience that specific and unique keywords, although they add to the vocabulary of the language, give a bit of error-checking that is worth the extra work for the compiler writer.

Now, consider what the WHILE should be translated into. It should be:

L1:     <condition>
        BEQ L2
        <block>
        BRA L1
L2:

As before, comparing the two representations gives us the actions needed at each point.

WHILE           { L1 = NewLabel;
                  PostLabel(L1) }
<condition>     { Emit(BEQ L2) }
<block>
ENDWHILE        { Emit(BRA L1);
                  PostLabel(L2) }

The code follows immediately from the syntax:

{ Parse and Translate a WHILE Statement }
procedure DoWhile;
var L1, L2: string;
begin
   Match('w');
   L1 := NewLabel;
   L2 := NewLabel;
   PostLabel(L1);
   Condition;
   EmitLn('BEQ ' + L2);
   Block;
   Match('e');
   EmitLn('BRA ' + L1);
   PostLabel(L2);
end;

Since we've got a new statement, we have to add a call to it within procedure Block:

{ Recognize and Translate a Statement Block }
procedure Block;
begin
   while not(Look in ['e', 'l']) do begin
      case Look of
       'i': DoIf;
       'w': DoWhile;
       else Other;
      end;
   end;
end;

No other changes are necessary.

OK, try the new program. Note that this time, the <condition> code is inside the upper label, which is just where we wanted it. Try some nested loops. Try some loops within IF's, and some IF's within loops. If you get a bit confused as to what you should type, don't be discouraged: you write bugs in other languages, too, don't you? It'll look a lot more meaningful when we get full keywords.

I hope by now that you're beginning to get the idea that this really is easy. All we have to do to accomodate a new construct is to work out the syntax-directed translation of it. The code almost falls out from there, and it doesn't affect any of the other routines. Once you've gotten the feel of the thing, you'll see that you can add new constructs about as fast as you can dream them up.