read


read
or learn more

Baysick: A Scala DSL Implementing BASIC

Mar 26, 2009

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

  1. Variables are denoted with the single quote which corresponds to Scala’s symbol literals
  2. The assignment operator is the Pascal-like :=
  3. The append operator for the PRINT form is %
  4. Only integer math is supported
  5. Strings cannot (currently) be compared using the relational operators
  6. Usage of Scala code within the BASIC forms is not fully supported
  7. There are currently only 6 math functions: ABS SQRT + - * and /

Issues

  1. 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.

  2. 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

  1. A subroutine facility via GOSUB and RETURN
  2. 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

  1. 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

  2. Thanks for the pointer. I will most certainly check it out. -m

  3. 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. ;-)

  4. 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.

  5. 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

  6. LaPingvino

    Sorry for the very late answer to this post, but for googling on this items google.com/codesearch may come in handy ;)

  7. 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/

  1. Quora - Jan 24th, 2011

Reply to “Baysick: A Scala DSL Implementing BASIC”