Honing my craft

Crafting Interpreters in OCaml - Building our Context-Free Grammar

May 28, 2019

I HIGHLY recommend reading the chapter in entirety before moving into this post.

One of the advantages of using OCaml (or really, a functional language with a strong type system) is that we can dismiss a lot of the boilerplate and OO design pattern work that Bob needs to configure his Expr.java. Let’s create a file called expr.ml.

The key bit of information in Bob’s code is here:

 defineAst(outputDir, "Expr", Arrays.asList(
    "Binary   : Expr left, Token operator, Expr right",
    "Grouping : Expr expression",
    "Literal  : Object value",
    "Unary    : Token operator, Expr right"

What this does is doing is creating 4 classes, and for each class is setting properties. We can do the same with a variant type!

open Scanner

type literal =
  | LiteralInt of int
  | LiteralString of string
  | LiteralBool of bool

type expr =
  | Binary of expr * Scanner.token * expr
  | Grouping of expr
  | Literal of literal option
  | Unary of Scanner.token * expr

Our tree contains nodes of many types. A binary node has a left and right expressions, and a token value. Our grouping is just an expression that we’ll handle by adding parentheses. A literal is either a None (representing the word “nil”) or Some int or string or boolean. Our unary is a token and an integer, where the token would be either ! or -.

With these few pieces in mind, we can move on to building our parser.

Nikhil Thomas

I work and live in Brooklyn, NY building software.