| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- IMPLEMENTATION MODULE AST;
- (* Arena-backed abstract syntax tree (Stage A).
- Layout:
- - `arena` is a fixed array of nodes; live count `nNodes`.
- - each node stores kind/op/ty, a child count and child indices.
- - `pool` is a fixed text area; `poolOff[i]`/`poolLen[i]` delimit
- the i-th interned string (NUL-free, so no terminator needed).
- No dynamic allocation: the sizes mirror SymTab's fixed tables and
- are ample for the compiler's own source when self-hosting. *)
- IMPORT FileIO;
- CONST
- MaxNodes = 65536;
- MaxTxt = 16384;
- PoolSize = 1048576; (* 1 MiB of pooled text *)
- MaxTxtLen = 255;
- (* arena has MaxNodes slots, indices 0..MaxNodes-1 *)
- HighNode = MaxNodes - 1;
- HighTxt = MaxTxt - 1;
- TYPE
- NodeRec = RECORD
- kind : INTEGER;
- op : INTEGER;
- ty : INTEGER;
- nch : CARDINAL;
- child : ARRAY [0 .. MaxChild - 1] OF Node;
- END;
- VAR
- arena : ARRAY [0 .. HighNode] OF NodeRec;
- nNodes : CARDINAL;
- pool : ARRAY [0 .. PoolSize - 1] OF CHAR;
- poolUse: CARDINAL;
- poolOff: ARRAY [0 .. HighTxt] OF CARDINAL;
- poolLen: ARRAY [0 .. HighTxt] OF CARDINAL;
- nTxt : CARDINAL;
- PROCEDURE Init;
- VAR i: CARDINAL;
- BEGIN
- nNodes := 0;
- nTxt := 0;
- poolUse := 0;
- (* nodes are zeroed lazily via InitNode; nothing else needed *)
- END Init;
- PROCEDURE AddTxt (s : ARRAY OF CHAR) : TxtIndex;
- VAR i, k, L, off: CARDINAL; dup: BOOLEAN;
- BEGIN
- L := 0;
- WHILE (L <= HIGH(s)) AND (s[L] # CHR(0)) DO INC(L) END;
- IF L > MaxTxtLen THEN L := MaxTxtLen END;
- (* dedupe *)
- i := 0;
- WHILE i < nTxt DO
- IF poolLen[i] = L THEN
- dup := TRUE;
- k := 0;
- WHILE (k < L) AND dup DO
- IF pool[poolOff[i] + k] # s[k] THEN dup := FALSE END;
- INC(k)
- END;
- IF dup THEN RETURN VAL(TxtIndex, i) END
- END;
- INC(i)
- END;
- IF (nTxt > HIGH(poolOff)) OR (poolUse + L > PoolSize) THEN
- RETURN NoTxt
- END;
- off := poolUse;
- k := 0;
- WHILE k < L DO pool[poolUse] := s[k]; INC(poolUse); INC(k) END;
- poolOff[nTxt] := off;
- poolLen[nTxt] := L;
- INC(nTxt);
- RETURN VAL(TxtIndex, nTxt - 1)
- END AddTxt;
- PROCEDURE Txt (i : TxtIndex; VAR s : ARRAY OF CHAR);
- VAR k, L: CARDINAL;
- BEGIN
- s[0] := CHR(0);
- IF (i < 0) OR (i >= VAL(INTEGER, nTxt)) THEN RETURN END;
- L := poolLen[i];
- k := 0;
- WHILE (k < L) AND (k < HIGH(s)) DO
- s[k] := pool[poolOff[i] + k]; INC(k)
- END;
- s[k] := CHR(0)
- END Txt;
- PROCEDURE TxtLen (i : TxtIndex) : CARDINAL;
- BEGIN
- IF (i < 0) OR (i >= VAL(INTEGER, nTxt)) THEN RETURN 0 END;
- RETURN poolLen[i]
- END TxtLen;
- PROCEDURE InitNode (n : Node);
- VAR j: CARDINAL;
- BEGIN
- arena[n].kind := 0;
- arena[n].op := -1;
- arena[n].ty := -1; (* SymTab.InvalidType, by value *)
- arena[n].nch := 0;
- j := 0;
- WHILE j < MaxChild DO arena[n].child[j] := NoNode; INC(j) END
- END InitNode;
- PROCEDURE NewSlot (): Node;
- BEGIN
- IF nNodes > HighNode THEN RETURN NoNode END;
- InitNode(VAL(INTEGER, nNodes));
- INC(nNodes);
- RETURN VAL(INTEGER, nNodes - 1)
- END NewSlot;
- PROCEDURE MakeNode (kind : INTEGER) : Node;
- VAR n: Node;
- BEGIN
- n := NewSlot();
- IF n # NoNode THEN arena[n].kind := kind END;
- RETURN n
- END MakeNode;
- PROCEDURE MakeLeaf (kind : INTEGER; name : ARRAY OF CHAR) : Node;
- VAR n: Node;
- BEGIN
- n := MakeNode(kind);
- IF n # NoNode THEN
- arena[n].child[0] := VAL(INTEGER, AddTxt(name));
- arena[n].nch := 1
- END;
- RETURN n
- END MakeLeaf;
- PROCEDURE MakeBin (kind, op : INTEGER; l, r : Node) : Node;
- VAR n: Node;
- BEGIN
- n := MakeNode(kind);
- IF n # NoNode THEN
- arena[n].op := op;
- arena[n].child[0] := l;
- arena[n].child[1] := r;
- arena[n].nch := 2
- END;
- RETURN n
- END MakeBin;
- PROCEDURE MakeUn (kind, op : INTEGER; e : Node) : Node;
- VAR n: Node;
- BEGIN
- n := MakeNode(kind);
- IF n # NoNode THEN
- arena[n].op := op;
- arena[n].child[0] := e;
- arena[n].nch := 1
- END;
- RETURN n
- END MakeUn;
- PROCEDURE Kind (n : Node) : INTEGER;
- BEGIN
- IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
- RETURN arena[n].kind
- END Kind;
- PROCEDURE SetKind (n : Node; kind : INTEGER);
- BEGIN
- IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
- arena[n].kind := kind END
- END SetKind;
- PROCEDURE Op (n : Node) : INTEGER;
- BEGIN
- IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
- RETURN arena[n].op
- END Op;
- PROCEDURE SetOp (n : Node; op : INTEGER);
- BEGIN
- IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
- arena[n].op := op END
- END SetOp;
- PROCEDURE Ty (n : Node) : INTEGER;
- BEGIN
- IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
- RETURN arena[n].ty
- END Ty;
- PROCEDURE SetTy (n : Node; t : INTEGER);
- BEGIN
- IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
- arena[n].ty := t END
- END SetTy;
- PROCEDURE NChild (n : Node) : CARDINAL;
- BEGIN
- IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN 0 END;
- RETURN arena[n].nch
- END NChild;
- PROCEDURE Child (n : Node; i : CARDINAL) : Node;
- BEGIN
- IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1)
- OR (i >= arena[n].nch) THEN
- RETURN NoNode
- END;
- RETURN arena[n].child[i]
- END Child;
- PROCEDURE AddChild (n : Node; c : Node) : BOOLEAN;
- BEGIN
- IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN FALSE END;
- IF arena[n].nch >= MaxChild THEN RETURN FALSE END;
- arena[n].child[arena[n].nch] := c;
- INC(arena[n].nch);
- RETURN TRUE
- END AddChild;
- PROCEDURE SetChild (n : Node; i : CARDINAL; c : Node);
- BEGIN
- IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN END;
- IF i < arena[n].nch THEN
- arena[n].child[i] := c
- ELSIF (i = arena[n].nch) AND (arena[n].nch < MaxChild) THEN
- arena[n].child[i] := c;
- INC(arena[n].nch)
- END
- END SetChild;
- PROCEDURE WriteSp (d : CARDINAL);
- VAR i: CARDINAL;
- BEGIN
- i := 0;
- WHILE i < d DO
- FileIO.WriteString(FileIO.StdOut, " "); INC(i)
- END
- END WriteSp;
- PROCEDURE IsLeafKind (k : INTEGER) : BOOLEAN;
- BEGIN
- RETURN (k = NkIdent) OR (k = NkIntLit) OR (k = NkRealLit)
- OR (k = NkStrLit) OR (k = NkCharLit) OR (k = NkTypeIdent)
- OR (k = NkImport)
- END IsLeafKind;
- PROCEDURE Dump (n : Node; depth : CARDINAL);
- VAR i: CARDINAL; s: ARRAY [0 .. MaxTxtLen] OF CHAR;
- BEGIN
- IF n = NoNode THEN
- WriteSp(depth); FileIO.WriteString(FileIO.StdOut, "(nil)");
- FileIO.WriteLn(FileIO.StdOut); RETURN
- END;
- WriteSp(depth);
- FileIO.WriteString(FileIO.StdOut, "kind=");
- FileIO.WriteInt(FileIO.StdOut, arena[n].kind, 1);
- FileIO.WriteString(FileIO.StdOut, " op=");
- FileIO.WriteInt(FileIO.StdOut, arena[n].op, 1);
- FileIO.WriteString(FileIO.StdOut, " ty=");
- FileIO.WriteInt(FileIO.StdOut, arena[n].ty, 1);
- IF IsLeafKind(arena[n].kind) AND (arena[n].nch > 0)
- AND (arena[n].child[0] # NoNode) THEN
- Txt(VAL(TxtIndex, arena[n].child[0]), s);
- FileIO.WriteString(FileIO.StdOut, " '");
- FileIO.WriteString(FileIO.StdOut, s);
- FileIO.WriteString(FileIO.StdOut, "'")
- END;
- FileIO.WriteLn(FileIO.StdOut);
- i := 0;
- WHILE i < arena[n].nch DO
- IF NOT IsLeafKind(arena[n].kind) THEN
- Dump(arena[n].child[i], depth + 1)
- END;
- INC(i)
- END
- END Dump;
- BEGIN
- Init
- END AST.
|