CSE 131B – Compiler Construction II Discussion 4: Project 1 1/31/2007
Overview • Arrays • Pointers • Records • Topics/Questions you may have
Array Declaration • Syntax: VAR List1 : ARRAY Index OF Type; VAR List2 : ARRAY Index OF ARRAY Index OF Type; • What to check in the declaration: • Index must be an INTEGER • Index > 0 (known at compile time ConstSTO)
Array Usage • Syntax: myArray[index]; myArray[index][index]; (myArray[index])[index]; (* notice how this still works *) • What to check: • myArray must be a variable (VarSTO) and of ArrayType • index must be equivalent to INTEGER
Multidimensional Arrays Given: VAR x : ARRAY 4 OFARRAY 3 OF INTEGER; a0 a1 a2 a3 b0 b1 b2 b0 b1 b2 b0 b1 b2 b0 b1 b2 Because of this, the following is valid: TYPE myArr = ARRAY 3 OF INTEGER; VAR x : ARRAY 4 OF myArr; VAR y : myArr; y := x; Remember: The result of an array element is ADDRESSIBLE
Implementation? • How can one encapsulate the information from the array declaration for later use? • Remember the Type Hierarchy: • One possibility is to store information such as elementType, dimSize. • In order to do this, you have to add these fields into the ArrayType definition and provide ways to set and read the information from them.
Further Analysis of Arrays VAR myArray : ARRAY 20 OF INTEGER; VAR x, y : INTEGER; BEGIN myArray[x] := myArray; myArray[x+2-y] := 15; myArray := 10; (* error, not assignment compatible *) END.
Pointer Declaration • Syntax: VAR x : POINTER TO Type; TYPE ptr = POINTER TO Type; VAR y : ptr; • What to check in the declaration: • Type must be a RECORD
Pointer Usage • Syntax: ptr. (* pointer dereference, like “ *ptr ” in C *) -- T_DOT NEW ptr; • What to check: • For a dereference (check 15), only things that are variables of pointer to records can be dereferenced. • For New (check 18), you must check to see if the argument is also of PointerType.
Further Analysis of Pointers TYPE ptr = POINTER TO RECORD a : REAL; END; VAR x, y : ptr; VAR z : REAL; BEGIN NEW x; (* like malloc, no actual allocation in Proj 1 *) x.a := 7; (* assign value of 7 into where x’s a field *) y := x; (* assign y to point where x points *) z := y.a; (* get y’s a field and put it into z *) END. Remember, no actual assignment of data here – that’s the next proj
Record Declaration • Syntax (think of C structs): VAR r : POINTER TO RECORD a, b : INTEGER; b : REAL; END; • What to check in the declaration: • Check for duplicate fields (field r.b in this case) • If a field is duplicated multiple times, an error is reported for each duplicate instance.
Record Usage • Syntax: myRec.myField • What to check: • myRec must be a VarSTO of some pointer to a record • myRec must contain the field (myField, in this case) • After checking, your result may be a VarSTO of the type of myField, since you want something ADDRESSIBLE
Further Analysis of Records TYPE rec = RECORD a, b : REAL; END; VAR myRec : POINTER TO rec; BEGIN myRec := myRec; (* fine – assignable pointers *) myRec.b := 3.6; (* assign 3.6 into b field *) myRec.a := myRec.b; (* assign b field into a field *) END.
Recursive Records • Recursive types are easily possible, since there will always be at least one POINTER type in a cycle. • When you encounter a Type declaration, you want that Type to be in scope immediately, even if you are not finished with the Type declaration (ie, it isn’t fully complete, but can still be referenced from the Symbol Table).
Recursive Record Examples TYPE linkedList = POINTER TO RECORD a : INTEGER; next : linkedList; END; TYPE rec = RECORD a : POINTER to rec; END;
Recursive Records • Think more about this – it is an important concept (not just for this class). • Some ideas: • Put a partially complete/empty TypeAliasSTO onto the SymTab before the actual type is know. • Have a stack of items that need to be re-checked at the end of the TypeDecl, and assume everything is fine until you reach the end of the declaration, then go through and re-check based on the stack.
Refresher on Type Equivalence • Remember the following rules: • All basic types use structural equivalence • Arrays and Records use strict name equivalence • Pointers use whatever the type they point to • Type aliases use loose name equivalence
Illustrative Example BEGIN i := m; (* okay, loose name equivalent *) i := r; (* error, not assignable *) r := i; (* okay, assignable *) f(r2); (* okay, same type *) f(r1); (* error, not strict name equivalent *) ff(r2); (* okay, same type *) ff(r1); (* error, not strict name equivalent *) g(a1); (* error, not strict name equivalent *) gg(a1); (* error, not strict name equivalent *) a1 := a1; (* okay, strict name equivalent *) a1 := a2; (* error, not strict name equivalent *) r1 := r1; (* okay, strict name equivalent *) r2 := p4; (* error, not strict name equivalent *) END. TYPE int = INTEGER; TYPE month = INTEGER; VAR i : int; VAR m : month; VAR r : REAL; TYPE rec = POINTER TO RECORD a : REAL; END; VAR r1 : POINTER TO RECORD a : REAL; END; VAR r2 : rec; FUNCTION f(VAR a : rec); (* ... *) END f; FUNCTION ff(a : rec); (* … *) END ff; VAR a1 : ARRAY 5 OF REAL; VAR a2 : ARRAY 5 OF REAL; FUNCTION g(a : ARRAY 5 OF REAL); (* ... *) END g; VAR p4 : POINTER TO RECORD a : REAL; END; For more info, see Appendix A of the Oberon spec
What to do Next! • Finish up Project 1! • Write more test programs to verify correctness. • Come to lab hours and ask questions.
Topics/Questions you may have • Anything else you would like me to go over now? • Anything in particular you would like to see next week?