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;