Motivation
The R47 does not offer anything like structured programming. Even old-school line-numbered BASIC interpreters offer more in this regard, and it was BASIC more than any other single language that the SP advocates were railing against. How much worse, then, is the R47’s flavor of RPN when it comes to adherence to these principles?
Pretty damn bad in my oh-so-humble opinion, which is why multiple efforts have been made to improve matters. This article will begin with the RPN foundations, laying out the basic situation, then advance until we cover the improvement efforts that touch most directly on the R47.
I cover the related topic of looping in a separate article.
IF-THEN
Arguably, this is the only type of control structure designed into classic RPN at a deep level, and even then, it’s pretty shallow. We call it do-if-true logic, and it affects only whether the immediately following instruction runs:
𝑥>? 0.
XEQ ‘doThing’ # perform the 𝑥>0 thing
⋮ # normal processing
Notice that the “normal processing” occurs both for the `x<=0` case and after doThing calls RTN. We aren’t even talking about a 1970s era BASIC interpreter’s IF…THEN…ELSE construct here. This paucity of power will be the cause of a lot of jumping about, alas.
There are dozens of different types of do-if-true tests in the R47, not merely the 𝑥?0 style exemplified above. For instance, you can set, clear, and test flags to create a finite state machine. There are even combined forms like FS?C to check whether a flag is set, and if so, clear it and run the next instruction. This type of thing is a direct reflection of RPN’s simple nature; without C-like logical operation chaining, everything a do-if-true test does must complete in a single operation.
IF-ELSE
But what if we did need an “or else” clause? Could we add one, with sufficient effort? Yes:
ℂ? # is there a complex number in X?
GTO 00 # yes; go handle the ℂ-valued case
⋮ # no; do ℝ-valued steps
RTN # finish by returning early
LBL 00
⋮ # do ℂ-valued steps
RTN # second conditional exit from subroutine, ewww…
A fair C translation of this is:
if (is_complex(X)) {
goto do_cpx; // yes; go handle the ℂ-valued case
}
else {
⋮ // no; do ℝ-valued steps
return; // finish by returning early
}
do_cpx: // do ℂ-valued steps
⋮
return; // second conditional exit
The evils of GTO aside, this is awkward to read and requires use of a cryptic local label to avoid polluting the global label namespace with a purely interior jump target. And, it’s only this easy for single if/else pairs in the subroutine; the more conditions you require, the more easily matters go from complicated to outright hairy.
Skip Instructions
Surely there is a better way?
Yes, there is, in the R47:
ℂ?
XEQ.SKP 00 # ℂ-condition handler
XEQ 01 # ℝ-condition handler
The indented do-if-true instruction executes local subroutine 00, and then on RTN skips past the next instruction, which allows a different jump instruction to immediately follow. Both branches of execution come back together after the XEQ 01 call.
The R47 also provides the RTN.SKP instruction, which allows this variation on the above construct:
ℂ?
XEQ 00 # jump to ℂ-condition handler
XEQ 01 # jump to ℝ-condition handler
LBL 00 # ℂ-condition handler
⋮ # do complex things
RTN.SKIP # return _past_ the XEQ 01 call!
Yes, this means the callee gets to decide the control flow of the caller! It is useful for writing your own do-if-true test subroutines:
LBL ‘NoMod35’ ; DIY do-if-true op; true if !(X%3 || X%5)
LocR 01
STO R.00
3 MOD
𝑥=? 0.
RTN.SKP ; X%3 == 0, so skip caller's next step
RCL R.00
5 MOD
𝑥=? 0.
RTN.SKP ; ditto for 5
RTN ; neither, so return normally
LBL ‘PEP001’
0 STO ‘a’
999 STO ‘c’
LBL 00 ; interior 999 down-to 1 loop
RCL ‘c’
XEQ ‘NoMod35’
GTO 01 ; executes as if in do-if-true context
RCL ‘c’ ; GTO skipped, so add c to the accumulator
STO+ ‘a’
LBL 01 ; end-of-loop handling for both cases
DSZ ‘c’
GTO 00
VIEW ‘a’ ; c-1 == 0, so display accumulated result
RTN
This is a more R47-ish solution than the straightforward port presented in Project Euler Problem #1.
One final “skip” instruction of this type is offered by the R47, RCL.SKP, the application of which I will leave as an exercise for the reader. 🧑🎓
A simpler and more direct form is SKIP/BACK, which jump forward/backward a given number of program steps. It appears to me that the intent is to extend these at some point in the future to allow indirection through variables and stack registers, but the PEM input does not presently allow it.
SWITCH/CASE
Going beyond that into if/then/else/else-if chains quickly goes beyond hairy and into hirsute. At that point, it is often better to reach for CASE:
LBL ‘CaseOf’
CASE ‘n’
GTO 01
GTO 02
GTO 03
GTO d
GTO c
LBL 01 ‘first case’ RTN
LBL 02 ‘second case’ RTN
LBL 03 ‘third case’ RTN
LBL d ‘default case’ RTN
LBL c ‘CHAOS!’ RTN
RTN
Nothing forces you to make the instructions following CASE to be GTO calls, but that formulation is an historically popular one called a computed goto. The referred-to ‘n’ value tells CASE how many instructions to skip, minus one, so n of 1 executes the GTO 01 call. The subroutine d is marked as the “default” case, but do not let this mislead you into believing this is a C-like switch-default pair, because as we see, what lies beyond the default is chaos.
(Exercise for the reader: what lies beyond chaos?)
A different switch-case like construct available in native R47 code is chains of KEY+GTO/XEQ pairs:
KEY 01 GTO 01 # unshifted first softmenu button pressed
KEY 02 GTO 02 # second (F2) button pressed
⋮
KEY 07 GTO 07 # f-shifted F1 pressed
⋮
KEY 18 GTO 18 # g-shifted F6 pressed
KEY 19 GTO 19 # ⬆︎ pressed
KEY 20 GTO 20 # ⬇︎ pressed
KEY 21 GTO 21 # EXIT pressed
There is no requirement that you match the key codes 01-21 with the GTO/XEQ target. I did that merely to draw a logical parallel, but other labels may well work better for you. The point is that the calculator executes down the chain until it finds a match, then jumps away to the handler.
One does not enter these pairs directly in a program. Instead, use the 🟧 PRGM 🟦 P.FN2 KEYG op to construct them by giving the key code and the jump target. The KEYX op constructs KEY+XEQ pairs instead.
This construct is obviously limited to reacting to keyboard input, and then only to the soft menu keys, optionally shifted, plus a few others.
Getting FORTHy
Neither CASE nor KEY+GTO/XEQ give us the full power of a C switch statement, despite it being early 1970s era tech, preceding all HP handheld programmable calculators.1
For that, the best alternative I can offer is RePIG, which includes an RPL-inspired CASE-THEN statement. The resulting compiled RPN code is quite verbose, utterly unoptimized, but you might find the cost a worthwhile tradeoff in favor of programming expressiveness.
(You may now wish to return to my R47 article index.)
License
This work is © 2026 by Warren Young and is licensed under CC BY-NC-SA 4.0
- ^ To be fair, the minicomputer required to run a C compiler — either the 18-bit PDP-7 or the 16-bit PDP-11 — would not scale down to fit in a handheld battery-powered device until approximately the era of the Psion Series 3.