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:
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 | 1 | 5.3 % | 5 |
++ | 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 in an 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
- Formatted strings use a similar but slightly different syntax, see Example of Gauge Strings.
- Strings should be entered using single quotes, for example: 'abcd'.
- Hexadecimal numbers can be entered using the 0xf or 0xF convention (for example, 0xff or 0xFF00FF00)
- Octal numbers can be entered by using a leading zero. For example, 022 is octal 18. Be careful not to enter leading zeros on decimal numbers.
- Scientific notation can be used: 5E2 represents 5 x 10 squared (500), 5E-2 is 0.005
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
- Simulation variables are not case-sensitive, they can be all upper, all lower or a mix of upper and lower case in your scripts.
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 Panels and Gauges SDK folder. 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 |