CSC 330 Lecture Notes Week 4
Type Systems and Semantics
SymbolTable <>---------------------------------------* SymbolTableEntry ----------- ---------------- parent String name entries TreeNode type level ---------------- ----------- SymbolTableEntry SymbolTable(int) SymbolTableEntry( SymbolTable newLevel(FunctionEntry fe, int size) String name, TreeNode type) SymbolTableEntry lookup(String name) toString SymbolTableEntry lookupLocal(String name) ^ boolean enter(SymbolTableEntry) |-------------|----| SymbolTable ascend() | | SymbolTable descend(String name) | | void dump(SymbolTable st) VariableEntry FunctionEntry String toString(int level) ------------- ------------- boolean isRef TreeNodeList formals int memoryLoc TreeNode body SymbolTable scope
program var i,j,k: integer; begin i := j + k * 10; end.
int i,j,k; void main() { i = j + k * 10; }
PROGRAM BEGIN VAR i ; j ; k IDENT integer ASSMNT i PLUS j TIMES k 10 ; Level 0 Symtab Contents: Symbol: i, Type: IDENT, is ref: false, mem loc: 0 Symbol: k, Type: IDENT, is ref: false, mem loc: 0 Symbol: j, Type: IDENT, is ref: false, mem loc: 0
vardecl ::= VAR vars:vs COLON type:t {: RESULT = new TreeNode2(sym.VAR, vs, t); parser.enterVars(vs, t); :} ; vars ::= var:v {: RESULT = new TreeNodeList(v, null); :} | var:v COMMA vars:vs {: RESULT = new TreeNodeList(v, vs); :} ; var ::= identifier:i {: RESULT = i; :} ;
protected void enterVars(TreeNodeList vars, TreeNode type) { TreeNode node; TreeNodeList rest; boolean done = false; for (node = vars.node, rest = vars.siblings; !done; ) { symtab.enter(new VariableEntry( (String) (((LeafNode) node).value), type, false, 0)); if (rest == null) { done = true; } else { node = rest.node; rest = rest.siblings; } } }
procdecl : ph:prochdr SEMI b:block {: RESULT = ph; RESULT.child4 = b; symtab = symtab.newLevel( new FunctionEntry(ph.child1.value, ph.child3, ph.child2, b, null), PROC_SYMTAB_SIZE); :}
procdecl ::= ph:prochdr ';' b:block {: RESULT = ph; RESULT.child4 = b; parser.entry.body = b; symtab = symtab.ascend; :} prochdr ::= PROC identifier:i L_PAREN formals:fs R_PAREN COLON ident:rt {: RESULT = new TreeNode4(sym.PROC, i, fs, rt, null); :} symtab = symtab.newLevel(parser.entry = new FunctionEntry(i.value, rt, fs, null, null) parser.PROC_SYMTAB_SIZE); :}
******************** Running JFlex ******************** Reading "pascal.jflex" Constructing NFA : 194 states in NFA Converting NFA to DFA : 86 states before minimization, 81 states in minimized DFA Old file "PascalLexer.java" saved as "PascalLexer.java~" Writing code to "PascalLexer.java" ******************** Running Cup ******************** Opening files... Parsing specification from standard input... Checking specification... Warning: Terminal "UNY_PLUS" was declared but never used Warning: Terminal "UNY_MINUS" was declared but never used Building parse tables... Computing non-terminal nullability... Computing first sets... Building state machine... Filling in tables... *** Shift/Reduce conflict found in state #77 between ifstmt ::= IF expr THEN stmt (*) and ifstmt ::= IF expr THEN stmt (*) ELSE stmt under symbol ELSE Resolved in favor of shifting. Checking for non-reduced productions... Writing parser... Closing files... ------- CUP v0.10k Parser Generation Summary ------- 0 errors and 3 warnings 41 terminals, 33 non-terminals, and 70 productions declared, producing 121 unique parse states. 2 terminals declared but not used. 0 non-terminals declared but not used. 0 productions never reduced. 1 conflict detected (1 expected). Code written to "PascalParser.java", and "sym.java". ---------------------------------------------------- (v0.10k) ******************** Running the Test Program ******************** PROGRAM BEGIN VAR i ; j ; k IDENT integer ; VAR x ; y ; z IDENT real ASSMNT i 10 ; ASSMNT j 20 ; Level 0 Symtab Contents: Symbol: z, Type: IDENT, is ref: false, mem loc: 0 Symbol: y, Type: IDENT, is ref: false, mem loc: 0 Symbol: x, Type: IDENT, is ref: false, mem loc: 0 Symbol: i, Type: IDENT, is ref: false, mem loc: 0 Symbol: k, Type: IDENT, is ref: false, mem loc: 0 Symbol: j, Type: IDENT, is ref: false, mem loc: 0
PascalParserBuggy.java:696: cannot resolve symbol symbol : variable child1 location: class TreeNode RESULT = op; op.child1 = ^ PascalParserBuggy.java:697: cannot resolve symbol symbol : variable child2 location: class TreeNode e1; op.child2 = e2; ^ 2 errors
case 42: // expr ::= expr relop expr
gamma = {<i, 154>, <j, 155>}
mu = {}
gamma = {<i, INT, 154>, <j, INT, 155>}
mu = {}
tm = {<i, INT>, <j, INT>}
gamma = {<i, 154>, <j, 155>}
int i,j,k; float x,y; int f(float x, string s) { boolean b1,b2; int[10] a; float z; // ... } int[10] g() { int x,y; struct {int i; float j;} s; float z; // ... }
gamma= {<i, INT, 0>,
<j, INT, 1>
<k, INT, 2>
<x, FLOAT, 3>
<y, FLOAT, 4>
<f, INT,
{<x, FLOAT, 0>, <s, STRING, 1>},
{<b1, BOOLEAN, 2>, <b2, BOOLEAN, 3>,
<a, INT ARRAY[10], 4>, <z, FLOAT, 5>}
<g, INT,
{},
{<x, INT, 0>, <s, INT, 1>,
<s, STRUCT {<i, INT, 0>, <j FLOAT, 1>}, 2>
<z, FLOAT, 3>}
}
sigma = {<x, 1>, <y, 2>, <z, 3>}
gamma = {<x, INT, 0>, <y, INT, 1>, <z, INT, 1>}
mu = {<0, 1>, <1, 2>, <2, 3>}- This, in turn, is an abstract version of a concrete symbol table and memory:
Level 0 Symtab Contents: Symbol: y, Type: INT, mem loc: 1 Symbol: z, Type: INT, mem loc: 2 Symbol: main, Type: VOID Symbol: x, Type: INT, mem loc: 0 Memory Dump: Location 0: 1 Location 1: 2 Location 2: 3- And all of this traces to the following EJay and Pascal programs (which are equivalent semantically):
EJay:
int x,y,z;
void main () {
x = 1;
y = 2;
z = 3;
}
Pascal:
program
var x,y,z: integer;
begin
x := 1;
y := 2;
z := 3;
end.
- So, getting back to state transformations, the meaning of every PL construct can be defined in terms of its state transition effects.
- E.g., the meaning of assignment can be defined in terms of its affect on a particular program state.
- Specifically, the meaning is:
An assignment statement transforms a pre-assignment state into a post- assignment state where the bound value of the assigned variable is replaced by the value of the expression on the RHS of the assignment.- There's a less bulky notation for the preceding mouthful, coming right up.
- Consider the preceding state
sigma = {<x, 1>, <y, 2>, <z, 3>}and the assignment statementy = 2 * z + 3;
- The resulting transformed state is
sigma = {<x, 1>, <y, 9>, <z, 3>}- The value of 9 comes from computing the RHS expression in the pre-assignment state.
- In our simplified memory model, the semantics of assigning to a not-yet-bound variable has the effect of adding a binding to the pre-assignment state.
- E.g., consider the assignment statement
given the preceding value of sigmaW = 4- The resulting transformed state is
sigma = {<x, 1>, <y, 9>, <z, 3>, <w, 4>}- The less bulky notation referred to above uses an overriding union operator, denoted U-bar
- U-bar is defined for two sets X and Y as follows:
X U-bar Y = replace in X all bindings <x, v> whose first member matches a binding <x, w> in Y with <x, w>, and then add to X any additional bindings in Y that are not in X.
- E.g., if
sigma1 = {<x, 1>, <y, 2>, <z, 3>}andsigma2 = <y, 9>, <w, 4>},thensigma 1 U-bar sigma 2 = {<x, 1>, <y, 9>, <z, 3>, <w, 4>}
M: Assignment, Env, Store -> Env', Store'where e' = e and s' = s such that the value binding for var is replaced with the value of expr, i.e,
M("var = expr", e, s) = e', s'
int x,y,z; z = x + 2*y;