In this note, I show how to develop an SCN (see below - like a DSL) for a game development system.

SCN means Solution Centric Notation. Basically a mini-DSL. See below.

Initial Grammar

  main = room+
  room = "room:" ws* id ws+ statement+ ";room"
  statement = widthStatement | heightStatement | tilesStatement | enterStatement
  widthStatement = "width" ws+ number eol
  heightStatement = "height" ws+ number eol
  tilesStatement = "tiles" ws* "(" numberList ")" eol
  enterStatement = "enter:" ws* tellStatement ";enter" eol
  tellStatement = "tell" ws+ string eol

  numberList = (number ws*)+
  number = negativeNumber | positiveNumber
  negativeNumber = "-" smallinteger
  positiveNumber = smallinteger

  smallinteger = dig+
  dig = "0" .."9"
  ws = " " | "\t" | "\n"
  id = firstIDChar followIDChar*
  firstIDChar = "a" .. "z" | "A" .. "Z"
  followIDChar = "0" .. "9" | firstIDChar
  string = quote notQuote* quote
  quote = "\""
  notQuote = ~quote any
  eol = ws+

Ohm-JS vs Other PEG Libraries

Ohm-JS rule names are case-sensitive.

In Ohm-JS, lower-case rule names work just like other PEGs (modulo minor syntactic differences).

In Ohm-JS, upper-case rule names skip spaces, so most of the ws stuff above could go away.

The other big difference between Ohm-JS and other PEG libraries is how matches are tagged. I will explain this later. Let’s just work on the grammar first.

Initial Test Code

room: default
  width 3
  height 3
  tiles (-1 -1 -1  -1 -1 -1  -1 -1 -1)
     tell "Something BAD happened.\nPlease report this bug!\nTHNX 1.0E6!!!"

Ohm Editor

Ohm Editor for ZodeTrip Screen Shot 2021-09-02 at 8.09.14 AM.pngExercise 1

Convert the grammar from Ohm-JS style to racket (#peg) style.

Use the same test grammar and make sure that you get the same result.

Gedanken: Do you find Ohm-Editor to be convenient, even when using a different #peg syntax?

Exercise 2

Convert the grammar so that



end room

Write new test code and test the new grammar.

Exercise 3


     tell "Something BAD happened.\nPlease report this bug!\nTHNX 1.0E6!!!"


     tell "Something BAD happened.\nPlease report this bug!\nTHNX 1.0E6!!!"
end enter

Exercise 4

Gedanken: At present, the id rule will accept keywords like tell, etc.

How would you make a list of keywords and include them in the id rule (hint: using negative lookahead)?


Syntaxes are Pattern-Matching Skins

A grammar is a pattern matcher.

Pattern matchers are popular today, often found in FP languages.

Grammars are the mothers of all pattern-matchers.

Treating syntaxes as light-weight skins produces a different, more productive, kind of programming.

PEG technology and cheap/fast CPUs and cheap memory makes it possible to re-think the use of syntax as something light-weight instead of something shrouded in mystery that is accessible only to compiler gurus.

2 Syntaxes

Some languages, like C and Lisp, collapse end room into single characters }and ).

Gedanken: Which style gives more lucid error checking?

Gedanken: Is it harder in the grammar to ask for end room instead of single characters?

Gedanken: Which is more writable?

Gedanken: What if we had 2 syntaxes, one with end room and another with }?

Gedanken: How easy is it to create separate syntaxes, for example to parse the end room syntax and to write it back out in } syntax?


SCN means Solution Centric Notation. In my vocabulary, a notation is like a mini-DSL.

When I build an SCN, I cheat and let the underlying language (the toolbox language) handle all of the heavy lifting. I use a grammar like a skin instead of as a full-blown programming language.

Lisp (and Scheme, and Racket) makes a great toolbox language.

Assembler is the mother of all toolbox languages.

We don’t want to get our hands dirty with assembler, so we create syntactic skins. [This used to be difficult in the 1950’s, but is easy in the 2020’s.]

See Also