The top row of five keys on the calculator are a bit special. When in run mode, and there are no program steps defined, they are single-key shortcuts for other operations that are shifted on other keys. The keys are labelled A through E, and when there is no program defined they invoke the operations 1/x, sqrt(X), Y^X, rolldown, and X<->Y.
As soon as even one program step is defined, or in programming mode, the keys become shortcuts for GOSUB operations. There are 10 possible targets: A through E, and a through e, the lowercase versions being chosen by the yellow F-shift key.
Defining these keys is a pattern that we can handle with a new macro, define-toprow-key. This macro creates three new key definitions: one for the shortcut arithmetic operation, and one for each of the two GOSUB operations.
At this point, we notice that the stack roll-down operation isn’t going to fit into our previous design of allowing implicit assignments to X by the forms in the function, because we can’t have any pops or pushes to the stack around that operation. So, we add a keyword override to disable the implicit X-assignment, and make it part of the form parser.
There are a few changes and bugfixes associated with this latest version, rather than reproducing all the new functions, I’ll just show the new macro. The rest of the file can be seen in the git repository under the tag v2014-10-29.
Here’s the macro, and its invocation:
(defmacro define-toprow-key ((col letter abbreviation doc &key implicit-x (updates-last-x t)) &body arith-forms) `(progn (define-op-key (:location (make-location :row 1 :col ,col :category-1 :ARITHMETIC) :modelist '(:RUN-NO-PROG) :abbreviation ,abbreviation :updates-last-x ,updates-last-x :implicit-x ,implicit-x :documentation ,(format nil "~S (when no program exists)" doc)) ,@arith-forms) (define-op-key (:location (make-location :row 1 :col ,col :category-1 :FLOW-CONTROL) :modelist '(:RUN-WITH-PROG) :abbreviation ,(format nil "GSB-~C" letter) :implicit-x ,implicit-x :updates-last-x nil :documentation ,(format nil "Call program label ~C" letter)) :RETCODE <- '(:GOSUB ,(format nil "~C" letter)) X <- X) (define-op-key (:location (make-location :row 1 :col ,col :category-1 :FLOW-CONTROL) :modelist '(:RUN-WITH-PROG) :abbreviation ,(format nil "GSB-~C" (char-downcase letter)) :implicit-x ,implicit-x :updates-last-x nil :documentation ,(format nil "Call program label ~C" (char-downcase letter))) :RETCODE <- '(:GOSUB ,(format nil "~C" (char-downcase letter))) X <- X))) (define-toprow-key (1 #\A "1/x" "Reciprocal") X <- (/ 1.0d0 X)) (define-toprow-key (2 #\B "sqrt" "Square root") X <- (sqrt (to-double-fp X))) (define-toprow-key (3 #\C "y^x" "Power") X <- (expt Y X)) (define-toprow-key (4 #\D "rolld" "Roll stack down" :implicit-x nil :updates-last-x nil) (roll-stack-down)) (define-toprow-key (5 #\E "x<>y" "Exchange X and Y" :updates-last-x nil) X <- Y Y <- X)