Grades and deadlines

Two Options

You have two options for how you will complete this lab:

Of course, it would be great if you want to take both options in a single interpreter! But we will only assign credit based on whichever option you indicate in the yaml file.

Option A: Builtins

(Skip down to Option B and ignore this section if you are taking that option.)

Getting started (files for option A)

Start by cloning the git repo corresponding to the language you used for the previous lab, by running one of these three commands:

# for EasyAs
git clone https://github.com/si413usna/startlab.git -b lab5.1-a-easyas lab5.1

# for Simple
git clone https://github.com/si413usna/startlab.git -b lab5.1-a-simple lab5.1

# for ddcw
git clone https://github.com/si413usna/startlab.git -b lab5.1-a-ddcw lab5.1

Go into the new directory and 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.

By contrast, from the programmer’s perspective built-in functions are exactly like any other function, just that the programmer didn’t have to define them.

Behind the scenes, when a user calls a built-in function, that should trigger some special interpreter code (i.e., code that you write in Java), to do whatever the function is supposed to do.

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
# then adds those numbers and returns the sum as another string.
def plus(num1, num2):
    return str(int(num1) + int(num2))

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 Interpreter.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 and submitting 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.

Submit your interpreter in the usual way, after completing the yml file:

Option B: Numbers

(Go back up to Option A and ignore this section if you are taking that option.)

Getting started (files for option B)

Start by cloning the git repo corresponding to the language you used for the previous lab, by running one of these three commands:

# for EasyAs
git clone https://github.com/si413usna/startlab.git -b lab5.1-b-easyas lab5.1

# for Simple
git clone https://github.com/si413usna/startlab.git -b lab5.1-b-simple lab5.1

# for ddcw
git clone https://github.com/si413usna/startlab.git -b lab5.1-b-ddcw lab5.1

The new directory has identical starter code to Lab 4.2. You do not need to implement functions for this lab, just numbers with variables, loops, and if statements. (If you have a working solution to that lab and want to start with your own code instead, then just replace the src/ directory with your working one from Lab 4.2.)

Adding numbers to your language

For this option, you need to change your language and the interpreter to support numbers. Specifically, you need to support:

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.

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))

Hints on adding numbers

In order to add support for numbers, you will need to:

Nothing you are being asked to do for this option 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 and submitting 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 this one, demonstrating the new number features in your language and how you chose to make them.

Submit your interpreter in the usual way, after completing the yml file: