Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


TMASM is an assembler for an obfuscated Turing Machine emulator.

I don't know why. Like a few other projects, I don't actually remember writing this. I do vaguely remember thinking about it. But writing a full assembler? Using lex and yacc?

Believe it or not, though, that's not the weirdest part of this. I didn't write the virtual machine. That already Paul E. Black's 1989 IOCCC entry (source, compile and go).

Not included here is what appears to have been a first, tentative step at de-obfuscating the code, which I assume I sensibly gave up on. I'm also not about to include somebody else's code without permission or a license.

I might be convinced to do so if I rewrite it, but otherwise, you'll need to rely on the original.


I can't believe you're still reading this...

Every Turing Machine assembler instruction has the same format:

  • Current State: Represented as a number. The maximum number is hard-coded as 127.

  • /, obligatory syntax.

  • Condition: The character (preceded by a ``` back-tick) expected on the tape at this position.

  • :, apparently because I said so.

  • Target State: The number of the state to which we transition when the condition is true.

  • /, like before.

  • Output: Character (again, preceded by a ``` back-tick) to write to the tape.

  • Direction: An L or R to optionally move the tape head.

  • Debug: Optionally, a p can be added to (I believe) activate the trace routine, though I'm not entirely convinced of that.

A typical line looks something like:

42/`1 : 13/`0 R p

End-of-line comments also start with a semi-colon (;), such as:

; This is a terrible comment

Yes, I used lex and yacc to do this, for some reason.


The first command-line parameter is the source. The second is your output binary.

If you don't supply the second parameter, the assembler automatically chooses a.out to guarantee conflict with any lazily-compiled C code you might have around. If you don't supply the first parameter, the assembler reads from stdin, which won't confuse you at all.

Run the resulting binary through Black's emulator, and at least in theory, you'll get some kind of result, especially if the commented code (the trace routine) is turned on.


There are two maybe-worthwhile example programs:

  • Invert binary data on the tape, printing new zeroes.

  • Generates Fibonacci numbers.


As with a lot of this old code, it may not be ready for prime time. If there are any bugs, I'll be happy to try to track things down, but it probably won't be a priority.

Hopefully, nobody will use this as a core part of their mission-critical toolchain...


Assembler for obfuscated Turing Machine







No releases published


No packages published