Q1: 1. struct declaration: struct name becomes class name. each struct field declaration follows the rules for variable declaration given below. 2. declaration of a variable of struct type (say, something like struct A x): - Translate it to "A x = new A()". - For each struct field fi of A (say of type struct Ti) --> - x.fi = new Ti(); // use the rule recursively. - for each int / pointer to struct field gi -- do nothing. 3. Declaring a variable of struct * type: struct A * x --> A x. 4. passing a struct variable (say x, of type struct T) as an argument: - Copy x to a new variable (say y, of type class T). - y = new T(); - y.gi = x.gi // for each non struct field gi. - for each struct field fi: recursively call this routine. - Pass y to the function. 5. Passing of a variable of struct * type: just call the function with the variable name. 6. Dereferencing struct fields: x.fi --> x.fi (remains unchanged) 7. Declaring a variable of int type: --> remains unchanged. 7. sizeof(x) --> If type of x is int/struct * --> 4 bytes (assuming sizeof(int) and sizeof(struct *X) is 4 bytes. Else --> Compute the sizeof the struct and emit the exact number. Q2: Lattice: \bot -> {Boolean, Int} -> \top Initialize: for all variables F(x) = \top Transfer functions: - variable declaration T1 x: F(x) = T1 \meet F(x) - copy: x = y // F(x) = F(x) \meet F(y) - copy: x = c // F(x) = F(x) \meet typeOf(c) - if-stmt and loop-stmts mainly introduce a join stmt. A use of a variable x is undefined - if F(x) = \bot. Initialize: for all variables F(x) = \top Transfer functions: - variable declaration T1 x: F(x) = T1 \meet F(x) - copy: x = y // If F(x) = \top F(x) = F(y); if F(x) != \bot if F(x) != F(y): Type mismatch - copy: x = c // If F(x) = \top F(x) = typeOf(c); if F(x) != \bot if F(x) != F(y): Type mismatch - if-stmt and loop-stmts mainly introduce a join stmt. A use of a variable x is undefined - if F(x) = \bot.