expected.tsv 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. # Expected results for tests/fixtures/*.pas - one line per fixture:
  2. #
  3. # <fixture-basename> OK <code> <data>
  4. # <fixture-basename> ERR <tp3-error-no> <relative-pos>
  5. #
  6. # Both the verdict AND the numbers are asserted by run_compile_tests.sh, so a
  7. # regression in the *reported error position* fails the suite just like a
  8. # regression in the generated code. That matters: error positions were once
  9. # silently wrong (a multi-character string literal swallowed the rest of the
  10. # source, so every later error pointed at end-of-file), and nothing caught it
  11. # because the old harness only printed the position for a human to squint at.
  12. #
  13. # Re-baseline deliberately, never to make a red test go green: if a fixture's
  14. # expectation has to change because the compiler legitimately improved, change
  15. # it in the same commit as the fix and say why in the message.
  16. #
  17. # ERR 102 = ENoLib, the original's "not implemented" path. The remaining ERR
  18. # rows are unimplemented features, not parser bugs:
  19. # t14 'array [..] of <type>' DECLARES and its constant-index element
  20. # access works now (CALC Stage 8): `b[1] := 2' stores TWO bytes, not
  21. # the whole ten-byte array, because a constant subscript folds
  22. # (index - lower bound) * element size into the address and the
  23. # expression carries the ELEMENT's width. data=15 = b (10) + a (2)
  24. # ... plus the temporaries; the row moved ERR->OK when the width
  25. # landed.
  26. # t25 a string literal used where a 16-bit word is wanted
  27. # uierror deliberate syntax error, pinned by the editor UI test
  28. #
  29. # The nine control-flow fixtures (t08 t09 t10 t11 t12 t13 t15 t27 t28) were
  30. # re-baselined upward when they were rewritten to PRINT their result, so each
  31. # has a .out file and is executed under qemu (run_com_exec.py) as well as
  32. # compiled here. Before that they assigned to a variable and fell off the end:
  33. # they asserted that the compiler produced bytes, and nothing about behaviour.
  34. # t13 also gained a second procedure, which is why it is bigger than the sum of
  35. # its parts. t08's data went 6 -> 7 because a CHAR variable joined the INTEGER.
  36. #
  37. # t02 t03 t05 t17 used to be ERR 102 as well: a multi-character literal was
  38. # rejected because writeln had no string support. They compile now, via the
  39. # inline-string path (CALL wrtinl, then <length><chars> in the code stream -
  40. # TPSRC8 pwrinlin / TPSRC4 xwrtinl), so their rows changed from ERR to OK and
  41. # their code sizes went up by the literal's own bytes.
  42. #
  43. # RE-BASELINED for v-TP3-8086-LOWERING, when conditional branches and SETcc
  44. # stopped being 386-only. Nine rows moved, every one of them UPWARD, and every
  45. # one of them by exactly the number of conditional sites in that fixture:
  46. #
  47. # +1 per site. A branch was 4 bytes (0F 8x rel16) and is now 5 (7x 03,
  48. # then the 3-byte EJMP). A comparison VALUE was 5 bytes (0F 9x rel8, then
  49. # MOV AH,0) and is now 6 (B8 01 00, 7x 01, DEC AX). So the deltas are
  50. # t09 +6 = 3 values + 3 branches, t10 +4 = 2+2, t11 +2 = 0+2,
  51. # t12 +4 = 2+2, t15 +2 = 1+1, t22 +2 = 0+2, t30 +1 = 0+1, t32 +3 = 1+2,
  52. # t33 +13 = 13 values.
  53. #
  54. # That arithmetic was CHECKED, not assumed: the site counts were counted out of
  55. # the linked images (the same CMP AX,CX and CMP AX,0000 anchors and the same
  56. # 7x 03 E9 shape that check_8086.py uses) and each row was only written after
  57. # its delta matched its count. Data sizes did not move at all. The bytes
  58. # themselves are pinned by check_8086.py, and the BEHAVIOUR is pinned by
  59. # run_com_exec.py -- this row only says how big the code is.
  60. #
  61. # RE-BASELINED when the runtime was wired into the code buffer. Every OK row
  62. # changed by exactly +3 code and -256 data, and both numbers are correct:
  63. #
  64. # +3 code the prologue now emits MOV AX,<header offset> before
  65. # CALL TU_InitMem, because InitMem takes the header offset in a
  66. # register (B8 lo hi) rather than on the stack. Previously the
  67. # prologue called offset 8, which is the hdrMax word - it only
  68. # "worked" because the runtime was not in the image at all.
  69. #
  70. # -256 data DataBytes() used to return dc, the ABSOLUTE end of the data
  71. # area, not a size. dc started at 100H, so every program reported
  72. # 256 more than it allocated - 260 for a program whose only data is
  73. # the two @@T1/@@T2 scratch words. The field is documented as
  74. # "emitted data size in bytes", so 4 is the true size and 260 was
  75. # the bug. It is a real correction, not a fit-to-the-test change:
  76. # the 6-byte rows are the fixtures that declare one global.
  77. #
  78. # ADDED for the BP displacement fix. These two fixtures are the first with
  79. # any frame access at all -- every earlier fixture put its variables in the
  80. # DATA segment, addressed absolutely, so the whole [BP+off] path had zero
  81. # coverage and a truncation there was invisible.
  82. #
  83. # t27_localvar five LOCAL variables, assigned and read back. Locals are
  84. # allocated downward from 0FFFEh and each access now costs 4
  85. # bytes (mod=10 + disp16) where it cost 3 (disp8), so its code
  86. # size reflects the fix rather than predating it. Both
  87. # encodings address the same place; only the rule for choosing
  88. # between them changed.
  89. # t28_farparam 70 declared parameters; the call passes 16, which is the
  90. # argument cap at the call site. Under TP3's frame rule the
  91. # LAST declared parameter is the one at BP+4, so p8 lands at
  92. # BP+128 and p1 at BP+142 - the first offsets a disp8 cannot
  93. # represent, since 80h is -128 and not +128. Under the old
  94. # code these two reads came from the wrong side of BP. This
  95. # fixture tests the ENCODING; it is executed too, but its .out
  96. # carries only the deterministic sum of the two slots the
  97. # sixteen pushed arguments land in (p55 + p70), never the
  98. # stack garbage that p1..p54 read. Do not read it as a claim
  99. # that a 70-argument call works.
  100. #
  101. # RE-BASELINED for the case-label fix, and this is the one re-baseline in this
  102. # file that is a CORRECTION rather than a new feature. EmMovAxSp used to emit
  103. #
  104. # 8B 44 24 00 MOV AX,[SP] <- 386 encoding, SIB byte
  105. #
  106. # which is 4 bytes. [SP] is not encodable on the 8086 at all: mod=00/rm=100
  107. # is [SI], and the SIB byte that 8B 44 needs did not exist until the 386. The
  108. # bytes were well formed, so every byte-level check passed, and fcml and qemu
  109. # both DECODED it - as MOV AX,[SI+0x24h], because that is what it is. Every
  110. # CASE label test therefore loaded a garbage address, every comparison failed,
  111. # and a case statement fell straight past its body. It now emits
  112. #
  113. # 58 50 POP AX ; PUSH AX <- 2 bytes
  114. #
  115. # which is observationally a peek. t22 has two labels, so its code is exactly
  116. # 4 bytes smaller: 96 -> 92. The number moving is the point - the old size was
  117. # the size of a wrong encoding, and a case fixture that is not executed cannot
  118. # tell you that from its size alone. t22 is executed (tests/run_com_exec.py).
  119. #
  120. # ADDED t29_readln: the first fixture that reads. It needs the CHAR class to
  121. # exist at all - see the note on TChar in Compiler.mod - so 7 data bytes where
  122. # t19 has 4 (n is 2, c is 1, and the two are 2-byte aligned, so 4 + 2 + 1
  123. # rounds up to 7) and 82 code bytes for the four runtime calls plus a literal
  124. # char argument. Its .out is compared byte for byte against qemu.
  125. #
  126. # RE-BASELINED for the procedure-skip jump. t13, t27 and t28 gained exactly
  127. # +3 code bytes: `E9 rel16`. These are the only three fixtures that declare a
  128. # PROCEDURE, and they are the only three rows that moved.
  129. #
  130. # The reason is a bug that only execution could find. The declaration part is
  131. # compiled BEFORE the main statement part, so a procedure's code lands between
  132. # the program prologue and the main body - and nothing jumped over it. A
  133. # program with a procedure ran off the end of the prologue straight into the
  134. # first procedure, which read its argument out of an uninitialised frame and
  135. # returned to address 0000h. t13_proc compiled, produced a plausible 53 bytes,
  136. # and was never run, so the suite was green over a program that could not
  137. # execute at all.
  138. #
  139. # The jump is emitted ONLY when a procedure or function is declared, which is
  140. # why the other 27 OK rows did not move. That condition is a lookahead over
  141. # the source buffer, because the jump must be emitted before the declaration
  142. # part but whether one is needed is only known after - see DeclaresProc in
  143. # Compiler.mod for why the alternative (always emit it) was rejected.
  144. #
  145. # t13_proc 53 -> 56
  146. # t27_localvar 122 -> 125
  147. # t28_farparam 123 -> 126
  148. # t31_procparam 66 -> 69
  149. #
  150. # t31_procparam is the fixture that proves the fix by running: it declares a
  151. # procedure, calls it, and prints what the procedure wrote. Before the fix it
  152. # never halted at all.
  153. #
  154. # ADDED t30/t31/t32, all three now EXECUTED (not just compiled):
  155. #
  156. # t30_forloop `for i := 1 to 5 do s := s + i` printed 21, not 15. The loop
  157. # test was emitted AFTER the body, making it a post-test loop:
  158. # the body ran a sixth time with i = 6. The code size and the
  159. # instruction bytes were both already correct - only the ORDER
  160. # was wrong, and no byte-level check can observe an order. The
  161. # test now precedes the body, so 96 bytes both before and after
  162. # this fix, which is the whole point: the number never moved and
  163. # the behaviour did.
  164. # t31_procparam procedure + one parameter. The non-termination above.
  165. # t32_forexit `for` with `exit` in the body. Two faults, both invisible to
  166. # a size check: the loop's exits were patched to the position
  167. # just past the body, which in a FOR is the STEP, so `exit`
  168. # incremented the control variable and jumped back into the test
  169. # - it did not exit; and the EXIT handler also emitted ADD SP,2
  170. # while the loop's `done` label emitted it again, dropping four
  171. # bytes off a stack that had two to give. Exits are now patched
  172. # at `done`, and the handler no longer touches the stack.
  173. # t33_cmpops all six relational operators as VALUES, each with a true case,
  174. # a false case and the equality boundary, plus one signed pair.
  175. # Added while making the 8086 branch/compare lowering checkable:
  176. # measuring which conditions the suite actually emitted showed
  177. # that `=', `<>' and `<=' were never used in a comparison at all,
  178. # because `writeln (a = b)` had no fixture. Only `<', `>' and
  179. # `>=' had coverage - and `>' vs `>=' had ALREADY been swapped
  180. # once (bug 29), so a hole either side of the operators that
  181. # were covered is the last place to leave one. m := -1, n := -2
  182. # makes the last line signed: unsigned, -1 > -2 is FALSE, so that
  183. # one line is what tells SETG from a byte compare.
  184. #
  185. # t36_argclobber eight lines of hand-derived output, added BEFORE the fix it
  186. # covers: this row was written while the compiler still lost a
  187. # computed argument, was proved red by running it, and its
  188. # numbers did not move when the fix landed - the fix reorders
  189. # bytes rather than adding them, so the same size came out of a
  190. # different order. A number that never moved and a behaviour
  191. # that did is the same shape as t30 above.
  192. #
  193. # t37_readbyte added BEFORE the fix it covers, and its .out was derived by
  194. # hand from the layout before the fix was written: `readln (b)'
  195. # of a BYTE went through rdint, which stores a WORD - and the
  196. # second byte of that word is the byte that FOLLOWS the
  197. # variable, which in this fixture is `n'. So `b' came out
  198. # right and `n' was silently rewritten: 1000 appeared as 768
  199. # (low byte zeroed) on line 1 and as 1023 (low byte set to
  200. # FF) on line 2, which is what the pre-fix run printed, and
  201. # what it was required to print before the fix was touched.
  202. # Neither size here moved when the fix landed: rdint and
  203. # rdbyte take the same argument the same way, so the dispatch
  204. # chooses which entry answers without changing how long the
  205. # call is. The WIDTH of the store is asserted by execution
  206. # (run_com_exec.py), not by this row - a size cannot see it.
  207. #
  208. # t38_readbool a boolean READ is refused, not misread. TP3 errors 66
  209. # ("I/O not allowed here", TPSRC8 prderrtp) and its runtime
  210. # has no boolean reader at all - xrdreal, xrdchar, xrdint and
  211. # xrdbyte exist; xrdbool does not. This compiler used to
  212. # accept it and dispatch to rdbool, which stores a WORD into
  213. # the one-byte variable - the same overflow t37 pins for a
  214. # byte, unobserved only because no fixture read a boolean.
  215. # The position is the ')' after b: IoCall has parsed the
  216. # whole argument, and the atom parser's Skip() has run, so the
  217. # parser stands on the delimiter when IoCall dispatches on
  218. # the variable's class.
  219. #
  220. # t39_strvar the first fixture with a STRING VARIABLE, and the first
  221. # declared type bigger than a word that is not an error: `var
  222. # s : string [10]' is 11 bytes - a length byte and ten
  223. # characters, the layout TPSRC8's `string' type gives a
  224. # variable (`INC BX / MOV varsize,BX', so n+1) - and DefVar's
  225. # `size > 2' catch-all (still the answer for an ARRAY at its
  226. # point of use) now exempts TString. Assignment is a literal
  227. # copied byte by byte: TPSRC8 asn2 sends a string through
  228. # estcpl's string arm, `MOV CL,max_len ; CALL strstore', and
  229. # this reproduces its observable result, truncation included.
  230. # writeln(s)/write(s) route to a new runtime entry, wrstr
  231. # (TPSRC4 xwrtstr without its field-width formatting), which
  232. # prints the length byte's worth of characters and nothing for
  233. # an empty string. A global AND a local string are exercised,
  234. # so the absolute and the [BP+off] address paths both have
  235. # coverage, and the .out is compared byte for byte under qemu
  236. # and Exec86. t40_readln and t41_strassign extend the same
  237. # ground: readln(s)/read(s) routes to a new runtime entry,
  238. # rdstr (TPSRC4 xrdstr), which stops at CR/LF/^Z and truncates
  239. # to the destination size, leaving the terminator pending for
  240. # the readln wrapper; and `s := t' for two string variables
  241. # routes to strstore (TPSRC2), pushed as both addresses (the
  242. # literal path above is a compile-time copy of the same
  243. # operation). Still refused: s [i] indexing - ENoLib.
  244. #
  245. # t39's code size moved 215 -> 217 with the local-frame fix
  246. # that t40 forced. Locals used to take the PRE-decrement
  247. # locFree as their base, so a local string started at BP-2 and
  248. # its characters ran UP through BP, the saved BP and the return
  249. # address: `readln(s)' into a local s stored "hello" over its
  250. # own caller's return address and the program jumped into the
  251. # string. Locals are now top-anchored (base placed so the last
  252. # byte lands on the top free byte), which leaves every INTEGER
  253. # local byte-for-byte where it was (-2, -4, ...) but moves a
  254. # string local down: t's base is now BP-6, and two of its byte
  255. # stores that used to wrap to [BP+0]/[BP+1] and fit the disp8
  256. # form are now disp16 - two bytes, hence 217. See t40.
  257. t01_minimal OK 29 4
  258. t02_writeln OK 38 4
  259. t03_inline_comment OK 38 4
  260. t04_var OK 48 6
  261. t05_own_line_comment OK 38 4
  262. t06_two_args OK 52 4
  263. t07_big OK 102 6
  264. t08_const OK 76 7
  265. t09_if OK 195 6
  266. t10_while OK 151 6
  267. t11_for OK 144 6
  268. t12_repeat OK 137 6
  269. t13_proc OK 126 6
  270. t14_types OK 41 15
  271. t15_label OK 90 6
  272. t16_str1 OK 42 4
  273. t17_two_str OK 45 4
  274. t18_writeln_bare OK 32 4
  275. t19_int1 OK 42 4
  276. t20_str3 OK 62 4
  277. t21_mixed OK 62 4
  278. t22_case OK 94 6
  279. t23_str_empty OK 36 4
  280. t24_str_quote OK 41 4
  281. t25_str_as_value ERR 102 48
  282. t26_str_mixed_args OK 58 4
  283. t27_localvar OK 256 6
  284. t28_farparam OK 153 8
  285. t29_readln OK 82 7
  286. t30_forloop OK 97 8
  287. t31_procparam OK 69 6
  288. t32_forexit OK 138 8
  289. t33_cmpops OK 404 12
  290. t34_arith OK 448 8
  291. t35_not OK 224 7
  292. t36_argclobber OK 492 12
  293. t37_readbyte OK 139 7
  294. t38_readbool ERR 66 659
  295. t39_strvar OK 217 15
  296. t40_readln OK 163 15
  297. t41_strassign OK 263 51
  298. # t42_multidecl multi-name declarations in both spellings: `var a, b, c :
  299. # integer', `procedure add3 (x, y, z : integer)' and
  300. # `procedure mix (u, v : integer ; w : integer)' (TP3's
  301. # grammar: names joined by ',', groups by ';'), plus the
  302. # older `p : integer, q : integer' form. data=12 is the four
  303. # 2-byte globals a,b,c,d plus the two @@T temporaries; the
  304. # .out proves each name landed on its own slot.
  305. t42_multidecl OK 304 12
  306. uierror ERR 41 331
  307. # t43_codewindow a program whose code exceeds the 4 KiB window between the
  308. # end of the runtime and the data base (runtime + 1000h). It
  309. # must be REPORTED as TP3 error 98 (memory overflow); before
  310. # Ebyte was bounded by dataBase it overran its own data and
  311. # produced a corrupt image with no diagnostic. Each of the 20
  312. # writeln cases below embeds 240 bytes inline (wrtinl), so the
  313. # overflow lands inside one of them at pos 4978.
  314. t43_codewindow ERR 98 4978
  315. # t44_strindex s[i] read and write on a string, as a CHAR. A STRING is a
  316. # length byte at s[0] then the characters, so s[i] is the one
  317. # byte at off+i; a constant index folds into boff exactly as
  318. # an array's would, and r.cls drops to TChar so LoadAtom,
  319. # Assignment and IoCall all treat it as one byte. Only a
  320. # constant index is accepted (a variable index is ENoLib, as
  321. # it already was for an array). data=16 is the global
  322. # string[10] (11 bytes), the char c (1) and two @@T temps.
  323. # The fix also had to drop ParseAtom's `r.boff := 0` after
  324. # ParseVar, which had been discarding every subscript.
  325. t44_strindex OK 258 16
  326. # t45_strindex_read readln (s[i]) reads one character into position i; the
  327. # reader classifies by arg.cls (TChar for an indexed string)
  328. # and pushes off+boff. data=15 is the global string[10]
  329. # (11 bytes) plus two @@T temps. t45_strindex_read.in feeds
  330. # 'X' then 'Y'.
  331. t45_strindex_read OK 134 15
  332. # t46_strindex_var s[i] with a VARIABLE index, both directions and in both
  333. # registers. ParseSub used to accept a constant only (ENoLib
  334. # otherwise, exactly as for an array), because off+i is a
  335. # run-time value; now it evaluates the index, then puts the
  336. # element's address in DI (LEA DI,[base] / ADD DI,AX), and
  337. # r.kind drops to 5 so LoadAtom reads [DI] and Assignment
  338. # PUSHes DI across its right-hand side. This fixture was red
  339. # (ERR 102) before that. It covers a global string, a LOCAL
  340. # string (the 8D BE disp16 LEA form), a computed index (i+1),
  341. # a subscript as a procedure argument, and `g[i] := h[j]`
  342. # where BOTH sides are indexed - the case that proves the
  343. # destination is saved across the source. data=31 is g and h
  344. # (string[10] = 11 each), i and j (4), c (1), and the two @@T
  345. # temporaries (4).
  346. t46_strindex_var OK 578 31
  347. # t47_strindex_var_read readln (g[i]) with a variable i. The reader needs
  348. # the computed address, not a folded off+boff, so IoCall
  349. # pushes DI (57) instead of LEA AX,[off] in that case.
  350. # data=15 is the global string[8] (9 bytes) plus i (2) and the
  351. # two @@T temporaries (4). t47_strindex_var_read.in feeds
  352. # 'X' into g[3] then 'Y' into g[6].
  353. t47_strindex_var_read OK 188 15
  354. # t48_strcmp string = <> < <= > >=, both operands string
  355. # VARIABLES, i.e. string-vs-string (a string SUBSCRIPT s[i] is
  356. # a CHAR, so s[i] = c would be a scalar compare). Five
  357. # blocks, and each block weights the six operators
  358. # 1,2,4,8,16,32 for =,<>,<,<=,>,>= so the printed sum says
  359. # exactly which ones held: 41 equal, 14 left < right, 50 left
  360. # > right. The weighting is not decoration: with a plain +1
  361. # every unequal pair sums to 3, because exactly two of the
  362. # four ordering tests hold, so 3,3,3,3 was reported while
  363. # every ordering comparison was INVERTED. The last block
  364. # sets b := '' - the empty string - which drives cmpstr's
  365. # min(len)=0 arm. code=1905 is 5*6 branch compares plus the
  366. # 6 value compares of the final writeln; data=24 is a and b
  367. # (string[8] = 9 each), n (2), and the two @@T temporaries (4).
  368. t48_strcmp OK 1905 24
  369. # t49_strcmp_lit the same operators with a string LITERAL in one or
  370. # both positions. A literal has no storage and the image
  371. # carries no initialised data, so PushStrAddr emits it inline
  372. # in the code stream (JMP over <len><chars>, then the LEA that
  373. # is its address); this pins that path. Block 3 has both
  374. # operands literal, including '' on both sides; the last line
  375. # takes the empty literal's relation as a VALUE. data=15 is s
  376. # (string[8] = 9), n (2), and the two @@T temporaries (4).
  377. t49_strcmp_lit OK 1006 15
  378. # t50_strcmp_type s = 'a' where s is a string: a one-character literal
  379. # is a CHAR constant in ISO Modula-2, not a string, so this
  380. # mixes TString with TScalar and ParseCmp rejects it. (''
  381. # does NOT: the zero-length string is a string, which is why
  382. # t49 may compare against it.) Pins the new mixed-operand
  383. # guard; ETypeErr at the comparison.
  384. t50_strcmp_type ERR 56 600
  385. # t51_strcat string concatenation, `a + b', where its result can
  386. # go: a writeln argument, an assignment source, and then an
  387. # operand again. The pairings are var+var, literal+var,
  388. # var+literal, var+char and char+var - every shape a string
  389. # operand admits except two CHARs, which t53 rejects. data=
  390. # 1842 is a,b,c (string[12] = 13 each), ch (1), the seven
  391. # scratches (7*256), the three CHAR operands ('!', and ch in
  392. # a+ch and in ch+a) at 2 bytes each, and the two @@T
  393. # temporaries (4).
  394. t51_strcat OK 537 1842
  395. # t52_strcat_nest nested concatenations - left-associative, so `a+b+'!''
  396. # is two occurrences and two scratches - plus a concatenation
  397. # as a comparison operand and a string ELEMENT as the left
  398. # operand of `+'. data=1574 is a,b (13 each), the six
  399. # scratches (6*256), the four CHAR operands ('!', '<', '>',
  400. # a[2]) at 2 bytes each, and the two @@T temporaries (4).
  401. t52_strcat_nest OK 501 1574
  402. # t53_strcat_type `'a' + 'b'': two CHARs under `+' is a type error. A
  403. # CHAR is a string operand, so `'a' + b' concatenates; BOTH
  404. # operands being CHARs, with no STRING on either side, is the
  405. # rejection. This is the one shape the BinOpEmit hook used
  406. # to miss - it tested for a STRING operand only, so two CHARs
  407. # fell through to integer addition and silently produced
  408. # CHR(195). ETypeErr at the `+' (pos is where the token
  409. # after the right operand starts, as t50's is).
  410. t53_strcat_type ERR 56 663
  411. # t54_strcat_strnum s + 1: a STRING operand makes `+' concatenation,
  412. # and both operands must then be strings or CHARs; a number
  413. # is neither. ETypeErr at the `+'.
  414. t54_strcat_strnum ERR 56 463
  415. # t55_strcat_overflow 128 characters read into a `string' and then
  416. # `s := s + s' asks for 256, past the 255 the scratch can
  417. # hold: TP3's xconcat raises "string too long" (error 16),
  418. # and the runtime leaves through INT 21h AH=4Ch with AL=16.
  419. # The program therefore exits 16 - pinned by
  420. # t55_strcat_overflow.exit, which is what turns "it stopped"
  421. # into "it overflowed". The .out stops at `read', before the
  422. # `after' a truncating implementation would have printed.
  423. # data=516 is s (the default string = 256), one scratch
  424. # (256), and the two @@T temporaries (4).
  425. t55_strcat_overflow OK 126 516
  426. # t56_include {$I t56_include.inc} - the include is expanded
  427. # before parsing (ExpandIncludes), so FromInclude, which
  428. # exists only in the .inc, is a real symbol here. The .inc
  429. # also carries a star-paren comment holding the text {$I} on
  430. # purpose: the scanner has to read that as comment text, not
  431. # as a directive, or the program breaks. code=56 data=4 (the
  432. # two @@T temporaries); the .out is `7', which is the
  433. # INCLUDED procedure actually running, so this is not just
  434. # "the name resolved".
  435. t56_include OK 56 4
  436. # t57_include_missing {$I t57_this_file_does_not_exist.inc}: an include
  437. # that cannot be opened is TP3 error 90 ("File not found",
  438. # TPSRC10 cdincl errb) AT THE DIRECTIVE - not a silent
  439. # swallow, which is exactly the bug this stage closes.
  440. t57_include_missing ERR 90 29
  441. # t58_include_nest t58_include_a.inc contains a second {$I}. TP3
  442. # permits only one level of include (error 96, "Illegal
  443. # nesting of include files", TPSRC10 cdincl), so the nested
  444. # directive is refused rather than expanded. The position is
  445. # inside the spliced text, i.e. in expanded-buffer
  446. # coordinates.
  447. t58_include_nest ERR 96 43
  448. # t59_typedconst `FXMax : Char = 'G'' - CALC.PAS:111, the first CALC
  449. # rung. Scalar typed constants fold to an immediate but
  450. # carry the DECLARED class, so `write (FXMax)' uses the char
  451. # writer and prints G; a plain `X = 'G'' is TScalar and would
  452. # print 71. Integer and Boolean take the same path; Boolean
  453. # also needs RdConst to read TRUE/FALSE, which it now does.
  454. # A structured typed constant (set/array) is still ENoLib -
  455. # it needs initialised storage this compiler lacks.
  456. t59_typedconst OK 65 4
  457. # t60_charcaret `^M' and `#27' - CALC.PAS:113 is `EofLine = ^M'. Both
  458. # are unquoted CHARACTER constants, so ParseAtom must accept
  459. # them as literals (not only RdConst in a declaration), or
  460. # `write (^M)' would not compile. The .out begins with the raw
  461. # bytes 0D 1B, which is the proof they are characters and not
  462. # the text "13"/"27"; the last two lines check the values
  463. # (EofLine = ^M, Esc = 27).
  464. t60_charcaret OK 75 4
  465. # t61_setconst `Numbers : set of Char = ['0'..'9']' - CALC.PAS:114.
  466. # TP3's HYBRID set layout (coeur-tp-ocr 4.7.2): only the whole
  467. # bytes covering the base range are stored, element e is bit
  468. # (e MOD 8) of byte ((e DIV 8) - (base DIV 8)), high byte
  469. # last. A set cannot fold to a word, so its bytes go in the
  470. # code stream behind a JMP (as string literals do) and the
  471. # name becomes addressable; no `seg cs' is needed because a
  472. # .COM's DS covers the code segment. `in' with a compile-time
  473. # element is answered at COMPILE time (TPSRC2 xsetin: AH > 255
  474. # -> FALSE, else test the bit). The .out is TRUE FALSE TRUE
  475. # TRUE - the constant, an inline literal, and a two-range
  476. # literal. data=4 is the @@T temporaries; the set's 32 bytes
  477. # are in the code stream, not the data area.
  478. t61_setconst OK 183 4
  479. # t62_enum `Attributes = (Constant, Formula, Txt, ...)' -
  480. # CALC.PAS:120. Each enumerator is a constant holding its
  481. # ordinal position; the TYPE is one byte and carries its
  482. # bounds 0..n-1, which sizes `set of Attributes' to ONE byte
  483. # (vs 32 for `set of Char'). A named constant may now be a
  484. # set element (RdConst resolved identifiers), which is what
  485. # `[Constant, Formula]' needs. .out TRUE FALSE TRUE FALSE.
  486. t62_enum OK 187 5
  487. # t63_record `CellRec = record ... end' - CALC.PAS:126. Fields
  488. # are non-compacted and juxtaposed; CellRec is 1 (set of
  489. # Attributes) + 71 (String[70]) + 6 (Real) + 1 + 1 (two
  490. # 0..20 subranges: both bounds in 0..255 -> ONE byte) = 80.
  491. # data=84 = 80 + the two @@T temporaries, so this row pins
  492. # the layout to the byte. Subrange sizing is part of it.
  493. # Field SELECTION is still a loud error (the next increment).
  494. t63_record OK 57 84
  495. # t64_arrays the 2-D array TYPE and an array TYPED CONSTANT -
  496. # CALC.PAS:133 and :137. Ranges are row-major, last fastest,
  497. # both kept in an ArrRec the symbol points at. Sheet is
  498. # 7*21*80 = 11760; XPOS is 7*2 = 14 and, like a set, its
  499. # bytes are CODE-RESIDENT (behind a JMP) because an array
  500. # constant cannot fold - so data=11764 is Sheet + the two
  501. # @@T temporaries, with XPOS in the code stream. Compile
  502. # only: the image is ~16 KB and the exec harness's boot
  503. # sector reads 8 KB (see the layout/execution stage).
  504. t64_arrays OK 67 11764
  505. # t65_array_access array ELEMENT and record FIELD access - the width
  506. # matters. `v[1] := 11' folds (1 - 1) * 2 into the address
  507. # and writes TWO bytes; `v[3] := v[1] + v[2]' reads two and
  508. # writes a third; `r.A := 5' adds the field's offset and takes
  509. # its width. .out is 33 then 12, so a wrong scaling, a wrong
  510. # lower-bound subtraction or a wrong store width all show up.
  511. # data=16 = v (8) + r (4) + the two @@T temporaries.
  512. t65_array_access OK 101 16