Due: Thursday, June 1 by 11 pm. You should use Gradescope to submit your assignment in two parts, corresponding to the written and programming parts below. Details are given in the "What to hand in" section at the bottom of the assignment. If you have late days remaining, you may still use up to 2 of them them on this assignment, as usual, if you wish.
Added Sunday, May 28: we want to allow a bit of extra time for this
assignment because of the end of the quarter crunch. So, for this
assignment, everyone can use two late days, meaning the final deadline
for everyone to turn in this assignment is 11 pm, Saturday, June 3,
even if you have already used all or most of your late days previously.
No further extensions or late days allowed after that deadline
except, of course, for serious emergencies beyond your control
(in which case you must send email to cse413-staff
as
soon as you can to notify the staff of the situation).
Answer the following questions about context-free grammars.
([[](()[()][[]])])[]((()))
.time,
arrow, banana, flies, like, a, an, the, fruit
Complete your calculator program by adding a parser and interpreter for the
calculator language to the scanner that you implemented
in the previous assignment. You should construct a recursive-descent parser
that calls the scanner's next_token
method to read the tokens
making up the input program, and parses and evaluates the calculator
statements
in the input. The parser/interpreter should contain a separate method for each
major calculator language construct such as statement and exp.
Each time one of these methods is called it should parse the corresponding part
of the grammar and evaluate the result. After each expression statement is evaluated,
the resulting value should be
printed to standard output. You should, of course, include additional methods
and data structures
as needed to organize your program cleanly. In particular you will need a hash
table (dictionary) to record variables and the values that they are currently bound to as
the calculator executes.
Hint: one useful way to calculate the value of an expression is to have each of the parser methods return the value of the expression or sub-expression they parse.
Your parser/interpreter need only work on syntactically correct input. But note that a syntactically correct program can contain an unbound variable, which should be handled as specified in the calculator language description.
You should test your calculator by evaluating a variety of statements, and
you should turn in a sample of the tests you performed that show that your
calculator works properly. These examples should range from simple expressions
consisting of a single number or identifier, to more complex expressions and
statements. In particular, your tests should demonstrate that the code to bind
names to values, use those names in expressions, and delete names with clear
,
all work properly.
Your parser/evaluator code should be contained in a file calc.rb
.
Your scanner code should continue to be in the scan.rb
file from the previous assignment.
You may, if you wish, break your program into additional source files in the same directory,
but it should be possible to run your program by executing the file calc.rb
using an appropriate ruby
command,
and by default the program should read input from the keyboard and display output on the screen,
i.e., don't make any special provisions in your program for reading or writing specific named files.
Be sure to include your name and other identifying information as comments
at the beginning of your file(s). There should also be descriptive comments as needed,
in particular to describe classes and important data structures.
A small amount of extra credit will be awarded for extending your calculator in interesting ways. Here are a few ideas:
clear
statements.sqrt(
exp)
. These can be implemented
by calling the corresponding functions in the Ruby math library.If you add any extensions to the language, you should do it systematically by figuring out how to extend the grammar, then implement the corresponding extensions in the parser/interpreter and, if necessary, scanner. Regardless of any extensions, your final calculator should accept any valid program described by the original grammar and execute it correctly.
Use Gradescope to submit your solutions to this assignment in two parts.
For the problems in Part I please turn in a pdf file
named hw8.pdf
with your answers. This can be a scanned
handwritten document if that is convenient, as long as it is clear
and legible.
Gradescope's web site has several instructional videos and help pages to outline the process,
and this guide
has specific information about scanning and uploading pdf files containing
assignments.
For Part II, turn in scan.rb
, calc.rb
and any other
source file(s) containing your Ruby code.
Also submit a text file named hw8.txt
containing some
examples of input and output that demonstrate that your calculator works on a variety of
test input containing input that is syntactically correct,
but has a mix of correct and incorrect input (e.g., using undefined variables, etc.).
The hw8.txt
file should be a transcript of a terminal session showing operation of your calculator.
In addition to the code and transcript files, you should also include a readme.txt
file that
describes what works and what doesn't and any extensions that you added. If you extended
the language, your readme.txt
file should
describe the changes you made to the grammar as well as give an overall description of the extension(s).
On Linux and OS X systems you can create a transcript file using
the command script hw8.txt
to start a new shell and
capture all of the input and output while it is running. Run your ruby
command there, then, when you're done, terminate ruby and type
exit
in the shell window. That will leave you back in the
original window where you ran script
, and there will be a
hw8.txt
file containing your work in the current directory.
Turn in that file.
Historically, Windows has not had a script command.
If no better tool is available, you can create a transcript file as follows.
Run ruby or irb in a command window. When you're done, right-click the window title bar
and pick edit>select all
from the popup menu, then pick edit>copy
.
Open a plain text editor like notepad++
,
paste the copied terminal session into a new window, and save that file as hw8.txt
.
Regardless of how you create the transcript file, you can do some light editing to delete major typos or false starts, but don't worry about minor problems or a few extra characters like backspaces entered to correct typing errors. We're interested in your overall demonstration, not in every small detail (as long as it's clear which things are false starts that should be ignored).