
Show HN: I wrote a BASIC interpreter in Go - stevekemp
https://github.com/skx/gobasic
======
mrspeaker
A while ago I started making a game
([https://www.youtube.com/watch?v=GwBiJR_rj_w](https://www.youtube.com/watch?v=GwBiJR_rj_w))
that was going to be about typing in program listings from magazines and books
(like "back in the day")... but the "twist" was going to be that the whole
world turned out to be alterable and scriptable with BASIC. The WIP title was
"BASIC Instincts".

The problem was I spent way to much time having fun making the interpreter (in
JavaScript) and then Else.HeartBreak() was released and it took the wind out
of my sails (because it was great!)... I might go back to it now though,
writing interpreters is really enjoyable!

------
jimnotgym
I still have fond memories of the various BASICs. I first used BBC basic at
school (unofficially), and it seemed like magic. I had an Atari ST and a got a
copy of STOS at home.

Whilst BASIC encourages all kinds of spaghetti, I'm still convinced it is a
better language than Python to start on. Control flow is so obvious to non-
programmers when it has line numbers.

~~~
jacquesm
Not all BASIC dialects have line numbers, there are some very elegant version
of basic out there. GFA basic for instance and BBC Basic. Both have named
functions and do not use line numbers.

~~~
opless
Not sure which BBC basic you used, but it certainly DID have line numbers when
I used it. (BBC Model B)

However there were user defined functions and procedures as I recall.

~~~
jacquesm
Yes your are 100% right, the line numbers were there in BBC Basic, but mainly
for editing rather than control purposes (though you could use the dreaded
GOTO statement if you absolutely had to). Keep in mind that this was just
before the days of the full screen editor embedded in your favorite
programming language.

GFA did away with them entirely.

The BBC had an odd editor, it was partly line and partly screen based,
allowing you to move a secondary cursor across the screen with the arrow keys,
and then a ´copy´ key to copy whatever character was under the second cursor
to the input cursor as though that key had been pressed. It sounds terrible
but it was actually quite quick in actual use.

~~~
laumars
What you’re describing there was pretty standard across all of the 8bit micro
computers. A few machines had the copy feature (eg the CPC464) and the control
flow in the BBC BASIC wasn’t anything that couldn’t be done in pretty much
every other dialect from that era (be it Microsoft BASIC, Locomotive or
whatever).

Personally I think it’s a bit of a stretch to say line numbers were mainly
there for editing. Even if you ignore GOTOs the most common method of running
pseudo-functions on the BBC Micro was GOSUB.

~~~
vram22
The BBC personal computer (that ran BBC Basic) also had a cool feature that
allowed you to drop down into 6502 assembly language right in the middle of
your BASIC program, just by enclosing your assembly language statements in [
and ].

I remember trying it out at a British Council library which had one such
machine available for members to use. Although I had done a little 6502
assembly language programming earlier (using both the PEEK and POKE approach
as well as using an assembler), just for fun, on other home computers, I never
got to do a lot of it, since by then, I moved on from BASIC and assembly to
languages like Pascal and then C. Good times.

~~~
laumars
There were actually a few machines that ran BBC BASIC. I’ve got a BBC Micro
model B hooked up in my “man cave” and I still play on that from time to time.

I’ve also got a few Amstrads CPCs - another range of British 8bit micros. They
ran Locomotive BASIC which was largely inspired by BBC BASIC so there is a
hell of a lot in common between those two dialects.

~~~
vram22
>There were actually a few machines that ran BBC BASIC.

Interesting, didn't know that.

>I’ve also got a few Amstrads CPCs - another range of British 8bit micros.

Cool. Had read about them in computer mags.

------
deckarep
Does anyone remember some installs shipped with a game called gorilla.bas? A
fun little game where you had two gorillas across a cityscape and the whole
idea was to take turns throwing bananas at each other to see who can get a
critical hit.

What made it hard is you had to enter both an angle and speed and hope you
calculated the right combination to hit the other player.

Eventually I wrote my own version of the game in flash/actionscript....but
it’s long gone.

~~~
tyingq
Here's a js/html5 port:
[http://www.kylem.net/stuff/gorilla.html](http://www.kylem.net/stuff/gorilla.html)

~~~
deckarep
Yep that looks like a legit clone of it. Thanks for the link.

------
vfinn
Peter Norvig did one for Python, and it's pretty cool:
[https://github.com/norvig/pytudes/blob/master/ipynb/BASIC.ip...](https://github.com/norvig/pytudes/blob/master/ipynb/BASIC.ipynb)

~~~
tyingq
Interesting abuse of a regex as the tokenizer. Cool.

~~~
elcomet
How is it an abuse? I thought using regex as the tokenizer was the main
approach

~~~
tyingq
I've never seen a tokenizer as one big regex that finds all the
types/functions/keywords all at once.

~~~
dboon
To get a bit theoretical, one way to write a lexer is to use a state machine
called a deterministic finite automata - a fancy term for a state machine that
is finite and always gives the same output given an input. Each new character
moves the state, and there are terminal states when you reach e.g. a space
which will spit out what kind of token you just read.

You can show that the things a regex can compute are the same things that this
kind of state machine can compute. I believe that most regex under the hood
use such a state machine, so it's very natural to use regex to tokenize.

------
JoeAltmaier
A fun project! I had a buddy tried this, wrote it in C++ over a week. Had
console, graphics, formatting and networking (I think).

The trick was first a parser, then use C++ objects for each construct and
instantiate one for each parsed element. The objects had a 'list' and a 'run'
method. They were linked in programmatic order. So run the first one, which
returns the next one to run (since it may vary with IF, GOTO etc)

Here it is! [http://www.moondew.com/basic/](http://www.moondew.com/basic/)

~~~
marktangotango
Sounds like interpreting from an instance of the AST. Pretty easy but there
are gotchas; like handling break/continue in loops. It’s an interesting
excercise everyone ought to try IMO.

------
vmlinuz
I once wrote a Logo interpreter in BASIC... For my Computer Studies GCSE (UK
national exams at 16) final project. It never actually _worked_ , but it was a
heroic effort!

~~~
jonsen
I once wrote an assembler in BASIC. We extended the instruction set of a
microprocessor by some external circuitry, so the standard assembler was not
very useful. BASIC was fine for the job. And it actually worked :)

------
tniemi
I think BASIC is something that everyone has to write at least once in their
lifetime.

My personal take is here (over 7 year old code, beware):
[http://tech.nimbus.fi/minibasic/](http://tech.nimbus.fi/minibasic/)

And I wrote that just to make this functional:
[http://tech.nimbus.fi/c128/](http://tech.nimbus.fi/c128/) (Try the "help"
command.)

~~~
abecedarius
Yep, and here was mine:
[https://github.com/darius/parson/blob/master/eg_basic.py](https://github.com/darius/parson/blob/master/eg_basic.py)
written to exercise a parsing library. It's super-slow.

~~~
peteri
Mine in c# is here
[https://github.com/peteri/ClassicBasic](https://github.com/peteri/ClassicBasic)

------
jacquesm
Could someone that has the ability to compile this check the output of

PRINT 3+4*5

please?

~~~
tyingq

      $ echo 'PRINT 3+4∗5' > test.bas 
      $ go run main.go test.bas
      34
    
      $ echo 'PRINT (3+4*5)' > test.bas
      $ go run main.go test.bas
      23
    
      $ echo 'PRINT (3+4)*5' > test.bas
      $ go run main.go test.bas
      35
    

No idea where it's getting 34 from though.

~~~
stevekemp
Grr. Expressions are hard:

    
    
        10 LET a = 3+4*5
        20 PRINT a, "\n"
    

Produces the expected outcome:

    
    
        -> 23
    

Bug filed:

[https://github.com/skx/gobasic/issues/41](https://github.com/skx/gobasic/issues/41)

~~~
jacquesm
Yes, but it should not require that LET statement. The expression evaluator
looks subtly broken.

~~~
stevekemp
Bug filed, as per the edited comment above. I definitely agree this is wrong!

~~~
tyingq
Don't know if it's the same bug, but "PRINT 1/0" returns 1. "PRINT (1/0)"
prints nothing. Using "LET a=1/0" raises a div by zero error. Also, "LET
a=1%0" panics.

~~~
stevekemp
The issue with the "PRINT 1/0" and "PRINT (1/0)" are the same as the previous
one.

LET a = 1/0 SHOULD produce a division by error, so I think that's correct. But
1%0 shouldn't panic. I'll fix that.

------
jhallenworld
I wrote a BASIC interpreter in VAX assembly language (in 1986). I feel old..

I enjoyed Atari 800 BASIC, so it was modeled after that, tokenized during line
entry so that it would not allow you to enter lines with bad syntax.

VAX assembly had instructions for spanning over characters given in a set or
scanning to a character in a set, so string processing was very nice.

You should use floating point for the line numbers so that you can always
insert more statements between existing lines :-)

------
donatj
Oooh wonderful! I wrote hundreds of games as a kid in QBasic and have had the
idea for years to write a QBasic to JavaScript transpiler so I could actually
showcase some of them online. With Go adding its WASM support, I’ve actually
been considering a Go interpreter as an option.

This is super inspiring. Nice work.

~~~
lixtra
Did you search for existing ones?

[https://github.com/smhanov/qb.js/blob/master/README.md](https://github.com/smhanov/qb.js/blob/master/README.md)
[https://news.ycombinator.com/item?id=1042896](https://news.ycombinator.com/item?id=1042896)

------
mikivujkovic
That's how Bill Gates started

~~~
hsnewman
Technically, I believe they (Paul Allen & Gates) ported the Basic from the
Harvard Dec-10 using a cross compiler. This was before there was licenses in
code.

~~~
rustcharm
No. They wrote a fresh version, but they did use an 8080 assembler on a
Dec-10.

