reMorse consist of four instructions. The dash(-) and dasher(- followed by a space) instructions select the next and previous operation respectively, from a circular list of seven operations. Dot(.) and dotty(. followed by a space) do the operation and the opposite of the operation which is being selected, respectively.
reMorse2, reMorse2.-, and reMorse4ever are the dialects of reMorse, among which only reMorse2.- is claimed as Turing-complete.
This overview will cover the reMorse2.- dialect, but the term "reMorse" will be used throughout.
The original language spec is somewhat unclear, and this explanation may contain mistakes and mis-interpretations.
The reMorse2.- syntax is essentially binary, but uses the morse-code-like "." (dot) and "-" (dash) as its digits. Dots and dashes are paired, and thus the language has four instructions: "..", ".-", "-." and "--". All non-dot/non-dash characters are ignored, so whitespace and comments (without dots or dashes) may be embedded in the code. (The original reMorse syntax described in the preview is a tad more complex than the reMorse descendants in its parsing rules.) Instructions are executed in sequence unless a jump occurs.
reMorse has 256 1-byte registers ordered in a circular list. Each register is initialized with the 0-index value of its place in the list. Thus Register 0 is initialized with 00, Register 1 is initialized with 01, and so on. The "register pointer" keeps track of the "current register" and initially starts on Register 1 (NOT Register 0).
reMorse has an unbounded stack for 1-byte values. In practice, the stack is more like a list, because the "stack pointer" is not necessarily at the top of the stack. The stack pointer points between values, and so may or may not have a value below or above it. A push or pop only affects the values below the stack pointer. The "stack byte" (if there is one) is the byte on the stack just below the stack pointer.
There are 9 operation/counter-operation pairs that may be performed in reMorse(2.-). They are ordered in a circular list. There is also an "operation pointer" which points to the current "operation pair". The instructions "--" and "-." increment/decrement the operation pointer respectively. The instructions ".." and ".-" perform the current operation/counter-operation respectively. The operation pointer starts on operation pair 1.
The operations are as follows:
- Push the byte at the current register onto the stack. Leave the register unchanged.
- Output the stack byte to STDOUT as an ASCII char. Leave the stack unchanged.
- Move the stack pointer up 1 ("fake push"). This operation causes an error if the stack pointer is at the top of the stack.
- Bit sort the stack byte in place.
- AND the stack byte with the current register, and replace the stack byte with the result.
- Left ROT the current register in place.
- Add the stack byte and the current register, and replace the stack byte with the result. (Overflows are assumed to wrap around.)
- Increase register pointer by value in current register.
- Skip the next N instructions, where N is the current register. If N is 00, this operation has no effect. If N is greater than the number of remaining instructions, the program terminates.
The respective counter-operations are as follows:
- Pop the stack byte into the current register. This operation causes an error if the stack pointer is at the top of the stack.
- Push a byte from STDIN onto the stack.
- Move the stack pointer down 1 ("fake pop"). This operation causes an error if the stack pointer is at the bottom of the stack.
- Reverse bit sort the stack byte in place.
- NOT the stack byte in place.
- Right ROT the current register in place.
- Subtract the current register from the stack byte, and replace the stack byte with the result. (Underflows are assumed to wrap around.)
- Decrease register pointer by value in current register.
- Go back N instructions, where N is the current register. If N is 00, this operation has no effect. If N is greater than the number of previous instructions, an error occurs. If N is 01, an infinite loop is entered.
After examining the operation set above, it should be obvious that, if the register pointer was initialized to start on Register 0, a program that never asked for input could never do anything!