Plov013 : Enhance the error checker
Previous versions did have some kind of syntax checker. As soon as one popped up, the program would end up in an infinite loop and that was the sign... By this time I got a bit bored of this and decided to give it a closer look. The best thing to do is make a construct similar to what Mocka does. Yet, this would take some more time and there are PLOV issues that I want to settle first. Below is a diff list of the most important changes applied to Plov.
Plov013 : Changes
In order to streamline errorchecking, a new ReadString procedure was necessary. So I started with making my own GetChar function. Nothing fancy, but it makes searching for EOL tokens easier. And it enables me to add a line/column counter for the error indicator.
PROCEDURE GetChar (VAR ch : CHAR);
BEGIN
TextIO.GetChar (inFile, ch);
IF ch = 11C THEN
INC (Xpos, 8)
ELSE
INC (Xpos)
END;
IF DebugMode THEN InOut.Write (ch) END;
IF ch = ASCII.LF THEN
INC (line);
Xpos := 0;
pastEOL := TRUE
END
END GetChar;
DebugMode is a constant defined in the header section. 11C of course is the Modula-2 notation for ASCII.TAB.
The rest is rather straighforward. If you came this far on this website I need not explain in detail why I
chose these lines of prose.
Here comes the new ReadString:
PROCEDURE ReadString (VAR str : Identifier);
VAR n, max : CARDINAL;
ch : CHAR;
BEGIN
n := 0; max := HIGH (str);
pastEOL := FALSE;
REPEAT GetChar (ch) UNTIL ch > ' ';
REPEAT
str [n] := ch;
INC (n);
GetChar (ch)
UNTIL (ch < '!') OR (n > max);
lastCH := ch;
IF n < max THEN str [n] := 0C END;
END ReadString;
It's a lot smaller than the previous one. Tedious linefeed checking has completely been removed. And now that
we have a decent character getter, we can also make a lineskipper:
PROCEDURE Skip2LF; VAR ch : CHAR; BEGIN REPEAT GetChar (ch) UNTIL ch = ASCII.LF END Skip2LF;Here is the new ErrorMessage function. I removed the bulk of the messages since they are just makeup.
CONST ErrorMax = 5;
PROCEDURE ErrorMessage (n : CARDINAL);
BEGIN
INC (ErrCount);
InOut.WriteLn; InOut.WriteString ("@@ -- ");
CASE n OF
0 : InOut.WriteString ("Error filling Symbol table") |
.
.
.
34 : InOut.WriteString ("Cannot open file '");
InOut.WriteString (buffer^[1]^); InOut.Write ("'")
ELSE
InOut.WriteString ("Unknown error detected.")
END;
InOut.WriteString (" in line "); InOut.WriteCard (line, 5); InOut.WriteLn;
InOut.WriteBf;
IF ErrCount = ErrorMax THEN
ShutDown;
HALT
END
END ErrorMessage;
Now I can filter until (in this case) five error messages have been issued and then abort. After 5 messages
things turn out in a mess most of the times, depending on where the previous error were. If a WHILE has been
mis spelled as WHLIE, the corresponding END just comes out of the blue, causing new (but false) error messages
so it's not wrong to put the compiler out of its misery.
Below is the new StatementSequence procedure:
PROCEDURE StatementSequence;
BEGIN
GetSymbol;
LOOP
CG ("");
IF findType (token) = Vartype THEN Assignment
ELSIF Strings.StrEq (token, "ELSIF") THEN RETURN
.
.
.
ELSIF Strings.StrEq (token, "ELSE") THEN RETURN
ELSE
Skip2LF;
ErrorMessage (10); (* Error in StatementSequence *)
GetSymbol
END
END
END StatementSequence;
If an error is found, the rest of the line is skipped, a message is sent out and the new symbol is collected
for a new journey around the LOOP. This works quite well.
In 'Assignment' something similar was done. After the errormessage, the rest of the line is skipped. This is the only sensible thing to do, since the Assignment-scanner is a statemachine and it already is in the WRONG state... So I skip the line and get back to 'StatementSequence' (with the RETURN) leaving possible further errors in this line to the next compilerrun.
PROCEDURE Assignment;
BEGIN
CG ("ADDRESS ");
IF weHaveLocals AND (FindLocal (token) = TRUE) THEN CG ("LOCAL ") END;
CG (token); CG ("");
pastEOL := FALSE;
GetSymbol;
IF Strings.StrEq (token, ':=') = FALSE THEN
ErrorMessage (17); (* Missing ':=' *)
Skip2LF;
GetSymbol;
RETURN
END;
GetSymbol;
Expression;
CG ("SAVE"); CG ("")
END Assignment;
Plov013 : see it run
Here's a messy source:
PROGRAP testt CONSTANT a = 1 END VARIABLE 1 2 ab END PROCEDURE hhhhhhh LOCAL aa ss 1a END BEGIN aa := ss + 22 aa : 0 END hhhhhhh BEGIN aa := a + 1 END testtSee how it compiles:
PROGRAP @@ -- PROGRAM expected in line 1That was quick. See how things change when I fix this error:
PROGRAM testt CONSTANT @@ -- BEGIN expected in line 3 a = 1 END @@ -- Undefined symbol or keyword in line 4 VARIABLE 1 2 ab END @@ -- Undefined symbol or keyword in line 6 PROCEDURE hhhhhhh @@ -- Undefined symbol or keyword in line 8 LOCAL aa ss 1a END @@ -- Undefined symbol or keyword in line 10After five error messages the compiler called it quits. Let's fix this error as well. Still, this silly error makes me wonder: would it be feasible to have the compiler hint what the programmer was after? Could Plov find out that this presumably was a misspelled CONSTANTS keyword?
PROGRAM testt CONSTANTS a = 1 END VARIABLE @@ -- BEGIN expected in line 5 1 2 ab END @@ -- Undefined symbol or keyword in line 6 PROCEDURE hhhhhhh @@ -- Undefined symbol or keyword in line 8 LOCAL aa ss 1a END @@ -- Undefined symbol or keyword in line 10 BEGIN aa := ss + 22 @@ -- Undefined symbol or keyword in line 13The statemachine got stateless... Still, after the most silly errors have been removed, the syntax checker behaves rather well. I'm kind of proud about this:
PROGRAM testt CONSTANTS a = 1 END VARIABLES 1 @@ -- Illegal identifier name : 1 in line 5 2 @@ -- Illegal identifier name : 2 in line 5 ab END PROCEDURE hhhhhhh LOCAL aa ss 1a @@ -- Illegal identifier name : 1a in line 9 END BEGIN aa := ss + 22 aa : @@ -- Missing assigment operator in line 13 0 END hhhhhhh BEGIN aa := a + 1 END testtIt reported five errors and then stopped. Error 6 is still in. Let's see if this will be found as well:
PROGRAM testt CONSTANTS a = 1 END VARIABLES ab END PROCEDURE hhhhhhh LOCAL aa ss END BEGIN aa := ss + 22 aa := 0 END hhhhhhh BEGIN aa := a + 1 @@ -- Undefined symbol or keyword in line 18 END testtNot bad!
PROGRAM testt CONSTANTS a = 1 END VARIABLES ab END PROCEDURE hhhhhhh LOCAL aa ss END BEGIN aa := ss + 22 aa := 0 END hhhhhhh BEGIN ab := a + 1 END testtYes! No errors anymore!
Page created on 14 September 2008 and
Page equipped with FroogleBuster technology