Gamma extends Beta by adding variables to the Value hierarchy and Commands to the Phrase hierarchy:
Gamma introduces a new type of value, the variable. A variable is a value that contains another value:
class Variable implements Value {
private Value content;
// etc.
}
We represent a variable with content equal to the Number 42 by the string
var<42>
Note that a variable might contain another variable:
var<var<42>>
This is somewhat analogous to the situation in C where a variable can hold a pointer to another variable:
int x = 42, *p = &x;
Gamma provides a primitive function called var for creating variable and a primitive function called val for dereferencing variables:
-> [define x 12]
done
-> [define y (var x)]
done
-> x
12
-> y
var<12>
-> (val x)
Error: only variables can be dereferenced
-> (val y)
12
-> (+ 1 y)
Error: var<12> is not a number
-> (+ 1 (val y))
13
Gamma syntax introduces commands into the Phrase hierarchy:
<Phrase> ::= <Command> | <Expression> | <Declaration>
There are two types of commands:
<Command> ::= <DataControl> | <SequenceControl>
There are three types of data control commands:
<DataControl> ::=
<Assignment> | <Print> | <Read>
<Assignment> ::= {assign
<Symbol> <Expression>}
<Print> ::= {print
<Expression>}
<Read> ::= {read
<Symbol>}
The assignment command changes the content of a variable:
-> {assign y 100}
ok
-> (val y)
100
-> {assign x 100}
Error: only variables can be assigned values
We can also change the value of a variable using a read command, which reads an expression from the command prompt, evaluates it, and assigns it to the variable:
-> {read y}
(+ 12 10)
ok
-> (val y)
22
The corresponding write command allows us to print expression values:
-> {print (+ 2 (val y))}
24
ok
->
Note that this is slightly different than typing the expression directly to the console's prompt:
-> (+ 2 (val y))
24
->
In the first case the value produced by the phrase is Affirmation.OK. Printing 24 is only a side effect. In the second case 24 is the value produced by the phrase (which is automatically printed by the console) and there is no side effect.
There are three types of sequence control commands:
<Selection> | <Iteration> | <Sequence>
<Sequence> ::=
{begin <Command>+}
<Selection> ::= {if
<Expression> <Command> <Command>?}
<Iteration> ::=
{while <Expression> <Command>}
The sequence command groups several commands into a single command:
-> {begin {print x} {print (val y)}}
12
22
ok
The selection command can be used for one-way and two-way selections:
-> {if (> x 10) {print true} {print false}}
true
ok
-> {if (< x 10) {print true}}
ok
The iteration command allows programmers to repeatedly evaluate a command until a condition becomes false:
-> {while (> (val y) 20) {begin
{print y} {assign y (- (val y) 1)}}}
var<22>
var<21>
ok
1. Note that all commands are bracketed by curly braces. This should make recognizing commands by the static isNext methods easy.
2. In order to implement the read and write commands you will need access to standard input and output. I recommend making these static fields in the ReadCommand and WriteCommand classes, respectively. For example:
class ReadCommand
extends Command {
private static final BufferedReader stdin =
new BufferedReader(
new InputStreamReader(System.in));
// etc.
}
(See
Console.java for the definition of stdout.)
3. Evaluating a read command is tricky. You will need to copy the steps used by the execute method of OmegaConsole:
class ReadCommand
extends Command {
private Symbol varName;
// assigned by parse
public Value eval(Environment
env) throws AppError {
1. read line from stdin
2. scan it with Lex.scan
3. parse it with Phrase.parse
4. evaluate the resulting phrase
5. evaluate varName,
this should be a variable
6. assign the value from 4 to the
variable from 5
7. return Affitrmation.OK
}
}