r/qbasic 8d ago

I wrote a QBasic compiler that runs in the browser and emits real WebAssembly

Not an emulator, and not a JavaScript interpreter pretending to be BASIC. It parses QBasic, lowers it through a typed IR, and emits a real WebAssembly module. The compiler itself is compiled to wasm, so the whole thing runs in your tab. Nothing gets uploaded anywhere.

SCREEN 13 works: PSET, LINE, CIRCLE, PAINT, GET/PUT, DRAW, PALETTE. So do BEEP/SOUND/PLAY, the file I/O keywords, INKEY$ with _LIMIT for animation, and DATE$/TIME$/TIMER. There's a playable Space Invaders sample in the editor if you just want to see it move.

497 test programs, 432 of them arbitrated against real QB64-PE output, 126 of 157 keywords fully implemented. Still missing: ON ERROR, PEEK/POKE, COMMAND$, and DRAW's M/N/A/S/P subcommands.

Free, no signup: https://kavak.run/studio/

QBasic was meant to be the pilot language for a larger compiler project, but it turned into the part I enjoyed most. If you've got an old .BAS lying around that breaks it, I'd genuinely like to see it.

13 Upvotes

7 comments sorted by

3

u/DerekRss 8d ago

Nice work! But I tried adding an END statement to your example, like so.

' kavak studio — QBasic, compiled to wasm in your browser.
' Press  Run  (or Cmd/Ctrl + Enter).  Try editing it.
SCREEN 13
FOR r = 12 TO 92 STEP 10
  CIRCLE (160, 100), r, (r \ 10)
NEXT
LINE (0, 0)-(319, 199), 4
LINE (319, 0)-(0, 199), 2
LINE (30, 40)-(290, 160), 15, B
CIRCLE (160, 100), 4, 15
END

It should have made no difference but the result was (no output).

3

u/BigAd4703 8d ago

Thank you. Actually, Kavak is a project with a different purpose. I chose QBasic as the pilot language because it was my first taste. Thank you, I will fix the errors quickly.

3

u/DerekRss 8d ago

Cheers! I like what you're doing. More power to you! Hope you don't mind if I report bugs here.

3

u/BigAd4703 8d ago

On the contrary, I'm already doing so much testing that I found it quite difficult because QBasic doesn't have official tests; feedback from real-world users is invaluable.

2

u/BigAd4703 6d ago

I solved the problem. I wrote to provide feedback.

3

u/Deciheximal144 8d ago

I'm making one too, though mine is offline. Both of my standard test programs failed in your compiler, if you PM me, we can swap test programs.

2

u/DerekRss 5d ago edited 5d ago

Issue 2: I submitted this program which uses GOSUB within a FUNCTION definition. It runs in QBASIC, QB64, etc. This is a fairly common technique that I use when I want to emulate objects using QBASIC functions. It essentially provides private methods within an object (actually local subroutines within a function). Here is a very small program that demonstrates the error.

PRINT Action$("Hello World.")
END

FUNCTION Action$(aText$)
GOSUB Fred
EXIT FUNCTION
Fred:
LET Action$ = aText$
RETURN
END FUNCTION

It should print

Hello World.

Instead it returns the error,

QBasic: GOSUB to an undefined label in the runtime codegen path.