Today:
Some rests from lecture 10 about type checking (ASU 6.1-6.3).
Intermediate code generation.
ASU 8.1-8.3. KP chapter 5.
Expr --> Expr1 ( Expr2 )Add function declarations to the declaration part, for example with the type syntax int -> int:
f : int -> int;Grammar for the function type:
f(7) + 3;
Type --> Type1 "->" Type2Translation scheme for the function type:
Translation scheme for type checking a function call:Type --> Type1 "->" Type2 { Type.type = function(Type1.type, Type2.type); }
Expr --> Expr1 ( Expr2 ) { if (Expr1.type == function(s, t) and Expr2.type == s) Expr.type == t; else Expr.type == type_error; }
More structural equivalence in C -- m1 and m2 have the same type:typedef int T1; typedef int T2; T1 t1; T2 t2; t1 = t2; // ok
Checking type equivalence:double m1[14][17]; double m2[14][17];
C uses structural equivalence for all types except records ("structs"):
This is to aviod cycles in the type representation:struct A { int foo; double fum; }; struct B { int blaj; double urko; }; struct A a; struct B b; a = b; // "incompatible types in assignment"
But note that TA1 and TA2 are the same type (since both are A):struct L { int foo; struct L* next; };
typedef struct A TA1; typedef struct A TA2; TA1 ta1; TA2 ta2; ta1 = ta2; // ok
Example: x + y * z
Note:temp1 = y * z temp2 = x + temp2
Postfix: a b - a b + -
Three-Address code:
Idea: Each internal node corresponds to a temp-variable!temp1 = a - b temp2 = a + b temp3 = temp1 - temp2
Example: a = b * -c + b * -c (The tree in Fig. 8.4a)
The DAG in Fig. 8.4b:temp1 = - c temp2 = b * temp1 temp3 = - c temp4 = b * temp1 temp5 = temp2 + temp4 a = temp5
temp1 = - c temp2 = b * temp1 temp5 = temp2 + temp4 a = temp5
param temp4 param a param b call f, 3
Production | Semantic rule |
---|---|
Start -> id = Expr | Start.code = Expr.code + { id.place ":=" Expr.place } |
Expr -> Expr1 + Expr1 | Expr.place = make_new_temp();
Expr.code = Expr1.code + Expr2.code + { Expr.place = Expr1.place "+" Expr2.place; } |
Expr -> Expr1 * Expr1 | Expr.place = make_new_temp();
Expr.code = Expr1.code + Expr2.code + { Expr.place = Expr1.place "*" Expr2.place; } |
Expr -> - Expr1 | Expr.place = make_new_temp();
Expr.code = Expr1.code + { Expr.place = "-" Expr1.place; } |
Expr -> ( Expr1 ) | Expr.place = Expr1.place; // No new temp!
Expr.code = Expr1.code; |
Expr -> id | Expr.place = id.place; // No temp!
Expr.code = ' '; // No code! |
While statement (very similar to generating stack machine code, see lecture 9);
Production | Semantic rule |
---|---|
Stmt -> while ( Expr ) Stmt1 |
Stmt.before = make_new_label();
Stmt.after = make_new_label(); Stmt.code = { "label" Stmt.before } + Expr.code + { "if" Expr.place "==" "0" "goto" Stmt1.after; } + Stmt1.code + { "goto" Stmt.before } + { "label" Stmt.after }; |
Op | Arg1 | Arg2 | result | |
---|---|---|---|---|
0 | uminus | c | temp1 | |
1 | * | b | temp1 | temp2 |
2 | uminus | c | temp3 | |
3 | * | b | temp3 | temp4 |
4 | + | temp2 | temp4 | temp5 |
5 | := | temp5 | a |
Skip: Also "triples" (but they are hard to optimize) and "indirect triples" (as easy to optimize as quadruples, but more complicated).