Programming Language Design

Boolean Expression Language


Learning Objectives

  • You understand and can implement a simple boolean expression language.
  • You know of the concept of syntax sugar.

Here, we look into a language for boolean computation — focusing on if true then true else false, and a variant with nested if statements possibly with spaces if true then if false then true else false else false.

Grammar

We can specify its grammar in a similar manner as with arithmetic expressions.

Littrue|falseSpace" "|Space" "ExprifSpaceExprSpacethenSpaceExprSpaceelseSpaceExpr|Lit

AST

The abstract syntax tree for boolean terms would have a way to create new booleans (True,False) and a way to destructure them (Ite).

TermTrue|False|Ite(if:Term,then:Term,else:Term)

In the Ite constructor, we use a mathematical “record notation” similar to Gleam records to indicate named fields.

AST as Formation Rules

Formation Rules

True-FTrue:TermFalse-FFalse:Term𝑡1:Term𝑡2:Term𝑡3:TermIte-FIte(if:𝑡1,then:𝑡2,else:𝑡3):Term

The suffix “-F” refers to a formation rule.

E.g. the term Ite(if:True,then:False,else:True) has the following formation tree:

True-FTrue:TermFalse-FFalse:TermTrue-FTrue:TermIte-FIte(if:True,then:False,else:True)

Evaluation Rules

Let’s call the mathematical type for booleans, which has the two elements 0 (false) and 1 (true), simply {0,1} (or 2).

The evaluation relation now looks like 𝑡𝑏, where 𝑡:Term and 𝑏:{0,1}.

FalseFalse0TrueTrue1𝑡1True𝑡2𝑏2IfTrueIte(if:𝑡1,then:𝑡2,else:𝑡3)𝑏2𝑡1False𝑡3𝑏3IfFalseIte(if:𝑡1,then:𝑡2,else:𝑡3)𝑏3

The idea behind the last two rules is to make our Ite rule lazy/short-circuiting meaning that it does not compute the value of the branch that was not taken. The naïve version would look like this:

𝑡1𝑏1𝑡2𝑏2𝑡3𝑏3IfIte(if:𝑡1,then:𝑡2,else:𝑡3)if𝑏1then𝑏2else𝑏3

Here, we use a mathematical if-then-else construction which works exactly the same as in programming, but here 𝑏1:{0,1} and 𝑏2,𝑏3:𝑇 for some type 𝑇.

Syntax Sugar for Lowering

Here’s a concrete example of how syntax sugar can be used to make a language more convenient for programmers.

TermSugarTrue|False|Ite(if:TermSugar,then:TermSugar,else:TermSugar)|Not(TermSugar)new!|And(TermSugar,TermSugar)new!|Or(TermSugar,TermSugar)new!

After parsing into a a TermSugar, we can do a desugaring translation into the original AST Term by turning the operators into if-then-elses. This would mean we don’t have to change the dynamics of the language. This is a nice way programming languages can add convenient features which don’t fundamentally alter the behavior of the language.

Let’s express the translate function using double square bracket notation: :TermSugarTerm. As always, we can do case analysis on the argument of type TermSugar:

TrueTermSugar=TrueTermFalse=FalseIte(if:𝑡1,then:𝑡2,else:𝑡3)=Ite(if:𝑡1,then:𝑡2,else:𝑡3)Not(𝑡)=Ite(if:𝑡,then:False,else:True)And(𝑡1,𝑡2)=Ite(if:𝑡1,then:𝑡2,else:False)Or(𝑡1,𝑡2)=Ite(if:𝑡1,then:True,else:𝑡2)

Using this operation, we can simply pull back the evaluation function to get

eval_sugar:TermSugar{0,1}eval_sugar(𝑡)=eval(𝑡)

Or, using the evaluation relation symbol:

Definition 4.6.1: Evaluation relation for TermSugar 𝑠Let 𝑡:TermSugar and 𝑏:{0,1}. 𝑡𝑠𝑏 if and only if 𝑡𝑏.

Loading Exercise...