HP48 GX

Reverse Polish LISP Language

RPL Language overview

RPL (Reverse Polish LISP) is a high-level programming language used in Hewlett-Packard graphing calculators, notably the HP-28, HP-48 series, and others. It’s a powerful language designed for mathematical and engineering computations, featuring a stack-based paradigm and reverse Polish notation (RPN). RPL is divided into two main types: User RPL and System RPL.

User RPL

User RPL is the high-level aspect of RPL, accessible and safe for general users. It operates within a sandboxed environment, protecting the calculator’s operating system from potential harmful operations.

Example of user RPL code

This program is an example in The HP48 Handbook modeling a particle in a chaotic orbit.


%%HP: T(3)A(D)F(.);
@ n a b x y (x,y) (x',y') -->
\<<
  "ORBIT PARAMETERS"
  {
    "ITERATES:" { }
    "A:" "B:" "X:" "Y:"
    "PMIN:" "PMAX:"
  }
  { 2 0 }
  { 0 0 0 0 0 (0,0) (0,0) }
  DUP
  IF INFORM
  THEN
    OBJ\-> DROP
    PICT PURGE
    { #0d #0d } PVIEW
    PMAX PMIN          @ n a b x y
    2 5 PICK 2 * -     @ n a b x y c
    3 PICK SQ DUP      @ n a b x y c x^2 x^2
    3 PICK *           @ n a b x y c x^2 c*x^2
    7 PICK 6 PICK * +  @ n a b x y c x^2 a*x+c*x^2
    SWAP 1 + / 0       @ n a b x y c w z
    \-> a b x y c w z
    <<                @ n
      0 SWAP           @ 0 n
      FOR n
        x
        IF n 10 >
        THEN DUP y R\->C PIXON
        END
        'z' STO
        b y * w +             @ b*y+w
        DUP 'x' STO           @ x
        a OVER * SWAP SQ      @ a*x x^2
        DUP c * SWAP 1 + / +  @ w=a*x+c*x^2/(1+x^2)
        DUP 'w' STO           @ w
        z - 'y' STO           @ y=w-z
      NEXT
    \>>
    { } PVIEW
  END
\>>

System RPL

System RPL is a lower-level language designed for more experienced users who need access to the calculator’s hardware and system-level functions. It’s much faster than User RPL but requires careful use to avoid crashes or other unintended behaviors.

Example of system RPL code

The following System-RPL program clears the key buffer and attention flag, then begins counting until the object ATTN? reports that [ON] has been pressed. The object FLUSHKEYS is used to remove the [ON] keystroke from the key buffer.


::
* Clear protection word, no arguments
  0LASTOWDOB! CK0NOLASTWD
* Turn off clock, clear ABUFF
  ClrDA1IsStat RECLAIMDISP
* Turn off the menu
  TURNMENUOFF
* Initial value of counter
  %0
* Clear the attention flag
  ATTNFLGCLR
* Run until [ON] been pressed
  BEGIN
    ATTN? NOT
  WHILE
    DUP EDITDECOMP$ DISPROW4 ( Decompile and display counter Increment counter )
    %1+                      ( Flush key buffer )
  REPEAT
* Clear attention flag
  FLUSHKEYS ATTNFLGCLR
* Signal display needs to be redrawn
  ClrDAsOK
;

Particularities of RPL

  • Stack-based: RPL uses a stack for operations, where operands are pushed onto the stack, and operations consume these operands from the stack.
  • Reverse Polish Notation: RPL employs RPN, a postfix notation where the operator follows the operands, eliminating the need for parentheses to define the order of operations.
  • Strong Emphasis on User-defined Functions: Users can create their custom functions and programs, extending the language’s capabilities.
  • Two Levels of Programming: RPL provides both User RPL for general users and System RPL for advanced users and developers, offering a range of access and control over the calculator’s functionalities.

Subroutines in RPL

This RPL code snippet demonstrates an advanced technique to implement subroutines, a feature not natively supported in standard RPL programming. It outlines a method for defining and using a subroutine within an RPL program, leveraging the EVAL function for execution.

  1. Initial Value: The code begins by pushing an initial value of 2.5 onto the stack. This value serves as an example input for the subroutine.
  2. Subroutine Definition: A subroutine is defined using RPL's :: ... ; structure. Within this structure, the ' character is used to quote the subroutine, preventing immediate execution and allowing it to be stored on the stack. The subroutine itself, :: LAM x LAM x %* ;, is a lambda function that calculates the square of a given number (x). %* is a placeholder representing multiplication in this pseudo-syntax, emphasizing the operation performed by the subroutine.
  3. Temporary Variables: Temporary variables are declared with { LAM x LAM SQUARE }, which associates the lambda function SQUARE with the operation defined in the subroutine. BIND is then used to bind these definitions to the named variables, making them available for use.
  4. Execution: The code illustrates two approaches to executing the square operation: directly using LAM x LAM x %* for an immediate calculation, and via the subroutine with LAM SQUARE EVAL, which evaluates the previously defined subroutine.
  5. Cleanup: Finally, ABND is used for memory cleanup, ensuring that temporary bindings are removed after the subroutine's execution.

This technique showcases the flexibility of RPL, allowing developers to creatively implement features beyond the language's standard capabilities.


::
* Initial value
2.5
* Put the subroutine on the stack
' :: LAM x LAM x %*  ;
* Define temporary variables
{  LAM x  LAM SQUARE  }
* Initialize temporary variables
BIND
::
"Direct"
LAM x LAM x %*
"Subroutine"
LAM SQUARE EVAL
;
* memory cleanup
ABND
;
              

Entering complex numbers

Entering complex numbers on the HP 48 can often be time consuming due to its unique input method. However, I found a thoughtful routine has been crafted to streamline this process, enhancing the user experience. This RPL (Reverse Polish LISP) subroutine simplifies the entry of complex numbers by allowing users to input the real and imaginary components as separate arguments. The routine checks these inputs to ensure they are valid numbers. If both inputs are valid, it constructs a complex number in the form of '(A,B)', where 'A' is the real part and 'B' is the imaginary part, converting it into a numerical object that can be easily manipulated in subsequent calculations, throwing an error if the input is malformed.


%%HP: T(3)A(D)F(.);
<< -> A B
  << A B A B TYPE
SWAP TYPE SWAP -> A
B T U
    <<
      IF 'T==0' 'U
==0' AND
      THEN '(A,B)'
->NUM
      ELSE
"ERROR 191:
Invalid Object"
MSGBOX
      END
    >>
  >>
>>