# Code Generation II Lecture 12

## Review

### Quiz

Write the following SimpleC program as an equivalent C program.

```def iseven(x : int) -> bool {
if ((x) == ((x / 2) * 2)) {
return true;
} else {
return false;
}
}

def main() -> int {
in : int;
b : bool;

printString("Enter an integer: ");
in = readInt();
printString("\n");
printBool(iseven(in));
printString("\n");
return 0;
}
```

Assume that printString, printBool, and readInt are already declared and defined the resulting C program and that "stdbool.h" is already included.

### Quiz Discussion

• What is program equivalence?
• How can we demonstrate equivalence?

For turing machines, a general algorithm for checking equivalence would be impossible, since it could solve the halting problem.

But we could find a proof of equivalence for a particular program, e.g., by using the formal semantics to prove that the set of instructions always yields the same output.

Functional equivalence: the same inputs yield the same outputs for all inputs, regardless of how those outputs are computed.

What observable behaviors may not be equivalent even for functional equivalent programs?

## Examples

• How the store works
• The trick with conditionals and while
• How this works with while as well

### How to specify languages with pointers

• Separate the environment (maps symbols to location) from the store (maps locations to values)
• Variable assignment
```S, E |- <e> => v
l = E.lookup(x)
S' = {l: v}S
----------------------
S, E |- <x = e;> => S'

l = E.lookup(x)
v = S.get(l)
-----------------
S, E |- <x> => v

l = E.lookup(x)
-----------------
S, E |- <&x> => l

l = E.lookup(x)
p = S.get(l)
v = S.get(p)
-----------------
S, E |- <*x> => v
```

## Denotational semantics

```
[[ simplec syntax ]] ::= c syntax

// literals
[[ n ]] ::= n
[[ b ]] ::= b
[[ s ]] ::= s

// expressions
[[ op e ]]     ::= op [[e]]
[[ e1 op e2 ]] ::= [[e1]] op [[e2]]
[[ ( e ) ]]      ::= ( [[ e ]] )

// variables
[[ x: t; ]]  ::= [[ t ]] x ;
[[ x ]]      ::= x
[[ x = e; ]] ::= x = [[ e ]] ;

// control-flow and statements
[[ while e s ]]       ::= while [[ e ]] [[ s ]]
[[ if e s1 else s2 ]] ::= if [[ e ]] [[ s1 ]] else [[ s2 ]]
[[ if e s  ]]         ::= [[ if e s else { } ]]
[[ e ; ]]      ::= [[ e ]] ;
[[ { st* } ]]         ::= { [[ st* ]] }

// functions
[[ def f(fs) -> t { d* st* } ]] ::= [[ t ]] f ( [[ fs ]] ) { [[ d* ]] [[ st* ]] }
[[ return e; ]] ::= return [[ e ]] ;
[[ f(actuals) ]] ::= f ( [[ actuals ]] )

```

## Extending the language

```[[ for (e1; e2; e3) s  ]] ::= [[ e1; while e2 { s e3; } ]]
```

## Implementing semantics as a visitor

• `[[ e ]]` is like the call to `visit()`
• `[[ st* ]]` is like iterating over each element and calling `visit()`
• `[[ t ]]` depends on where it is used
• Visitors construct strings
```In the given Type.java API, these are already defined for =[[ t ]]=:
- getDeclarationType for declarations
- getAnonymousType for definitions
- getReferenceType for function arguments
```

## Example program

```def iseven(x : int) -> bool {
b : bool;
if ((x) == ((x / 2) * 2)) {
b = true;
} else {
b = false;
}
return b;
}
```

Looking at the parse tree, each node is constructing a string that represents the translation of the construct. Constructs that have child nodes are like a template where the child node's string fills in the placeholders. For example, `return true;`

```[[ return e ; ]] ::= return [[ e ]] ;
[[ true ]]       ::= true ;
```

## Prologue

```@Override
public String visitProgram(GrammarParser.ProgramContext ctx) {
// TODO: also support adding a prologue to the output and/or make simpleh headers for them (probably needed in order to get type checker to work)
// emit the stdbool header for the bool type
StringBuilder sb = new StringBuilder();
sb.append("#include \"stdbool.h\"\n");
sb.append("#include \"malloc.h\"\n");
sb.append("int printInt(int);\n");
sb.append("int printBool(bool);\n");
sb.append("int printString(char *);\n");
sb.append("int readInt();\n");
sb.append("bool readBool();\n");
sb.append("char * readString();\n");
for (GrammarParser.ToplevelContext tctx : ctx.toplevel()) {
sb.append(visit(tctx));
}
return sb.toString();
}
```

## Getting type names

```@Override
public String visitDef(GrammarParser.DefContext ctx) {
StringBuilder sb = new StringBuilder();
String name = ctx.ID().getText();
assert scope.hasSymbol(name);  // guaranteed by typechecker
Type type = scope.getSymbol(name);
assert type instanceof Type.FunctionType;  // guaranteed by typechecker
Type.FunctionType funType = (Type.FunctionType) type;
sb.append("\n");
sb.append(funType.returnType.getAnonymousType());
sb.append(" ");
sb.append(name);
sb.append("(");
assert scope.hasScope(name);  // guaranteed by typechecker
scope = scope.getScope(name);
if (null != ctx.formalParams()) {
String delim = "";
for (GrammarParser.FormalParamContext formalParam : ctx.formalParams().formalParam()) {
String paramName = formalParam.ID().getText();
assert scope.hasSymbol(paramName);  // guaranteed by typechecker
Type paramType = scope.getSymbol(paramName);
sb.append(delim);
sb.append(paramType.getReferenceType(paramName));
delim = ", ";
}
}
sb.append(")");
sb.append(" ");
sb.append("{");
sb.append("\n");
for (GrammarParser.DeclContext dctx : ctx.decl()) sb.append(visit(dctx));
for (GrammarParser.StmtContext sctx : ctx.stmt()) sb.append(visit(sctx));
scope = scope.getParent();
sb.append("}");
sb.append("\n");
return sb.toString();
}

@Override
public String visitDecl(GrammarParser.DeclContext ctx) {
StringBuilder sb = new StringBuilder();
String name = ctx.ID().getText();
assert scope.hasSymbol(name);  // guaranteed by typechecker
Type type = scope.getSymbol(name);
sb.append(type.getDeclarationType(name));
sb.append(";");
sb.append("\n");
return sb.toString();
}
```

## The implementation

### Relevant skeleton files

• `src/simplec/CodeGen.java`
• You implement this for your project
• Visitors for each grammar construct

### Building and running your compiler

```# from root of your repository
source configure.sh
cd src/simplec
make
java Compiler ../../tests/example.simplec | tee ../../tests/example.c
gcc -o ../../tests/example.bin ../../tests/example.c ../../runtime/io.c
echo "432" | ../../tests/example.bin
```

If "make" fails, be sure you have ANTLR in your CLASSPATH and PATH (which `source configure.sh` will do for you), check that you have no compilation errors in your `*.java` files, and be sure you are in the =src/simplec` directory.

Compiler will emit C code. Well compiling the C code, be sure to link it with io.c to provide definitions for the print and read functions. Execute the resulting binary as usual.

## Project

(2.5 weeks)

### Implement your code generator

• References to keep on hand
• Write test programs as you go
• Start from leaves of the grammar and simpler constructs in the grammar
• Build up to complex ones, once the child nodes are well-tested and working
• Assume the child nodes' are correct, and implement parent visitor on its own
• Submission instructions
• Submit your completed CodeGen.java with your git repo
• Submit your tests cases in your git repo
• Double-check that the compiler is buildable and runnable
• Run `make clean` and/or reclone your repo in another directory to build from scratch
• Double-check that all test cases have the expected output

Created: 2023-04-13 Thu 14:59