Plov : The symbol table
Before we start coding the compiler, I want to engineer a symbol table and a way to store and process the
symbols. This is a starting point. The symbol table is liable to change over the course of this project.
The linked list is simple in construction and use. But it can be a dog to implement in a program that already
does some things. So I decided to go it the easy road: first construct a simple Symbol table and a means to
keep it in memory. This project is strongly based on the Mocka Lili subject. Use the navigator to get to the
lili subject.
Plov001 : a symbol table and handler
Below is the source of Plov001.mod. If you studied the lili.mod file you may see some similarities. :o)
MODULE Plov001;
(* Plov is the PL/0 compiler as modified by Verhoeven *)
(* Ver Comment : Date *)
(* ----- ----------------------------------------------------- ------------ *)
(* 0.01 First version: read symbols and store them in a list 01 Oct 2007 *)
(* *)
IMPORT InOut, MemPools, Strings, SYSTEM;
TYPE Identifier = ARRAY [0..31] OF CHAR;
SymbolType = (Module, Procedure, Constant, Variable);
SymbolPtr = POINTER TO SymbolNode;
SymbolNode = RECORD
Name : Identifier;
next : SymbolPtr;
type : SymbolType;
value,
address : CARDINAL
END;
VAR string : Identifier;
token : Identifier;
Symbols : MemPools.MemPool;
firstSymbol,
thisSymbol : SymbolPtr;
currentType : SymbolType;
currentValue : CARDINAL;
PROCEDURE StoreSymbol (str : Identifier) : BOOLEAN;
VAR thisOne, nextOne : SymbolPtr;
BEGIN
thisOne := firstSymbol;
LOOP
IF Strings.StrEq (thisOne^.Name, str) THEN RETURN FALSE END;
IF thisOne^.next = NIL THEN EXIT END;
thisOne := thisOne^.next
END;
MemPools.PoolAllocate (Symbols, nextOne, SYSTEM.TSIZE (SymbolNode));
thisOne^.next := nextOne;
WITH nextOne^ DO
next := NIL;
Name := str;
type := currentType
END;
RETURN TRUE
END StoreSymbol;
PROCEDURE PrintNames;
VAR thisOne : SymbolPtr;
BEGIN
thisOne := firstSymbol;
(* IF Strings.StrEq (thisOne^.Name, "|") THEN thisOne := thisOne^.next END; *)
LOOP
InOut.WriteString (thisOne^.Name); InOut.WriteLn;
IF thisOne^.next = NIL THEN
EXIT
ELSE
thisOne := thisOne^.next
END
END
END PrintNames;
PROCEDURE Init;
BEGIN
MemPools.NewPool (Symbols);
MemPools.PoolAllocate (Symbols, firstSymbol, SYSTEM.TSIZE (SymbolNode));
WITH firstSymbol^ DO
Name := "|";
next := NIL
END
END Init;
BEGIN
Init;
LOOP
InOut.ReadString (string);
IF Strings.StrEq (string, "Exit") THEN EXIT END;
IF StoreSymbol (string) = FALSE THEN
InOut.WriteString (">>> Duplicate name : ");
InOut.WriteString (string);
InOut.WriteLn
END
END;
PrintNames;
MemPools.KillPool (Symbols)
END Plov001.
In essence, this is a copy of the first linked list in the lili topic. It just has been tailored for it's use
as symbol table handler. Unlike real geniuses like Wirth and Gutknecht, my small brain needs longer
identifiers to keep them apart. So no variablenames like sym, alt, succ or whatever.
FROM InOut IMPORT Write, Read, WriteLn;instead, all imported symbols are referenced with the dot operators like in
InOut.Read InOut.Write InOut.WriteLnThis makes it easier to find back which version of the symbol is used and hence it is easier to look it up in the reference manuals.
Some output
Of course this program will not do fancy tricks. It is a single purpose topic without any use at this moment. Still, it can be shown to work. I start it (after compiling) and then feed it with some text from the command line. 'Exit' terminates the input section.
jan@beryllium:~/modula/Plov$ Plov001 MODULE hi; PROCEDURE testit; BEGIN END hi. Exit | MODULE hi; PROCEDURE testit; BEGIN END hi. jan@beryllium:~/modula/Plov$Everything read is treated as a symbol (apart from the 'Exit' word, which is still acted upon but not included in the linked list). And another example:
jan@beryllium:~/modula/Plov$ cat source
PROGRAM factorial
CONSTANT max
VARIABLE result, value
BEGIN
val := 1
LOOP
result := result * value
INC (value)
IF value > max THEN EXIT END
END
RETURN result
END factorial
Exit
jan@beryllium:~/modula/Plov$ Plov001 <source
>>> Duplicate name : :=
>>> Duplicate name : result
>>> Duplicate name : value
>>> Duplicate name : value
>>> Duplicate name : max
>>> Duplicate name : END
>>> Duplicate name : result
>>> Duplicate name : END
>>> Duplicate name : factorial
|
PROGRAM
factorial
CONSTANT
max
VARIABLE
result,
val
BEGIN
value
:=
1
LOOP
result
*
INC
(value)
IF
>
THEN
EXIT
END
RETURN
jan@beryllium:~/modula/Plov$
This looks assuring. No strange things encountered so far. The stepwise refinement can begin now.
Page created on 1 October 2007 and
Page equipped with FroogleBuster technology