RPN is an unusual language in that much of the code you write is
actually the bytecode that is executed by RPN. All RPN bytecode is made
up of typeable ASCII characters (for instance the bytecode for addition
is '+').

All scripts contain structure such as the header, title, and labels,
which is not RPN-Code. The RPN-Code is all the executable code in a
script, and there are two supported modes of writing RPN-Code. These
modes are selected by the script header which should start with either
"RPN.2" or "RPN.4". RPN.3 has been dropped because it is incompatible
with and harder to use than RPN.4. If you need to migrate code from
RPN.3 format to RPN.4 see Migrating from RPN.3

In RPN.2 form, all code your write is bytecode and spaces are
stripped out of your code.

In RPN.4 form, code is broken into words based solely on
whitespace, so "4+2" is one word with a length of 3; while, " 4 + 2 "
is 3 words each with a length of one. These words are then executed as
described below (the first match from the list is used):

Name

Action

Format

1.

local

( -- value ) get local

[a-z|A-Z|0-9|_] not starting with a digit. Like C identifiers.

2.

subroutine

( ? -- ? ) call subroutine

any characters except: "()'[]`{};

3.

=local

( value -- ) set local

=[local
format]

4.

number

( -- value ) push number

123,
2e-4, .3, ...

5.

command

( ? -- ? ) execute command

fixed

6.

bcode

( ? -- ? ) run string as bytecode

any

RPN has a simple trace utility to aid in script debugging. Executing
the code, 'Ut', toggles the trace state. Pressing the Record button
while a function is running will also activate the trace utility and
allow the function to be traced, aborted, or continued. The stack gauge
(between the stack and function display) is updated periodically while
functions are running.

When an illegal action is taken in RPN-Code the function which is
running aborts, and a message is displayed to the user indicating the
reason for the error.

To edit the currently visible script choose Edit... from the Script
menu (to make the menus visible tap the upper left corner of the screen
or use your device's built-in menu button or key). If the RPN-Code for
the script is available, the editor will be opened and the code loaded.
Scripts installed and migrated from before RPN 3.50 will not have
RPN-Code installed and you will need to paste their source in from its
original source. The edit form and its parts are detailed below:

Script Editor Title

Tap here to access the Edit menu.

Save Button

Save changes to the script.

Cancel Button

Tap here to discard changes without loading the script for use.

Next Placeholder Button (>>)

Move cursor to the next place holder. The tab key or stroke also
does this.

Code Area

The code for the script is edited here.

Token Popup - var

Insert available subroutine and variable names into the script.

Structure Popup - {x}

Insert various programming structures with placeholders for input.

Stack Popup - stack

Insert stack commands into script.

Query Popup - cond

Insert query commands into script.

Arithmatic Popup - arith

Insert basic math commands into script.

Math Popup - math

Insert math commands into script.

Make any changes you wish to the script and then press Save to load
the script into RPN for use. If you wish to create a new script from an
old one, simply change the title in the RPN-Code and a new script will
be created when you press Save, leaving the old script unmodified.

You can use the Export menu item to create an exportable database of
your script. After selecting Export, you will be asked which export
database to place the script into. This allows you to make a package
containing several scripts that are to be distributed together.

Once the export is created and after hotsync, you will find a
database in your backup folder named "Yrpn_MyExportName.pdb". You can
rename this file however you wish provided you leave the ".pdb"
extension.

The best place to distribute your exported scripts is at the
RPN Coweb.

The following tutorial will walk through an example of creating a
script. The steps for inputing the script are as follows:

Start the script editor using the Edit... item in the Script Menu.

Enter the script text (delete the starting text if needed).

Tap the Save button.

Structure of a Script

The structure of a script is explained below using an example script:

0

RPN.4.a

1

[dialog] D'hello world' ;

2

[a]xa; [=a]Xa;

3

"Example"

4

"Hello" dialog ;

5

~

6

"X" a ; \ recall 'a' to tos

7

"_set(X)" =a ;

8

~

9

"_+X" a + ;

10

"abs(X)" a 0<( a neg : a ) ;

0

Script header: RPN.2 or RPN.4 is required for all scripts; '.a' creates
one global variable.

1

Subroutine: just below the script header any number of subroutines can
be defined; each is labeled with a name inside brackets. This
subroutine opens a dialog displaying 'a subroutine'.

2

Subroutines: Define subroutines to access the global variable.

3

Title: the script name which will be displayed in the script popup
menu. The title is the first label in double quotes in the script.

4

Button: buttons are defined from left to right and top to bottom in the
script button area; the code after the label will be executed when the
user taps the button.

5

New line: buttons defined after the ~ will be on the line below
previous buttons in the script area.

6

Button: this button will put the variable 'a' on the stack.

7

Button: this button will set the variable 'a'; the leading underscore
character allows the user to drag values to the button and should be
used for all buttons taking exactly one value off the stack. The
underscore is not displayed as part of the name.

8

New line: start the third line of buttons in the script.

9

Button: this button puts the variable 'a' on the stack and adds.

10

Button: a slightly more complex button script:
if a < 0 then neg(a) else a end

Subroutines are an important part of writing readable code. After the
header of each script you can define a list of subroutines for that
script and then call the subroutines by name in any part of your
RPN-Code.

Each script has 0-255 global variables. The number defined is
determined by the script header. For instance, starting a script with
"RPN.4.c" defines three global variables ('a' to 'c'). These variables
can be accessed from anywhere in the script and are presistent and even
backed-up when you sync your device.

To read the 'b' variable onto the stack, you use the RPN-Code 'xb'.
To write from the stack to the variable, use the RPN-Code: 'Xb'.

To define more than 26 globals you have to use RPN.4 form and define
them in groups of 10 using a capital letter in header. You can access
them using the X@ and x@ bcodes. So RPN.4.C will define 30 variables
(the first 26 can still be accessed with x[a-z]).

When such a conditional is executed a boolean value should be on the
top of the stack. Either the true or the false section of code is
executed but never both. Conditionals can of course be nested, and the
false code section including the ':' is optional. Example (which
negates tos if it is negative and adds 4 otherwise):

dup 0 < (n : 4+)

The other conditional related RPN-Code can be found in the RPN-Code
Reference.

The first five characters of any RPN script must be of the form
RPN.X[.g[(+|-)w]] where X is the RPN-Code version number that the
script requires. Currently the version for new script should always be
'2' or '4'. The variable field of the header indicates the number of
global variables and is discussed in the section on global variables.
The width field of the header, w, indicates how to adjust the width of
the script window. Valid widths are -8 to 8. The width of the window is
adjusted by 10 pixels per increment, so RPN.2.a+5 makes the script area
40 pixels wider than its usual 80 pixels. The variable and width field
are optional. If they both are present the variable field must come
first.

Subroutines are of the following form: [name] code ;
Subroutines named with a single letter can be called by using the
RPN-Code, C. Other subroutines are called by name if using RPN.4.
Subroutines must come after the "RPN.X" and before the first label.

Labels are formed by enclosing text in quotes. The first label is
the title of the script being defined. '"' is not a valid label
character.

Defining a button is done by specifying a label followed by the
button's RPN-Code. All button definitions must end in a semi-colon.

Starting a function label with the '_' character allows values to be
dragged to that button. The '_' character is not displayed and the
function should have the following stack signature: (n --> ?). The ':'
character signals the beginning of the button's help string. The ':'
and following characters are not displayed. When help is turned on the
entire button label (3 lines maximum) is shown in a RPN dialog (use '\'
for a line feed);

The '~' character is used to separate lines of buttons. There can be
up to 4 lines of buttons defined by any script. All lines have the same
height, and all buttons on a row are of the same width. This height and
width is adjusted according to the number of lines and buttons.

The '\' character is used to delimit comments.

The end of a line also ends a comment.

Note: There must be an even number of ' and " characters in every valid
script; otherwise, error checking will reject the script.

Example:

RPN-Code can contain special commands words rather than bytecode.
While making your code longer (usually) these commands make your code
more readable. Unlike bytecodes, all of these commands need to be
delimited by whitespace on both sides.

The following RPN-Code list describes the basic operations which are
most commonly used in scripting RPN. There is a complete list in the
next section for all RPN-Code.
Stack:In the Stack column, the number of items removed from the stack and
the number of items put onto the stack are listed separated by the
»character.

Format

Name

Stack

Notes

0-9

number

0 » 1

push 0-9 onto stack

#'xxx'

literal

0 » 1

convert string to number using base 10 and push
the value onto the stack

;

exit

0 » 0

exit subroutine

V

setVar

1 » 0

set local variable; this variable is unique to
each subroutine (ie. each subroutine has its own value of v

v

getVar

0 » 1

push the subroutine's local variable onto the
stack

+ - * /

basics

2 » 1

add, subtract, multiply, divide; removes two
values from the stack and return result

P

power

2 » 1

returns nos**tos

b

abs

1 » 1

absolute value

n

negate

1 » 1

negate

g1

dup

1 » 2

duplicate tos

d1

drop

1 » 0

remove tos from the stack

r2

swap

2 » 2

swap the top two stack items

h

depth

0 » 1

puts the stack depth on the stack (1 2 3 --> 1 2
3 3)

&| ^ >

boolean operations

2 » 1

logical and bitwise binary operations

!

boolean not

1 » 1

converts true to false, and false to true

=X

equal

2 » 1

returns true if |nos-tos| '=0' does an exact
comparison

(

if

1 » 0

start conditional

:

else

0 » 0

separate conditional code; mark end of code to
execute when true and beginning of code to execute when false; else is
not required

)

endif

0 » 0

close conditional

{

begin

0 » 0

begin loop

}

repeat

0 » 0

repeat loop

B

break

0 » 0

leave current loop

D'text'

dialog

0 » 1

show dialog and report button pressed;
D'Do you like\RPN?|yes|no|maybe|' creates

Unfortunately, with the introduction of RPN.4 form of RPN-Code, the
RPN.3 form had to be dropped. Many of your RPN.3 scripts will work
without modification. Below is the list of changes you will need to
make sure your RPN.3 code can be used in future versions of RPN:

Change the header to be RPN.4 rather than RPN.3.

Wherever you used the old local.make or local.set syntax replace
both =local. Currently .set and .make still work but they will be
removed soon.

RPN.3 allowed you to access globals by single character references.
RPN.4 does not. Simply define a subroutine for each variable: [a]xa;
and that will allow the same code to work, though you might consider
naming your globals something better than a-z.

Subroutines are now searched before locals, this is so that
[=global]Xa; will be found instead of setting a local.

RPN includes special subroutine forms for intercepting and handling
events. When event handlers are called RPN does not enter the user's
input or update the display after the handler is done; the handler
should use 'Ue' and 'Ud' to cause an enter and display action to occur.
Handlers which override the a default behavior (such as a key or button
action) of RPN should use 'Uh', handled, to signal that the event has
been handled. If the handler does not execute 'Uh' then RPN will handle
the event as usual. The handler subroutines have the form {x}ByteCodes;
where x determines the event to handle as follows:

Stack Notation:Each byte code is described in stack notation having the form,
"before --> after." This notation documents the required arguments and
the results of the byte code. All byte codes consume their arguments,
so "x y --> x+y" means x and y are popped off the stack and x+y pushed
on to the stack. The shorthand tos, nos, and flag are used for
TopOfStack, NextOnStack, and boolean values. The table of byte codes
also includes links to further information on some byte codes.

Boolean values [(-1,1)=false, other=true] are produced by
comparison operations and can be combined using logical operators. Only
the whole part of the number is used to determine its logical value, so
the non-inclusive range (-1,1) is false. In general, boolean values
should not be mixed with numerical values and should not be left on the
stack; however, it may be of use to know that the logical operators
(|^)are actually bitwise operators as long as their inputs fit into a
unsigned 32-bit number. Negative numbers can be used as boolean values
but only their absolute value matters; logical operations return
unsigned numbers regardless of input signs. The not code, !, is logical
rather than bitwise. If you find the above information confusing,
please just think of the boolean codes as operating on the special
values returned by comparison (ie. you don't need to think about what
the numerical value of booleans are unless you combine them with
numbers, display them, or use a number as a boolean).

Format

Name

Stack Description

Notes

!

not

flag --> !flag

negate a boolean (logical negation)

&

and

flag1 flag2 --> flag1

AND together two booleans
(limited range bitwise)

|

or

flag1 flag2 --> flag1|flag2

OR together two booleans
(limited range bitwise)

^

xor

flag1 flag2 --> flag1^flag2

XOR together two booleans
(limited range bitwise)

=X

equal

nos tos --> flag

returns true if |nos-tos| use '=@' to
get X from the stack; '=0' does an exact comparison

RPN's control codes allow you to setup conditional and looping
structures. Both can be nested (to greater than 100 levels).

Format

Name

Stack Description

Notes

(

if

flag -->

start conditional

:

else

-->

separate conditional code; mark end of code to
execute when true and beginning of code to execute when false; else is
not required

)

endif

-->

close conditional

{

begin

-->

begin loop

}

repeat

-->

repeat loop

B

break

-->

leave current loop

]

continue

-->

goto the beginning of the current loop

_[x[a-z]|v]

var break

-->

decrement indicated variable (see section on
variables) and break if the variable is negative after decrementing
(note: '_x@' is not valid)

R

restart

-->

restart the current routine

CX

call

-->

call subroutine labeled [x]

;

exit

-->

exit function

.

abort

-->

silently abort the current program

c

choose

tos -->

a switch statement; format: "c(0-:1:2:3:4+)"
where the numbers indicate the code that tos selects; note the last
block is executed by by large inputs and the first block is executed by
inputs less than or equal to zero; the skip command can be used to
implement ranges: "c(0-:1:,:2|3:4+)"

There are two kinds of variables in RPN which are accessed with
low-level RPN-Code.

One local variable is available to all buttons and subroutines. This
variable is private to each routine and is accessed using the codes 'v'
and 'V' (they are volatile hence the naming).

The local variable is always available and should be used before
globals unless the value needs to be persistent. Using it can speed
your code, use less system resources, simplify your global variable
space, and make your code less affected by later changes in RPN.

Global persistent variables are also provided by RPN. Global
variables are stored with your function set and and cannot be accessed
outside your set (but they are global within the set). Globals are
declared in the RPN-Code header. Specifying RPN.3.g, indicates that
this code needs global variables a-g to be created and managed by RPN.
Function sets can be created with no globals by leaving off the global
specifier (ie. RPN.3). These globals are accessed using the 'x' and 'X'
codes (see below). Accessing an undefined variable will abort your
function. When the Functions|Replace menu command is used to overwrite
a set having the same name as the set being installed, the global
variables defined in both sets are copied from the old to the new set.
If you replace a script, global variables are copied over from the
previous installation.

Globals can also be accessed dynamically using 'x@' and 'X@' where an
index to the globals is on the stack. This is a one-based array (ie.
1x@ == xa).

X indicates mode to get; r=radianFlag;
v=rpnVersionNumber; other modes may be defined later

G'xxx'

goto function set

-->

goto (load) the function set named xxx

U[t|d|e|b|o|h|T]

user interface action

see notes

opcode

name

action

t

trace

--> toggle byte code tracing mode

d

display

--> redraw the RPN stack and input
display

e

enter

--> process the user inout line

b

base

tos --> set the base to tos (1<tos>257)

h

handled

--> signal that an event handler
handled the event and RPN should not handle the event

T

Timer

tos --> set the timer event to happen in
tos/100 seconds

z

zero

tos --> the character used to diplay a
given digit is given by c(d)=Z+d when Z!='0' and (d>9 ? 'A':'0')+d
otherwise; RPN digits are case insensitive iff Z='0'=48; this byte code
sets Z (so #'48'Uz is the normal mode)

T[t|m|h|D|M|Y]

time

--> time

get time in ticks, minutes, hours, Days,
Months, or Years

D'text|button1|...'

dialog

--> button

run dialog and report button pressed;
example D'Do you like\RPN?|yes|no|maybe|' illustrates the current
features of dialogs; the |buttons| are optional: D'Hello' is legal; if
you start a button name with \ then it will be the default button which
is selected if the user does something other than choose a button.

?X

require

-->

require X arguments to proceed; use '?@' to get X
from the stack

S

sound

freq durAmp-->

freq in Hz; durAmp=10*duration (in
100ths of a second) + amp[0-8]

KX

Key

-->

simulate the user entering the character, X; if 'K'
starts a function then a user Enter is not processed before running the
function

RPN's stack codes all take a stack index an opcode. Indexes start
at one (zero is not a valid stack index). Using an invalid stack index
aborts the running function. The special opcode '@' (read 'd@' as "drop
at") indicates that the stack index is on the stack. This stack index
is an index to the stack after the index itself is removed from the
stack (ie. d1 == 1d@).

Format

Name

Stack Description

Notes

gX

get

X+1 X...tos --> X+1 X...tos X

copy the Xth stack item
to the top; g1=dup; g2=over

pX

put

X+1 X X-1...tos --> X+1 tos X-1...

put TOS into Xth
slot on the stack; p1=drop; p2=swap drop

dX

drop

X+1 X...tos --> X+1...tos

drop the Xth stack item;
d1=drop

rX

rotate

X+1 X...tos --> X+1...tos X

move Xth to top; r1=nop;
r2=swap; r3=rot

kX

tuck

X+1 X...tos --> X+1 tos X...nos

move top to Xth
position; k1=nop; k2=swap; k3=tuck; tuck is the inverse of rotate
(r3k3==nop if depth>=3)

h

depth

--> depth

puts the stack depth on the stack (1 2 3 -->
1 2 3 3)

Z

store

... --> ...

store the whole stack temporarily (storage
not persistent across relaunches of RPN and shared by all code); does
not change the stack at all

z

recall

... --> previous_stack

recall the last stored state of
the stack (empty stack if nothing was stored)