reader.sl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % Reader.SL - NMODE Command Reader
  4. %
  5. % Author: Alan Snyder
  6. % Hewlett-Packard/CRC
  7. % Date: 23 August 1982
  8. % Revised: 16 February 1983
  9. %
  10. % 16-Feb-83 Alan Snyder
  11. % Declare -> Declare-Flavor.
  12. % 3-Dec-82 Alan Snyder
  13. % GC calls cleanup-buffers before reclaiming.
  14. % 21-Dec-82 Alan Snyder
  15. % Use generic arithmetic on processor times (overflowed on 9836).
  16. % Add declaration for NMODE-TIMER-OUTPUT-STREAM.
  17. %
  18. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  19. (CompileTime (load objects extended-char fast-int pathnames))
  20. % External variables used here:
  21. (fluid '(nmode-allow-refresh-breakout))
  22. % Global variables defined here:
  23. (fluid '(
  24. nmode-command-argument % Numeric C-U argument (default: 1)
  25. nmode-command-argument-given % T if C-U used for this command
  26. nmode-command-number-given % T if an explicit number given
  27. nmode-previous-command-killed % T if previous command KILLED text
  28. nmode-current-command % Current command (char or list)
  29. nmode-previous-command % Previous command (char or list)
  30. nmode-current-command-function % Function for current command
  31. nmode-previous-command-function% Function for previous command
  32. nmode-autoarg-mode % T => digits start command argument
  33. nmode-temporary-autoarg % T while reading command argument
  34. nmode-command-killed % Commands set this if they KILL text
  35. nmode-command-set-argument % Commands like C-U set this
  36. nmode-reader-exit-flag % Internal flag: causes reader to exit
  37. nmode-gc-check-level % number of free words causing GC
  38. nmode-timing? % T => time command execution
  39. nmode-display-times? % T => display times after each command
  40. nmode-timer-output-stream % optional stream to write times to
  41. % The following variables are set when timing is on:
  42. nmode-timed-step-count % number of reader steps timed
  43. nmode-refresh-time % time used for last refresh
  44. nmode-read-time % time used for last read command
  45. nmode-command-execution-time % time to execute last command
  46. nmode-total-refresh-time % sum of nmode-refresh-time
  47. nmode-total-read-time % sum of nmode-read-time
  48. nmode-total-command-execution-time% sum of nmode-command-execution-time
  49. nmode-gc-start-count % GCKnt when timing starts
  50. nmode-gc-reported-count % GCKnt when last reported
  51. nmode-total-cons-count % total words allocated (except GC)
  52. ))
  53. (setf nmode-timing? NIL)
  54. (setf nmode-display-times? NIL)
  55. (declare-flavor output-stream nmode-timer-output-stream)
  56. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  57. (fluid '(nmode-exit-on-abort))
  58. (de nmode-reader (nmode-exit-on-abort)
  59. % Execute refresh/read/dispatch loop. The loop can terminate in the following
  60. % ways: (1) A command can cause the reader to exit by either calling
  61. % EXIT-NMODE-READER or by throwing 'EXIT-NMODE. In this case, the reader
  62. % terminates and returns NIL. (2) A command can throw 'ABORT. If
  63. % NMODE-EXIT-ON-ABORT is non-NIL, then the reader will terminate and return
  64. % 'ABORT; otherwise, it will ring the bell and continue. (3) A command can
  65. % throw '$BREAK$ or 'RESET; this throw is relayed. Other errors and throws
  66. % within a command are caught, messages are printed, and execution resumes.
  67. (let* ((nmode-reader-exit-flag NIL) % FLUID variable
  68. (nmode-previous-command-killed NIL) % FLUID variable
  69. (nmode-command-killed NIL) % FLUID variable
  70. (nmode-command-argument 1) % FLUID variable
  71. (nmode-command-argument-given NIL) % FLUID variable
  72. (nmode-command-number-given NIL) % FLUID variable
  73. (nmode-current-command NIL) % FLUID variable
  74. (nmode-previous-command NIL) % FLUID variable
  75. (nmode-current-command-function NIL) % FLUID variable
  76. (nmode-previous-command-function NIL) % FLUID variable
  77. (nmode-command-set-argument NIL) % FLUID variable
  78. (nmode-timing? NIL) % FLUID variable
  79. (*MsgP T) % FLUID variable
  80. (*BackTrace T) % FLUID variable
  81. )
  82. (while (not nmode-reader-exit-flag)
  83. (catch-all
  84. #'(lambda (tag result)
  85. (cond
  86. ((eq tag 'abort)
  87. (if nmode-exit-on-abort (exit 'abort) (Ding)))
  88. ((or (eq tag '$Break$) (eq tag 'RESET))
  89. (nmode-select-buffer-channel)
  90. (throw tag NIL))
  91. ((eq tag '$error$) (Ding))
  92. ((eq tag 'exit-nmode) (exit NIL))
  93. (t (Printf "*****Unhandled THROW of %p" tag) (Ding))
  94. ))
  95. (nmode-reader-step)
  96. ))))
  97. (de nmode-reader-step ()
  98. (cond ((not nmode-timing?)
  99. (nmode-refresh)
  100. (nmode-gc-check)
  101. (nmode-read-command)
  102. (nmode-execute-current-command)
  103. )
  104. (t (nmode-timed-reader-step))
  105. ))
  106. (de nmode-read-command ()
  107. % Read one command and set the appropriate global variables.
  108. (when (not nmode-command-set-argument) % starting a new command
  109. (setf nmode-previous-command-killed nmode-command-killed)
  110. (setf nmode-previous-command nmode-current-command)
  111. (setf nmode-previous-command-function nmode-current-command-function)
  112. (setf nmode-command-argument 1)
  113. (setf nmode-command-argument-given NIL)
  114. (setf nmode-command-number-given NIL)
  115. (setf nmode-command-killed NIL)
  116. (setf nmode-temporary-autoarg NIL)
  117. (nmode-set-delayed-prompt "")
  118. )
  119. (setf nmode-current-command (input-command))
  120. (setf nmode-current-command-function
  121. (dispatch-table-lookup nmode-current-command))
  122. )
  123. (de nmode-execute-current-command ()
  124. (setf nmode-command-set-argument NIL)
  125. (if nmode-current-command-function
  126. (apply nmode-current-command-function NIL)
  127. (nmode-undefined-command nmode-current-command)
  128. ))
  129. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  130. % Timing Support
  131. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  132. (de start-timing-command ()
  133. (let ((fn (prompt-for-file-name
  134. "Timing output to file:"
  135. (namestring (make-pathname 'name "timing" 'type "txt"))
  136. )))
  137. (cond ((not (setf nmode-timer-output-stream (attempt-to-open-output fn)))
  138. (write-prompt "Unable to open file.")
  139. (Ding)
  140. )
  141. (t
  142. (reclaim)
  143. (nmode-start-timing))
  144. )))
  145. (de stop-timing-command ()
  146. (cond (nmode-timing?
  147. (nmode-stop-timing)
  148. (if nmode-timer-output-stream (=> nmode-timer-output-stream close))
  149. (setf nmode-timer-output-stream nil)
  150. )))
  151. (de nmode-start-timing ()
  152. (setf nmode-timing? T)
  153. (setf nmode-total-refresh-time 0)
  154. (setf nmode-total-read-time 0)
  155. (setf nmode-total-command-execution-time 0)
  156. (setf nmode-timed-step-count 0)
  157. (setf nmode-gc-start-count GCknt*)
  158. (setf nmode-gc-reported-count nmode-gc-start-count)
  159. (setf nmode-total-cons-count 0)
  160. )
  161. (de nmode-stop-timing ()
  162. (cond (nmode-timing?
  163. (setf nmode-timing? NIL)
  164. (nmode-timing-message
  165. (BldMsg "Total times: Refresh=%d Read=%d Execute=%d Cons=%d #GC=%d"
  166. nmode-total-refresh-time
  167. nmode-total-read-time
  168. nmode-total-command-execution-time
  169. nmode-total-cons-count
  170. (- GCknt* nmode-gc-start-count)
  171. ))
  172. (nmode-timing-message
  173. (BldMsg "Number of reader steps: %d" nmode-timed-step-count))
  174. (if (> nmode-timed-step-count 0)
  175. (nmode-timing-message
  176. (BldMsg "Averages: Refresh=%d Read=%d Execute=%d Cons=%d"
  177. (/ nmode-total-refresh-time nmode-timed-step-count)
  178. (/ nmode-total-read-time nmode-timed-step-count)
  179. (/ nmode-total-command-execution-time nmode-timed-step-count)
  180. (/ nmode-total-cons-count nmode-timed-step-count)
  181. ))))))
  182. (de nmode-timed-reader-step ()
  183. (let ((heapx (GtHeap NIL))
  184. gc-happened
  185. )
  186. (nmode-timed-refresh)
  187. (nmode-gc-check)
  188. (nmode-timed-read-command)
  189. (nmode-timed-execute-current-command)
  190. (setf heapx (- heapx (GtHeap NIL)))
  191. (setf gc-happened (> GCknt* nmode-gc-reported-count))
  192. (setf nmode-gc-reported-count GCknt*)
  193. (cond ((not gc-happened)
  194. (setf nmode-timed-step-count (+ nmode-timed-step-count 1))
  195. (setf nmode-total-refresh-time
  196. (+ nmode-total-refresh-time nmode-refresh-time))
  197. (setf nmode-total-read-time
  198. (+ nmode-total-read-time nmode-read-time))
  199. (setf nmode-total-command-execution-time
  200. (+ nmode-total-command-execution-time
  201. nmode-command-execution-time))
  202. (setf nmode-total-cons-count
  203. (+ nmode-total-cons-count heapx))
  204. ))
  205. (nmode-timing-message
  206. (BldMsg "%w Refresh=%d Read=%d Execute=%d %w"
  207. (string-pad-left (command-name nmode-current-command) 20)
  208. nmode-refresh-time
  209. nmode-read-time
  210. nmode-command-execution-time
  211. (if gc-happened
  212. (BldMsg "#GC=%d" nmode-gc-reported-count)
  213. (BldMsg "Cons=%d" heapx)
  214. )
  215. ))))
  216. (de nmode-timed-refresh ()
  217. (let ((ptime (processor-time)))
  218. (nmode-refresh)
  219. (setf nmode-refresh-time (difference (processor-time) ptime))
  220. ))
  221. (de nmode-timed-read-command ()
  222. (let ((ptime (processor-time)))
  223. (nmode-read-command)
  224. (setf nmode-read-time (difference (processor-time) ptime))
  225. ))
  226. (de nmode-timed-execute-current-command ()
  227. (let ((ptime (processor-time)))
  228. (nmode-execute-current-command)
  229. (setf nmode-command-execution-time (difference (processor-time) ptime))
  230. ))
  231. (de nmode-timing-message (s)
  232. (cond (nmode-display-times? (write-message s))
  233. (nmode-timer-output-stream
  234. (=> nmode-timer-output-stream putl s))
  235. ))
  236. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  237. % Garbage Collection
  238. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  239. (de nmode-gc-check ()
  240. % Check to see if a garbage collection is needed (because we are low on
  241. % space). If so, display a message and invoke the garbage collector. (If a
  242. % garbage collection happens "by itself", no message will be displayed.)
  243. (if (not nmode-gc-check-level) (setf nmode-gc-check-level 1000))
  244. (when (< (GtHeap NIL) nmode-gc-check-level)
  245. (nmode-gc)
  246. ))
  247. (de nmode-gc ()
  248. % Perform garbage collection while displaying a message.
  249. (let ((nmode-allow-refresh-breakout NIL)) % FLUID variable
  250. (write-prompt "Garbage Collecting!")
  251. (cleanup-buffers)
  252. (reclaim)
  253. (write-prompt
  254. (BldMsg "Garbage Collection Done: Free Space = %d words" (GtHeap NIL)))
  255. ))
  256. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  257. % Miscellaneous Functions
  258. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  259. (de exit-nmode-reader ()
  260. % Set flag to cause exit from NMODE reader loop.
  261. (setf nmode-reader-exit-flag T)
  262. )
  263. (de nmode-undefined-command (command)
  264. (nmode-error (BldMsg "Undefined command: %w" (command-name command)))
  265. )
  266. (de nmode-error (s)
  267. (let ((nmode-allow-refresh-breakout NIL)) % FLUID variable
  268. (write-prompt s)
  269. (Ding)
  270. ))
  271. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  272. % Numeric Argument Command Functions:
  273. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  274. (de argument-digit ()
  275. % This procedure must be attached only to extended characters whose base
  276. % characters are digits.
  277. (let* ((command nmode-current-command)
  278. (base-ch (if (FixP command) (X-base command)))
  279. (n (if (and base-ch (digitp base-ch)) (char-digit base-ch)))
  280. )
  281. (if (null n)
  282. (Ding)
  283. (argument-digit-number n)
  284. )))
  285. (de negative-argument ()
  286. (if (not nmode-command-number-given)
  287. % make "C-U -" do the right thing
  288. (cond ((> nmode-command-argument 0) (setf nmode-command-argument 1))
  289. ((< nmode-command-argument 0) (setf nmode-command-argument -1))
  290. ))
  291. (setf nmode-command-argument (- nmode-command-argument))
  292. (setf nmode-command-argument-given T)
  293. (setf nmode-command-set-argument T)
  294. (nmode-set-delayed-prompt
  295. (cond
  296. ((= nmode-command-argument 1) "C-U ")
  297. ((= nmode-command-argument -1) "C-U -")
  298. (t (BldMsg "C-U %d" nmode-command-argument))
  299. )))
  300. (de universal-argument ()
  301. (setf nmode-command-argument (* nmode-command-argument 4))
  302. (setf nmode-command-argument-given T)
  303. (setf nmode-command-set-argument T)
  304. (setf nmode-temporary-autoarg T)
  305. (cond
  306. (nmode-command-number-given
  307. (nmode-set-delayed-prompt (BldMsg "C-U %d" nmode-command-argument))
  308. )
  309. (t (nmode-append-separated-prompt "C-U"))
  310. ))
  311. (de argument-or-insert-command ()
  312. % This command interprets digits and leading hyphens as argument
  313. % prefix characters if NMODE-AUTOARG-MODE or NMODE-TEMPORARY-AUTOARG
  314. % is non-NIL; otherwise, it self-inserts.
  315. (let ((base-ch
  316. (if (FixP nmode-current-command) (X-base nmode-current-command)))
  317. )
  318. (cond
  319. ((and (digitp base-ch) (or nmode-temporary-autoarg nmode-autoarg-mode))
  320. (argument-digit (char-digit base-ch)))
  321. ((and (= base-ch #/-)
  322. (or nmode-temporary-autoarg nmode-autoarg-mode)
  323. (not nmode-command-number-given))
  324. (negative-argument))
  325. (t (insert-self-command))
  326. )))
  327. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  328. % Numeric Argument Support Functions:
  329. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  330. (de argument-digit-number (n)
  331. (cond
  332. (nmode-command-number-given % this is not the first digit
  333. (setf nmode-command-argument
  334. (+ (* nmode-command-argument 10)
  335. (if (>= nmode-command-argument 0) n (- n))))
  336. )
  337. (t % this is the first digit
  338. (if (> nmode-command-argument 0)
  339. (setf nmode-command-argument n)
  340. (setf nmode-command-argument (- n))
  341. )))
  342. (nmode-set-delayed-prompt (BldMsg "C-U %d" nmode-command-argument))
  343. (setf nmode-command-argument-given T)
  344. (setf nmode-command-number-given T)
  345. (setf nmode-command-set-argument T)
  346. )
  347. % Convert from character code to digit.
  348. (de char-digit (c)
  349. (cond ((digitp c) (difference (char-int c) (char-int #/0)))))
  350. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  351. (undeclare-flavor nmode-timer-output-stream)