CompileTest.mod 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. MODULE CompileTest ;
  2. (* Direct test harness for the TP3 compiler.
  3. Reads fixture paths from stdin, one per line, loads each into TextBuf
  4. exactly the way the shell's LoadWorkFile does, then calls Compiler.Compile
  5. and prints a one-line verdict plus a source excerpt with a caret under the
  6. error position.
  7. This is the fast loop for compiler work: no pty, no editor, no screen
  8. redraws - just Compile's own errNo / errPos, which is what actually
  9. matters. (The pty harness in matrix.py covers the shell/editor UI.)
  10. Usage: printf 'a.pas\nb.pas\n' | ./compiletest *)
  11. FROM Posix IMPORT read, write, open, close ;
  12. FROM TextBuf IMPORT TextLimit, Clear, Length, CharAt, InsertCh ;
  13. FROM Compiler IMPORT Compile, CodeBytes, DataBytes, CodeByteAt,
  14. ImageBytes, ImageByteAt, DataBase ;
  15. FROM SYSTEM IMPORT ADR, BYTE ;
  16. CONST
  17. STDIN = 0 ;
  18. STDOUT = 1 ;
  19. O_RDONLY = 0 ;
  20. VAR
  21. lineBuf : ARRAY [0..255] OF CHAR ;
  22. pathCopy : ARRAY [0..511] OF CHAR ;
  23. txt : ARRAY [0..79] OF CHAR ;
  24. mark : ARRAY [0..79] OF CHAR ;
  25. PROCEDURE PutCh (ch : CHAR) ;
  26. VAR n : LONGINT ;
  27. BEGIN
  28. n := write (STDOUT, ADR (ch), 1)
  29. END PutCh ;
  30. PROCEDURE PutStr (s : ARRAY OF CHAR) ;
  31. VAR i : CARDINAL ; n : LONGINT ;
  32. BEGIN
  33. i := 0 ;
  34. WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
  35. n := write (STDOUT, ADR (s [i]), 1) ;
  36. INC (i)
  37. END
  38. END PutStr ;
  39. PROCEDURE PutCard (n : CARDINAL) ;
  40. VAR dig : ARRAY [0..9] OF CHAR ; i : CARDINAL ;
  41. BEGIN
  42. IF n = 0 THEN
  43. PutCh ("0")
  44. ELSE
  45. i := 0 ;
  46. WHILE n > 0 DO
  47. dig [i] := CHR (ORD ("0") + (n MOD 10)) ;
  48. n := n DIV 10 ;
  49. INC (i)
  50. END ;
  51. WHILE i > 0 DO
  52. DEC (i) ;
  53. PutCh (dig [i])
  54. END
  55. END
  56. END PutCard ;
  57. PROCEDURE NL ;
  58. BEGIN
  59. PutCh (CHR (13)) ;
  60. PutCh (CHR (10))
  61. END NL ;
  62. PROCEDURE StrCopy (VAR dst : ARRAY OF CHAR ; src : ARRAY OF CHAR) ;
  63. VAR i : CARDINAL ;
  64. BEGIN
  65. i := 0 ;
  66. WHILE (i <= HIGH (dst)) AND (i <= HIGH (src)) AND (src [i] # 0C) DO
  67. dst [i] := src [i] ;
  68. INC (i)
  69. END ;
  70. IF i <= HIGH (dst) THEN
  71. dst [i] := 0C
  72. END
  73. END StrCopy ;
  74. PROCEDURE ReadLineStr (VAR s : ARRAY OF CHAR) : BOOLEAN ;
  75. (* one line from stdin; FALSE at EOF/blank line *)
  76. VAR ch : CHAR ; n : LONGINT ; i : CARDINAL ;
  77. BEGIN
  78. i := 0 ;
  79. s [0] := 0C ;
  80. LOOP
  81. n := read (STDIN, ADR (ch), 1) ;
  82. IF n # 1 THEN
  83. IF i = 0 THEN
  84. RETURN FALSE
  85. END ;
  86. s [i] := 0C ;
  87. RETURN TRUE
  88. END ;
  89. IF (ch = CHR (10)) OR (ch = CHR (13)) THEN
  90. IF i = 0 THEN
  91. RETURN FALSE
  92. END ;
  93. s [i] := 0C ;
  94. RETURN TRUE
  95. END ;
  96. IF i < HIGH (s) THEN
  97. s [i] := ch ;
  98. INC (i)
  99. END
  100. END
  101. END ReadLineStr ;
  102. PROCEDURE LoadFile (p : ARRAY OF CHAR) : BOOLEAN ;
  103. (* same CR/LF normalisation as the shell's LoadWorkFile *)
  104. VAR fd : INTEGER ; k : LONGINT ; b : BYTE ; prevCR : BOOLEAN ;
  105. BEGIN
  106. fd := open (ADR (p), O_RDONLY, 0) ;
  107. IF fd < 0 THEN
  108. RETURN FALSE
  109. END ;
  110. Clear ;
  111. prevCR := FALSE ;
  112. LOOP
  113. IF Length () >= TextLimit THEN
  114. EXIT
  115. END ;
  116. k := read (fd, ADR (b), 1) ;
  117. IF k # 1 THEN
  118. EXIT
  119. END ;
  120. IF b = 26 THEN
  121. EXIT (* ^Z ends the text *)
  122. ELSIF b = 10 THEN
  123. IF NOT prevCR THEN
  124. InsertCh (Length (), CHR (13)) (* lone LF -> CR *)
  125. END ;
  126. prevCR := FALSE
  127. ELSIF b = 13 THEN
  128. InsertCh (Length (), CHR (13)) ;
  129. prevCR := TRUE
  130. ELSE
  131. InsertCh (Length (), CHR (ORD (b))) ;
  132. prevCR := FALSE
  133. END
  134. END ;
  135. k := close (fd) ;
  136. RETURN TRUE
  137. END LoadFile ;
  138. PROCEDURE ShowAt (pos : CARDINAL) ;
  139. (* print the source around pos, with '^' under pos *)
  140. VAR s, e, i : CARDINAL ;
  141. BEGIN
  142. IF pos > 40 THEN
  143. s := pos - 40
  144. ELSE
  145. s := 0
  146. END ;
  147. e := pos + 30 ;
  148. IF e > Length () THEN
  149. e := Length ()
  150. END ;
  151. IF e > s + 78 THEN
  152. e := s + 78
  153. END ;
  154. i := 0 ;
  155. WHILE s + i < e DO
  156. txt [i] := CharAt (s + i) ;
  157. IF txt [i] = CHR (13) THEN
  158. txt [i] := " "
  159. END ;
  160. IF s + i = pos THEN
  161. mark [i] := "^"
  162. ELSE
  163. mark [i] := "-"
  164. END ;
  165. INC (i)
  166. END ;
  167. txt [i] := 0C ;
  168. mark [i] := 0C ;
  169. PutStr (" " ) ;
  170. PutStr (txt) ;
  171. NL ;
  172. PutStr (" " ) ;
  173. PutStr (mark) ;
  174. NL
  175. END ShowAt ;
  176. VAR
  177. errNo, errPos : CARDINAL ;
  178. ok : BOOLEAN ;
  179. dump, image : BOOLEAN ;
  180. PROCEDURE Hex (b : BYTE ; VAR out : ARRAY OF CHAR) ;
  181. (* ISO will not index a plain string constant as an array, so compute the
  182. two nibbles instead of using a "0123456789ABCDEF" lookup. *)
  183. VAR d : CARDINAL ;
  184. BEGIN
  185. d := VAL (CARDINAL, b) DIV 16 ; (* BYTE arith yields BYTE *)
  186. IF d < 10 THEN
  187. out [0] := CHR (ORD ("0") + d)
  188. ELSE
  189. out [0] := CHR (ORD ("A") + d - 10)
  190. END ;
  191. d := VAL (CARDINAL, b) MOD 16 ;
  192. IF d < 10 THEN
  193. out [1] := CHR (ORD ("0") + d)
  194. ELSE
  195. out [1] := CHR (ORD ("A") + d - 10)
  196. END
  197. END Hex ;
  198. PROCEDURE PutHexNib (d : CARDINAL) ;
  199. (* one hex digit. Do NOT reuse Hex for this: Hex formats a BYTE as two
  200. chars, so printing 4 nibbles through it emits 8 digits and every offset
  201. reads 16x too large. *)
  202. VAR c : CHAR ;
  203. BEGIN
  204. IF d < 10 THEN
  205. c := CHR (ORD ("0") + d)
  206. ELSE
  207. c := CHR (ORD ("A") + d - 10)
  208. END ;
  209. PutCh (c)
  210. END PutHexNib ;
  211. PROCEDURE PutCardHex4 (n : CARDINAL) ;
  212. (* 4 hex digits, e.g. "0010" for 16 *)
  213. VAR d : CARDINAL ;
  214. BEGIN
  215. d := 4096 ; (* 16^3, no "**" needed *)
  216. WHILE d > 0 DO
  217. PutHexNib ((n DIV d) MOD 16) ;
  218. d := d DIV 16
  219. END ;
  220. PutStr (": ")
  221. END PutCardHex4 ;
  222. PROCEDURE DumpCode ;
  223. (* hex dump of the emitted PROGRAM, 16 bytes per line. The runtime is not
  224. part of the program, so the program starts at 0 and is CodeBytes() long. *)
  225. VAR i, n : CARDINAL ;
  226. hx : ARRAY [0..1] OF CHAR ;
  227. b : BYTE ;
  228. BEGIN
  229. i := 0 ;
  230. WHILE i < CodeBytes () DO
  231. PutStr (" " ) ;
  232. PutCardHex4 (i) ;
  233. n := 0 ;
  234. WHILE (n < 16) AND (i + n < CodeBytes ()) DO
  235. b := CodeByteAt (i + n) ;
  236. Hex (b, hx) ;
  237. PutCh (hx [0]) ;
  238. PutCh (hx [1]) ;
  239. PutCh (" ") ;
  240. INC (n)
  241. END ;
  242. NL ;
  243. i := i + 16
  244. END
  245. END DumpCode ;
  246. PROCEDURE DumpImage ;
  247. (* The whole linked image - [entry JMP][runtime][program header][program code] -
  248. which is what a .COM would actually contain. The runtime's own bytes
  249. (rtSz below, derived rather than written down) are shown only at the head
  250. and the tail: enough to prove the blob is really in there, without burying
  251. the program in 28 lines of library. *)
  252. VAR i, n, rtSz, total, from, lim : CARDINAL ;
  253. hx : ARRAY [0..1] OF CHAR ;
  254. BEGIN
  255. rtSz := ImageBytes () - CodeBytes () ;
  256. total := ImageBytes () ;
  257. PutStr (" image=") ;
  258. PutCard (total) ;
  259. PutStr (" rtSz=") ;
  260. PutCard (rtSz) ;
  261. PutStr (" dataBase=") ;
  262. PutCard (DataBase ()) ;
  263. PutStr (" dataEnd=") ;
  264. PutCard (DataBase () + DataBytes ()) ;
  265. NL ;
  266. PutStr (" rt head " ) ;
  267. i := 0 ;
  268. WHILE i < 16 DO
  269. Hex (ImageByteAt (i), hx) ;
  270. PutCh (hx [0]) ; PutCh (hx [1]) ; PutCh (" ") ;
  271. INC (i)
  272. END ;
  273. NL ;
  274. i := rtSz - 16 ;
  275. WHILE i < total DO
  276. from := i ;
  277. lim := total ;
  278. IF lim > from + 16 THEN
  279. lim := from + 16
  280. END ;
  281. PutStr (" " ) ;
  282. PutCardHex4 (from) ;
  283. n := 0 ;
  284. WHILE (n < 16) AND (from + n < lim) DO
  285. Hex (ImageByteAt (from + n), hx) ;
  286. PutCh (hx [0]) ; PutCh (hx [1]) ; PutCh (" ") ;
  287. INC (n)
  288. END ;
  289. NL ;
  290. i := i + 16
  291. END
  292. END DumpImage ;
  293. PROCEDURE IsCmd (c1, c2, c3, c4, c5 : CHAR ) : BOOLEAN ;
  294. (* the line "@word" switches a dump mode on for the rest of the run *)
  295. VAR i : CARDINAL ;
  296. BEGIN
  297. IF lineBuf [0] # "@" THEN
  298. RETURN FALSE
  299. END ;
  300. i := 0 ;
  301. WHILE (i <= HIGH (lineBuf)) AND (lineBuf [i] # 0C) DO
  302. INC (i)
  303. END ;
  304. IF i # 6 THEN
  305. RETURN FALSE
  306. END ;
  307. RETURN (lineBuf [1] = c1) AND (lineBuf [2] = c2) AND (lineBuf [3] = c3)
  308. AND (lineBuf [4] = c4) AND (lineBuf [5] = c5)
  309. END IsCmd ;
  310. BEGIN
  311. PutStr ("FIXTURE RESULT") ;
  312. NL ;
  313. WHILE ReadLineStr (lineBuf) DO
  314. IF IsCmd ("d", "u", "m", "p", " ") THEN
  315. dump := TRUE (* "@dump": hex-dump from here on *)
  316. ELSIF IsCmd ("i", "m", "a", "g", "e") THEN
  317. image := TRUE (* "@image": whole image, layout too *)
  318. ELSE
  319. StrCopy (pathCopy, lineBuf) ;
  320. IF LoadFile (pathCopy) THEN
  321. ok := Compile (errNo, errPos) ;
  322. IF ok THEN
  323. PutStr (lineBuf) ;
  324. PutStr (" OK code=") ;
  325. PutCard (CodeBytes ()) ;
  326. PutStr (" data=") ;
  327. PutCard (DataBytes ()) ;
  328. NL ;
  329. IF image THEN
  330. DumpImage ()
  331. ELSIF dump THEN
  332. DumpCode ()
  333. END
  334. ELSE
  335. PutStr (lineBuf) ;
  336. PutStr (" ERROR ") ;
  337. PutCard (errNo) ;
  338. PutStr (" at pos ") ;
  339. PutCard (errPos) ;
  340. NL ;
  341. ShowAt (errPos)
  342. END
  343. ELSE
  344. PutStr (lineBuf) ;
  345. PutStr (" CANNOT OPEN") ;
  346. NL
  347. END
  348. END
  349. END
  350. END CompileTest.