Boom, A Little Language for Arithmetic

Motivation

You have now learned a lot about programming languages, but you have not had a chance to put all the pieces together. The best way to appreciate how languages are processed is to write language processors. The best way to appreciate how to implement a language is to implement one.

For the next few assignments, you will implement a simple programming language for numbers named Boom.

When you know how to write language interpreters, they become a practical option for solving a larger set of programming problems, even simple ones like manipulating numbers, boolean values, or colors. Over the next few homework assignments, we will use this idea to implement such a small language. The language turns out to be useful enough that we could extend it for use in a larger set of programs.

Language Grammar

BNF Description

The initial version of the language consists of exact numbers and simple arithmetic expressions. Here is the BNF description of the language:

      <exp> ::= <number>
              | ( <unary-op> <exp> )
              | ( <exp> <binary-op> <exp> )

 <unary-op> ::= - | sq
<binary-op> ::= + | - | * | / | %
              | @ | ^ | <<

<number> can be any exact number, positive or negative, including integers and rationals. The semantics of the values and operators are defined below.

Example Expressions

These are all legal Boom expressions:

2                 (2 + 4)
20                (4 * (10 ^ 3))
(sq 16)           (2 * (4 / (sq 6)))
(- (2 + 4))       ((2 * 14) + (4 << 6))
(8 << 3)          ((8 % 3) + ((- 4) * (6 @ 10)))

As the grammar indicates, expressions nest arbitrarily deeply.

Semantics

Unary Expressions

A unary operator takes an expression that evaluates to a number as its operand and returns a new number.
  • (- operand) returns the negation of its operand.
    (- (1 + 2)) equals -3.
  • (sq operand) returns the square of its operand.
    (sq (1 + 2)) equals 9.

Binary Expressions

The binary operators take two numbers as their operands.
  • The first three — +, -, and * — mean what you expect them to mean from past experience: addition, subtraction, and multiplication.
  • (exp1 / exp2) computes integer division.
    (17 / 4) equals 4.
  • (exp1 % exp2) computes the remainder from integer division.
    (17 % 4) equals 1.
  • (exp1 @ exp2) computes the average of its operands.
    (8 % 4) equals 6, and (17 % 4) equals 10.
  • (m ^ n) raises m to the power of n.
    (2 ^ 4) equals 16, and (10 ^ 3) equals 1000.
  • (exp << n) shifts exp to the left by n places, padding with 0s.
    (8 << 3) equals 8000.

Syntactic Sugar

All of the features defined above are part of the core of the Boom language except:

In Boom, syntactic abstractions are preprocessed away before expressions are evaluated.

The remaining operators, both unary and boolean, are part of the core of the language. The behavior of the core operators is implemented directly in the Boom interpreter.