due: Friday, November 1
In this assignment you will implement code generation for the Cubex programming language.
Your submission has to have two parts:
cubex_lib.h
that you can #include
in your generated C file.out.c
(details below)We've decided not to burden you with reading a full semantics for the Cubex language. That means that you should implement the "obvious" semantics of statements, expressions, classes, interfaces, et cetera. (We place "obvious" in quotations because the correct mathematical formulation of those semantics is far from obvious!)
The nitty-gritty details:
We provided a small library and makefile that you have to use for your compiler.
The top-level execution of the compiled Cubex program should be triggered by a call to the function
cubex_main()
in out.c
. (cubex_main()
is forward-declared in
cubex_main.h
). The file out.c
should #include exactly three other files:
cubex_main.h
, cubex_external_functions.h
and cubex_lib.h
and be otherwise self-contained.
The only code allowed to run when a Cubex program is invoked is that in
out.c
and that in our provided library functions. A compiler breaking this rule intentionally
will get a 0.
Your output must adhere to the ANSI C90 standard and generate no warnings when run with -Wall.
Our provided header file will define the following functions:
void print_line(char* str, int len)
which prints len
characters starting at str. Note that this
means you should be using some String data structure that stores lengths, not
regular old null-terminated C strings!
-
int next_line_length()
which gets the length of the next input line. Returns 0 if
there are no more lines of input. (All input Strings will be guaranteed to be nonempty.)
-
void read_line(char* buffer)
which writes the next input line to the
buffer starting at buffer
, or is a no-op if the input is empty.
-
void* x3malloc(int size)
-
void x3free(void* ptr)
-
char unichar(int uni)
which returns an ASCII character given its unicode representation.
(We will not test any characters out of ASCII range.)
-
int charuni(char c)
which is the inverse of unichar
.
A few parts of the semantics are less than obvious. The following
constraints, along with the above directive to implement the obvious
semantics whenever such are available, should give you enough information to
complete this assignment. Of course, we reserve the right to add to this
list when we discover that we have (inevitably) left something out.
The initial variable input of type Iterable<String>
is
retrieved by successive calls to read_line
. Also, read_line should only be called when a line of input is actually needed.
For example, the generated program for:
return ["Hello","World!"]++input;
should print "Hello" and "World!" before calling read_line.
- The elements of the
Iterable<String>
returned at top-level should
be printed with print_line
.
- For all expressions e based on predefined operators (including ++), if the evaluation of the argument expressions
terminates, the evaluation of e should terminate (this may affect how you implement appending
of iterables.)
- The built-in constructor for
String
should not terminate if passed an infinite
Iterable
- You must employ a reasonable garbage collection strategy. Every block of allocated memory must be freed
before the program terminates (we will test this), and furthermore must be freed as soon as
it is no longer needed, or some short time thereafter (we will test this, also).
- You should generate code that will compile on both 32 and 64 bit systems.
- Do not worry about arithmetic overflow problems. We promise not to use
any grading tests that would overflow any reasonable implementation of Cubex
arithmetic with 32-bit ints.
Staging
This assignment will be graded in a staged mode, which means that you can concentrate on some parts of the
assignment and leave others out with a predictable loss of points. Our tests will be organized in the following
stages (same as PA3), meaning that programs only consist of the things in that stage and the preceding ones:
- Statements
- Non-generic functions
- Generic functions
- Non-Generic classes without inheritance
- Generic classes without inheritance
- Generic classes with single interface inheritance
- Generic classes with single interface inheritance + interface method implementations
- Generic classes with class inheritance
- Generic classes with multiple interface inheritance
Note: Any stage (including stage 1) may contain code related to Iterable, which
you have to handle to the fullest extent.
The distribution of tests to stages is identical to PA3:
80% of the tests will test programs in stages 1-3.
10% of the tests will test programs in stages 4 and 5.
10% of the tests will test programs in stages 6-9.
How to submit
You have to include the complete source code in the jar-file, including inputs for any lexer/parser generators you might use.
You will need a manifest file (MANIFEST.MF) that sets the classpath. Your manifest file should look like this:
Manifest-Version: 1.0
Class-Path: . antlr-4.1-complete.jar
Main-Class: [your-class-name-here]
The following code snippet does this packaging for you (.g4 is the file extension for ANTLR files).
jar cvfm x3c.jar MANIFEST.MF *.class *.java *.g4
The preamble file
Like the generated code, this file may only #include
the library files we provided.
You can use it to implement all data structures and functions common to all generated programs.
The text file
Finally, we ask that you submit a small text file (.txt) that contains the following information:
- Who you discussed the problem set with. Remember that the solution must be your own, but you can discuss
your ideas with others provided you mention that in this file.
- What the distribution of work in your team was like. Who did what?
- Any additional comments you might have about the problem set.
Source control
We recommend that you use some kind of source control. Be aware that your repositories should not be publicly viewable on the web. GitHub offers private repositories for students.
Testing
You should thoroughly test your solutions before turning them in. We provided some
basic test examples for you to play with, but keep in mind that we will
test your submissions with more complex examples, too. The way a test works is that after running
java -jar x3c.jar x3_test1.x3
make
cat x3_test.in | xargs ./a.out > x3_test1_actual.out
the content of x3_test1_actual.out should be equal to x3_test1.out .