AST.mod 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 = 65536;
  13. MaxTxt = 16384;
  14. PoolSize = 1048576; (* 1 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 TxtLen (i : TxtIndex) : CARDINAL;
  87. BEGIN
  88. IF (i < 0) OR (i >= VAL(INTEGER, nTxt)) THEN RETURN 0 END;
  89. RETURN poolLen[i]
  90. END TxtLen;
  91. PROCEDURE InitNode (n : Node);
  92. VAR j: CARDINAL;
  93. BEGIN
  94. arena[n].kind := 0;
  95. arena[n].op := -1;
  96. arena[n].ty := -1; (* SymTab.InvalidType, by value *)
  97. arena[n].nch := 0;
  98. j := 0;
  99. WHILE j < MaxChild DO arena[n].child[j] := NoNode; INC(j) END
  100. END InitNode;
  101. PROCEDURE NewSlot (): Node;
  102. BEGIN
  103. IF nNodes > HighNode THEN RETURN NoNode END;
  104. InitNode(VAL(INTEGER, nNodes));
  105. INC(nNodes);
  106. RETURN VAL(INTEGER, nNodes - 1)
  107. END NewSlot;
  108. PROCEDURE MakeNode (kind : INTEGER) : Node;
  109. VAR n: Node;
  110. BEGIN
  111. n := NewSlot();
  112. IF n # NoNode THEN arena[n].kind := kind END;
  113. RETURN n
  114. END MakeNode;
  115. PROCEDURE MakeLeaf (kind : INTEGER; name : ARRAY OF CHAR) : Node;
  116. VAR n: Node;
  117. BEGIN
  118. n := MakeNode(kind);
  119. IF n # NoNode THEN
  120. arena[n].child[0] := VAL(INTEGER, AddTxt(name));
  121. arena[n].nch := 1
  122. END;
  123. RETURN n
  124. END MakeLeaf;
  125. PROCEDURE MakeBin (kind, op : INTEGER; l, r : Node) : Node;
  126. VAR n: Node;
  127. BEGIN
  128. n := MakeNode(kind);
  129. IF n # NoNode THEN
  130. arena[n].op := op;
  131. arena[n].child[0] := l;
  132. arena[n].child[1] := r;
  133. arena[n].nch := 2
  134. END;
  135. RETURN n
  136. END MakeBin;
  137. PROCEDURE MakeUn (kind, op : INTEGER; e : Node) : Node;
  138. VAR n: Node;
  139. BEGIN
  140. n := MakeNode(kind);
  141. IF n # NoNode THEN
  142. arena[n].op := op;
  143. arena[n].child[0] := e;
  144. arena[n].nch := 1
  145. END;
  146. RETURN n
  147. END MakeUn;
  148. PROCEDURE Kind (n : Node) : INTEGER;
  149. BEGIN
  150. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
  151. RETURN arena[n].kind
  152. END Kind;
  153. PROCEDURE SetKind (n : Node; kind : INTEGER);
  154. BEGIN
  155. IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
  156. arena[n].kind := kind END
  157. END SetKind;
  158. PROCEDURE Op (n : Node) : INTEGER;
  159. BEGIN
  160. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
  161. RETURN arena[n].op
  162. END Op;
  163. PROCEDURE SetOp (n : Node; op : INTEGER);
  164. BEGIN
  165. IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
  166. arena[n].op := op END
  167. END SetOp;
  168. PROCEDURE Ty (n : Node) : INTEGER;
  169. BEGIN
  170. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN -1 END;
  171. RETURN arena[n].ty
  172. END Ty;
  173. PROCEDURE SetTy (n : Node; t : INTEGER);
  174. BEGIN
  175. IF (n >= 0) AND (n <= VAL(INTEGER, nNodes) - 1) THEN
  176. arena[n].ty := t END
  177. END SetTy;
  178. PROCEDURE NChild (n : Node) : CARDINAL;
  179. BEGIN
  180. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN 0 END;
  181. RETURN arena[n].nch
  182. END NChild;
  183. PROCEDURE Child (n : Node; i : CARDINAL) : Node;
  184. BEGIN
  185. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1)
  186. OR (i >= arena[n].nch) THEN
  187. RETURN NoNode
  188. END;
  189. RETURN arena[n].child[i]
  190. END Child;
  191. PROCEDURE AddChild (n : Node; c : Node) : BOOLEAN;
  192. BEGIN
  193. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN FALSE END;
  194. IF arena[n].nch >= MaxChild THEN RETURN FALSE END;
  195. arena[n].child[arena[n].nch] := c;
  196. INC(arena[n].nch);
  197. RETURN TRUE
  198. END AddChild;
  199. PROCEDURE SetChild (n : Node; i : CARDINAL; c : Node);
  200. BEGIN
  201. IF (n < 0) OR (n > VAL(INTEGER, nNodes) - 1) THEN RETURN END;
  202. IF i < arena[n].nch THEN
  203. arena[n].child[i] := c
  204. ELSIF (i = arena[n].nch) AND (arena[n].nch < MaxChild) THEN
  205. arena[n].child[i] := c;
  206. INC(arena[n].nch)
  207. END
  208. END SetChild;
  209. PROCEDURE WriteSp (d : CARDINAL);
  210. VAR i: CARDINAL;
  211. BEGIN
  212. i := 0;
  213. WHILE i < d DO
  214. FileIO.WriteString(FileIO.StdOut, " "); INC(i)
  215. END
  216. END WriteSp;
  217. PROCEDURE IsLeafKind (k : INTEGER) : BOOLEAN;
  218. BEGIN
  219. RETURN (k = NkIdent) OR (k = NkIntLit) OR (k = NkRealLit)
  220. OR (k = NkStrLit) OR (k = NkCharLit) OR (k = NkTypeIdent)
  221. OR (k = NkImport)
  222. END IsLeafKind;
  223. PROCEDURE Dump (n : Node; depth : CARDINAL);
  224. VAR i: CARDINAL; s: ARRAY [0 .. MaxTxtLen] OF CHAR;
  225. BEGIN
  226. IF n = NoNode THEN
  227. WriteSp(depth); FileIO.WriteString(FileIO.StdOut, "(nil)");
  228. FileIO.WriteLn(FileIO.StdOut); RETURN
  229. END;
  230. WriteSp(depth);
  231. FileIO.WriteString(FileIO.StdOut, "kind=");
  232. FileIO.WriteInt(FileIO.StdOut, arena[n].kind, 1);
  233. FileIO.WriteString(FileIO.StdOut, " op=");
  234. FileIO.WriteInt(FileIO.StdOut, arena[n].op, 1);
  235. FileIO.WriteString(FileIO.StdOut, " ty=");
  236. FileIO.WriteInt(FileIO.StdOut, arena[n].ty, 1);
  237. IF IsLeafKind(arena[n].kind) AND (arena[n].nch > 0)
  238. AND (arena[n].child[0] # NoNode) THEN
  239. Txt(VAL(TxtIndex, arena[n].child[0]), s);
  240. FileIO.WriteString(FileIO.StdOut, " '");
  241. FileIO.WriteString(FileIO.StdOut, s);
  242. FileIO.WriteString(FileIO.StdOut, "'")
  243. END;
  244. FileIO.WriteLn(FileIO.StdOut);
  245. i := 0;
  246. WHILE i < arena[n].nch DO
  247. IF NOT IsLeafKind(arena[n].kind) THEN
  248. Dump(arena[n].child[i], depth + 1)
  249. END;
  250. INC(i)
  251. END
  252. END Dump;
  253. BEGIN
  254. Init
  255. END AST.