Plov008 : multiple assignments

While running a test to check the behavior of the EXIT statement I ran into a problem. It looked like multiple assignments were not taken care of. So I made a more difficult test program, test20:

      
PROGRAM test20

VARIABLES a b c d e f g h i j k END

BEGIN
   LOOP
      REPEAT
      a := a + 1
      UNTIL  a = 20
      b := a
      IF  b = 12  THEN  EXIT  END
      c := a + b x c - d
      k := a - j x 2
   END
END test20
   
And it fell astray. The problem was not new to me but I forgot about it... In normal Wirthian languages lines of code are auto terminated. That is: if a line of code is closed by any kind of keyword, the line is properly dealt with. If no keyword is coming up, you need to please the compiler by appending a ';' to the end of the previous line of code to signal that 'something else is coming'.

My compiler relies on a token that is already there, although invisible: the ASCII linefeed. Or at least: it should.

Plov008 : the source

So we need to detect linefeeds. There is only one place where we can do that: in 'GetSymbol'. The current GetSymbol is rather simple: it issues a TextIO.GetString function call and that's it. We have no way to find out what happens inside this function so we need to write our own version:

PROCEDURE ReadString (VAR  str : Identifier);

VAR	n, max		: CARDINAL;
	ch		: CHAR;

BEGIN
   n := 0;		max := HIGH (str);
   IF  lastCH = ASCII.LF  THEN  pastEOL := TRUE  ELSE  pastEOL := FALSE  END;
   REPEAT
      TextIO.GetChar (inFile, ch);
      IF  ch = ASCII.LF  THEN  
	 pastEOL := TRUE
(*	 ;InOut.Write ("#")	*)
      END
   UNTIL  ch > ' ';
   REPEAT
      str [n] := ch;
      INC (n);
      TextIO.GetChar (inFile, ch)
   UNTIL  (ch < '!') OR (n > max);
   lastCH := ch;
   IF  n < max  THEN  str [n] := 0C  END
END ReadString;
   
The new ReadString. The line that is commented out is a remnant of the debug code. Just ignore it. What the function does is: The BOOLEAN var pastEOL is the main reason to make this string reader. And while we were at it, the last character read is also remembered in the (new) global variable 'lastCH' (I stole this from the FST compiler). Reason: at the end of the line with 'c := a + b x c - d' the linefeed is not part of the leading whitespace for the next line. It is the terminating character of the previous GetSymbol....
PROCEDURE isComment;

BEGIN
   REPEAT  GetSymbol  UNTIL  Strings.StrEq (token, '*)');
   GetSymbol
END isComment;
   
The 'isComment' procedure takes care of nested comments. Just like Professor Wirth showed me.
PROCEDURE GetSymbol;

BEGIN
   IF  TextIO.EOF (inFile) = FALSE  THEN
(*      TextIO.GetString (inFile, token);			*)
      ReadString (token);
      IF  Strings.StrEq (token, '(*')  THEN  isComment  END
   ELSE
      InOut.WriteString ("EOF!!!   ")
   END;
   InOut.WriteString (token);		InOut.Write (11C);		InOut.WriteBf
END GetSymbol;
   
The new GetSymbol procedure. This is how you deal with experimental additions:
  1. comment out the old line of code
  2. enter the new line of code
This makes undoing things easier.

Of course, making the new ReadString is not the only change. We also need to use the new variable and act upon it. This is done in the expression evaluator:

      
PROCEDURE Expression;

VAR	op	: CHAR;

BEGIN
   Term;
   op := token [0];
   WHILE  (token [0] = '+') OR (token [0] = '-')  DO
      GetSymbol;
      Term;
      IF  op = '+'  THEN
	 CG ("ADD");
	 CG ("")
      ELSE
	 CG ("SUBTRACT");
	 CG ("")
      END;
      IF  pastEOL  THEN  RETURN  END
   END
END Expression;
   
Think about it why I had to put the line here. Plov008 : see it work

Below is a table with PLOV on the left and PALO on the right. There are two PALO fields. You'll find out why, by reading down the page.

Plov PALO I PALO II
PROGRAM test20 # PROGRAM test20
VARIABLES a b c d e f g h i j k END VARIABLE        a
VARIABLE        b
VARIABLE        c
VARIABLE        d
VARIABLE        e
VARIABLE        f
VARIABLE        g
VARIABLE        h
VARIABLE        i
VARIABLE        j
VARIABLE        k
BEGIN LABEL MAINLOOP
LOOP LABEL LOOP-1
REPEAT LABEL-0
a := a + 1 STORE ADDRESS OF a
FETCH VALUE OF a
STORE 1
ADD
SAVE RESULT
UNTIL a = 20 FETCH VALUE OF a
STORE 20
IF NOT EQUAL JUMP TO LABEL-0
b := a STORE ADDRESS OF b
FETCH VALUE OF a
SAVE RESULT
IF b = 12 THEN EXIT END FETCH VALUE OF b
STORE 12
IF NOT EQUAL JUMP TO LABEL IF-00

JUMP TO XLOOP-1

JUMP TO LABEL XIF-0
LABEL XIF-0

FETCH VALUE OF b
STORE 12
IF NOT EQUAL JUMP TO LABEL IF-00

JUMP TO XLOOP-1

JUMP TO LABEL XIF-0
LABEL IF-00
LABEL XIF-0

c := a + b x c - d STORE ADDRESS OF c
FETCH VALUE OF a
FETCH VALUE OF b
FETCH VALUE OF c
MULTIPLY
ADD
FETCH VALUE OF d
ADD
SAVE RESULT
STORE ADDRESS OF c
FETCH VALUE OF a
FETCH VALUE OF b
FETCH VALUE OF c
MULTIPLY
ADD
FETCH VALUE OF d
SUBTRACT
SAVE RESULT
k := a - j x 2 STORE ADDRESS OF k
FETCH VALUE OF a
FETCH VALUE OF j
STORE 2
MULTIPLY
SUBTRACT
SAVE RESULT
END JUMP TO LOOP-1
LABEL XLOOP-1
END test20 LABEL EXITMAINLOOP
# Done #

Impressive, isn't it?

It isn't:

Back to the drawing board!

Plov008 : the fix

The drawing board was happy: the source language was Modula-2 so it didn't need to use a dozen magicians to go through the source. The first problem (the ADD that should have been a SUBTRACT) was easily solved:

Old New
PROCEDURE Expression;

VAR	op	: CHAR;

BEGIN
   Term;
   op := token [0];
   WHILE  (token [0] = '+') OR (token [0] = '-')  DO
      GetSymbol;
      Term;
      IF  op = '+'  THEN
	 CG ("ADD");
	 CG ("")
      ELSE
	 CG ("SUBTRACT");
	 CG ("")
      END;
      IF  pastEOL  THEN  RETURN  END
   END
END Expression;
      
PROCEDURE Expression;

VAR	op	: CHAR;

BEGIN
   Term;
   op := token [0];
   WHILE  (op = '+') OR (op = '-')  DO
      GetSymbol;
      Term;
      IF  op = '+'  THEN
	 CG ("ADD");
	 CG ("")
      ELSE
	 CG ("SUBTRACT");
	 CG ("")
      END;
      op := token [0];
      IF  pastEOL  THEN  RETURN  END
   END
END Expression;
      

As you can see in the old code, the while loop was entered with a value of 'op' but 'op' never changed inside the loop! So the value was static. The fix was easy.

What remains is the missing IF label. I must confess that I was not overly happy with the way in which I fixed the IF loop and I did not test it extensively. And so things take a turn of their own...

The fix was easy. The label generators were in the wrong place.... The problem is: if I make a side by side comparison, even a 1280 screen is not wide enough. So I made a screenshot with arrows... The red blocks are in the NEW position and came from their OLD positions.

The new source code is in the PALO table above. And a syou see, I fooled you: the tests were done with Plov009...

Page created on 2 September 2008 and

Page equipped with FroogleBuster technology