We’re almost done with the back-end that talks to the UI, at least for interactive use. There is one category of keypresses that we haven’t handled yet, the compound keys. These are key sequences such as “STO” “+” “2”. This example takes the value in the X register and adds it to the value in memory register 2, holding the result in register 2. There are similar compound keys for subtraction, multiplication, and division.
Compound keys are defined in calc1.lisp, with a special location record that includes the abbreviation strings of the two keys that must be pressed, in sequence, to invoke the compound key. We want to notice when a compound key sequence has been pressed, and substitute the compound key’s abbreviation in the flow. This is how that is done:
;; Look for compound keys (dolist (k (get-compound-keys)) (let* ((location (key-struct-key-location k)) (ck (location-compound-key location))) (when (and (string= abbrev (first ck)) (string= arg (second ck))) (setf key k) (setf arg (funcall fetch-argument-closure (key-struct-abbrev key))) (unless arg (return-from handle-one-keypress :MISSING-ARGUMENT)) (return))))
One final step before switching to UI coding is the packaging of symbols. We create a package called hp-internals that will hold everything we’ve written so far. Because the functions for this package are defined in multiple .lisp files, I prefer not to use the :export keyword in the defpackage form, but instead have each module that produces exported symbols do the export explicitly with the export function.
Here is the defpackage, in constants.lisp:
(defpackage :HP67-INTERNALS (:use :COMMON-LISP) ) (in-package :HP67-INTERNALS)
Here is a sample export form, in stack.lisp:
(in-package :HP67-INTERNALS) (export '(STACK-REGISTERS STACK-MEMORY STACK-PROGRAM-MEMORY STACK-ERROR-STATE))
Now, to invoke and test the compound keypresses, we would do something like this:
CL-USER> (import '(hp67-internals:handle-one-keypress hp67-internals:get-new-stack-object hp67-internals:get-new-mode-object)) T CL-USER> (let ((stack (get-new-stack-object 4)) (mode (get-new-mode-object)) (arg-fcn #'(lambda (x) (format t "Argument for ~A: " x) (read)))) (handle-one-keypress "8" arg-fcn nil stack mode) (handle-one-keypress "sto -" arg-fcn nil stack mode) stack) Argument for sto-: 2 #S(HP67-INTERNALS::STACK :REGISTERS (8 0 0 0) :REGISTERS-COPY (8 0 0 0) :NUM-REGISTERS 4 :LAST-X 0 :ASSEMBLER #S(HP67-INTERNALS::TOKEN-ASSEMBLER :MANTISSA-SIGN 1 :MANTISSA #<SB-IMPL::STRING-OUTPUT-STREAM {10044FDA53}> :MANTISSA-DIGITS 0 :EXPONENT-SIGN 1 :EXPONENT #(0 0) :EXPONENT-DIGITS 0 :TRANSLATION ((:|0| . "0") (:|1| . "1") (:|2| . "2") (:|3| . "3") (:|4| . "4") (:|5| . "5") (:|6| . "6") (:|7| . "7") (:|8| . "8") (:|9| . "9") (:DOT . ".") (:EEX . "d") (:ENTER . :ENTER) (:CLX . :CLX) (:CHS . :CHS)) :SEEN-DOT NIL :SEEN-EXPT NIL :FINALIZED NIL) :MEMORY (("2" . -8)) :FLAGS (("0") ("1") ("2") ("3")) :PROGRAM-MEMORY NIL :COMPLEX-ALLOWED-P NIL :ERROR-STATE NIL)
This code is available in the git repository under the tag v2014-11-20.