Now, we’ll talk a bit about domain-specific languages. The Lisp language, with its macros and natural ability to parse its own syntax, is well-suited to creating a domain-specific language. This is a novel programming language designed to simplify certain aspects of the problem. It is for the convenience of the programmer, and usually not for the user, so it’s not likely that the aim is to do away entirely with Lisp syntax, it’s to make the Lisp programmer’s job easier and to simplify the reading of the code.
So, this HP67 emulator is going to need to have data structures to represent keys, and associated operations. Let’s consider first some basic mathematical operations, we’re not going to talk about things like memory registers or programming mode.
The HP67 has a four-number stack. The most-recently-added value to the stack is called the X value, and is the value that is usually displayed on the screen of the calculator. Beyond that is the Y register, then two more values that are not usually given a name, but which I will call Z and W. EDIT #1 2014-10-09: In fact, the manual for the HP-67 calculator calls these X, Y, Z, and T. We will use W instead of T because of the practical difficulties of using T in Lisp forms.
Let’s look at the sort of operations we will want to implement. There’s the addition operator, which consumes X and Y and pushes the sum X+Y onto the stack. There’s the sine function, which consumes X and replaces it with its sine, in the appropriate angular units. There’s the rectangular-to-polar function, which consumes X and Y and pushes the angle as Y and the radius as X. A simple notation for this might be:
X <- (+ Y X)
X <- (sin X)
X <- (sqrt (* X X) (* Y Y)) Y <- (atan Y X)
These representations are easily read, and we’d like to make use of them in the definitions of our keys, but we’d also like to allow the possibility that the programmer wants to use a full Lisp form, such as this, for factorials of positive integers:
(let ((n X) (rv X)) (assert (and (integerp X) (> X 0))) (dotimes (i (1- n)) (setf rv (* rv (- n i 1)))) X <- rv)
So, we’re going to write some code that permits these to appear, as written above. While X, Y, Z, W will be considered reserved names for purposes of Lisp forms written in the key operation, anything else will be allowed. Also, for functions that only push a single X value onto the stack, we will allow the programmer to omit the “X <-” construct, so the key’s definition can simply say:
(+ Y X)
if the programmer prefers that. I’ll show how we do that in upcoming posts.