Skip to content

Repository files navigation

lmc

The Little Man Computer in your terminal: an interactive debugger plus commands for assembling, running and inspecting programs from scripts. Built on CoreLittleManComputer.

$ lmc countdown.lmc          # open the debugger
$ lmc run countdown.lmc -i 3 # run it headless
3
2
1
0

Install

swift build -c release
cp .build/release/lmc /usr/local/bin/

Requires macOS 14 and Swift 6.

The debugger

lmc debug program.lmc, or just lmc program.lmc, opens the program in a full-screen view of the machine: the 100 mailboxes, the registers, the in-basket and out-basket, the program listing with the next instruction marked, and a trace of what has run.

Key Action
s or space Execute one instruction
r Run at the current speed, or pause
i Place a card in the in-basket
e Change the mailbox under the cursor
b Toggle a breakpoint at the cursor
arrows Move the cursor around the mailboxes
+ / - Run faster or slower (1 to 64 per second, or flat out)
R Reset the program and in-basket
o Switch overflow between fault and wrap
? Help
q Quit

The mailbox holding the next instruction is green, the mailbox the last instruction read is cyan, the one it wrote is yellow, breakpoints are red and data is dimmed. When the program reaches INP with an empty in-basket the input prompt opens by itself, and a run resumes once you supply a value.

Options: -i 1,2,3 pre-fills the in-basket, --speed 8 sets the run speed, and --overflow wrap chooses wrap-around arithmetic. The debugger needs an interactive terminal of at least 80 by 24 characters; in scripts and pipelines use lmc run.

Commands

lmc run <program> [-i values] [--trace] [--json] [--overflow fault|wrap] [--max-cycles n] [--no-prompt] runs a program and prints each output on its own line. When the program needs input that -i did not supply it reads a line from standard input, so printf '6\n7\n' | lmc run multiply.lmc works. --trace prints every instruction as it executes; --json prints a report with the outputs and the final machine state.

lmc assemble <file> [--format listing|words|json] [-o out] translates assembly into machine words. The default listing shows address, word, label and statement; words prints one word per line; json writes a program file every other command accepts.

lmc disassemble <file | words...> turns words back into assembly: lmc disassemble 901 902 000 prints INP, OUT, HLT.

lmc check <files...> assembles without running and reports problems as file:line:column: error: message, so editors can jump to them.

lmc samples [name] [--run] lists the built-in sample programs, prints one, or runs one with its documented inputs.

<program> is a .lmc assembly file, a .json program, or - for standard input.

Exit codes

Code Meaning
0 The program halted
1 The source did not assemble
2 The program caused a machine fault
3 A file could not be read or written
4 The program needed input that was not available
5 The cycle limit was reached without halting
6 The command cannot run here, such as the debugger without a terminal

Layout

Sources/lmc          The executable entry point
Sources/LMCKit
├── Commands         One file per subcommand
├── Support          Program loading, listings, the synchronous runner, exit codes
├── Terminal         Raw mode, key parsing, a styled canvas
└── Debugger         State, pure reducer, renderer, and the session that ties them to a terminal
Tests/LMCKitTests    Swift Testing suites for everything above the terminal itself

The debugger's logic is a pure reducer over a plain state value and a pure renderer onto a canvas, so all of it is unit tested without a terminal; DebuggerSession only merges keys, engine events and resizes into that reducer and writes frames.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages