Armed with these new scanner procedures, we can now begin to fix the compiler to use them properly. The changes are all quite minor, but there are quite a few places where changes are necessary. Rather than showing you each place, I will give you the general idea and then just give the finished product.
First of all, the code for procedure Block doesn't change, though its function does:
{ Parse and Translate a Block of Statements }
procedure Block;
begin
Scan;
while not(Token in ['e', 'l']) do begin
case Token of
'i': DoIf;
'w': DoWhile;
'R': DoRead;
'W': DoWrite;
else Assignment;
end;
Scan;
end;
end; |
Remember that the new version of Scan doesn't advance the input stream, it only scans for keywords. The input stream must be advanced by each procedure that Block calls.
In general, we have to replace every test on Look with a similar test on Token. For example:
{ Parse and Translate a Boolean Expression }
procedure BoolExpression;
begin
BoolTerm;
while IsOrOp(Token) do begin
Push;
case Token of
'|': BoolOr;
'~': BoolXor;
end;
end;
end; |
In procedures like Add, we don't have to use Match anymore. We need only call Next to advance the input stream:
{ Recognize and Translate an Add }
procedure Add;
begin
Next;
Term;
PopAdd;
end; |
Control structures are actually simpler. We just call Next to advance over the control keywords:
{ Recognize and Translate an IF Construct }
procedure Block; Forward;
procedure DoIf;
var L1, L2: string;
begin
Next;
BoolExpression;
L1 := NewLabel;
L2 := L1;
BranchFalse(L1);
Block;
if Token = 'l' then begin
Next;
L2 := NewLabel;
Branch(L2);
PostLabel(L1);
Block;
end;
PostLabel(L2);
MatchString('ENDIF');
end; |
That's about the extent of the required changes. In the listing of TINY Version 1.1 below, I've also made a number of other “improvements” that aren't really required. Let me explain them briefly: