10.8. Control Structures

We're almost home. With Boolean expressions in place, it's a simple matter to add control structures. For TINY, we'll only allow two kinds of them, the IF and the WHILE:

<if> ::= IF <bool-expression> <block> [ ELSE <block>] ENDIF
<while> ::= WHILE <bool-expression> <block> ENDWHILE

Once again, let me spell out the decisions implicit in this syntax, which departs strongly from that of C or Pascal. In both of those languages, the “body” of an IF or WHILE is regarded as a single statement. If you intend to use a block of more than one statement, you have to build a compound statement using BEGIN-END (in Pascal) or '{}' (in C). In TINY (and KISS) there is no such thing as a compound statement … single or multiple they're all just blocks to these languages.

In KISS, all the control structures will have explicit and unique keywords bracketing the statement block, so there can be no confusion as to where things begin and end. This is the modern approach, used in such respected languages as Ada and Modula 2, and it completely eliminates the problem of the “dangling else.

Note that I could have chosen to use the same keyword END to end all the constructs, as is done in Pascal. (The closing '}' in C serves the same purpose.) But this has always led to confusion, which is why Pascal programmers tend to write things like

end { loop }

or

end { if }

As I explained in Part Chapter 5, Control Constructs, using unique terminal keywords does increase the size of the keyword list and therefore slows down the scanning, but in this case it seems a small price to pay for the added insurance. Better to find the errors at compile time rather than run time.

One last thought: The two constructs above each have the non-terminals

<bool-expression> and <block>

juxtaposed with no separating keyword. In Pascal we would expect the keywords THEN and DO in these locations.

I have no problem with leaving out these keywords, and the parser has no trouble either, on condition that we make no errors in the bool-expression part. On the other hand, if we were to include these extra keywords we would get yet one more level of insurance at very little cost, and I have no problem with that, either. Use your best judgment as to which way to go.

OK, with that bit of explanation let's proceed. As usual, we're going to need some new code generation routines. These generate the code for conditional and unconditional branches:

{ Branch Unconditional  }
procedure Branch(L: string);
begin
   EmitLn('BRA ' + L);
end;

{ Branch False }
procedure BranchFalse(L: string);
begin
   EmitLn('TST D0');
   EmitLn('BEQ ' + L);
end;

Except for the encapsulation of the code generation, the code to parse the control constructs is the same as you've seen before:

{ Recognize and Translate an IF Construct }
procedure Block; Forward;
procedure DoIf;
var L1, L2: string;
begin
   Match('i');
   BoolExpression;
   L1 := NewLabel;
   L2 := L1;
   BranchFalse(L1);
   Block;
   if Look = 'l' then begin
      Match('l');
      L2 := NewLabel;
      Branch(L2);
      PostLabel(L1);
      Block;
   end;
   PostLabel(L2);
   Match('e');
end;

{ Parse and Translate a WHILE Statement }
procedure DoWhile;
var L1, L2: string;
begin
   Match('w');
   L1 := NewLabel;
   L2 := NewLabel;
   PostLabel(L1);
   BoolExpression;
   BranchFalse(L2);
   Block;
   Match('e');
   Branch(L1);
   PostLabel(L2);
end;

To tie everything together, we need only modify procedure Block to recognize the “keywords” for the IF and WHILE. As usual, we expand the definition of a block like so:

<block> ::= ( <statement> )*

where

<statement> ::= <if> | <while> | <assignment>

The corresponding code is:

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

OK, add the routines I've given, compile and test them. You should be able to parse the single-character versions of any of the control constructs. It's looking pretty good!

As a matter of fact, except for the single-character limitation we've got a virtually complete version of TINY. I call it, with tongue planted firmly in cheek, TINY Version 0.1.