Alpha is a simple expression-oriented language with LISP-like syntax.
Here's an EBNF for Alpha:
<Expression> ::= <Literal> | <FunCall>
<FunCall> ::= (
<Operator> <Expression>+ )
<Operator> ::= + | *
<Literal> ::= -?<Digit>*(.<Digit>+)?
<Digit> ::= 0 .. 9
Here's a sample session with the Alpha interpreter:
-> -3.1416
value = -3.1416
-> ( + 2 3 )
value = 5.0
-> ( + ( * 2 3 ) ( * 4 ( + 5 3.1416 )
) )
value = 38.5664
-> quit
bye
The design of Alpha uses the Interpreter pattern:
1. We don't need a context in this simple language because the only symbols are + and *.
2. Values are doubles.
3. Each node knows how to parse itself.
4. Each node knows how to evaluate itself.
We can combine the Interpreter pattern and the Visitor pattern:
The implementation is contained in the following files:
The visitors are defined in the following files:
Beta extends Alpha by adding symbols and definitions:
<Phrase> ::= <Expression> | <Definition>
<Expression> ::= <Literal> | <Symbol> | <FunCall>
<Definition> ::= [ define
<Symbol> <Expression> ]
<Symbol> ::= <Char>(<Char> | <Digit>)*
<Char> ::= a..z | A..Z
Here's a sample session:
-> [ define pi 3.14 ]
done
-> ( + 2 pi )
value = 5.14
->
Design and write an interpreter for Beta.
Hint: eval now needs a symbol table parameter:
abstract class Phrase
{
abstract double eval(Map<Symbol,
Double> context);
// etc.
}
The context will be initialized by the interpreter and passed to the eval method of each phrase. Definitions will add new rows to the context.