# HP-67

## NAME

hp67 - a scientific calculator in Reverse Polish Notation

## SYNOPSIS

hp67 [-n|--noexit] [--program=program|-p program] [--ignorercfile|-i] [--help|-h]

## DESCRIPTION

This program emulates an HP-67 calculator with a few minor variations. This calculator uses the 'Reverse Polish Notation' favoured by Hewlett-Packard.

Reverse Polish Notation is somewhat different from the "forward" notation available on many, probably most, handheld calculators. It is the notation used by the Forth system of languages. Here are some examples of how the notation works:

To evaluate: (3 + 4*7) / (2 + 8^3)

You hit the following sequence of keys:

```3  <ENTER>
4  <ENTER>
7  *
+
2  <ENTER>
8  <ENTER>
3  y^x
+
/
```

The <ENTER> key is used to separate different numbers entered consecutively. As numbers are entered they are pushed onto a LIFO stack. The most recently entered number, at the top of the stack, is called the 'X' value, the next most recently entered number is the 'Y' value. On the screen the 'X' appears nearest the bottom, with 'Y' immediately above it. Unary operations such as 'sin' pop a single number (X) off the stack, act on that number, and push the result onto the stack. Binary operations such as '/' pop two numbers off the stack, and divide the first number popped (X) into the second (Y), then push the result onto the stack. This has the effect of reducing by one the total number of elements on the stack. Look over the above example until it's clear. Another register, 'LSTX', is not displayed on the stack. This holds the value which 'X' held before the last operation was made. Not all operations will update this number. LSTX is most commonly used in error correction, such as if you typed '*' instead of '/', and in the implementation of automatic constants.

### OPTIONS

-n, --noexit
Disable the CTRL-D exit key. This behaviour is desirable if the program is run from within a dedicated xterm, such as via the following shell script:
#! /bin/sh #

/usr/X11R6/bin/color_xterm \$@ -ls -tn xterm-color \ -e hp67 --noexit &

This script can then be invoked, for instance, as follows:
hp67.sh -iconic -geometry +700+400
to produce a dedicated xterm window which cannot be aborted, short of sending the program a killing signal.
-p program, --program=program
Load the program space with the named program during. Equivalent to issuing the command r/prog program from the keyboard immediately when the program begins.
-i, --ignorercfile
-h, --help
Issue a usage message and exit.

## Command entry format

Numbers must be entered alone on the line. They may be expressed in fixed or scientific notation. Examples of valid entries on the command line are:

12.493 12.4e-5 .008E4 1.2E+4

Note that it is not normally possible to enter negative numbers directly at the command line prompt (but see the entry for '{' in the section on "magic" keys in curses mode.)

Commands and operations may be entered alone on the command line, or immediately after a valid number, with argument if allowed. The argument must be separated from the command by one or more blanks or tab characters. Examples of valid commands and operations are:

```+
sto speedoflight
dsp 9
fix
```

See the list of operations for details of which commands require operands.

If an operation pops a non-existent stack element, it is not an error, a zero is obtained. Similarly, an attempt to read an uninitialized memory element returns a zero.

## Display layout

The calculator requires at least an 80x22 screen to work, and the layout of buttons is most logical when the number of columns is exactly 80. The upper portion of the screen consists of buttons showing the currently valid commands to the calculator. The right side has a numeric keypad, while the lower-left portion is responsible for interaction with the user. The lower-middle portion shows the most recently accessed memory elements, up to 15 if the number of screen rows is large enough, and the first 8 characters of the element's label (assuming an 80 column screen).

In immediate (interactive) mode, a number of stack elements are displayed in this region, with X at the bottom, Y above it, and higher elements above those.

In program mode, the current insertion and run point is shown with an arrow to its left. Above and below it are neighbouring program elements. New elements are inserted after the position of the arrow, and when the calculator runs, the arrow always shows the next step which will be executed.

A stepping mode also exists. If a program is interrupted with a keypress, or if "step" is entered in immediate mode, then the display shows part of the stack, and part of the program. The program window shows the next step which will be performed, the earlier step in the program memory (not necessarily the last step performed, if that was a branch), and the step after the next one to be performed. Every time "step" is entered, one program step is executed and the insertion/run pointer is updated.

## Curses magic behaviour

When operating in curses mode, hp67 performs some extra actions for certain input sequences.

The '#' is a comment character for almost all functions. The disk I/O functions ignore it, and so can load file names containing the character, but all other operations consider that the argument ends with the last non-whitespace before the '#' character appears. A comment may not be the only content of the input line.

If a line of input begins with a character which identifies it as a number, such as a digit or decimal point, then it continues to accept characters until such time as one shows up which is not part of a valid float. The valid float is passed to the interpreter, while the remaining text waits on the input line. So, if the sequence "102s" is typed, it is as if the number "102", then <ENTER>, then "s" were typed. If the sequence "45e+l" is entered, it is interpreted as "45", <ENTER>, "e+l". Note that there is at present no command which begins "e+l", so this is likely not to appear in normal use. If the sequence "1e4e" is typed, it is interpreted as "1e4" (10000), <ENTER>, "e". This number watching allows one to avoid an extra keypress, it is legal to type "30 ENTER 40 +", the result is seventy.

Note that the following sequence on the command line: "3+4" <ENTER> may not do what you expect. This has the effect of pushing 3 onto the stack, adding it to whatever was on the stack before, then pusing 4 onto the stack.

Now, the input line supports a few special command sequences.

In the following, the notation "M-a" means "meta (lowercase) a". This sequence can be produced by holding down the ALT key on terminals which support this, or prefixing the 'a' keypress with ESC.

The following are 'hot keys'. If they are entered in the first position on a blank input line their functions will be invoked:

<DELETE>
In immediate mode, invokes the "clx" function to delete the top element of the stack. In program mode, deletes the current program line.
M-<SPACE>
In immediate mode, invokes the "step" function.
M-<key>
If <key> is a printable key, in immediate mode this invokes the command "run <key>", running a subroutine identified by the single letter label <key>. In program mode, this invokes the command "label <key>", creating an entry point identified by the single letter label <key>.
<CTRL>-D
In immediate mode, exits the calculator. In program mode, returns to immediate mode.
UP-ARROW
In program mode, moves the program insertion/execution pointer back one space.
DOWN-ARROW
In program mode, moves the program insertion/execution pointer forward one space (without executing the step).
{
As the first element on the line, the '{' character disables (for the current input line) the magic floating-point number parsing described above. This is intended for future expansion, when input types such as complex numbers may use different characters to mark input. It can be used to enter negative numbers at the command line.
CTRL-L
forces curses to redraw the entire window from scratch. Useful if the window is resized, or if some other output to the screen intrudes.

All control keys not listed above are filtered at the keyboard read stage and can never be embedded into labels or commands. The TAB key is immediately translated into a blank at read time.

On terminals which support ncurses mouse events, the function list at the top of the screen, and the keypad on the right side, are both clickable to invoke the corresponding action. Commands which take no arguments are sent with an implied <ENTER> following them, so simply pressing the text of "sin" calculates the sine of the current X value. Commands which take arguments are sent with an implied BLANK following them, allowing the user to enter the argument. Numbers on the keypad, of course, are sent without modification.

## LIST OF COMMANDS

The following commands are available either in programming or in user mode:

+ --'Addition operator X <- Y + X LSTX
This operator takes no arguments. It pops the top two elements of the stack and adds them together, pushing the result on the stack.
- --'Subtraction operator X <- Y - X LSTX
As above, but it subtracts.
* --'Multiplication operator X <- Y * X LSTX
As above, but it multiplies.
/ --'Division operator X <- Y / X LSTX
! --'Factorial operator X <- !X LSTX
This operator takes no arguments. It replaces the value in the X register with the factorial of the number. The factorial is the product of all natural numbers less than or equal to the number. If the value in X is not an integer, it returns the real-number generalization of the factorial, the gamma function of 'X+1'. An error occurs if X is a negative integer, or if an overflow occurs.
recip --'Reciprocal operator X <- 1 / X LSTX
This operator takes no arguments. It replaces the value in the X register with its reciprocal.
chs --'Change sign operator X <- -X LSTX
This operator takes no arguments. It replaces the value in the X register with its negative value.
sin --'Sine operator X <- sin(X) LSTX
This operator takes no arguments. It repalces the value in the X register with its sine, where X is interpreted as an angle in the units of the 'THETA' flag. See below for information on changing this flag.
cos --'Cosine operator X <- cos(X) LSTX
As above, but for cosine.
tan --'Tangent operator X <- tan(X) LSTX
As above, but for tangent.
asin --'Inverse sine operator X <- asin(X) LSTX
As above, but for inverse sine.
acos --'Inverse cosine operator X <- acos(X) LSTX
As above, but for inverse cosine.
atan --'Inverse tangent operator X <- atan(X) LSTX
As above, but for inverse tangent.
sqrt --'Square root operator X <- sqrt(X) LSTX
This operator takes no arguments. It replaces the value in the X register with its square root. This won't work for negative numbers.
square --'Square operator X <- X ^ 2 LSTX
This operator takes no arguments. It replaces the value in the X register with its square.
ln --'Natural logarithm operator X <- ln(X) LSTX
This operator takes no arguments. It replaces the value in the X register with its natural logarithm.
exp --'Exponential operator X <- exp(X) LSTX
This operator takes no arguments. It replaces the value in the X register with e^X.
log10 --'Base 10 logarithm X <- log(X) LSTX
This operator takes no arguments. It replaces the value in the X register with its base 10 logarithm.
exp10 --'Power on 10 operator X <- 10^X LSTX
This operator takes no arguments. It replaces the value in the X register with 10^X.
y^x --'Power operator X <- Y ^ X LSTX
This operator takes no arguments. It replaces the value in the X register with the value Y^X. This returns errors if X is negative and Y is not an integer, or if X is zero and Y is less than or equal to zero.
abs --'Absolute value operator X <- abs(X) LSTX
This operator takes no arguments. It replaces the value in the X register with its absolute value.
dsp --'Set display precision
This operator takes one argument, an integer between 0 and 14 inclusive. In 'fix' and 'sci' modes this sets the number of digits to appear to the right of the decimal point. In 'eng' mode this sets the total number of digits to appear on the screen to 'n+1'. In other words, changing from 'sci' to 'eng' mode does not change the precision of the display. This operator is available with indirection. If the argument is "(i)" it will set the number of digits to the greatest integer value of the I register, if that value lies in the correct range.
fix --'Set fixed display mode
This operator takes no arguments. It sets the display of stack elements to fixed point notation. Numbers which cannot be displayed in this notation in the precision specified by 'dsp' will be displayed instead in scientific notation.
sci --'Set scientific notation display mode
This operator takes no arguments. It sets the display of stack elements to scientific notation. In this form all numbers are written with a single digit preceding the decimal point, and a four digit exponent on the right of the display.
eng --'Set engineering notation display mode
As above, but between one and three digits precede the decimal point, and the exponent is always a multiple of three.
In hexadecimal mode, all numbers are displayed in hexadecimal format, as the next integer closer to zero (i.e. rounding down for positive values, and up for negative values). In hexadecimal mode the magic input completion is disabled, and numbers can be entered as either octal, decimal, or hexadecimal integers. A number beginning with '0x' is interpreted as hexadecimal, otherwise a number beginning with '0' is octal. In all other cases the number is treated as a decimal value.
deg --'Set degrees mode THETA = degrees
This operator takes no arguments. It sets the internal 'THETA' flag to degrees. All subsequent angles are interpreted in units of degrees, and functions which return angles return them in degrees.
As above, but it sets angles to radians.
As above, but it sets angles to gradians. There are 400 gradians in a circle, and if you use this mode even once I'll be surprised.
sto --'Store to memory register <label> <- X
This operator takes a single argument. That argument can be any string which does not contain a '#' and does not begin with a '.'. The current X value will be written into the memory identified by this label. If no such memory register exists, it is created. This operator can also use indirect addressing. If the label is "(i)", the current value of the I register is extracted, converted to an integer, then to a character string, and passed as if it were the argument typed on the command line. So, if I holds the value 214.1, the X register is stored to the memory element labelled "214".
rcl --'Recall from memory reg. X <- <label>
As above, but it recalls from memory and pushes the number obtained onto the stack. The current X value is not lost, it is merely pushed up with the rest of the stack.
sto+ --'Add to memory register <label> <- <label>+X
This operator takes one argument, the memory label. It acts like the register, it adds the current X value to it. This operation is available with indirection.
sto- --'Subtract from memory reg. <label> <- <label>-X
As above, but it subtracts X from the memory register.
sto* --'Multiply into memory reg. <label> <- <label>*X
As above, but it multiplies X into the memory register.
sto/ --'Divide into memory reg. <label> <- <label>/X
As above, but it divides X into the memory register.
x<>y --'Swap X and Y X <--> Y
This operator takes no arguments. It exchanges the X and Y elements on the stack. This is useful, for instance, if you want to evaluate X^Y. You can first swap X and Y, then use the 'pow' operator.
r>p --'Rectangular to polar conversion LSTX
This operator takes no arguments. It converts the pair (X,Y) into polar form.
```               X <- sqrt(X^2 + Y^2)
Y <- atan2(Y,X)
```
p>r --'Polar to rectangular conversion LSTX
This operator takes no arguments. It reads the X register as a distance and the Y register as an angle, and converts to cartesian form. This has the effect:
```                X <- X * cos(Y)
Y <- X * sin(Y)
```
The former Y value is lost.
d>r --'Degrees to radians conv. X <- X * 180/pi LSTX
This operator takes no arguments. It converts the value in the X register from degrees to radians. Note that it does not change the value of the 'angmode' internal flag.
r>d --'Radians to degrees X <- X * 180/pi LSTX
This operator takes no arguments. It converts the value in the X register from an angle in radians to one in degrees. Note that it does not change the value of the internal 'THETA' flag.
pi --'Numerical value of pi X <- pi
This operator takes no arguments. It is shorthand for entering the first 19 decimal places of 'pi'. It pushes 'pi' onto the stack. The X register is not lost, it moves into the Y register, and so on down the stack.
h>hms --'Hours to hours/minutes/seconds conversion LSTX
This operator takes no arguments. It reads the X register as a number of hours, and converts it to hh.mm.ssss form. See the 'hms+' and 'hms>h' operators description for more information.
hms>h --'Convert hours/minutes/seconds to hour LSTX
This operator takes no arguments. It reads the X register as a number in hh.mm.ssss form and converts the result to a fraction of an hour. So, 1.30 would become 1.5, since one hour and thirty minutes is equal to an hour and a half.
hms+ --'Add in hours/min/sec fmt. X <- X + Y hms LSTX
This operator takes no arguments. It adds X and Y as if they were in the form: hh.mmssss. That is, the integer part of the number is taken as hours, the first two digits after the decimal point are taken as minutes, and all digits after that are interpreted as seconds. For instance, 3.182014 would become 3 hours, 18 minutes, 20.14 seconds. After the addition, the result is adjusted so that the seconds and minutes fields do not equal or exceed sixty. For example:
```        1.4020   <ENTER>
1.3052
hms+
```
yields: 3.1112
int --'Integer roundoff X <- (int)X LSTX
This operator takes no arguments. It rounds the number in the X register to the next integer closer to zero.
frac --'Fractional part X <- frac(X) LSTX
This operator takes no arguments. It discards the integer portion of X. If X is negative, it still discards the whole part, so that

frac(-1.2) = -0.2
round --'Round off to displayed value
This operator takes no arguments. It rounds off the value in the X register to the actual value displayed on the screen. If the X register holds 1.2284, and the display mode is 'fixed' and 'dsp 2', then the screen will display the value '+1.23'. The 'rnd' function rounds off the internal representation to match.
rci --'Recall from I register
This operator takes no arguments. It pushes the current I value onto the stack, pushing the rest of the stack down to accomodate it.
sti --'Store in I register I <- X
This operator takes no arguments. It stores the current X value in I. The former value of I is lost, nothing else is changed. Note that this function cannot be replaced by "sto (i)" as that would invoke the indirection behaviour of the "sto" function.
dsz --'Decrement; skip if zero I <- I - 1
This operator takes no arguments. It decrements the I register. If a program is executing, and the I register is zero after the decrement, then the next program step is skipped.
dsz(i) --'Decrement indirect; skip if zero
This operator takes no arguments. It decrements the memory register whose label matches I. If the register is zero after the decrement and a program is executing, the next program step is skipped.
isz --'Increment; skip if zero I <- I + 1
As 'dsz', but it increments the register.
isz(i) --'Increment indirect, skip if zero
As 'dsz(i)', but it decrements the register.
x<>i --'Exchange X and I X <--> I
This operator takes no arguments. It exchanges the current X and I values.
stat+ --'Add statistical data pair LSTX
This operator takes no arguments. It takes the current X and Y values and updates internal registers containing the sum of: X, X^2, Y, Y^2, and X*Y. The X value is replaced by the total number of data pairs collected. This function can also be used if you are only processing X values, rather than X,Y pairs. Just ignore the results from the 'Y' values. This operator updates memory elements accessible to any running program. These are, "_stats_sumx", "_stats_sumx2", "_stats_sumy", "_stats_sumy2", "_stats_sumxy", "_stats_n", and contain the sum of values of X, X squared, Y, Y squared, X * Y, and the number of points, respectively.
stat- --'Subtract statistical data pair LSTX
As above, but it subtracts out the values from the internal registers. This is usually used to remove erroneous data pairs entered with 'sum+'.
avg --'Obtain average X and Y values LSTX
This operator takes no arguments. It replaces the current X and Y values with the average values of X and of Y entered with 'sum+'.
sdev --'Obtain standard deviation of X and Y values LSTX
This operator takes no arguments. It replaces the current X and Y values with the standard deviations of X and of Y entered with 'sum+'.
% --'Percentage operator X <- Y * X/100 LSTX
This operator takes no arguments. It multiplies the top two elements on the stack, and then divides by 100.
%chg --'Percent change operator X <- (X-Y)*100/Y LSTX
This operator takes no arguments. It changes the value in the X register to the percentage of Y by which X differs from Y.
clx --'Clear X value X <- Y
This operator takes no arguments. It pops the stack, discarding the X value and promoting the former Y value to the new X value. Note that this is subtly different from the clear operator on the HP-67, repeated invocations of which do not clear the entire stack.
rdown --'Roll stack down
This operator takes no arguments. It rolls the stack so that the X value goes to the bottom of the stack, and all other registers move up one position, making the former Y value into the new X value. This differs from the HP-67 roll down operator in that it rolls only active stack elements. The HP-67 has a stack size of four, and the X register is always moved into the fourth position, even if fewer than four stack elements were in use.
rup --'Roll stack up
This operator takes no arguments. It rolls the stack so that the bottom stack element moves into the X position, and all other stack elements move one level deeper. This differs from the HP-67 operator in the same way as 'rdown' above.
lastx --'Retrieve LastX register
This operator takes no arguments. It pushes the current contents of LSTX onto the stack.
clstk --'Clear stack space
This operator takes no arguments. It deletes all stack elements.
clreg --'Clear memory registers
This operator takes no arguments. It deletes all memory registers, freeing the memory and returning it to the machine.
goto --'Move the program counter to a position
This operator takes one argument. It moves the program counter to the label or line number represented by the argument. Line numbers are in the form of a decimal point followed immediately by a numeric string. Valid labels cannot begin with a decimal point, so there is no ambiguity. It can be invoked with indirection, in which case it searches for the label which matches the integer value of the I register, for positive I, or steps back exactly N steps for negative I, where N is the value of int(I).
R/S --'Run/stop
This operator takes no arguments. It halts program execution immediately and returns to user mode. The current return stack is not lost, so the program can be stepped through from this point without losing subroutine information. The program will continue after this instruction if 'run' is entered without arguments. Note that a running program hitting a R/S statement is, technically, an error, so the calculator will sound or flash an alert if the terminal supports that.
sf --'Set flag
This operator takes one or two arguments, the first one a label or the indirection operator, and sets a binary flag with that label identifier. If the argument list ends in the string " clr", then this is stripped from the label and the resulting flag is a clear-on-test flag. The clear-on-test status is updated every time that the 'sf' operator is called, so a given flag can be clear-on-test in one part of the program, and explicit-clear-only in another. The program keeps a list of all set flags. This is used to pass information (usually on flow) between different parts of a program. If the flag is already set it has no effect.
cf --'Clear flag
Unsets the flag named by the argument. If the flag was not already set it is not an error.

The following commands are available only in immediate mode:

run --'Run a program
This operator can take one argument, or no arguments. If invoked with no arguments it runs from the current program counter location. If invoked with an argument it runs from that label. If the target label is a single character it can be invoked with the M-<key> hot key.
While a program is running it can be stopped by pressing any key.
prog --'Enter programming mode
This operator takes no arguments. It allows the user to key in programs. hp67 re-enters user mode when 'immed' is entered.
step --'Step through a program
Executes the command under the current insertion pointer, and advances the pointer to the next element.
r/prog --'Load a program from a disk file
This operator takes one argument, the pathname of the text file which contains the program to load. The program loaded is inserted after the current program counter location. Care should be taken that this doesn't insert it into the middle of another program segment, or that one will be trashed efficiently. This function cannot be used inside a program, and one loaded file cannot call another file to load.

Variables and memories can be loaded this way also. When loading the program starts out in programming mode, but if the token 'immed' appears in the file then subsequent lines are interpreted as if they had been issued in immediate mode. They can put numbers on the stack, act on them with operators, store them to memory labels, exactly as if the commands had been typed at the keyboard. A later 'prog' token can switch back to programming mode. The file is parsed until an error or the end of file is encountered. Be careful not to leave a blank line at the end of the file, since a blank line is interpreted as the <<~ENTER~>> command.

w/prog --'Save program elements
This operator takes one argument, the pathname of the text file which should be written with the program instructions. The text is written out, including comments.
w/data --'Save memory elements
This operator takes one argument, the pathname of the text file which will be used to store non-zero memory elements. The format is compatible with the input required 'r/prog' operator, so loading the file with that command restores the memory as it appeared when the present when the file is re-loaded, unless those elements have the same label as the ones being loaded. Note that there is a possibility for unexpected behaviour here, if a program element existed and was exactly zero, then was saved, and re-loaded after the element was assigned a non-zero value, then the new value is not reset to zero. To ensure that the program memory is exactly the same as that which was saved, it is recommended that you invoke 'clreg' before loading the memory.

The following commands are available only in programming mode:

label --'Create a label
This operator takes one argument, a printable ASCII string which does not begin with a period. It is used as the target of branches and M-<key>.
gosub --'Go to a subroutine
This operator takes one argument, a valid label or the indirection notation. It pushes the return address onto an internal stack and continues execution from the label. The 'rtn' statement returns from the subroutine. As with other features of this program, subroutine nesting is limited only by the total memory available.
rtn --'Return from a subroutine
This operator takes no arguments. It pops a return address and continues execution from there. If there are no more entries on the stack it returns to the user mode.
f? --'Check flag
This operator takes one argument. If the flag pointed to by the label is not set then the next program step is skipped. If the flag is a clear-on-test flag, then it is cleared.
x==0 --'Check X=0?
This operator takes no arguments. If the value contained in the X register is not zero then the next program step is skipped.
x==y --'Check X=Y?
As above, but the condition for executing the next program step is that X must equal Y.
x!=0 --'Check X not equal to zero?
See above, you figure it out.
x!=y --'Check X not equal to Y?
See above, you figure it out.
x<0 --'Check X is negative?
See above.
x<=y --'Check X is not greater than Y?
See above.
x>0 --'Check X is positive and non-zero?
See above.
x>y --'Check X is greater than Y?
See above.
clprg --'Clear program space
This operator takes no arguments. It can only be executed from programming mode. It erases all program elements.
immed --'Exit programming mode
This operator takes no arguments. It exits programming mode and enters user mode. <CTRL>-D is a shorthand hot key for this.

## MORE NOTES ON PROGRAMMING HP67 CALCULATOR

This program maintains the concept of a program counter. The program counter marks the place where the next program step will be inserted if you're writing a new program, and marks the place where the next instruction will be executed in user or stepping mode. It is incremented immediately before the current command is executed. If the program hits an 'rtn' statement, then, the program counter is pointing to the statement after the calling 'gosub' when it returns. Typing 'run' without arguments at this point will send the program on from there.

When the user or program issues a 'goto label' command the label is searched forward from the statement after the current program counter, if necessary cycling round at the end and coming back from the first program location, until it either finds the label or returns to its starting point. The latter results in an error. Notice that labels need not be unique, and the 'goto', 'gosub', and 'run' statements will all branch to the first label after the current program counter which matches the search string. A 'goto .linenum' command has no such ambiguity, as all line numbers are necessarily unique.

The return address stack is flushed out when any one of the following occurs:

1)
the user enters 'prog' mode and deletes or adds a step.
2)
the user issues a 'load' command which changes program memory.
3)
the user isses a 'run' or 'step' command with a label. If no label is given the stack is NOT cleared.

If the return stack is cleared a subroutine or two deep into your program you will not be able to resume it and expect it to run to completion. The next 'rtn' statement, instead of returning to the calling gosub, will return to user mode instead.

When writing functions which might be used as subroutines later, take care to choose variable names which are unlikely to collide with those of the caller, for instance by appending to all names a string identifying the function of the module. If I implement name scoping at some future time this won't be so critical. If the function modifies the I register, that value should be saved on entry and restored just prior to exit, so that the calling function's behaviour is not affected.

The R/S command can be used as a breakpoint. Insert it in the program, and execution will halt when it hits that line, then you can step through with the "step" function, or press "run" and the program will continue from the point following the breakpoint. Also, by putting R/S immediately after a decision command like "x>y", "f?", or "x==0" you can make conditional breakpoints.

## MAGIC TO KEEP IN MIND

The memory label "(i)" (without the quotation marks) is special. Any attempt to assign to it or read from it results, instead, in access to the memory element whose label is the string representation of the integer value of the I register. To change or retrieve the value of the I register, the sti or rci functions must be used.

Similarly, the goto label "(i)" and flag "(i)" are special, see above.

The statistical functions update special named memory elements, see the description of "stat+".

Labels cannot begin with a '.'

The '#' character begins a comment.

Flags can be made to clear on test.

## FILES

\$HOME/.hp67rc
This file, if it exists, is read in as a preloaded program file, unless overridden by command line arguments or the HP67PROGRAM environment variable.

## ENVIRONMENT

HP67PROGRAM
This variable, if set, contains the name of the program file to read when the emulator starts up, unless overridden by command line arguments. If this variable is set, and the \$HOME/.hp67rc file exists, then the latter will be read only if the former does not resolve to a readable file.

Version 1.0 completed Feb 11, 1997

Copyleft GPL 1997 by Christopher Neufeld

Distribute freely so long as this file is included.

This program is essentially a re-write of the RPN classic desk accessory for the Apple ][GS which I released in 1993. If anybody out there has actually used the CDA version, please let me know.

## AUTHOR

Christopher Neufeld

## Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
SPECIFICS OF THE HP-67 EMULATOR
Command entry format
Display layout
Curses magic behaviour
LIST OF COMMANDS
MORE NOTES ON PROGRAMMING HP67 CALCULATOR
MAGIC TO KEEP IN MIND
FILES
ENVIRONMENT