John Maeda created the DBN language as a tool to teach programming to non-developers. It was quite an influential language; in fact it was the precursor of the popular processing language, developed by Maeda’s students Casey Reas and Ben Fry, taking many ideas from DBN.
Unfortunately, DBN hasn’t been open-sourced and the documentation of it is almost nonexisting, let alone any official specification of the language. There is only one book written about it (although a blurry copy exists in google books, censored enough to miss very important parts), and the DBN software amounts to a Java applet in the official website and a Java program that you can run on your own computer.
h2. Crash course in PEG.js grammar definitions
If you want to quickly test the grammar output as you go, use PEG.js online version, it is immensely useful on the early stages of grammar definition.
Also, keep in mind that what I explain here is a 10.000 foot overview of PEG.js and it is by no means a tutorial; if you want to learn real language grammar definition with PEG.js you must read the real documentation for it, and have some idea about parsers, lexers, tokens and their friends.
1. Defining the basics
Before we start, one thing worth oting is that PEG.js doesn’t have a separate stage for “lexing”. The lexer is integrated seamlessly in the generated parser, so we don’t have to worry about it.
Ok, so the first thing to do is to define the building bocks for the language. Note that the parser doesn’t take anything for granted, so we will have to define how our language handles whitespace as well.
As you can see, the language is very clear and takes inspiration from regular expressions. The above peg grammar defines strings, integers (DBN has no decimals), points in a 2D canvas, and basic arithmetic (the latter adapted from the arithmetic grammar given at the PEG.js site as example).
A rule is composed of several parts: its name, the matching expression and the optional parser action, which is enclosed between brackets and transforms the output of the rule.
For example, for the
This rule checks for a “[” character followed by a
value rule (which is defined separately), followed by a whitespace rule (also defined separately), followed by another
value rule and a closing “]”.
[4 2] we would get the output
["[", "a", " ", "b", "]"].
point rule references two other rules,
ws, which look like this:
value will try to sequentially match any of the expressions separated by “/”, and it will return the first sucessful match. The whitespace
ws rule uses a RegExp construct to match any single space or tab character.
2. DBN Commands
Now we will define the “meat” of our grammar. Fortunately enough, DBN is a language with a rather simple syntax. A basic program could look like this:
This program runs the instructions inside the
repeat loop, which is equivalent to a classical
for loop. It loops from 0 to 300 while assigning the current iteration value to the variable A and drawing different lines on the canvas.
As we see above, a basic command in DBN takes the following form:
command_name value_1 value_2 value_n
And a rule
command to parse it:
Let’s break the matching expresion down:
- Match 0 or more whitespace characters.
- Match an alphanumeric word that might include the ‘?’ char, and label it as “cmd”.
- Match 0 or more DBN
valueexpressions preceded by a whitespace and label them as “args”.
- Match at least one linebreak.
In case an expression
command is matched, we will pass the
cmd and the
args results to the parsing expression, who will return an object with some particular properties that manipulate the values in the way we want. In that case we just do some basic filtering to the arrays resulting from the matches.
An important thing to note down is that any match gotten using the operators
+ will return an array with as many coincidences as there are in the matching expression. That means that we will have to take care of filtering these arrays so we obtain the results we want. A clear example is the
cmd variable, which returns an array with all the characters of the command name matched, so in the parsing expression we have to join it to form a real string.
3. DBN Blocks
Our grammar can already process DBN commands, but this is pretty limited functionality. Any interesting program will at least have loops and block commands, and we still can’t parse these.
In order to process block commands we will create the new rules
block we match any group of
commands or nested
block_commands that are inside braces, taking into account the possible whitespaces that we might find.
block_command the matching expression is very straightforward, but there is an interesting bit in the parsing expression, where we attach
c as a property, and we return
type: “command”, array of parameters
args and that
block property we just added, which contains the commands inside the block.
And we’re finished! Our grammar can now parse DBN programs and generate its JSON AST. Parsing the basic program that I wrote above as an example generates this tree. You can find the complete grammar file here.