stack86 · compiler & emulator
The Stack86 IDE: C source on the left, the generated 8086 assembly on the right, and a build log reporting the pipeline.

Overview

A browser IDE that compiles nine languages down to 8086 assembly, then runs the result on an emulator you can single-step.

You have written a for loop ten thousand times. Stack86 shows you what the machine actually does with it.

  • Write in C, C++, C#, Go, Java, JavaScript, Python, Rust or TypeScript
  • Read the 8086 assembly it compiles to
  • Step through it and watch registers, flags, stack and memory change
A trial licence compiles C; a full licence compiles all nine languages.
Key facts
RoleSole author, backend, frontend and toolchain
ShapeASP.NET Core modular monolith plus an Angular 22 SPA
Languages inC, C++, C#, Go, Java, JavaScript, Python, Rust, TypeScript
Target8086 assembly, executed by a browser emulator
Tests956 backend test methods, 864 frontend specs, 100 end to end
Public repositoryA reduced variant: sign-in and persistence removed

Architecture

A modular monolith with one dependency direction and one deliberate process boundary.

The dashed line is the process boundary: compile on the server, execute in the browser.
  • Compilation stays on the server, where each language is checked by its own toolchain: TCC, javac, rustc, gofmt, Node, Python.
  • Execution stays in the browser, because a held-down Step button cannot wait for the network.
  • Every stage is a filter, and each language takes its chain from one registry, so the whole back half is shared.
  • I wrote the CQRS layer instead of taking MediatR: two interfaces and a dispatcher were all it needed.

Domain design

One small intermediate representation that every language has to fit into.

Nine languages in, one IR in the middle, one 8086 back end out.
  • Front ends know nothing about the 8086. They produce IR and diagnostics, nothing else.
  • Registers, segments and INT 21h live only behind the code generator.
  • Wiring a language in is one registry entry, not a special case.

Data and control flow

One build, from the keystroke to the stepping emulator.

The log moves while the stages run; after that, every step is a local function call.

Testing strategy

956 backend tests, 864 frontend specs, 100 end to end, and a build that fails on any warning.

  • A pipeline stage or a front end is a unit test. Routing, auth or the database make it an integration test.
  • Green tests did not catch the editor collapsing to five pixels, so I keep Playwright screenshots next to them.
  • StyleCop and ESLint with warnings as errors, and no escape hatch to any in either language.

What I would change

  • No register allocator yet: every value gets a stack slot, so the assembly is two to three times longer than it needs to be.
  • The optimiser is a single copy-propagation pass. Constant folding and dead-store elimination are still missing.
  • A toolchain missing on the server looks like a compiler bug, not a missing dependency.
  • The languages are not equally deep, and the language picker should say so.