AST.mod 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. IMPLEMENTATION MODULE AST;
  2. (* Arena-backed abstract syntax tree (Stage A).
  3. Layout:
  4. - `arena` is a fixed array of nodes; live count `nNodes`.
  5. - each node stores kind/op/ty, a child count and child indices.
  6. - `pool` is a fixed text area; `poolOff[i]`/`poolLen[i]` delimit
  7. the i-th interned string (NUL-free, so no terminator needed).
  8. No dynamic allocation: the sizes mirror SymTab's fixed tables and
  9. are ample for the compiler's own source when self-hosting. *)
  10. IMPORT FileIO;
  11. CONST
  12. MaxNodes = 262144;
  13. MaxTxt = 65536;
  14. PoolSize = 4194304; (* 4 MiB of pooled text *)
  15. MaxTxtLen = 255;
  16. (* arena has MaxNodes slots, indices 0..MaxNodes-1 *)
  17. HighNode = MaxNodes - 1;
  18. HighTxt = MaxTxt - 1;
  19. TYPE
  20. NodeRec = RECORD
  21. kind : INTEGER;
  22. op : INTEGER;
  23. ty : INTEGER;
  24. nch : CARDINAL;
  25. child : ARRAY [0 .. MaxChild - 1] OF Node;
  26. END;
  27. VAR
  28. arena : ARRAY [0 .. HighNode] OF NodeRec;
  29. nNodes : CARDINAL;
  30. pool : ARRAY [0 .. PoolSize - 1] OF CHAR;
  31. poolUse: CARDINAL;
  32. poolOff: ARRAY [0 .. HighTxt] OF CARDINAL;
  33. poolLen: ARRAY [0 .. HighTxt] OF CARDINAL;
  34. nTxt : CARDINAL;
  35. PROCEDURE Init;
  36. VAR i: CARDINAL;
  37. BEGIN
  38. nNodes := 0;
  39. nTxt := 0;
  40. poolUse := 0;
  41. (* nodes are zeroed lazily via InitNode; nothing else needed *)
  42. END Init;
  43. PROCEDURE AddTxt (s : ARRAY OF CHAR) : TxtIndex;
  44. VAR i, k, L, off: CARDINAL; dup: BOOLEAN;
  45. BEGIN
  46. L := 0;
  47. WHILE (L <= HIGH(s)) AND (s[L] # CHR(0)) DO INC(L) END;
  48. IF L > MaxTxtLen THEN L := MaxTxtLen END;
  49. (* dedupe *)
  50. i := 0;
  51. WHILE i < nTxt DO
  52. IF poolLen[i] = L THEN
  53. dup := TRUE;
  54. k := 0;
  55. WHILE (k < L) AND dup DO
  56. IF pool[poolOff[i] + k] # s[k] THEN dup := FALSE END;
  57. INC(k)
  58. END;
  59. IF dup THEN RETURN VAL(TxtIndex, i) END
  60. END;
  61. INC(i)
  62. END;
  63. IF (nTxt > HIGH(poolOff)) OR (poolUse + L > PoolSize) THEN
  64. RETURN NoTxt
  65. END;
  66. off := poolUse;
  67. k := 0;
  68. WHILE k < L DO pool[poolUse] := s[k]; INC(poolUse); INC(k) END;
  69. poolOff[nTxt] := off;
  70. poolLen[nTxt] := L;
  71. INC(nTxt);
  72. RETURN VAL(TxtIndex, nTxt - 1)
  73. END AddTxt;
  74. PROCEDURE Txt (i : TxtIndex; VAR s : ARRAY OF CHAR);
  75. VAR k, L: CARDINAL;
  76. BEGIN
  77. s[0] := CHR(0);
  78. IF (i < 0) OR (i >= VAL(INTEGER, nTxt)) THEN RETURN END;
  79. L := poolLen[i];
  80. k := 0;
  81. WHILE (k < L) AND (k < HIGH(s)) DO
  82. s[k] := pool[poolOff[i] + k]; INC(k)
  83. END;
  84. s[k] := CHR(0)
  85. END Txt;
  86. PROCEDURE InitNode (n : Node);
  87. VAR j: CARDINAL;
  88. BEGIN
  89. arena[n].kind := 0;
  90. arena[n].op := -1;
  91. arena[n].ty := -1; (* SymTab.InvalidType, by value *)
  92. arena[n].nch := 0;
  93. j := 0;
  94. WHILE j < MaxChild DO arena[n].child[j] := NoNode; INC(j) END
  95. END InitNode;
  96. PROCEDURE NewSlot (): Node;
  97. BEGIN
  98. IF nNodes > HighNode THEN RETURN NoNode END;
  99. InitNode(VAL(INTEGER, nNodes));
  100. INC(nNodes);
  101. RETURN VAL(INTEGER, nNodes - 1)
  102. END NewSlot;
  103. PROCEDURE MakeNode (kind : INTEGER) : Node;
  104. VAR n: Node;
  105. BEGIN
  106. n := NewSlot();
  107. IF n # NoNode THEN arena[n].kind := kind END;
  108. RETURN n
  109. END MakeNode;
  110. PROCEDURE MakeLeaf (kind : INTEGER; name : ARRAY OF CHAR) : Node;
  111. VAR n: Node;
  112. BEGIN
  113. n := MakeNode(kind);
  114. IF n # NoNode THEN
  115. arena[n].child[0] := VAL(INTEGER, AddTxt(name));
  116. arena[n].nch := 1
  117. END;
  118. RETURN n
  119. END MakeLeaf;
  120. PROCEDURE MakeBin (kind, op : INTEGER; l, r : Node) : Node;
  121. VAR n: Node;
  122. BEGIN
  123. n := MakeNode(kind);
  124. IF n # NoNode THEN
  125. arena[n].op := op;
  126. arena[n].child[0] := l;
  127. arena[n].child[1] := r;
  128. arena[n].nch := 2
  129. END;
  130. RETURN n
  131. END MakeBin;
  132. PROCEDURE MakeUn (kind, op : INTEGER; e : Node) : Node;
  133. VAR n: Node;
  134. BEGIN
  135. n := MakeNode(kind);
  136. IF n # NoNode THEN
  137. arena[n].op := op;
  138. arena[n].child[0] := e;
  139. arena[n].nch := 1
  140. END;
  141. RETURN n
  142. END MakeUn;
  143. PROCEDURE Kind (n : Node) : INTEGER;
  144. BEGIN
  145. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
  146. RETURN arena[n].kind
  147. END Kind;
  148. PROCEDURE Op (n : Node) : INTEGER;
  149. BEGIN
  150. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
  151. RETURN arena[n].op
  152. END Op;
  153. PROCEDURE SetOp (n : Node; op : INTEGER);
  154. BEGIN
  155. IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
  156. arena[n].op := op END
  157. END SetOp;
  158. PROCEDURE Ty (n : Node) : INTEGER;
  159. BEGIN
  160. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
  161. RETURN arena[n].ty
  162. END Ty;
  163. PROCEDURE SetTy (n : Node; t : INTEGER);
  164. BEGIN
  165. IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
  166. arena[n].ty := t END
  167. END SetTy;
  168. PROCEDURE NChild (n : Node) : CARDINAL;
  169. BEGIN
  170. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN 0 END;
  171. RETURN arena[n].nch
  172. END NChild;
  173. PROCEDURE Child (n : Node; i : CARDINAL) : Node;
  174. BEGIN
  175. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1)
  176. OR (i >= arena[n].nch) THEN
  177. RETURN NoNode
  178. END;
  179. RETURN arena[n].child[i]
  180. END Child;
  181. PROCEDURE AddChild (n : Node; c : Node) : BOOLEAN;
  182. BEGIN
  183. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN FALSE END;
  184. IF arena[n].nch >= MaxChild THEN RETURN FALSE END;
  185. arena[n].child[arena[n].nch] := c;
  186. INC(arena[n].nch);
  187. RETURN TRUE
  188. END AddChild;
  189. PROCEDURE SetChild (n : Node; i : CARDINAL; c : Node);
  190. BEGIN
  191. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN END;
  192. IF i < arena[n].nch THEN
  193. arena[n].child[i] := c
  194. ELSIF (i = arena[n].nch) AND (arena[n].nch < MaxChild) THEN
  195. arena[n].child[i] := c;
  196. INC(arena[n].nch)
  197. END
  198. END SetChild;
  199. PROCEDURE WriteSp (d : CARDINAL);
  200. VAR i: CARDINAL;
  201. BEGIN
  202. i := 0;
  203. WHILE i < d DO
  204. FileIO.WriteString(FileIO.StdOut, " "); INC(i)
  205. END
  206. END WriteSp;
  207. PROCEDURE IsLeafKind (k : INTEGER) : BOOLEAN;
  208. BEGIN
  209. RETURN (k = NkIdent) OR (k = NkIntLit) OR (k = NkRealLit)
  210. OR (k = NkStrLit) OR (k = NkCharLit) OR (k = NkTypeIdent)
  211. END IsLeafKind;
  212. PROCEDURE Dump (n : Node; depth : CARDINAL);
  213. VAR i: CARDINAL; s: ARRAY [0 .. MaxTxtLen] OF CHAR;
  214. BEGIN
  215. IF n = NoNode THEN
  216. WriteSp(depth); FileIO.WriteString(FileIO.StdOut, "(nil)");
  217. FileIO.WriteLn(FileIO.StdOut); RETURN
  218. END;
  219. WriteSp(depth);
  220. FileIO.WriteString(FileIO.StdOut, "kind=");
  221. FileIO.WriteInt(FileIO.StdOut, arena[n].kind, 1);
  222. FileIO.WriteString(FileIO.StdOut, " op=");
  223. FileIO.WriteInt(FileIO.StdOut, arena[n].op, 1);
  224. FileIO.WriteString(FileIO.StdOut, " ty=");
  225. FileIO.WriteInt(FileIO.StdOut, arena[n].ty, 1);
  226. IF IsLeafKind(arena[n].kind) AND (arena[n].nch > 0)
  227. AND (arena[n].child[0] # NoNode) THEN
  228. Txt(VAL(TxtIndex, arena[n].child[0]), s);
  229. FileIO.WriteString(FileIO.StdOut, " '");
  230. FileIO.WriteString(FileIO.StdOut, s);
  231. FileIO.WriteString(FileIO.StdOut, "'")
  232. END;
  233. FileIO.WriteLn(FileIO.StdOut);
  234. i := 0;
  235. WHILE i < arena[n].nch DO
  236. IF NOT IsLeafKind(arena[n].kind) THEN
  237. Dump(arena[n].child[i], depth + 1)
  238. END;
  239. INC(i)
  240. END
  241. END Dump;
  242. BEGIN
  243. Init
  244. END AST.