RPN Scripting


Contents
Related Links

Overview

In addition to the newer LUA Scripting, Prepar3D supports Reverse Polish Notation (RPN) scripting. The evaluation of RPN scripts is done using a stack and reverse polish notation. For example, if you want a gauge to show altitude in thousands of feet, divide the value of INDICATED ALTITUDE by 1000. In RPN this would be:

(A:INDICATD ALTITUDE, feet) 1000 /

To execute an arithmetic operation, put both operands first in the script and then include the symbol of operation (the divide symbol in this case). This is how some programmable calculators performed arithmetic operations in the past.

This convention works the following way: When the script parser comes across a value, it pushes it onto the top of the stack. When the script parser comes across an operator, it pops from the stack the number of operands that the operator works on (usually one or two values).

Whatever value is left on top of the stack at the end of the execution is the result of the calculated expression. The Examples section provides a list of simple and more complex script examples.

The Variable Overview article describes all of the systems that support variable access.


Operators

The operators that are available in RPN are as follows:

Operator Operation Arguments Example Result
Common Operator
+ addition 2 3 5 + 8
- subtraction. If the stack contains A B -, then the calculation is A - B. 2 (L:Value) 90 - The local value minus 90.
/ division. If the stack contains A B /, then the calculation is A / B. 2 5 2 / 2.5
* multiplication 2 pi 2 * 2 pi
% taking modulo 2 5 3 % 2
++ increment 1 4 ++ 5
-- decrement 1 4 -- 3
/-/
neg
negates a number 1 4 /-/ -4
Comparison Operators
== true if equal 2 (L:Value) 0 == if{ A } Operation A is carried out if Value is 0.
!= true if not equal 2 (L:Value) 0 != if{ A } Operation A is carried out if Value is not 0.
> true if greater than 2 (L:Value1) (L:Value2) > if{ A } els{ B } If Value1 is greater than Value2, operation A is carried out, otherwise operation B is carried out.
< true if less 2 (L:Value1) (L:Value2) < if{ A } els{ B } If Value1 is less than Value2, operation A is carried out, otherwise operation B is carried out.
>= true greater than or equal 2 (L:Value1) (L:Value2) >= if{ A } els{ B } If Value1 is greater than or equal to Value2, operation A is carried out, otherwise operation B is carried out.
<= true if less than or equal 2 (L:Value1) (L:Value2) <= if{ A } els{ B } If Value1 is less than or equal to Value2, operation A is carried out, otherwise operation B is carried out.
? The third operand determines whether the first (True) or second (False) is selected. 3 A B True ? This evaluates to A.
Bit Operators
& bitwise AND 2 5 3 & 1
| bitwise OR 2 5 3 | 7
^ bitwise XOR 2 5 3 ^ 6
~ bitwise NOT 1 5 ~ -6
>> shift right operand number of bits 2 5 3 >> 0
<< shift left operand number of bits 2 5 3 << 40
Logical Operators
!, NOT NOT 1 (L:Local) ! (>L:Local) Toggles the variable Local
&&, AND AND 2 (L:Local) 0xFF00 && (>L:Local) The variable Local is ANDed with hex 0xFF00
||, OR OR 2 (L:Local) 07777 OR (>L:Local) The variable Local is ORed with octal 7777.
Numerical Operators
abs Absolute value 1 -5 abs 5
int
flr
Calculates nearest integer number which is less than the source number 1 5.98 flr 5
rng Range; returns True if the third operand lies between values one and two. 3 4 7 6 rng True
cos Cosine (input in radians) 1 pi cos -1
lg Logarithm to base 10 1 10 lg 1
min Minimum 2 5 2 min 2
sin Sine (input in radians) 1 pi sin 0
acos Arc cosine (returns radians) 1 pi acos
ctg cotangent (input in radians) 1 pi ctg
ln Natural logarithm 1 2.718282 ln 1
sqr Square 1 5 sqr 25
asin arc sine 1 pi asin
eps Floating-point relative accuracy 1 1 eps 2^(-52)
log Logarithm of operand one, to the base of operand two. 2 8 2 log 3
pi Pi = 3.14159; puts pi on the stack 0 pi 3.14159
sqrt Square root 1 25 sqrt 5
atg2 arc tangent with two inputs (input in radians) 2
exp Exponent; e to the power of the operand 1 1 exp 2.718282
max Maximum 2 5 2 max 5
pow Power of; the first value to the power of the second 2 2 5 pow 32
tg Tangent (input in radians) 1 pi tg 0
atg arc tangent with one input 1 pi atg
Special Operators
div Divides integers; its result is always an integer 2 5 3 div 1
ceil Calculates nearest integer number which is bigger than the source 1 4.3 ceil 5
near Calculates the nearest integer number, rounding .5 up. 1 4.5 near 5
dnor
d360
rdeg
Normalizes an angle expressed in degrees. The result is a value between 0 and 360. 1 -15 dnor 345
rddg Converts radians to degrees 1 pi rddg 180
dgrd Converts degrees to radians 1 180 dgrd pi
rnor Normalizes an angle expressed in radians, the result of this operation is between 0 and 2 pi 1 5 pi 1.8584
if{ .... } If statement, note there is no space between the if and the { 1 (L:Value) 0 == if{ A } Operation A is carried out if Value is 0.
els{ .... } Else statement, note there is no space between the els and the { 1 (L:Value1) (L:Value2) <= if{ A } els{ B } If Value1 is less than or equal to Value2, operation A is carried out, otherwise operation B is carried out.
quit The quit statement allows expression evaluation to stop completely, and avoid the use of nesting if{ statements. 0 pi quit (L:Value1) (L:Value2) <= if{ A } els{ B } pi. The rest of the script is ignored.
g0...gn Goto label. Execution will jump to the specified label. Labels are set by entering a colon followed by the label number. 0 g4 Execution jump to :4
case Case statement 50 40 30 20 10 5 (L:value) case The "5" indicates there are five case values, which are selected depending on the evaluation of (L:value).
If the evaluation is equal to or greater than 0, but less than 1, the result is 10. If the evaluation is equal to or greater than 1, but less than 2, the result is 20, and so on.
String Operators
lc Converts a string to lowercase 1 'ABcd10' lc 'abcd10'
uc
cap
Converts a string to uppercase 1 'ABcd10' uc 'ABCD10'
chr Converts a number to a symbol 1 65 chr 'A'
ord Converts a symbol to an integer 1 'A' ord 65
scat Concatenates strings 2 'abc' 'red' scat 'abcred'
schr Finds a symbol in a string
scmp Compares strings, case sensitive 2 (M:Event) 'LeftSingle' scmp 0 == if{ A }els{ B } Performs A if the left mouse button has been pressed, otherwise performs B
scmi Compares strings, ignoring case 2 'left' 'Left' scmi 0 == if{ 'yes' } 'yes'
sstr Finds a substring 2 'cd' 'abcde' sstr 2
ssub Extracts a substring 2 'ab' 'abcde' ssub 'cde'
symb Extracts a single character 2 'abc' 1 symb 'b'
Stack Operators
b Backup the stack 0
c Clears the stack 0 stack: 1 2 3 c stack:
d Duplicates the value that is on the top of the stack 1 stack: 5 d stack: 5 5
p Pops and discards the top value on the stack 1 stack: 1 2 3 p stack: 1 2
r Reverses the top and second values on the stack 2 stack: 1 2 3 r stack: 1 3 2
s0, s1, … s49 Stores the top value in an internal register, but does not pop it from the stack. 1 stack: 1 2 3 s0 stack: 1 2 3
s0: 3
l0, l1, … l49 Loads a value from a register to the top of the stack 1 stack: 1 2 3 s0 l0 stack: 1 2 3 3
sp0, sp1, … sp49 Stores the top value and pops it from the stack 1 stack: 1 2 3 sp0 stack: 1 2
sp0: 3


Notes


Examples

The table below gives a range of script examples that can be used for aircraft. See also the examples for the GaugeText object, and a few examples in the Gauge Color Scripts section.

Aircraft Script Examples

# Expression Gauge Description
1 (A:LIGHT NAV, bool) Navigation Lights Returns True (1) if the navigation light switch is on, False (0) otherwise.
2 (A:TRAILING EDGE FLAPS LEFT ANGLE, radians) 1.1 * Flaps Returns the left flaps angle in radians, multiplied by 1.1. Multiplications like this can help reduce rounding errors when making comparisons with integer settings.
3 (A:PARTIAL PANEL ELECTRICAL,enum) ! Electrical gauges The enum for this variable is (0 = OK, 1= fail, 2 = blank), so in this case the result is inverted by the "!" operator to give 1 = OK and 0 = fail.
4 (A:PLANE HEADING DEGREES GYRO, degrees) /-/ dgrd HSI Compass ring Returns the aircraft heading negated and converted to radians.
5 (A:NAV GSI:1,percent) 250 / HSI Glideslope deflection Returns the percentage for the GSI (Glideslope deviation indicator) for Nav1, divided by 250.
6 (P:Units of measure, enum) 2 == if{ (A:RADIO HEIGHT, meters) } els{ (RADIO HEIGHT, feet) } Radio Height (or Radar Altitude)  needle The Units of measure enum is:
0 = English
1 = Metric (with altitude in feet)
2 = Metric (with altitude in meters)
So if this enum value is 2, the If statement is evaluated, otherwise the Els statement is evaluated.
7 (A:PARTIAL PANEL ELECTRICAL,enum)! if{ 25 (A:GENERAL ENG FUEL PRESSURE:1, psi) - } els{ 25.5 } Fuel Pressure If the Partial Panel Electrical is OK (see Example 3 above) then 25 minus the fuel reading for engine 1 is returned, if not the fixed value of 25.5 is returned.
8 (A:FUEL TANK SELECTOR 1, enum) 0 ==
(A:FUEL TANK SELECTOR 1, enum) 3 == or
if{ pi 2 / } els{ 0 }
Right Valve of Fuel Gauge If all the fuel tanks are selected (FUEL TANK SELECTOR enum value is 0) or the right fuel tank is selected (the enum value is 3) then the fuel valve is set at pi/2, otherwise it is set at zero.
9 (A:NAV1 OBS, degrees) d (A:PARTIAL PANEL HEADING, bool) (A:PARTIAL PANEL ELECTRICAL, bool) or 0 ==
if{ (A:PLANE HEADING DEGREES GYRO, degrees) 90 - - } dgrd
GPS element of HSI If the PARTIAL PANEL HEADING is false and the PARTIAL PANEL ELECTIRCAL is false, then this expression returns the NAV1 OBS reading  minus the (PLANE HEADING DEGREES GYRO reading minus 90), converted to radians.
10 (P:Units of measure, enum) 2 ==
if{ (A:INDICATED ALTITUDE, meters) } els{ (A:INDICATED ALTITUDE, feet) } 100000 / 360 * dgrd
Altimeter ten thousand foot needle Divides the altitude by one hundred thousand, then multiplies by 360, and converts the result from degrees to radians.
11 (L:Show Volts 1,bool)
    if{  (A:ELECTRICAL GENALT BUS VOLTAGE:1, volts) 2 *
       } els{
          (A:ELECTRICAL GENALT BUS AMPS:1, amps) }
Amps/Volts  If the local variable Show Volts 1 is true, the bus voltage for engine 1, multiplied by 2, is returned. Otherwise the bus amps for engine 1 is returned.
12 (A:ADF Radial:1,degrees) 360 +
d360 dgrd
ADF The ADF radial value in degrees is added to 360 and then normalized to a value between 0 and 360. It is then converted to radians.

Notes


String Formatting

Certain XML Gauge Elements, such as the GaugeText Objects, and Scenario Objects, such as the On Screen Text, support using scripting to more intricately format the text that is to be displayed. While GaugeText Objects support the full list of options to follow, On Screen Text only supports the text based formatting options.


NOTE: This syntax is NOT the same as generic RPN script syntax and care must be taken not to confuse the two.

Formatting Numbers

The format for numbers is contained within the !...! marks.

The last letter is required and is case-sensitive, is the formatting of the variable, where:

The formatting letter can be preceded by a number, which is the minimum number of digits to display, and is optional. For decimal numbers the following rules apply:

For floating point numbers, the following rule applies:

Examples of Number Formatting


String Result Description
%( 12.34 )%!4.3f! 12.340 The 4 in 4.3 is ignored.
%( 12.34 )%!04.3f! 12.340 Leading "0"s are not added to floating point numbers.
%( 12345.6789 )%!4.3f! 12345.679 The number before decimal point does not limit the number of digits displayed before decimal point.
%( 34.56 )%!+d! +35 Rounding, not truncation, has occurred.
%(234)%!5d!   234 Two leading spaces have been prefixed to the number.
%( 'foo' )%!5s!  foo Two leading spaces have been prefixed to the string
%( 234 )%!3s! 234 The number is output as a string, with a minimum of three digits.

Conditional Formatting

The format of conditions (if, then, else, and case statements) in gauge strings is different from that in other scripts. In gauge strings use the %{if}, %{else}, and %{end} constructs to choose which text to display.  Note that these keywords are case-sensitive and must be typed in lowercase. Also, there must not be a space between the "%" and the "{". An if statement can be used without a corresponding else, in which case nothing is displayed if the result of the condition is false. The syntax for usage is one of the following:

For example: %( 1 )%{if}ON%{else}OFF%{end} would give the output ON. Whereas %( 0 )%{if}The value is true%{else}The value is false%{end} would give the output :The value is false.

In the Example of Gauge Strings below, note also the case and loop statements.

Escape Code Formatting

It is also possible to insert escape code sequences into gauge strings.

Escape code Translation
\{tabs=50R,60C, 244L} Set 3 tab stops; the first is right-aligned, the second is centered, and last is left-aligned.
\{fnt1} Switch to the first alternate font specified as a child of the gauge text element
\{fnt} Return to the default font
\{up} Superscript
\{dn} Subscript
\{md} Normal (neither superscript nor subscript)
\{bo} Bold
\{ul} Underline
\{itl} Italic
\{strk} Strikeout
\{blnk} Blink
\{rev} Reverse background/foreground color for text
\{nr} Normal -- clear all properties previously set.
\{lcl} Line color
\{blc} Background line color
\{clr} Color
\{bck} Background color
\{dplo=X} Put a degrees symbol above the next character after the ?=?
\{dpl=XY} Make X superscript and Y subscript
\{lsp=23} Set line spacing to 23
\{lsp} Set line spacing to default
\{ladj=L} Set horizontal text alignment to left. (use ?C? for center or ?R? for right)
\{line=240} Draw a horizontal line with width 240
\{lmrg=20} Set the left margin to 20
\{rmrg=30} Set the right margin to 30
\{img1} Insert image #1 (a text element can have image children)

Examples


Gauge string Description
Fuel Pressure The text will appear exactly as entered: Fuel Pressure
Fuel Capacity: %((A:FUEL TOTAL CAPACITY))%!1.2f! The fuel capacity of the aircraft will be given as a floating point number accurate to two decimal places, following the initial string, such as:
Fuel Capacity: 80.55
%((A:ENG ON FIRE:1) (A:ENG ON FIRE:2) ! if{ 'Warning: Engine Fire' } ) The text string "Warning: Engine Fire" will appear if either or both of the engines are on fire.
%( 1 )%{if}ON%{else}OFF%{end} The text ON would be rendered. If there is no {else} statement, then no text will be displayed if the condition evaluates to false.
%( 3 )%{case}%{ :0 }AIRPORT%{ :1 }INTERSECTION%{ :2 }NDB%{ :3 }VOR%{ :4 }MARKER%{end} A case statement can be used to select a text string from a group of strings. The case numbers do not have to be sequential. The example would produce the result:
VOR
%((C:Mission:OnScreenTimerValue) 60 / 60 / flr )%!02d!:
%((C:Mission:OnScreenTimerValue) 60 / flr 60 %)%!02d!:
%((C:Mission:OnScreenTimerValue) flr 60 %)%!02d!.
%((C:Mission:OnScreenTimerValue) 10 * flr 10 % )%!01d!
Takes the custom on-screen timer value and displays the time in hours, minutes, seconds and tenths of a second.
The !02d! indicates that the text output should be displayed with two digits (for example, 06). The % signs inside the string refer to the modulus operator, and the colons and period between the statements will appear on the screen as text, for example:
01 : 14: 08 . 2
85 %% To output the percent character, use two percent signs in the script:
85 %
%(10 s2 1 s1)%{loop}%( l1 )%!s! %( l1 ++ s1 l2 <)%{next} This statement sets up two registers s1 and s2, with the numbers 1 and 10, then loops to print out:
1 2 3 4 5 6 7 8 9
Whatever value is on top of the stack when the %(next) statement is reached is evaluated as a boolean to determine if execution of the loop should continue.
\b        Indented Text The parser will strip leading whitespace.  A backspace '\b' can be used to override this behavior if indented text is required.

The Infix2Postfix Tool

The Infix2Postfix tool makes it easier to both understand the logic of existing postfix (often called reverse Polish) notation, and enables the writing of scripts in the more normal infix notation familiar to all programmers. The Infix2Posfix tool is in the following folder:

SDK/Panels Gauges User Interface/Panels

The following screen shots show a conversion from infix to postfix, and vice versa. You can use the Paste button to take infix notation from the clipboard, and the Copy button to copy the postfix notation to the clipboard, so that it can be pasted into a gauge script. Alternatively use the File menu to select an existing XML gauge file, and you can then step through the scripts in the file, and examine the conversion to infix. The syntax for the infix notation is similar to C# or C++, and is available in a text file through an option in the Help menu.

Note

This tool is for educational purposes only, there are some scripts that it will not convert correctly.

Converting from infix to postfix
Converting from postfix to infix