Grades and deadlines
-
Initial deadline: 23:59 on Wednesday 18 November
-
How to submit: Turn in your completed
lab5.1.ymlfile, along with everything in thesrc/mainfolder of your maven project.You must submit via the command line in order to preserve the folder structure. Use either of these two commands to do it:
club -csi413 -plab5.1 -f lab5.1.yml sqrt_prog src/main aichat.mdor
submit -c=si413 -p=lab5.1 lab5.1.yml sqrt_prog src/main aichat.md(you can download the club tool here)
-
Collaboration and AI: Recall the course policy on collaboration and AI usage. For this lab:
-
You are free to discuss the lab with any classmate (without looking at Java code), diagram out your solution, etc., as long as that collaboration is clearly documented in your YAML file.
-
You can collaborate with any classmate who is working on a different language from you, as long as that is cited and you do your own work.
-
You may use the class Gemini Gem as long as you cite where/how you used it and you turn in a complete transcript of all relevant conversations.
-
You may not use other AI tools besides the course-specific Gemini Gem. If you think there is something useful that you aren’t able to do with the Gem, talk to your instructor!
-
-
Grading:
In this lab you will complete one or both of the following tasks:
- Add support for two built-in functions to your Lab 4.2 interpreter
- Add support for numbers to one of the Lab 4.2 starter languages.
There are a total of 10 points available towards your total lab grade, as follows:
- If your submission meets all the requirements for Part A (but not for part B), you will earn 7 points.
- If your submission meets all the requirements for Part B (but not for part A), you will earn 7 points
- If your submission meets the requirements for both parts, you will earn 10 points.
-
Resubmissions:
We will follow the same resubmission policy for all labs this semester. For any given deadline you must at least demonstrate significant progress or you get a zero that cannot be revised. The initial deadline for this lab is the same regardless of any other pending resubmissions on previous labs. If your work is not yet up to the standard, you will receive a new deadline of one week later (up to the end of the semester) and a chance to revise for full credit.
Two Parts - Both Optional
This lab has two parts. But both parts are independent, and you can complete them in either order, or only do one.
-
You will add built-in functions to your own working interpreter from last lab.
Completing this part requires that you already completed the last lab on functions. It will be more intellectually/conceptually challenging than part B, but will also require much less actual coding work than part B.
-
You will add numbers to one of the three starter languages from last lab.
This one does not require you to have a working solution to the previous lab. The tests for this part will not test function calls at all.
Completing this part will be a better starting point if you feel a little less confident on the previous lab, want a good review where you touch on all of the pieces of the interpreter we’ve seen this semester, and want to do a little more actual coding work to get it done.
Getting started (for both parts)
Start by cloning the git repo corresponding to the language you used for the previous lab, by running one of these three commands:
# for Hibana
git clone https://github.com/si413usna/startlab.git -b lab5.1-hibana lab5.1
# for DIGEST
git clone https://github.com/si413usna/startlab.git -b lab5.1-digest lab5.1
# for void
git clone https://github.com/si413usna/startlab.git -b lab5.1-void lab5.1
You should see just a few files there:
-
lab5.1.yml: You need to fill this in, of course. -
read_plus: For part A only: A program in your language that demonstrates the two built-in functions you need to enable (you don’t need to change it). -
sqrt_prog: For part B only: A program you need to write in your language to match the square root program shown below. -
get_src.sh: For part B only: A little helper script to get the starter code from last lab to get started here. -
run.sh: Small bash script to help compile and run your code with maven. -
pom.xml: Tells mvn how to compile your code. You don’t need to touch this.
Part A: Builtins
(Skip down to Part B and ignore this section if you are starting with that part.)
Files for Part A
Clone the git repo using the instructions above.
Notice there is no src/ directory here.
That’s because the first thing you need to do is
to copy your entire src/ folder from your
working solution to Lab 4.2. That will be your starting point for this
lab.
In the new directory, you will find a new program in your language,
called read_plus. Your goal will be to implement built-in functions
for the read and plus functions so that this program (or any other
program like it) works in your interpreter.
What is a built-in function?
A built-in function in a programming language is something which looks syntactically like any other regular function call, but which is pre-defined when any program in that language starts. Typically, these built-in functions might be used to do common tasks, or to access special capabilities that otherwise wouldn’t be available to the programmer.
Most programming languages include a lot of built-in functions. In
Python these include things like print(), abs(), and open().
It’s important to distinguish these from keywords, which are also kind
of “built-in” to the language, but do not behave like regular functions
and in fact have a special role in the token spec and grammar. Things
like if, while, else are examples of keywords in Python.
Built-ins are also different from library functions, which are
typically written in the target language itself and #included or
imported directly.
By contrast, built-ins work like this:
- They do not require any changes to the language syntax (tokens and grammar). Built-ins look to the programmer just like calling any other function.
- When executed, they run special code baked in to the interpreter, rather than executing normal code in the language itself.
In other words, a built-in looks like any other function in your language, but the code to actually run it will be written (for you) in Java, the language of the interpreter itself.
The built-in functions you need to write
We are asking you to write two built-in functions and add them to your interpreter in your language. Here are equivalent definitions of these functions in Python, so that it’s clear what they are supposed to do:
# Takes a string for a file name, then reads and returns the entire
# file contents as a single string
def read(fname):
with open(fname) as fin:
return fin.read()
# Takes two strings which hold digit characters representing two numbers
# then adds those numbers and returns the sum as another string.
def plus(num1, num2):
return str(int(num1) + int(num2))
Note on error handling
Yes, you should do proper error handling in your builtin
functions. Remember there is an Errors.error("message here") function
that’s already provided for you in the Errors.java class. For both
read and plus, you should catch potential run-time errors (like
specifying a filename that doesn’t exist, or entering non-numerical
strings) and print a sensible error message rather than crashing your
interpreter with a stack trace.
Hints on how to get built-ins working
Most importantly, you should not need to change your token spec, grammar, or AST generation at all in order to get built-in functions to work. If you find yourself editing those files, take a step back and consider whether you really want/need to!
In my sample solutions, I just created one new file that I called
Builtins.java, and then added a few new lines of code to
RunState.java. (Of course, you might structure your solution in a
different way, and that is totally OK as long as it works!)
To get these two built-in functions to work, somewhere you have to have your code in Java to do the thing that each built-in does (reading a file or adding two string-represented integers). That is actually the easy part; I’m sure you could write those few lines of Java in your sleep by now!
The tricky part is figuring out how to connect these methods/classes, with the running interpreter. Precisely how you do this will depend on how you got function calls working in the previous lab. Now you need to mimic what a function definition would do, except you are going to kind of hard-code these two function definitions into the global frame, in Java, before the interpreter ever starts executing the user code. You might need to create a special closure object, create a new binding somewhere, etc. – you figure out the details!
Just like with the last lab, I recommend starting with something easy (like a test builtin that takes no arguments and has no return value), then working your way up by adding arguments/parameters first, then return values, until a “fully powered” built-in function works correctly.
Testing your work
The included read_plus program in your language, can be used to test
your code. Of course you will need to make some test file(s) in your
directory in order to test it out! I also recommend you make some
smaller, simpler testing programs as you develop and debug your
interpreter.
Complete the yml file and submit using the commands at the top of this
page.
Part B: Numbers
Files for part B
Clone the git repo using the instructions above.
If you completed part A, you’re ready to go.
Otherwise, if you completed lab 4.2, copy your src/ directory from that lab into your
directory for this lab.
Otherwise — if you are starting here and didn’t complete lab 4.2 —
then run the provided ./get_src.sh script to download the starter code
from lab 4.2.
Either way, you should be starting with an interpreter for your language that does everything from the unit 3 labs (at least): strings, booleans, variables, if statements, and while loops.
Adding numbers to your language
For this part, you need to change your language and the interpreter to support numbers. Specifically, you need to support:
- Integer literals
- Printing numbers
- Reading numbers from the command line
- Saving numbers as variables
- Converting a number to a string
- Adding, multiplying, or subtracting two numbers
- Less-than comparison of two numbers
(Notice, division and mod are not included! Just the things on this list.)
Importantly, your changes must be backwards-compatible with the existing language, meaning that the programs we previously wrote in your language, without numbers should still work.
(And if you complete part A, those built-in functions should still work
as described there — the built-in plus function should still operate
on strings, not actual numbers.)
Here is a Python program (to estimate the square root of a given integer) that demonstrates the new features you need to add to your language and interpreter:
print("Enter a number")
target = int(input())
if target < 1:
print("Too small")
target = 1234
cur = 1
while cur*cur < target:
cur = cur + 1
prev = cur - 1
if target - prev*prev < cur*cur - target:
sqrt = prev
else:
sqrt = cur
print("Square root of " + str(target) + " is close to " + str(sqrt))
You need to fill in the empty file sqrt_prog with code in your
language which will do the equivalent to the code above.
Hints on adding numbers
In order to add support for numbers, you will need to:
-
Add some new tokens to
tokenSpec.txt. At the very least you will need a new token type for integer literals, and you may need to add more new tokens for some of the operators as well. -
Add new grammar rules to
Grammar.g4for the new kinds of statements and expressions you need to support numbers and the required operations -
Modify
Value.javaso that it supports an additional type (numbers/integers) besides strings and booleans -
Add new AST node definitions in
Expr.javaandStmt.javato support the new kinds of expressions and statements in your language -
Write new visit methods in
ASTGen.javato handle each of the new grammar rules you added, and create AST nodes from the parse tree nodes
Nothing you are being asked to do for this part is really “new”, in the sense that we have done all these things in previous interpreter labs in the semester. Essentially you have to do a little bit of what you did in all the previous interpreter labs, which hopefully can be a nice review of all the steps and pieces of your interpreter.
Testing your work
You need to write a program equivalent to the Python square root program above, in your language. Your program should really be line-by-line equivalent to that one, demonstrating the new number features in your language and how you chose to make them.
I also strongly recommend that you write some smaller, simpler programs to test each feature as you develop it. Like maybe start with a program that just prints an integer literal like 42 and try to get that working, then add the ability to add numbers, test it, etc. etc.
Once it works, complete the yml file and submit using the commands at the top of this
page.