C and C++ compiled to JavaScript, by a compiler that runs in the page.

PRISM compiles the unmodified source of games and emulators from the DOS, Windows 95 and early Linux years — MAME, Quake, Doom, ScummVM, Keen Dreams — and runs them in a browser tab. It is written in plain JavaScript: no WebAssembly, no build step, no dependencies.

C / C++ / asm → preprocessor → parser + types (i386 or 16-bit DOS ABI) → JavaScript source → the browser's JIT

The game is not ported. Its source compiles as it shipped, and the platform it was written for — DOS, X11, Win32, SDL, OpenGL — is supplied in JavaScript underneath it.

Live C

Type C or C++, press Run. The whole chain happens in this tab: preprocess, parse, lay out, emit JavaScript, link, run. The Emitted JS pane shows what your code became. Each example is a place where a compiler that emits JavaScript has to do something that is not a translation.

layout.c

The i386 ABI: struct offsets, padding and bitfields, as gcc lays them out.

floats.c

Type punning: a float's bits read as an integer, as Quake's renderer does.

pointers.c

Function pointers as data, as in a MAME opcode table or a Doom thinker.

stdin.c

A program blocked in fgets while the page keeps painting.

shapes.cpp

C++ lowered to C: constructors, virtual calls, the old cfront idea.

Open Live C

What it compiles

Languages

  • C89/C99 with the GNU extensions real code uses.
  • A C++98 subset: classes, virtual and multiple inheritance, templates, exceptions. Enough for ScummVM, Enemy Territory and Tux Racer.
  • The program's own assembly, translated from its source rather than emulated: Borland inline asm, TASM modules, Watcom #pragma aux, NASM.

Machines

  • i386 System V, flat 32-bit.
  • 16-bit real-mode DOS, small to large models, with far and huge pointers and real segmentation.
  • Platform layers: libc and POSIX, DJGPP, Watcom, Borland, Allegro, X11, svgalib, Win32 and Winsock, SDL 1.2 and 2, OpenGL 1.x with GLU and GLUT on WebGL.

What runs

MAME 0.34 DJGPP15 of 15 games bit-identical to a native gcc build over 1,500 frames.
Quake, GLQuakeThe same pixels on DOS, X11, svgalib and Win32; GLQuake within 1 pixel of 307,200 of Mesa.
Quake II, Quake III, Enemy TerritoryPlay; Quake II's GL renderer within 3 pixels of Mesa.
Doom, Heretic, Hexen, Hexen IIPlay; Doom with its sound server running as a second process.
ScummVM 0.6.1 and 0.10.0 C++Thirteen engines; 3,000 of 3,000 frames and every audio buffer equal to a native g++ build, for 20 game demos.
Keen Dreams 16-bitPlays; its screens are those of the shipped KDREAMS.EXE under DOSBox-X.
And moreOpenDUNE, Jump 'n Bump, SDLPoP, OpenTyrian, Tux Racer, Cube, Chromium B.S.U., Lua 5.4, PuTTY, SQLite.
Not yetAn optimiser; Catacomb 3-D, which generates code at run time; picture references for some GL games.

Tier-0 output runs about 9.5× slower than clang -O2 native; in the browser, Cube draws at about 145 frames a second through WebGL. The full list, with what holds each result.

Checked against other compilers

No gate answers its own question. Each one compares PRISM with an independent implementation, and carries a deliberate mutation it must catch.

Preprocessorgcc -E, token for token, over 289 whole translation units.
Layoutsgcc 12 for i386 (about 105,000 checks); Open Watcom and Borland C++ 2.0 for 16-bit DOS.
Semanticsc-testsuite and gcc.c-torture with 0 wrong answers; csmith programs against gcc -O0 and -O2.
AssemblyTurbo Assembler 2.5's own object code, executed under Unicorn.
ProgramsNative builds of the same sources, Mesa, and the shipped DOS binaries under DOSBox-X.

Run the games yourself

The game sources and data are not in this repository and are never fetched by it. Each target names where its published source comes from; the data is yours to supply.

git clone https://github.com/jfrelat-lab/prism && cd prism
git clone --depth 1 -b v5.4.7 https://github.com/lua/lua.git corpus/lua
node tools/build.mjs targets/lua.json --run "--args=-e print(6*7)"
node tools/serve.mjs --data=/path/to/your/game/files
node tools/site.mjs && node tools/serve.mjs --site --games=~/games

Node 22. The shelf in web/ compiles each program in a worker and shows it on a canvas; tools/serve.mjs exists for the COOP/COEP headers SharedArrayBuffer needs. The last line serves this page from your own export, with your game folders behind it: the games found there say your copy and play from them. Sibling project: MIRAGE, which runs the x86 binary when there is no source.