emojinterp is a command-line interpreter for the Emoji++ programming language, implemented in Rust for COMPSCI5119.
- Ensure you have a recent Rust toolchain installed (via
rustup). - In the project directory (where
Cargo.tomllives), run:
cargo build --releaseThis produces the executable at:
target/release/emojinterpBasic usage:
./target/release/emojinterp -f emoji.txt-
-h,--help
Show help/usage information. -
-V,--version
Print version information (this implementation is1.0.0). -
-s N,--size N
Set the memory size (number ofi32cells).Nmust be a positive integer.- Default:
16.
-
-f FILE,--file FILE(required)
Set the Emoji++ source file to execute.- If the file cannot be opened, the program prints
ERROR: File FILE not found
and exits. - With
--debug, the memory/debug dump is printed even in this error case.
- If the file cannot be opened, the program prints
-
-t,--trace
Enable per-instruction trace mode.
For each executed instruction, the interpreter prints:N: Instruction-Namewhere
Nis the instruction count starting at 0, andInstruction-Nameis a textual description such asIncrement-Data,Increment-Index,Output-Char, etc. -
-d,--debug
Enable end-of-program debug mode.
On both normal termination and runtime errors (after setup), the interpreter prints:
Total instructions interpreted: N
Memory size: M
0 : x
1 : y
...
M-1 : z
The interpreter treats the input file as a sequence of Unicode characters and ignores any characters that are not Emoji++ instructions. The supported instructions are:
➡️: Move data pointer right by 1 (increment index).⬅️: Move data pointer left by 1 (decrement index).😀: Increment current memory cell (mem[data_ptr] += 1).🙁: Decrement current memory cell (mem[data_ptr] -= 1).✏️: Interpretmem[data_ptr]as a Unicode scalar value and print the corresponding character.👓: Read a signed decimal integer from standard input and store it inmem[data_ptr].👍: Loop start.- If
mem[data_ptr] == 0, jump to the instruction after the matching👎. - Otherwise, continue to the next instruction.
- If
👎: Loop end.- Jump back to the matching
👍.
- Jump back to the matching
Memory:
- A fixed-size vector of
i32, initialised to zero. - Data pointer starts at 0.
- Instruction pointer starts at the first instruction.
The interpreter detects and reports several kinds of errors. All error lines start with ERROR: and are printed to standard error (stderr):
- File cannot be opened:
ERROR: File FILE not found
- Unmatched or improperly nested loops:
ERROR: Unmatched loop endERROR: Unmatched loop start
- Out-of-bounds memory access (data pointer < 0 or ≥ memory size) for any instruction that reads/writes memory:
ERROR: Memory access out of bounds
- Invalid output character:
ERROR: Invalid character output
- Input errors:
ERROR: Failed to read inputERROR: Invalid integer input
When --debug is enabled, the debug dump is printed even when such runtime errors occur (including the file-not-found case, where memory is still all zeros).
- Argument parsing uses the
clapcrate with#[derive(Parser)]. - Memory size uses
NonZeroUsizeto ensure it is always positive. - The source file is parsed into an internal
Instructionenum; all non-Emoji++ characters are ignored as comments. - Loop matching uses a stack and a
HashMap<usize, usize>to pair👍and👎. Unbalanced pairs cause immediate errors. - Parsing of the input file is performed in a separate thread using an
mpscchannel, purely as an exercise in concurrency; the rest of the interpreter runs on the main thread.
Given a simple program file emoji.txt:
😀😀➡️😀✏️
You can run:
./target/release/emojinterp -f emoji.txt -t -dThis will show a trace of each instruction executed, followed by the final memory dump.