|
CS 341 - Principles of Programming Languages
Homework #6 |
Due: at the beginning of class 11
Note: This work is to be done in pairs. Each pair will
submit one assignment. Although you may divide the work, both team members
should be able to present/describe their partner's work upon request.
To submit this homework, change into the directory containing all necessary
files: MiniScheme1.jj and supporting abstract syntax tree .java files, and enter
the command "submit341 ms1".
MiniScheme Project
Phase 1
In this phase of the project, you will implement an interpreter for a very
small initial subset of the MiniScheme language (which is in turn a subset of
Scheme). This phase will implement simple I/O and simple integer
expressions.
It is recommended that you begin with simple classes to represent
an abstract syntax tree (AST) node, environment, and value-environment pair,
such as these. You will add your own AST nodes
for the more specific classes corresponding to grammar elements below.
Your code should first parse the grammar into an AST, and then evaluate that AST
(which in the future could mean that a node is visited for evaluation many
times).
Specification:
- The main interpreter method generated by MiniScheme1.jj will be in
MiniScheme1.java. Running "java MiniScheme1 <MiniScheme file>" should
interpret the given file <MiniScheme file> specified as a command-line
argument (i.e. args[0] in your MiniScheme1 main method), read input from standard input,
write output to standard output, and print error messages to standard error
(System.err).
- (newline) will print a newline to standard output.
- (read) will read a line from standard input, seek to parse it as an
integer, and evaluate the expression as that integer. If a non-integer
is entered, then the following message will be printed to the standard error
stream: "read expects type <integer>, given: " concatenated with the
non-integer input and a newline. In the event of such an error
execution exits (System.exit) with code 13.
- (write <expression>) will print the integer the expression evaluates to
standard output without a newline. As with Scheme, write returns an
unspecified value. (You may, for instance, return a null/void value,
but no code should rely on this value, including my test code. Trying
to do an operation with this return value should produce an error.)
- Integers are defined as in the R5RS Scheme standard and may include sign
and leading zeros.
- Predefined binary arithmetic procedures are plus (+), minus (-), times
(*) and integer division (quotient). It is recommended that you create
a single AST node for all arithmetic expressions, constructing each with the
operator token (+/-/*/quotient), and evaluating conditioned on the operator
token.
- All arguments of a binary arithmetic procedure are evaluated before
checking for error cases (e.g. division by zero, non-numeric argument).
- A quotient of a number with zero should cause the standard error stream
message "quotient: undefined for 0" and an exit with code 2.
- If the first argument of a binary arithmetic procedure is not an
integer, print "<operator>: expects type <integer> as 1st argument" to
standard error, where "<operator>" is replaced by the given operator itself.
If the first argument is an integer, but the second is not, similarly print
"<operator>: expects type <integer> as 2nd argument". In either error
case, exit with code 3.
- If write is given a non-integer value, similarly print "write: expects
type <integer> as 1st argument" and exit with code 3.
- After successful complete interpretation of standard input (including
I/O), execution exits with code 0.
Common Errors
- Don't create more than one Scanner object for multiple reads
from System.in. Create a single public static Scanner field
that is initialized when the class is loaded and contains a persistent
single input stream that is reused each time a read expression is evaluated.
- Don't emulate our IDE read-eval-print loop; follow the R5RS I/O
standard. This means that:
- the behavior of command "plt-r5rs ___.scm" should be largely the
same (except error messages) as "java MiniScheme1 ___.scm",
- you shouldn't prompt for reads, and
- you shouldn't print top-level program expression evaluations (only
write and newline write to System.out).
Grammar
Grammar notes:
- Non-terminals are surrounded with angle brackets "<" and ">".
- Terminals (e.g. "(" and ")" are represented as themselves without
quotes, unless otherwise noted below).
- --> denotes a right arrow. Choices to the right of the arrow are
separated by a pipe (i.e. "|").
- { }* and { }+ denote a Kleene star and plus/cross, respectively. { }?
denotes an optional subexpression.
<program> --> { <expression> }*
<expression> --> <literal>
|
<derived expression>
<literal> --> <integer>
<integer> --> { + | - }?
{ <digit> }+
<digit> --> [0-9]
<derived expression> --> ( read )
| ( write <expression> )
| ( newline )
| ( + <expression> <expression> )
| ( - <expression>
<expression> )
| ( * <expression> <expression> )
| ( quotient <expression>
<expression> )