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.
Also: this entire project will use Qualified Identifiers. So there will not be symbols that are imported separately with something like
	FROM	InOut		IMPORT	Write, Read, WriteLn;
   
instead, all imported symbols are referenced with the dot operators like in
	InOut.Read	InOut.Write	InOut.WriteLn
   
This 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