CompileTest.mod 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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, SetSource ;
  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. SetSource (p) ; (* {$I} resolves beside this file *)
  111. Clear ;
  112. prevCR := FALSE ;
  113. LOOP
  114. IF Length () >= TextLimit THEN
  115. EXIT
  116. END ;
  117. k := read (fd, ADR (b), 1) ;
  118. IF k # 1 THEN
  119. EXIT
  120. END ;
  121. IF b = 26 THEN
  122. EXIT (* ^Z ends the text *)
  123. ELSIF b = 10 THEN
  124. IF NOT prevCR THEN
  125. InsertCh (Length (), CHR (13)) (* lone LF -> CR *)
  126. END ;
  127. prevCR := FALSE
  128. ELSIF b = 13 THEN
  129. InsertCh (Length (), CHR (13)) ;
  130. prevCR := TRUE
  131. ELSE
  132. InsertCh (Length (), CHR (ORD (b))) ;
  133. prevCR := FALSE
  134. END
  135. END ;
  136. k := close (fd) ;
  137. RETURN TRUE
  138. END LoadFile ;
  139. PROCEDURE ShowAt (pos : CARDINAL) ;
  140. (* print the source around pos, with '^' under pos *)
  141. VAR s, e, i : CARDINAL ;
  142. BEGIN
  143. IF pos > 40 THEN
  144. s := pos - 40
  145. ELSE
  146. s := 0
  147. END ;
  148. e := pos + 30 ;
  149. IF e > Length () THEN
  150. e := Length ()
  151. END ;
  152. IF e > s + 78 THEN
  153. e := s + 78
  154. END ;
  155. i := 0 ;
  156. WHILE s + i < e DO
  157. txt [i] := CharAt (s + i) ;
  158. IF txt [i] = CHR (13) THEN
  159. txt [i] := " "
  160. END ;
  161. IF s + i = pos THEN
  162. mark [i] := "^"
  163. ELSE
  164. mark [i] := "-"
  165. END ;
  166. INC (i)
  167. END ;
  168. txt [i] := 0C ;
  169. mark [i] := 0C ;
  170. PutStr (" " ) ;
  171. PutStr (txt) ;
  172. NL ;
  173. PutStr (" " ) ;
  174. PutStr (mark) ;
  175. NL
  176. END ShowAt ;
  177. VAR
  178. errNo, errPos : CARDINAL ;
  179. ok : BOOLEAN ;
  180. dump, image : BOOLEAN ;
  181. PROCEDURE Hex (b : BYTE ; VAR out : ARRAY OF CHAR) ;
  182. (* ISO will not index a plain string constant as an array, so compute the
  183. two nibbles instead of using a "0123456789ABCDEF" lookup. *)
  184. VAR d : CARDINAL ;
  185. BEGIN
  186. d := VAL (CARDINAL, b) DIV 16 ; (* BYTE arith yields BYTE *)
  187. IF d < 10 THEN
  188. out [0] := CHR (ORD ("0") + d)
  189. ELSE
  190. out [0] := CHR (ORD ("A") + d - 10)
  191. END ;
  192. d := VAL (CARDINAL, b) MOD 16 ;
  193. IF d < 10 THEN
  194. out [1] := CHR (ORD ("0") + d)
  195. ELSE
  196. out [1] := CHR (ORD ("A") + d - 10)
  197. END
  198. END Hex ;
  199. PROCEDURE PutHexNib (d : CARDINAL) ;
  200. (* one hex digit. Do NOT reuse Hex for this: Hex formats a BYTE as two
  201. chars, so printing 4 nibbles through it emits 8 digits and every offset
  202. reads 16x too large. *)
  203. VAR c : CHAR ;
  204. BEGIN
  205. IF d < 10 THEN
  206. c := CHR (ORD ("0") + d)
  207. ELSE
  208. c := CHR (ORD ("A") + d - 10)
  209. END ;
  210. PutCh (c)
  211. END PutHexNib ;
  212. PROCEDURE PutCardHex4 (n : CARDINAL) ;
  213. (* 4 hex digits, e.g. "0010" for 16 *)
  214. VAR d : CARDINAL ;
  215. BEGIN
  216. d := 4096 ; (* 16^3, no "**" needed *)
  217. WHILE d > 0 DO
  218. PutHexNib ((n DIV d) MOD 16) ;
  219. d := d DIV 16
  220. END ;
  221. PutStr (": ")
  222. END PutCardHex4 ;
  223. PROCEDURE DumpCode ;
  224. (* hex dump of the emitted PROGRAM, 16 bytes per line. The runtime is not
  225. part of the program, so the program starts at 0 and is CodeBytes() long. *)
  226. VAR i, n : CARDINAL ;
  227. hx : ARRAY [0..1] OF CHAR ;
  228. b : BYTE ;
  229. BEGIN
  230. i := 0 ;
  231. WHILE i < CodeBytes () DO
  232. PutStr (" " ) ;
  233. PutCardHex4 (i) ;
  234. n := 0 ;
  235. WHILE (n < 16) AND (i + n < CodeBytes ()) DO
  236. b := CodeByteAt (i + n) ;
  237. Hex (b, hx) ;
  238. PutCh (hx [0]) ;
  239. PutCh (hx [1]) ;
  240. PutCh (" ") ;
  241. INC (n)
  242. END ;
  243. NL ;
  244. i := i + 16
  245. END
  246. END DumpCode ;
  247. PROCEDURE DumpImage ;
  248. (* The whole linked image - [entry JMP][runtime][program header][program code] -
  249. which is what a .COM would actually contain. The runtime's own bytes
  250. (rtSz below, derived rather than written down) are shown only at the head
  251. and the tail: enough to prove the blob is really in there, without burying
  252. the program in 28 lines of library. *)
  253. VAR i, n, rtSz, total, from, lim : CARDINAL ;
  254. hx : ARRAY [0..1] OF CHAR ;
  255. BEGIN
  256. rtSz := ImageBytes () - CodeBytes () ;
  257. total := ImageBytes () ;
  258. PutStr (" image=") ;
  259. PutCard (total) ;
  260. PutStr (" rtSz=") ;
  261. PutCard (rtSz) ;
  262. PutStr (" dataBase=") ;
  263. PutCard (DataBase ()) ;
  264. PutStr (" dataEnd=") ;
  265. PutCard (DataBase () + DataBytes ()) ;
  266. NL ;
  267. PutStr (" rt head " ) ;
  268. i := 0 ;
  269. WHILE i < 16 DO
  270. Hex (ImageByteAt (i), hx) ;
  271. PutCh (hx [0]) ; PutCh (hx [1]) ; PutCh (" ") ;
  272. INC (i)
  273. END ;
  274. NL ;
  275. i := rtSz - 16 ;
  276. WHILE i < total DO
  277. from := i ;
  278. lim := total ;
  279. IF lim > from + 16 THEN
  280. lim := from + 16
  281. END ;
  282. PutStr (" " ) ;
  283. PutCardHex4 (from) ;
  284. n := 0 ;
  285. WHILE (n < 16) AND (from + n < lim) DO
  286. Hex (ImageByteAt (from + n), hx) ;
  287. PutCh (hx [0]) ; PutCh (hx [1]) ; PutCh (" ") ;
  288. INC (n)
  289. END ;
  290. NL ;
  291. i := i + 16
  292. END
  293. END DumpImage ;
  294. PROCEDURE IsCmd (c1, c2, c3, c4, c5 : CHAR ) : BOOLEAN ;
  295. (* the line "@word" switches a dump mode on for the rest of the run *)
  296. VAR i : CARDINAL ;
  297. BEGIN
  298. IF lineBuf [0] # "@" THEN
  299. RETURN FALSE
  300. END ;
  301. i := 0 ;
  302. WHILE (i <= HIGH (lineBuf)) AND (lineBuf [i] # 0C) DO
  303. INC (i)
  304. END ;
  305. IF i # 6 THEN
  306. RETURN FALSE
  307. END ;
  308. RETURN (lineBuf [1] = c1) AND (lineBuf [2] = c2) AND (lineBuf [3] = c3)
  309. AND (lineBuf [4] = c4) AND (lineBuf [5] = c5)
  310. END IsCmd ;
  311. BEGIN
  312. PutStr ("FIXTURE RESULT") ;
  313. NL ;
  314. WHILE ReadLineStr (lineBuf) DO
  315. IF IsCmd ("d", "u", "m", "p", " ") THEN
  316. dump := TRUE (* "@dump": hex-dump from here on *)
  317. ELSIF IsCmd ("i", "m", "a", "g", "e") THEN
  318. image := TRUE (* "@image": whole image, layout too *)
  319. ELSE
  320. StrCopy (pathCopy, lineBuf) ;
  321. IF LoadFile (pathCopy) THEN
  322. ok := Compile (errNo, errPos) ;
  323. IF ok THEN
  324. PutStr (lineBuf) ;
  325. PutStr (" OK code=") ;
  326. PutCard (CodeBytes ()) ;
  327. PutStr (" data=") ;
  328. PutCard (DataBytes ()) ;
  329. NL ;
  330. IF image THEN
  331. DumpImage ()
  332. ELSIF dump THEN
  333. DumpCode ()
  334. END
  335. ELSE
  336. PutStr (lineBuf) ;
  337. PutStr (" ERROR ") ;
  338. PutCard (errNo) ;
  339. PutStr (" at pos ") ;
  340. PutCard (errPos) ;
  341. NL ;
  342. ShowAt (errPos)
  343. END
  344. ELSE
  345. PutStr (lineBuf) ;
  346. PutStr (" CANNOT OPEN") ;
  347. NL
  348. END
  349. END
  350. END
  351. END CompileTest.