Perlstone (semi-humorously named after Perl due to the comparisons between it and line noise) is a simple scripting language used in CraftBook for controlling programmable logic controllers.
The state of Perlstone is defined by:
- A stack (one per function)
- A 32-cell persistent variable table (shared by all functions)
- A 32-cell temporary variable table (shared by all functions, but reset on each execution)
- A 32-cell local variable table (one per function, created when the function is called)
- A 'shift register' modifying which cell the store and load opcodes access for each variable table.
- Three input registers
A function consists of a string composed of an arbitrary number of opcodes. They may take arguments, and optionally return a single boolean value. A function returns after the last opcode in it is executed, or when an opcode is executed to explicitly cause it to return.
When a function is called, a new local variable table is created, with all cells initialized to 'false', as well as a stack, which is initialized to contain the arguments that the function was called with. These are persistent only for the duration of the function.
All three variable tables are index using the numbers 0-9 as well as the letters a-v. The numbers 0-9 are mapped to the first to tenth cells of the variable table, and the letters a-v are mapped to the eleventh to the 32nd cells of the variable table.
Variable tables are labeled using the characters 'p' for the persistent table, 't' for the temp table, and 'l' for the local table. Uppercase versions of the index characters can also be used. When applicable, the uppercase versions ignore the shift register.
Each variable table has a shift register which acts as a filter to its cell indexes. When a lowercase table indexer is used, the contents of the shift register is added, modulo 32, to the index before accessing/storing a value.
The three input registers are named 'A', 'B', and 'C'. They each contain a single boolean value, and may not be set in Perlstone code, and are instead usually set by the code calling it.
A script consists of up to one hundred functions, separated using the character ':'. They are indexed using the numbers 00 to 99, with the index 0 being the first function, the index 1 being the second, etc.
Functions 0-2 are the entry points for a Perlstone program. Every time a programmable logic controller's state updates, all values in the temporary variable table are set to 'false', then, the input registers are set to the inputs to the PLC. Nonexistent inputs will be set to 'false'. Then, the function 00 is used to generate the output A, the function 01 is used to generate the output B, and the function 02 is used to generate the output C. If no value is returned, or the function does not exist, the PLC will behave as if false was returned instead.
If an error occurs, script execution will halt, and, an error will display on the PLC's sign. The PLC will not preform further updates until it is destroyed and recreated.
|Opcode||Operands||From stack||To stack||Description|
|+||t||Pushes true onto the stack|
|-||f||Pushes false onto the stack|
|A||a||Pushes contents the A input register onto the stack|
|B||b||Pushes contents the B input register onto the stack|
|C||c||Pushes contents the C input register onto the stack|
|Memory manipulation operations|
|>||r||Increments the shift register for table r by 1|
|<||r||Decrements the shift register for table r by 1|
|e||r||Resets the shift register for table r to 0|
|S||r n||v||Pops the top value of the stack, and stores it to slot n in the table r|
|L||r n||v||Pushes the value n in the table r onto the stack|
|d||a||aa||Duplicates the top value of the stack|
|p||a||Pops the top value of the stack, and discards it|
|v||n||v(...)||v(...)v||Copies the value n values down in the stack onto the top|
|x||xy||yx||Swaps the top two values of the stack|
|!||a||r||Pops the top value of the stack, and pushes its inverse|
|^||ab||r||Pops the top two values of the stack, and pushes the XOR of them|
|&||ab||r||Pops the top two values of the stack, and pushes the AND of them|
||||ab||r||Pops the top two values of the stack, and pushes the OR of them|
|=||ab||r||Pops the top two values of the stack, and pushes their equality ( XNOR )|
|.||abcd||ef||r|| Pops the top two values of the stack (e and f), then:
a, b, c, and d are encoded as either the number '0' and '1' for false and true respectively, or the characters '+' and '-' for true and false respectively.
|Flow control functions|
|c||ff n||123...||r?||Pops n values off the stack and calls the function f (referenced by a two-digit number) and pushes the previously popped values onto the called function's stack; pushes the return value (if one exists) of the called function onto the calling function's stack|
|t||ff n||123...||r?||Calls the function defined by f with n arguments as in opcode c; and returns it's result, or lack of a result|
|[c]||v||Pops a value from the stack. if the value is false, do nothing, otherwise, execute the code block c, then, repeat this process.|
|s||Returns from the current function|
|r||v||Pops the top value off the stack, and pushes that value onto the stack of the calling function and returns from the current function|
- Added the >, < and, e opcodes, and the P/R/L modifiers for table affecting opcodes.
- Added the x opcode.
- MC3034 (no reset):
- MC3036 (no reset):
6-bit combination lock
- Input A: Check input (button)
- Input B: Input state (switch)
- Input C: Reset
The combination is 101001.
C[t040s]A![Lp5[ +r]s]Lp0d![c030 +=d[+Sp0-]![t04 0-]-r][t050]:::
Br:------Sp0Sp1 Sp2Sp3Sp4Sp5:Lp 1d![c030-=d[+Sp 1-]![t040-]-r][
t060]:Lp2d![c03 0+=d[+Sp2-]![t0 40-]-r][t070]:L p3d![c030-=d[+S
p3-]![t040-]-r] [t080]:Lp4d![c0 30-=d[+Sp4-]![t 040-]-r][t090]:
Lp5d![c030+=d[+ Sp5+r]![t040-r] ][t040]-r