RCEM
Random Code Executation Machine (RCEM) is an esoteric computer language invented in March 2008 by User:Feuermonster. Data is stored on an infinite tape. In addition, there exists a cell (called I-Cell), which can store numbers. Every cell can have one of the following values: 0 (false), 1 (true), or 2 (maybe).
Basics
RCEM is based on the idea of a tape, infinite in size and populated by cells capable of storing ternary digits, also known as trits. Partaking of this threefold nature, the following digits are allowed per cell:
- 0 (false)
- 1 (true)
- 2 (maybe)
The current cell on this tape is referenced by a movable pointer. An additional cell, not physically bound to the tape and named the I-Cell, permits the maintenance of an integer number of arbitrary size and sign. Data can be communicated to and fro between the tape, interpreted as binary in such a context, and the I-Cell.
Instructions
RCEM defines commands to operate on the current cell, the I-Cell, and the communication betwixt these. A command might accept zero, one or two arguments.
| Command | Meaning |
|---|---|
rx |
Moves the pointer x steps to the right.
|
lx |
Moves the pointer x steps to the left.
|
sx |
Sets the current cell to x, where x might be 0, 1, or 2.
|
o_ |
Prints out the value which is stored at the current cell. |
i_ |
Reads a value from the input and stores it in the current cell. |
x_ |
Sets the value of the current cell to a random value which might be 0, 1, or 2. |
^x |
Changes the current cell by XOR-combining it with the cell at cells[current + x].
|
+x |
Changes the current cell by AND-combining it with the cell at cells[current + x].
|
c_ |
Switches the current cell value from 0 to 1 or from 1 to 0. |
++ |
Adds 1 to the current cell. |
-- |
Subtracts 1 from the current cell. |
2x |
If the current cell has the value 2, its value is replaced by x.
|
m+ |
Adds 1 to the I-Cell. |
m- |
Subtracts 1 from the I-Cell. |
mp |
Prints out the I-Cell as a number. |
mo |
Prints out the I-Cell as a character. |
mi |
Reads a value from the input and stores it in the I-Cell. |
m::x::y |
Reads the cells from cells[x] to cells[y] as binary digits, concatenates them, and stores their represented decimal value into the I-Cell. E.g., m::0::8 would read the cells 0 to 8. See the examples below.
|
z::x::y |
Reads the decimal number from the I-Cell, converts it into its binary representation, and stores the bits into the cells cells[x] to cells[y].
|
If the value n of a cell would be >=3, the value will instead be set to n % 3.
Loops
RCEM defines the following loops as control structures. Each variant is discriminated by its own activation condition; however, if the current cell equals 2, every loop will be executed, even if relying upon a certain cell configuration.
| Loop | Condition |
|---|---|
(…) |
The code will be executed if the current cell has the value 0. |
{…} |
The code will be executed if the current cell has the value 1 |
<…> |
The code will be executed if the I-Cell value is not 0. |
/…\ |
The code will be executed if the current cell has the value 2. |
[…] |
The code will be executed if Rnd(2) yields 1, giving a chance of 50%.
|
Examples
s2[r1s2] Infinite loop.
s2o_ This will print 2.
x_[r1x_] Random loop.
x_r9([r1][l2]x_) An other random based loop.
r65s1l65(m+r1)mo This will Print 'A'.
s0r1s1r1s0r1s1l3m::0::3mp This will print '5'.
m+m+m+m+m+z::0::2o_r1o_r1o_ This will print '101'.
x_/x_\o_ Prints out '1' or '0'
<m-> Sets the I-Cell to 0.
Implementations
The following Common Lisp implementation of an interpreter models the infinite tape as a hash table. Each tape cell is represented by an entry in the hash table, the key of which assumes the cell index, associated with the cell value as a ternary digit (trit).
(deftype trit ()
'(integer 0 2))
(defun parse-rcem (code)
"Parses and interprets the RCEM CODE and returns NIL."
(declare (type string code))
(let ((position 0)
(memory (make-hash-table :test #'eql)) ;; Maps: [integer] -> [trit].
(pointer 0)
(i-cell 0))
(declare (type fixnum position) (type hash-table memory) (type integer pointer i-cell))
(flet
((expect-token (token)
(declare (type string token))
(loop
for token-character of-type character across token
for code-character of-type character = (char code position)
do (if (char= token-character code-character)
(incf position)
(error "Invalid character ~s, instead of ~s."
token-character code-character))))
(peek-next-character ()
(the character (char code (1+ position))))
(read-integer ()
(let ((end (or (position-if-not #'digit-char-p code :start position)
(length code))))
(declare (type fixnum end))
(the integer
(prog1
(parse-integer code :start position :end end)
(setf position end)))))
(move-past-section-terminator (initiator terminator)
(declare (type character initiator terminator))
(let ((nesting-level 0))
(declare (type (integer 0 *) nesting-level))
(loop do
(incf position)
(let ((current-character (char code position)))
(declare (type character current-character))
(cond
((char= current-character terminator)
(if (zerop nesting-level)
(loop-finish)
(decf nesting-level)))
((char= current-character initiator)
(incf nesting-level))))))
(the fixnum (incf position)))
(move-to-section-initiator (initiator terminator)
(declare (type character initiator terminator))
(let ((nesting-level 0))
(declare (type (integer 0 *) nesting-level))
(loop do
(decf position)
(let ((current-character (char code position)))
(declare (type character current-character))
(cond
((char= current-character initiator)
(if (zerop nesting-level)
(loop-finish)
(decf nesting-level)))
((char= current-character terminator)
(incf nesting-level))))))
(the fixnum position))
(check-cell-indices (start-cell-index end-cell-index)
(declare (type integer start-cell-index end-cell-index))
(when (> start-cell-index end-cell-index)
(error "Start index ~d > end index ~d." start-cell-index end-cell-index)))
(current-cell ()
(the trit (gethash pointer memory 0)))
((setf current-cell) (new-value)
(declare (type integer new-value))
(the trit (setf (gethash pointer memory 0) (mod new-value 3))))
(cell-at (index)
(declare (type integer index))
(the trit (gethash index memory 0)))
((setf cell-at) (new-value index)
(declare (type integer new-value index))
(the trit (setf (gethash index memory 0) (mod new-value 3)))))
(loop
while (< position (length code))
for character of-type character = (char code position)
do
(case character
(#\r (incf position)
(let ((number-of-steps (read-integer)))
(declare (type integer number-of-steps))
(incf pointer number-of-steps)))
(#\l (incf position)
(let ((number-of-steps (read-integer)))
(declare (type integer number-of-steps))
(decf pointer number-of-steps)))
(#\s (incf position)
(let ((new-cell-value (read-integer)))
(declare (type integer new-cell-value))
(setf (current-cell) new-cell-value)))
(#\o (expect-token "o_")
(format T "~a" (current-cell)))
(#\i (expect-token "i_")
(let ((input (read)))
(declare (type T input))
(setf (current-cell) input)))
(#\x (expect-token "x_")
(setf (current-cell) (random 3)))
(#\^ (incf position)
(let ((pointer-offset (read-integer)))
(declare (type integer pointer-offset))
(setf (current-cell)
(logxor (current-cell)
(cell-at (+ pointer pointer-offset))))))
(#\+ (let ((next-character (peek-next-character)))
(declare (type character next-character))
(case next-character
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(incf position)
(let ((pointer-offset (read-integer)))
(declare (type integer pointer-offset))
(setf (current-cell)
(logand (current-cell)
(cell-at (+ pointer pointer-offset))))))
(#\+ (expect-token "++")
(incf (current-cell) 1))
(otherwise
(error "Invalid command: +~c." next-character)))))
(#\- (expect-token "--")
(decf (current-cell) 1))
(#\c (expect-token "c_")
(case (current-cell)
(0 (setf (current-cell) 1))
(1 (setf (current-cell) 0))
(T NIL)))
(#\2 (incf position)
(let ((new-cell-value (read-integer)))
(declare (type integer new-cell-value) (ignorable new-cell-value))
(when (= (current-cell) 2)
(setf (current-cell) new-cell-value))))
(#\m (incf position)
(let ((next-character (char code position)))
(declare (type character next-character))
(case next-character
(#\+ (incf i-cell 1)
(incf position))
(#\- (decf i-cell 1)
(incf position))
(#\p (format T "~d" i-cell)
(incf position))
(#\o (format T "~c" (code-char I-cell))
(incf position))
(#\i (let ((input (read)))
(declare (type T input))
(setf i-cell input)
(incf position)))
(#\: (expect-token "::")
(let ((start-cell-index 0)
(end-cell-index 0)
(new-i-cell-value 0))
(declare (type integer start-cell-index end-cell-index)
(type integer new-i-cell-value))
(setf start-cell-index (read-integer))
(expect-token "::")
(setf end-cell-index (read-integer))
(check-cell-indices start-cell-index end-cell-index)
(loop
for cell-index of-type integer from end-cell-index downto start-cell-index
for cell-value of-type trit = (cell-at cell-index)
for bit-index from 0 by 1
do (case cell-value
(0 (setf (ldb (byte 1 bit-index) new-i-cell-value) 0))
(1 (setf (ldb (byte 1 bit-index) new-i-cell-value) 1))
(2 (setf (ldb (byte 1 bit-index) new-i-cell-value) 1))
(T (error "Invalid cell value in cell ~d: ~d." cell-index cell-value))))
(setf i-cell new-i-cell-value)))
(otherwise
(error "Invalid command: 'm~c'." next-character)))))
(#\z (incf position)
(expect-token "::")
(let ((start-cell-index 0)
(end-cell-index 0))
(declare (type integer start-cell-index end-cell-index))
(setf start-cell-index (read-integer))
(expect-token "::")
(setf end-cell-index (read-integer))
(check-cell-indices start-cell-index end-cell-index)
(loop
for cell-index of-type integer from start-cell-index to end-cell-index
for i-cell-bit-index of-type unsigned-byte from 0 by 1
do (setf (cell-at cell-index)
(if (logbitp i-cell-bit-index i-cell) 1 0)))))
(#\( (if (zerop (current-cell))
(incf position)
(move-past-section-terminator #\( #\))))
(#\) (move-to-section-initiator #\( #\)))
(#\< (if (not (zerop i-cell))
(incf position)
(move-past-section-terminator #\< #\>)))
(#\> (move-to-section-initiator #\< #\>))
(#\/ (if (= (current-cell) 2)
(incf position)
(move-past-section-terminator #\/ #\\)))
(#\\ (move-to-section-initiator #\/ #\\))
(#\[ (if (or (= (current-cell) 2)
(= (random 2) 1))
(incf position)
(move-past-section-terminator #\[ #\])))
(#\] (move-to-section-initiator #\[ #\]))
(otherwise
(error "Invalid command: ~s at position ~d." character position)))))))
An exemplary invocation is:
;; Prints the character 'A' to the standard output. (parse-rcem "r65s1l65(m+r1)mo")