t36_argclobber.pas 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. program t36;
  2. { t36 -- every argument of a call keeps its own value.
  3. All three call parsers used to read the whole argument list first and emit
  4. the pushes afterwards:
  5. ParseCallArgs `p (a, b)' as a statement
  6. ParseCall a function call inside an expression
  7. IoCall write/read, one call per argument
  8. A computed argument (kind 2) has already been emitted and lives only in AX,
  9. so once the parser had moved on to the NEXT argument, AX belonged to
  10. whatever that argument computed and the earlier value was gone by the time
  11. the push loop reached it. TPSRC8 cproc/cprlp1 does it the other way round
  12. -- `CALL exprsave', then `CALL epushax', for each argument as it is parsed,
  13. and then a CALL, which is why the original cannot lose one.
  14. So: parse one argument, put it on the stack, parse the next. The callee
  15. follows the same ground truth from the other end (RESUME-TP3.md 3.11, and
  16. the Code Generation Internals stack frame): the LAST declared parameter is
  17. the one at BP+4, because the first declared is pushed first and so ends up
  18. farthest away.
  19. Every line below is derived by hand from the Pascal. The parameters are
  20. u, v, w in declaration order, and a=5, b=3, c=7, x=0 throughout, so each
  21. expected line can be written down without running anything:
  22. p3 (a, b, c) 5 3 7 three plain names: pins the three
  23. slots against either half of the
  24. convention being flipped alone
  25. p2 (x, a + b) 0 8 computed argument LAST
  26. p2 (a + b, x) 8 0 computed argument FIRST: the deferred
  27. push printed `0 0' here
  28. p3 (a+b, x, c*2) 8 0 14 two computed, one named
  29. p2 (add2 (a+b, 4), x) 12 0 a call nested in an argument
  30. b2 (a > b, x > c) TRUE FALSE boolean parameters, both computed
  31. write add2 (c*2, a) 19 a function call parsed by ParseCall
  32. write (b>a, ' ', x+1) FALSE 1 IoCall, two losses at once: deferred
  33. until the whole list had been read,
  34. the first argument was pushed as the
  35. THIRD argument's value (`TRUE') and
  36. the third was pushed after the earlier
  37. arguments' runtime calls had already
  38. had AX (`544' instead of 1)
  39. READ is not here on purpose: it refuses anything but a plain name, a name
  40. emits no code while it is parsed, and there is therefore nothing to lose. }
  41. var
  42. a : integer ;
  43. b : integer ;
  44. c : integer ;
  45. x : integer ;
  46. procedure p2 (u : integer, v : integer) ;
  47. begin
  48. writeln (u, ' ', v)
  49. end ;
  50. procedure p3 (u : integer, v : integer, w : integer) ;
  51. begin
  52. writeln (u, ' ', v, ' ', w)
  53. end ;
  54. procedure b2 (u : boolean, v : boolean) ;
  55. begin
  56. writeln (u, ' ', v)
  57. end ;
  58. function add2 (u : integer, v : integer) : integer ;
  59. begin
  60. add2 := u + v
  61. end ;
  62. begin
  63. a := 5 ;
  64. b := 3 ;
  65. c := 7 ;
  66. x := 0 ;
  67. p3 (a, b, c) ;
  68. p2 (x, a + b) ;
  69. p2 (a + b, x) ;
  70. p3 (a + b, x, c * 2) ;
  71. p2 (add2 (a + b, 4), x) ;
  72. b2 (a > b, x > c) ;
  73. writeln (add2 (c * 2, a)) ;
  74. writeln (b > a, ' ', x + 1)
  75. end.