HP-67   A scientific calculator in Reverse Polish Notation

version 1.0 completed Feb 11, 1997

Copyleft GPL 1997 by Christopher Neufeld


        Distribute freely so long as this file is included.


   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  pow
   +
   /

   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. 



Specifics of the HP-67 emulator


   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      Updates 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      Updates LSTX
   As above, but it subtracts.

*     Multiplication operator.         X  <-  Y * X      Updates LSTX
   As above, but it multiplies.

/     Division operator.               X  <-  Y / X      Updates LSTX

!     Factorial operator.              X  <-  X!         Updates 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      Updates LSTX
   This operator takes no arguments.  It replaces the value in the X
register with its reciprocal. 

chs   Change sign operator             X  <-  -X         Updates LSTX
   This operator takes no arguments. It replaces the value in the X
register with its negative value.

sin   Sine operator                    X  <-  sin(X)     Updates 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)     Updates LSTX
   As above, but for cosine.

tan   Tangent operator                 X  <-  tan(X)     Updates LSTX
   As above, but for tangent.

asin  Inverse sine operator            X  <-  asin(X)    Updates LSTX
   As above, but for inverse sine.

acos  Inverse cosine operator          X  <-  acos(X)    Updates LSTX
   As above, but for inverse cosine.

atan  Inverse tangent operator         X  <-  atan(X)    Updates LSTX
   As above, but for inverse tangent.

sqrt  Square root operator             X  <-  sqrt(X)    Updates 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      Updates LSTX
   This operator takes no arguments.  It replaces the value in the X
register with its square. 

ln    Natural logarithm operator       X  <-  ln(X)      Updates LSTX
   This operator takes no arguments.  It replaces the value in the X
register with its natural logarithm. 

exp   Exponential operator             X  <-  exp(X)     Updates LSTX
   This operator takes no arguments.  It replaces the value in the X
register with e^X. 

log10  Base 10 logarithm operator      X  <-  log(X)     Updates 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       Updates LSTX
   This operator takes no arguments.  It replaces the value in the X
register with 10^X.

y^x   Power operator                   X  <-  Y ^ X      Updates 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)     Updates 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.

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. 

rad   Set radians mode                 THETA  =  radians
   As above, but it sets angles to radians.

grd   Set gradians mode                THETA  =  gradians
   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 register      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
'sto' operator, but rather than replacing the value in that memory
register, it adds the current X value to it.  This operation is
available with indirection.

sto-  Subtract from memory register    <label>  <-  <label> - X
   As above, but it subtracts X from the memory register.

sto*  Multiply into memory register    <label>  <-  <label> * X
   As above, but it multiplies X into the memory register.

sto/  Divide into memory register      <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                    Updates 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                    Updates 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 conversion    X  <-  X * 180/pi Updates 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   Updates 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          Updates 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              Updates 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 format      X  <-  X + Y hms  Updates 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     Updates 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)        Updates 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                         Updates 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                    Updates 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                      Updates 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        Updates 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  Updates 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   Updates 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
'w/data' command was run. It does not erase memory elements which are
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
'run' commands. For single-character labels you can use the shorthand
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)" is 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.

----------


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.

					Christopher Neufeld
					Feb 11, 1997
					neufeld@caliban.physics.utoronto.ca
