Milestone 3, csc431, Spring 2018
1 Goal
The goal of the third milestone is to be feature-complete, adding while, structs, and closures.
2 While loops
While loops are similar to those in Java; a guard, that must evaluate to a boolean, precedes a body block.
3 Structures
Structures are similar to C, with a few key differences. Unlike C, all structure values are represented as pointers, so a declaration like
struct foo{ |
struct bar a; |
struct bar b; |
}; |
... will take eight bytes in memory, regardless of the size of the bar structure. (This is like Java.)
Using the new operator will allocate a new structure. Its values will not be initialized. Referring to a field before it has been assigned will result in undefined behavior (ugh).
You may implement the new operator in C, using malloc(). If malloc() returns null, the program must halt.
The null value is a legal value in any struct type.
4 Closures
In milestone 3, it’s legal to refer to bound variables in the environment, as long as those variables are not mutated anywhere in the program. So, this is a legal portion of a program:
fun addermaker (int x) (int -> int) { |
fun adder(int y) int {return x+y;} |
return adder; |
} |
fun addermaker (int x) (int -> int) { |
int z; |
z = x; |
fun adder(int y) int {return z+y;} |
return adder; |
} |
.. even though they might appear to produce the same result, because in this case, the z variable is mutated.
The idea here is to prevent us from having to deal with closing over mutable bindings, which requires a more extensive rewriting of the program.
5 Miscellaneous forms
There are miscellaneous other forms:
read: Programmers can write, e.g., z = read; to read an integer from stdin, terminated by any kind of whitespace or an eof. Leading whitespace on stdin must be ignored. If characters other than digits or whitespace appear on stdin, the program should halt. If an EOF occurs before a digit is seen, the program should also halt.
print: Programmers can write, e.g., print 3+4; to print an integer to stdout. An optional endl prints a newline after the number; otherwise, a space is printed after the number. The given expression must evaluate to an integer.
delete: This triggers a call to free().
You may implement all three of these using calls to C functions.
6 Miscellaneous removals
There are a few features that are in Professor Keen’s Mini language that we are leaving out. Generally speaking, these fall into the category of "convenient, but not changing the expressiveness of the language."
Here’s the list:
void functions: All functions must return a value. Programmers can just use false as a default return value.
invocations: A function call by itself is not a legal statement. If she wants to write something like this, a programmer may just introduce a dummy variable to receive the result.
top-level global variables: Sorry, no top-level variables. Programmers can always model these using internal functions and mutable structures.
blocks: You don’t need to support nested blocks.
7 Language Grammar
Here’s the grammar of the language:
| ‹program› | ::= | ‹type decl›* ‹function›* |
| ‹type decl› | ::= | struct ‹id› { {‹decl› ;}+ } ; |
| ‹decl› | ::= | ‹type› ‹id› |
| ‹type› | ::= | int | bool | ( ‹type›* -> ‹type› ) | struct ‹id› |
| ‹declaration› | ::= | ‹type› ‹id-list› ; |
| ‹id-list› | ::= | ‹id› {, ‹id›}* |
| ‹type-id-list› | ::= | ‹type› ‹id› {, ‹type› ‹id›}* |
| ‹function› | ::= | fun ‹id› ( [‹type-id-list›] ) ‹return type› { ‹function contents› } |
| ‹function-contents› | ::= | ‹declaration›* ‹function›* ‹statement›* |
| ‹return type› | ::= | ‹type› |
| ‹block› | ::= | { ‹statement›* } |
| ‹statement› | ::= | ‹assignment› | ‹print› | ‹conditional› |
|
| | | ‹loop› | ‹delete› | ‹ret› |
| ‹assignment› | ::= | ‹lvalue› = {‹expression› | read} ; |
| ‹print› | ::= | print ‹expression› [endl] ; |
| ‹conditional› | ::= | if ( ‹expression› ) ‹block› [else ‹block›] |
| ‹loop› | ::= | while ( ‹expression› ) ‹block› |
| ‹delete› | ::= | delete ‹expression› ; |
| ‹ret› | ::= | return ‹expression› ; |
| ‹invocation› | ::= | ‹id› ‹arguments› ; |
| ‹lvalue› | ::= | ‹id› {. ‹id›}* |
| ‹expression› | ::= | ‹eqterm› {{&& | ||} ‹eqterm›}* |
| ‹eqterm› | ::= | ‹boolterm› {{== | !=} ‹boolterm›}* |
| ‹boolterm› | ::= | ‹simple› {{< | > | <= | >=} ‹simple›}* |
| ‹simple› | ::= | ‹term› {{+ | -} ‹term›}* |
| ‹term› | ::= | ‹unary› {{* | /} ‹unary›}* |
| ‹unary› | ::= | {! | -}* ‹selector› |
| ‹selector› | ::= | ‹factor› {. ‹id›}* |
| ‹factor› | ::= | ( ‹expression› ) | ‹id› [‹arguments›] | ‹number› |
|
| | | true | false | new ‹id› | null |
| ‹arguments› | ::= | ( ) |
|
| | | ( ‹expression› {, ‹expression›}* ) |
8 Submitting your compiler
This time, we’re going to pair github submission with a demo.
8.1 Demo
During the lab on the due date, I’m going to be posting a set of example programs, and each team will demo their project running on the given example programs.
8.2 Github submission
Submit your code by pushing to a milestone-3 branch. Your README should specify which virtual machine you’re using, and how to build the project on the virtual machine. You must supply a consieuten executable that accepts an input file name and produces an executable named "a.out".
8.3 Grading rubric
Here’s the general breakdown of the points, as in earlier assignments:
Milestone 2: 8 points
Structs: 2 points
While: 2 points
Closures: 2 points
I/O features: 2 points