Baysick: A Scala DSL Implementing BASIC
This post was featured on the Scala website. It is advised to jump there first and then sneak back here … eventually.
A couple weeks back I came across a post on creating the simplest possible BASIC DSL written in Scala by Szymon Jachim. The implementation itself was dead simple to understand, but I suspected it was due to the fact that it only provided GOTO
and PRINT
. The title of the post was ease of making DSLs in Scala – nobody cares, which was unfortunate because I think that many people care, including myself, so I took it upon myself to extend the DSL to be a pseudo-implementation of Tiny BASIC. In a nutshell, I found that it was simple to create an internal DSL providing a simple dialect of BASIC using Scala. There were some sticking points, which I will touch on later, but overall it was a joy. The code is available for public consumption, so feel free to try it, criticize it, and/or improve it. I find it retains its simplicity even after extending the original to provide additional forms and functions.
Here is a simple Lunar Lander game written in Baysick.
[sourcecode lang=”bas” gist=”122994″] object Lunar extends Baysick { def main(args:Array[String]) = { 10 PRINT “Welcome to Baysick Lunar Lander v0.9” 20 LET (‘dist := 100) 30 LET (‘v := 1) 40 LET (‘fuel := 1000) 50 LET (‘mass := 1000)
60 PRINT "You are drifting towards the moon."
70 PRINT "You must decide how much fuel to burn."
80 PRINT "To accelerate enter a positive number"
90 PRINT "To decelerate a negative"
100 PRINT "Distance " % 'dist % "km, " % "Velocity " % 'v % "km/s, " % "Fuel " % 'fuel
110 INPUT 'burn
120 IF ABS('burn) <= 'fuel THEN 150
130 PRINT "You don't have that much fuel"
140 GOTO 100
150 LET ('v := 'v + 'burn * 10 / ('fuel + 'mass))
160 LET ('fuel := 'fuel - ABS('burn))
170 LET ('dist := 'dist - 'v)
180 IF 'dist > 0 THEN 100
190 PRINT "You have hit the surface"
200 IF 'v < 3 THEN 240
210 PRINT "Hit surface too fast (" % 'v % ")km/s"
220 PRINT "You Crashed!"
230 GOTO 250
240 PRINT "Well done"
250 END
RUN
} } [/sourcecode]
Notes
- Variables are denoted with the single quote which corresponds to Scala’s symbol literals
- The assignment operator is the Pascal-like
:=
- The append operator for the
PRINT
form is%
- Only integer math is supported
- Strings cannot (currently) be compared using the relational operators
- Usage of Scala code within the BASIC forms is not fully supported
- There are currently only 6 math functions:
ABS
SQRT
+
-
*
and/
Issues
As has been mentioned by innumerable programmers advocating (and deriding) DSLs, you are often constrained by the host language in the grammar, error reporting, and hosting capabilities of your DSL. While Scala allows you to support bizarre grammars without significantly increasing the complexity, it does not necessarily facilitate a simple way to provide solid error reporting and hosting. This is not necessarily a limitation of Scala per se, but instead for general purpose languages. In order to effectively build a wide range of DSLs divorced from their underlying host we need a language that is especially geared toward building DSLs. The two important language features that Scala provides that makes it especially conducive for DSLs are operator notation and implicits. Usually, a language is considered DSL-friendly if it allows you to omit the dot on a method call, but a really powerful DSL metalanguage would have to go much much further than that.
For some strange reason I could not coax Scala into allowing my
LET
forms to be parenthesis free. I assume that it is an error on my part, but I was never able to solve it before my artificial deadline expired.
Todo
- A subroutine facility via
GOSUB
andRETURN
- Allow strings to be compared using the relation operators
So there you have it — Baysick: A Scala DSL Implementing BASIC.
-m
8 Comments, Comment or Ping
Don Stewart
Probably worth checking out the Haskell BASIC EDSL, which uses overloading to avoid the “interpreter” like approach of putting the statements in a data structure directly.
It also compiles the overloaded AST to native code via LLVM.
http://hackage.haskell.org/cgi-bin/hackage-scripts/package/BASIC
Mar 26th, 2009
fogus
Thanks for the pointer. I will most certainly check it out. -m
Mar 27th, 2009
Szymon Jachim
Yes… the title was a typical kind of “README.!!!”, but expressed how I felt after talking about DSL with some Java devs. It’s not that they did’t care… they didn’t even know what a term DSL means. What I saw in the eyes of my listeners was mostly a mix of boredom and misunderstanding… until I show arguably useless inline BASIC code. Maybe I’m just a bad speaker or I tried to fit too much into a 5 minute talk. ;-)
Apr 14th, 2009
Szymon Jachim
I forgot about the most important: I love what you did with the code! :-) The only thing I would change is to allow 40 LET ‘fuel = 1000 instead of 40 LET (‘fuel := 1000) For this you could use update() method like this: object LET { def update(s: Symbol, v: Any) = lines(num) = Let(/…/) } In the similar manner one could implement single “=” sign after IF or FOR.
Apr 14th, 2009
fogus
Szymon,
Thank you for stopping by and commenting on the post. I knew that there was a way to enable
=
but for the life of me I could not find it. I blame the inherent difficultly in Googling for=
. ;) I’m glad that you liked the code, and thanks again for providing the motivation.-m
Apr 30th, 2009
LaPingvino
Sorry for the very late answer to this post, but for googling on this items google.com/codesearch may come in handy ;)
Feb 5th, 2010
Adrian McMenamin
I know am coming to this a few years(!) late, but I have written a BASIC-like DSL in Groovy which may interest people: https://cartesianproduct.wordpress.com/binsic-is-not-sinclair-instruction-code/
Jun 26th, 2012
Reply to “Baysick: A Scala DSL Implementing BASIC”