Grades and deadlines
-
Initial deadline: 23:59 on Monday 10 November
-
How to submit: Turn in your completed
lab4.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 -plab4.1 -f lab4.1.yml src/mainor
submit -c=si413 -p=lab4.1 lab4.1.yml src/main(you can download the club tool here)
If you used an AI tool to help with this lab (you should use Gemini), turn in a file
aichat.mdas well. Remember the course guidelines for the use of generative AI on labs. -
Grading:
In this lab you will complete the following tasks:
-
Design a new, original programming language that supports all features from the Unit 3 labs, plus first-class functions with lexical scope.
-
Write an example program and input/output test cases demonstrating clearly how your language works.
-
Write another program to match the behavior of the “dinner program” example given below.
-
Provide the full syntax of your language in the form of
tokenSpec.txtandParseRules.g4files, to correctly scan and parse any program in your language. -
Thoroughly test, then submit your code along with a completed YAML file
If your submission meets the requirements for each task, you will receive 7 points towards your total lab grade.
-
-
Collaboration
You can freely collaborate with any other students in SI413, as long as that collaboration is clearly documented and you all turn in a unique, original language spec.
-
Resubmissions:
We will follow the same resubmission policy for all labs this semester:
def points_earned(deadline, max_points, previous_submission=None): while current_time() < deadline: wait() submission = get_from_submit_system() if meets_all_requirements(submission): return max_points elif significant_progress(previous_submission, submission): return points_earned(deadline + one_week, max_points, submission) else: return 0
Getting started: files
Start by downloading the starter code. Running this command will create
a new directory lab4.1:
git clone https://github.com/si413usna/startlab.git -b lab4.1 lab4.1
In there you will find:
lab4.1.yml: for you to fill in and submit- Empty tokens and parser spec files in
src/main/resources/si413/tokenSpec.txtandsrc/main/antlr4/si413/ParseRules.g4that you will need to fill in - A Java program
ParseTreeGen.javathat will do scanning and parsing on an input source file you specify, then print out the full token stream and parse tree. run.sh: Helper script to run the parse tree generator
All you need to fill in for this lab are the YAML file, tokenSpec.txt,
and ParseRules.g4 files.
Task 1: Design your language
You need a language that supports all of the string and boolean operations from Unit 3, but now must additionally support functions with lexical scope and closures.
Your language must treat functions as first-class, so that they can be created within and returned from other functions, and passed as arguments, assigned to variables, and so on.
Your language should be original and should not look the same as existing languages, or other languages we have all used in previous weeks. (You can base it off a language you designed for a previous lab, as long as it wasn’t one of the ones chosen for everyone to use.)
Some of the choices you should think about are:
-
What do function definitions look like? Can we create “anonymous” (i.e. unnamed) functions with some kind of
lambdasyntax, or do you always have to give a function a name? -
What do function calls look like?
-
Will your language use static or dynamic typing?
(In the previous unit labs, we kind of “forced” you to have static typing because of the structure of the AST. But with functions, the typing gets more complicated, since you would also have to deal with the types of arguments and return values.)
-
Do functions always take exactly one argument, or do they allow any number of arguments?
(Note, there are a number of languages which demand every function takes exactly one argument. This can greatly simplify the function definition and function call syntax! You might want to look up the concept of currying.)
-
Do functions always need to return a value? If not, is it the same as returning some special value like
None, or something else? -
Within a function, how is the return value indicated? Is it just the last expression in the function, or does it have to be an explicit statement, or does it use a special variable assignment, or …?
Fill in the langauge_name and language_description fields in the
YAML file.
Task 2: Write the specs for your syntax
Fill in the tokenSpec.txt and ParseRules.g4 files with
(respectively) your formal token spec and ANTLR grammar.
In the starter code provided, it uses ANTLR to read in any source code file, and then (using the syntax specs that you write) print out the token stream and the parse tree for that source code. Use this to test out your syntax specs and the example programs you write!
For example, let’s say you have a test program in your language at
my-prog.txt. Then you could run
mvn compile
./run.sh my-prog.txt
and that should print out all the tokens in my-prog.txt according to
your tokenSpec.txt, and also display an ASCII art version of the
corresponding parse tree according to your ParseRules.g4.
Of course, if something is wrong with your tokens or grammar, you should pay attention to the error messages you see here!
Task 3: Write an example program.
Write a complete example program that demonstrates all the features of your language. Make good use of variable names, spacing, and comments so that your code is easily readable and understandable.
Be sure to feature how your function definitions and function calls work!
If this example program is done correctly, it should be self-documenting: anyone who looks at your example program should pretty much get the idea of how your language works without having to read anything else.
Fill in the example_program field,
as well as example_input1, example_output1,
example_input2, and example_output2, in the YAML file.
Make sure this works with the parse tree generator! When you submit your lab, we will check that the example program you wrote correctly tokenizes and parses using the spec you wrote from the previous part.
Task 3: Write the dinner program in your language
Here is a simple Python program that demonstrates the features your language should support:
def table_tracker(name):
first = True
total = ""
def order(food):
nonlocal first, total, name
print("Table " + name + " ordering " + food)
if first:
first = False
total = food
else:
total = total + ", " + food
return total
return order
def string_eq(s1, s2):
return not s1 < s2 and not s2 < s1
table1 = table_tracker("CS profs")
table1("Kimchi")
print("Your name?")
table2 = table_tracker(input())
done = False
t2got = "nothing"
while not done:
print("What do you want?")
food = input()
if string_eq(food, "done"):
done = True
else:
t2got = table2(food)
table1("Tteokbokki")
total1 = table1("Samgyeopsal")
print("We got " + total1 + " and you got " + t2got)
You need to write a program in your language which is exactly
equivalent to this one in terms of its run-time behavior.
That is, running your program in your (eventually) working interpreter,
should be the same as running the code above using the python3
interpreter.
Fill in the dinner_program field in the YAML file. You don’t need to
provide sample input/output pairs for this one.
Task 5: Test and submit
Be sure to test your own example programs with the parse tree generator using your own token spec and grammar. This is how you make sure that your syntax spec is correctly describing the language as you intended, and it will also help us get to work more quickly next week when we have to write an interpreter for some of these languages!
Follow the submit commands at the top of this page to turn everything in.