Category Archives: Uncategorized

The HP67 emulator and a tiny domain-specific language

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:
calc1.lisp

(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.

A Lisp project: HP67 emulator

When I was in CÉGEP, my parents gave me a calculator as a birthday present.  An HP-67, it is a programmable RPN calculator.  I used it constantly, though it eventually had to retire because I could no longer get replacement battery packs for it, and it couldn’t run off the mains without a working battery pack.  Still, I got about 15 years of use out of it.  I’ve always preferred RPN calculators, and when I use infix calculators I have to be very careful not to lose my partial results.

I also tend to write HP-67 emulators.  I started with a CDA (classic desk accessory) version for my Apple ][GS.  I probably still have the sources on my old Apple ][GS, but it’s boxed up in the basement.  I did, though, find them still on comp.sources.apple2, more than 20 years after I posted them, so I’ve pulled them out and put them into an archive here.  It was compiled with ORCA/C and ORCA/M, the C compiler and assembler commonly used for development on the Apple ][GS.

A few years later, I decided to learn C++, and used the HP-67 emulator as my practice problem.  The resulting program, hp67, is one I still use frequently today.  Its sources and screenshots are available here.  It used to ship with redhat, but I don’t think it’s packaged anymore.

The emulators I wrote are programmable, though it’s now many years since I’ve invoked the programmable mode in hp67.  The programming mode in the HP-67 is mostly a keypress recorder, but with simple flow control.  The mode supports goto, gosub, and conditional operators that skip over the next program step when the condition is not met.  Together, these operations allow the calculator to be programmed to perform more complex, repetitive operations.

Now, I’m going to start doing some development of an hp-67 emulator in Lisp, just to provide some real examples of some of the Lisp features I’ve been describing in these pages.  I’ll probably put the sources on github later, for easier access.

We’ll be making use of handlers, macros, a tiny domain-specific language, and other features.  I’m an engine writer, I don’t like doing user interface stuff, and have little experience with it, so I’ll be writing my code from the engine outward, but with an eye to plugging in different front-ends.  The C++ version of the calculator is an interactive, ncurses-based program, but I may aim for a stream-processing calculator and for a proper GUI version, we’ll see what happens when we get to the front-end.

Cameras in cell phones

My former cell phone was a Palm Centro, reasonable for the time, but with an extremely low resolution camera.  Even though I’ve had my Galaxy S III for two years now, I usually don’t think of the camera as particularly capable, just something that’s on hand.  My usual photos with it have tended on the blurry side.  So, I was surprised when two photos I took of a grasshopper on the garden shed actually turned out as good as I might expect with a “real” camera.20140906_171227

20140906_171238

Maybe I just have to use the camera more carefully, and it’ll prove to be better than I thought it was.

Concluding thoughts on the “less familiar parts of Lisp” series

I’ve now finished my brief walk-through of the functions, macros, and special forms described in the Common Lisp Hyper Spec.  Note that these posts only scratch the surface of the CLHS, there is a lot more useful and informative material there, such as standard class hierarchies (including error type hierarchies), definitions, examples, and collected discussions related to clarification of the standard.

This project was primarily for my own benefit, to better understand those features of the language that I hadn’t run into in my use of Common Lisp.  The language definition is, with a few exceptions for convenience, quite orthogonal.  That is, the standard tends not to define so many functions that you can do a particular thing several different ways.  Given this, knowing that I only recognized perhaps half of the commands in the language indicated that I was missing out on a lot of things that Lisp could do, and this series of posts was intended to allow me to familiarize myself with the other parts of the language.  To that end, I made sure not to skip any entry merely because I wasn’t clear on its definition.  Some experimentation, searching the web, and checking through source code of packages and Lisp implementations allowed me to grasp those functions.

So, for me, this was a useful project, and I’d recommend doing something like it to a newcomer who is trying to get a better grasp of Common Lisp.  As with any language, understanding your tools is immensely important, not just to avoid reinventing features with your own special bugs, but also to help in the layout and planning of your code before you start writing.

There’s one more thing a newcomer to Lisp should do, and that is really get a firm grasp of macros.  We know that C and C++ discourage C-preprocessor macros, for valid reasons, but Lisp macros are a very different species, and once you understand their power, it opens up entire new realms of possibilities.  There are those who claim that a good understanding of Lisp macros even helps when programming in other languages, and perhaps that’s true, at least for some.  I think an understanding of Lisp macros helps the programmer to think of the algorithms themselves in an abstract way, just as algorithms help the programmer think of data in an abstract way, and that that abstraction leads to a more complete understanding of the problem.