Documente Academic
Documente Profesional
Documente Cultură
Lecture 01
Computer Laboratory
University of Cambridge
1
Compilation is a type of Translation
5
OCAML
http://caml.inria.fr/
Ocaml is a dialect of ML
Inferred type is
美しい日本の ML コンパイラ
Eijiro Sumii
Tohoku University
http://www.kb.ecei.tohoku.ac.jp/~sumii/
http://min-caml.sourceforge.net/
7
The MinCaml Language
A minimal functional language
8
Mind The Gap
let rec gcd m n = MinCaml
if m = 0 then n else
if m <= n then gcd m (n - m) else gcd n (m - n)
in print_int (gcd 21600 337500)
.section ".rodata"
.global min_caml_start
.align 8
min_caml_start:
.section ".text"
save %sp, -112, %sp
gcd.7:
set 21600, %i2
cmp %i2, 0
set 337500, %i3
bne be_else.19
Compile st %o7, [%i0 + 4]
nop
call gcd.7
mov %i3, %i2
add %i0, 8, %i0 ! delay slot
retl
sub %i0, 8, %i0
nop
ld [%i0 + 4], %o7
be_else.19:
st %o7, [%i0 + 4]
cmp %i2, %i3
call min_caml_print_int
bg ble_else.20
add %i0, 8, %i0 ! delay slot
nop
sub %i0, 8, %i0
sub %i3, %i2, %i3
ld [%i0 + 4], %o7
b gcd.7
ret
nop
restore
ble_else.20:
sub %i2, %i3, %i2
mov %i3, %o4
mov %i2, %i3 SPARC assember
mov %o4, %i2 9
b gcd.7
nop
A closer look at the Gap
The Compiler
Hardware
targeted
Program executable
Front-end Middle-end Back-end
Text code
Hardware independent
intermediate code INTERPRET!
Interpreter
(example: JVM) RUN!
Operating System
Something to Ponder:
A compiler is just a program.
But how did it get compiled?
Raw Metal
Is this a chicken-and-egg
problem? 12
The Shape of a Front End
13
The Shape of a “Middle End”
middle-end
Intermediate-Code
Parse Tree
Analysis of symbol Type Intermediate
definition and use. code
Checking Annotated generation
Annotated
Parse tree Parse tree
Assembly code
Back end
Intermediate
ARM code generation ARM code
code
Target?
SPARC code generation SPARC code
…
…
…
PDP-11 code generation PDP-11 code
15
Assembly, Linking, Loading
assembly
code file
assembly
code file
… assembly
code file
(main tasks)
From symbolic
…
names and
addresses to
assembler assembler assembler numeric codes
and numeric
…
addresses
Name
Object code linker resolution,
Link errors creation of
libraries single address
space
single executable object code file
RUN! Address
relocation,
Operating System memory
loader allocation,
dynamic
16
linking
Reading
21. Revi ew
18
Compiler Construction
Lecture 02
Lexical Analysis
Computer Laboratory
University of Cambridge
1
The Front-End
2
From Character Streams to Token Streams
lexer
T
FLOAT ID(match0) LPAREN CHAR STAR
O
ID(s) RPAREN LBRACE IF LPAREN BANG
K
ID(strncmp) LPAREN ID(s) COMMA STRING(0.0)
E
COMMA NUM(3) RPAREN RPAREN RETURN
N
REAL(0.0) SEMI RBRACE EOF
S
3
Note that white-space and comments have vanished!
Regular Sets
Notation:
(p)+ = ((p)* p)
5
Operations on Regular Expressions
a|b {a,b}
(a|b)(a|b) {aa, ab, ba, bb}
a* {e, a, aa, aaa, …}
a*b {b,ab, aab, aaab, …}
(a|b)* {e, a, b, ab, ba, aa, bb, ….
abbbabbab}
a*|b* {e, a, aa, aaa, …, b, bb, bbb…}
6
Finite Automata
Deterministic Finite Automaton (DFA)
M = (Q, ∑, δ, i , F)
where
(1) Q is a finite non-empty set of states
(2) ∑ is a finite set of input symbols
(3) i ∈Q (initial state)
(4) F ⊆ Q (final states)
(5) δ is a partial mapping from Q x ∑ to Q
(transition function: move function)
start 0 a 1 b 2 b 3
8
DFA Example
b b
a b
0 1 2 b 3
a
a
a
DFA:
• No state has an e-transition
• For each state S and input symbol a, there is at
most one edge labeled a leaving S. 9
Define Tokens with Regular Expressions (Finite
Automata)
Keyword: if
1 2 3
i f
1 2 3
i f
Σ-{f}
Σ-{i} Σ
“dead state” 0 Σ 10
Define Tokens with Regular Expressions (Finite
Automata)
Keyword: 1 2 3
i f KEY(IF)
if
Keyword: 1 2 3
then t h
KEY(then)
e
n
5 4
[a-zA-Z0-9]
Identifier: 1 2
[a-zA-Z] ID(s)
[a-zA-Z][a-zA-Z0-9]*
11
Define Tokens with Regular Expressions (Finite
Automata)
[0-9]
number: 1 2
[0-9] NUM(n)
[0-9][0-9]*
[0-9]
real: 1 2
[0-9] NUM(n)
([0-9]+ ‘.’ [0-9]*)
| ([0-9]* ‘.’ [0-9]+) .
[0-9]
. 3
4 [0-9]
5 12
[0-9]
No Tokens for “White-Space”
[A-za-z0-9’ ‘]
1 2
%
White-space: ‘‘ \n
(‘ ‘ | ‘\n’ | ‘\t’)+ \t
| ‘%’ [A-Za-z0-9’ ‘]+’\n’ 3
\n
13
Traditional Regular Language Problem
e
and an input string w, determine if w∈Le
.
14
What is the “lexing problem”?
e1 e2 … ek
and an input string w, find a partition
w=w 1 w 2 ...w n
such that for each wj there is a ei such that w j ∈L e i .
WHITE-SPACE
ifthen2006hello
??
LEX
??
ID(Ifthen2006hello)
ifthen2006hello
LEX
ID(Ifthen2006hello)
17
White-Space is NOT Ignored!
LEX
KEY(IF) KEY(THEN) NUM(2006) ID(hello)
ifthen2006hello
LEX
ID(Ifthen2006hello)
18
Constructing a Lexer
INPUT:
Construct all Construct a single Construct a single
an ordered
corresponding non-deterministic deterministic
list of regular
finite automata finite automata finite automata
expressions
e1 NFA 1
e2 NFA 2
use priority NFA DFA
…
ek NFA k
1 2:ID 3:ID
t h
(1) Keyword : then
z]
e
[a-su
gi-
‘‘
f-z]
[a-
(2) Ident : [a-z][a-z]* - d 4:ID
-z] [a
(2) White-space: ‘ ‘ 7:W - m o -z]
6:ID [a n
[a [a-z] 19
-z 5:THEN
]
What about longest match?
e
[a-su
gi-
z]
‘‘ then |thenx$ 7 7
f-
[a-
e1 e2 … ek
and an input string w, find a list of pairs
Source Lexical
tokens Parser
Program Analyzer
DFA Transitions
Ordered List of Scanner
Regular Expressions Generator
“LEX”
24
(some of the) OCAML Lexical Classes
Maximum ID Length?
letter ::= A … Z | a … z Every implementation
will have a limit. Ocaml’s is
ident ::= (letter | _) { letter | 0…9 | _ | ' } 16,000,000 characters
and as assert asr begin class constraint do done downto else end
exception external false for fun function functor if in include inherit
initializer land lazy let lor lsl lsr lxor match method mod module
mutable new object of open or private rec sig struct then to true
try type val virtual when while with
Computer Laboratory
University of Cambridge
1
CFG Example
E ::= ID
E ::= NUM
E is a non-terminal symbol
E ::= E * E
ID and NUM are lexical classes
E ::= E / E
*, (, ), +, and – are terminal symbols.
E ::= E + E
E ::= E + E is called a production rule.
E ::= E – E
E ::= ( E )
E E*E
E
+
E E
- E
( E )*E Leftmost
(E +E)*E derivation 17 4 2 10
( 17 + E ) * E
( 17 + 4 ) * E
( 17 + 4 ) * ( E )
( 17 + 4 ) * ( E – E ) The Derivation Tree for
( 17 + 4 ) * ( 2 – E ) ( 17 + 4 ) * (2 – 10 )
( 17 + 4 ) * ( 2 – 10 )
3
More formally, …
5
L(G) = The Language Generated by Grammar G
6
Ambiguity
E E
E E E
* E
+
E E E E
+ 3 1 *
1 2 2 3
Both derivation trees correspond to the string
1+2*3
(G2) E
S :: = E$ (start, $ = EOF)
E ::= E + T (expressions)
E
+ T
| E–T T F
| T
1 *
F 3
T ::= T * F (terms)
| T/F
| F 2
1 + 2 * 3$
Note: L(G1) = L(G2). 8
Can you prove it?
Famously Ambiguous
What does
mean?
S OR S
9
Rewrite?
(G4)
S ::= WE | NE
WE ::= if E the n WE else WE | bla h-b lah
NE ::= if E the n S
| if E the n WE else NE
Now, S
if E then S
WE
(1) Some context free languages are inherently ambiguous --- every
context-free grammar will be ambiguous. For example:
{a b c d } {a b c d ∣m≥1, n≥1}
n n m m n m m n
L= ∣m≥1, n≥1 ∪
repeat
for each production X Y1 Y2 … Yk
if Y1, … Yk are all nullable, or k = 0
then nullable[X] := true
for each i from 1 to k, each j from i + I to k
if Y1 … Y(i-1) are all nullable or i = 1
then FIRST[X] := FIRST[X] union FIRST[Y(i)]
if Y(i+1) … Yk are all nullable or if i = k
then FOLLOW[Y(i)] := FOLLOW[Y(i)] union FOLLOW[X]
if Y(i+1) … Y(j-1) are all nullable or i+1 = j
then FOLLOW[Y(i)] := FOLLOW[Y(i)] union FIRST[Y(j)] 15
until there is no change
Eliminating Left Recursion
Note that
(G6)
E ::= T and
S :: = E$
E ::= E + T
will cause problems
E ::= T E’
since FIRST(T) will be included
(G2)
in FIRST(E + T) ---- so how can
S :: = E$ E’ ::= + T E’
we decide which poduction
| – T E’
To use based on next token?
E ::= E + T |
| E–T
Solution: eliminate “left recursion”!
| T T ::= F T’
E ::= T E’
T ::= T * F T’ ::= * F T’
| T/F | / F T’
E’ ::= + T E’
| F |
|
F ::= NUM F ::= NUM
| ID | ID
|(E) Eliminate left recursion |(E)
16
First, Follow, nullable table for G6
(G6)
S :: = E$
Nullable FIRST FOLLOW
E ::= T E’
S False { (, ID, NUM } {}
E’ ::= + T E’
E False { (, ID, NUM } { ), $ } | – T E’
|
E’ True { +, - } { ), $ }
T ::= F T’
T False { (, ID, NUM } { ), +, -, $ }
T’ ::= * F T’
T’ True { *, / } { ), +, -, $ } | / F T’
|
F False { (, ID, NUM } { ), *, /, +, -, $ }
F ::= NUM
| ID
|(E)
17
Predictive Parsing Table for G6
Table[ X, T ] = Set of productions NOTE: this could
lead to more than
X ::= Y1…Yk in Table[ X, T ] one entry! If so, out
of luck --- can’t do
if T in FIRST[Y1 … Yk] recursive descent parsing!
or if (T in FOLLOW[X] and nullable[Y1 … Yk])
+ * ( ) ID NUM $
S S ::= E$ S ::= E$ S ::= E$
S E$ E$
T E’$ T E’$
F T’ E’$ F T’ E’$
( E ) T’ E’$ ( E ) T’ E’$
( T E’ ) T’ E’$ ( T E’ ) T’ E’$
( F T’ E’ ) T’ E’$ ( F T’ E’ ) T’ E’$
( 17 T’ E’ ) T’ E’$ ( 17 T’ E’ ) T’ E’$
( 17 E’ ) T’ E’$ ( 17 E’ ) T’ E’$
( 17 + T E’ ) T’ E’$ ( 17 + T E’ ) T’ E’$
( 17 + F T’ E’ ) T’ E’$ ( 17 + F T’ E’ ) T’ E’$
( 17 + 4 T’ E’ ) T’ E’$ ( 17 + 4 T’ E’ ) T’ E’$
( 17 + 4 E’ ) T’ E’$ ( 17 + 4 E’ ) T’ E’$
( 17 + 4 ) T’ E’$ ( 17 + 4) T’ E’$
( 17 + 4 ) * F T’ E’$ ( 17 + 4)* F T’ E’$
… …
… …
( 17 + 4 ) * ( 2 – 10 ) T’ E’$ ( 17 + 4 ) * ( 2 – 10 ) T’ E’$
( 17 + 4 ) * ( 2 – 10 ) E’$ ( 17 + 4 ) * ( 2 – 10 ) E’$
( 17 + 4 ) * ( 2 – 10 ) ( 17 + 4 ) * ( 2 – 10 )
20
Compiler Construction
Lecture 04
LR Parsing --- PART I
Computer Laboratory
University of Cambridge
1
But wait! What if there are conflicts in
the predictive parsing table?
(G7) Nullable FIRST FOLLOW
X ::= Y | a
X true { c,a } { c, a,d }
a c d
Most programming
languages have
grammars in
LALR(1)
(G8)
S :: = S ; S | ID = E | print (L)
L ::= E | L, E
L ::= E | L COMMA E
5
A Right-most derivation …
S
(G8) S;S
S ; ID = E
S ::= S ; S S ; ID = E + E
S ; ID = E + ( S, E )
| ID = E
S ; ID = E + ( S, ID )
| print (L) S ; ID = E + ( S, d )
S ; ID = E + ( ID = E, d )
E ::= ID S ; ID = E + ( ID = E + E, d )
| NUM S ; ID = E + ( ID = E + NUM, d )
|E+E S ; ID = E + ( ID = E + 6, d )
| (S, E) S ; ID = E + ( ID = NUM + 6, d )
S ; ID = E + ( ID = 5 + 6, d )
S ; ID = E + ( d = 5 + 6, d )
L ::= E
S ; ID = ID + (d = 5 + 6, d )
| L, E S ; ID = c + ( d = 5 + 6, d )
S ; b = c + ( d = 5 + 6, d )
ID = E ; b = c + ( d = 5 + 6, d )
ID = NUM ; b = c + ( d = 5 + 6, d)
ID = 7 ; b = c + ( d = 5 + 6, d )
a = 7 ; b = c + ( d = 5 + 6, d )
6
Now, turn it upside down …
a = 7 ; b = c + ( d = 5 + 6, d )
ID = 7 ; b = c + ( d = 5 + 6, d )
ID = NUM; b = c + ( d = 5 + 6, d )
ID = E ; b = c + ( d = 5 + 6, d )
S ; b = c + ( d = 5 + 6, d )
S ; ID = c + ( d = 5 + 6, d )
S ; ID = ID + ( d = 5 + 6, d)
S ; ID = E + ( d = 5 + 6, d )
S ; ID = E + ( ID = 5 + 6, d )
S ; ID = E + ( ID = NUM + 6, d )
S ; ID = E + ( ID = E + 6, d )
S ; ID = E + ( ID = E + NUM, d )
S ; ID = E + ( ID = E + E, d )
S ; ID = E + ( ID = E, d )
S ; ID = E + ( S, d )
S ; ID = E + ( S, ID )
S ; ID = E + ( S, E )
S ; ID = E + E
S ; ID = E
S;S 7
S
Now, slice it down the middle…
a = 7 ; b = c + ( d = 5 + 6, d )
ID = 7 ; b = c + ( d = 5 + 6, d )
ID = NUM ; b = c + ( d = 5 + 6, d )
ID = E ; b = c + ( d = 5 + 6, d )
S ; b = c + ( d = 5 + 6, d )
S ; ID = c + ( d = 5 + 6, d )
S ; ID = ID + ( d = 5 + 6, d )
S ; ID = E + ( d = 5 + 6, d )
S ; ID = E + ( ID = 5 + 6, d )
S ; ID = E + ( ID = NUM + 6, d )
S ; ID = E + ( ID = E + 6, d )
S ; ID = E + ( ID = E + NUM , d )
S ; ID = E + ( ID = E + E , d )
S ; ID = E + ( ID = E , d )
S ; ID = E + ( S , d )
S ; ID = E + ( S, ID )
S ; ID = E + ( S, E )
S ; ID = E + E
S ; ID = E
S ; S
S
The rest of the input string
A stack of terminals and
non-terminals 8
Now, add some actions. s = SHIFT, r = REDUCE
a=7; b = c + ( d = 5 + 6, d ) s
ID =7; b = c + ( d = 5 + 6, d ) s, s
ID = NUM ; b = c + ( d = 5 + 6, d ) r E ::= NUM
ID = E
; b = c + ( d = 5 + 6, d ) r S ::= ID = E
S
S ; ID ; b = c + ( d = 5 + 6, d ) s, s
S ; ID = ID = c + ( d = 5 + 6, d ) s, s
S ; ID = E + ( d = 5 + 6, d ) r E ::= ID
S ; ID = E + ( ID + ( d = 5 + 6, d ) s, s, s
S ; ID = E + ( ID = NUM = 5 + 6, d ) s, s
S ; ID = E + ( ID = E + 6, d ) r E ::= NUM
S ; ID = E + ( ID = E + NUM + 6, d ) s, s
S ; ID = E + ( ID = E + E
,d) r E ::= NUM
S ; ID = E + ( ID = E
S ; ID = E + (S ,d) r E ::= E+E, s, s
S ; ID = E + ( S, ID ,d) r S ::= ID = E
S ; ID = E + ( S, E ) ) R E::= ID
S ; ID = E + E ) s, r E ::= (S, E)
S ; ID = E r E ::= E + E
S;S r S ::= ID = E
S r S ::= S ; S
SHIFT = LEX + move token to stack 9
ACTIONS
Q: How do we know when to shift and
when to reduce? A: Build a FSA from
LR(0) Items!
(G10) S ::= • A $
S ::= A • $
S : := A $
A ::= • (A)
A :: = ( A ) A ::= ( • A )
| ( ) A ::= ( A • )
A ::= ( A ) •
If
A ::= • ( )
X ::= αβ
A ::= ( • )
is a production, then A ::= ( ) •
LR(0) items indicate what is on the stack
X ::= α • β (to the left of the • ) and what is still in
the input stream (to the right of the • )
is an LR(0) item. 10
Key idea behind LR(0) items
11
The NFA for LR(0) items
12
Example NFA for Items
S :: = • A $ S : := A • $ A ::= • (A)
A ::= ( • A ) A ::= ( A • ) A ::= ( A) •
A ::= • ( ) A ::= ( •) A ::= ( ) •
A
S ::= • A $ S ::= A • $ A ::= (A) •
ε ε )
( A
A ::= • (A ) A ::= ( • A ) A ::= ( A • )
ε
( )
A ::= • ( ) A ::= ( • ) A ::= ( ) •
13
The DFA from LR(0) items
• After the NFA for LR(0) is constructed, the resulting DFA
for LR(0) parsing can be obtained by the usual
NFA2DFA construction.
• we thus require
– ε-closure (I)
– move(S, a)
17
Building the DFA states
18
DFA Example
s1
A S ::= A • $
s0
S ::= • A$ s2
A ::= • (A) A ::= ( • A) (
A ::= ( • )
A ::= • ( ) ( A ::= • (A)
s3
A ::= (A • )
A ::= • ( )
A
) )
s5 s4
A ::= ( ) • A ::= (A) •
19
Building
CreatingParse TableTable(s)
the Parse Example
State ( ) $ A
s0 shift to s2 goto s1
(G10)
s1 accept
• S ::=
s2 shift to s2 shift to s5 goto s3
A$
s3 shift to s4
• A ::= (A
) s4 reduce (2) reduce (2) reduce (2)
s5 reduce (3) reduce (3) reduce (3)
• A ::= (
) s1
A S ::= A • $
s0
S ::= • A$ s2
A ::= • (A) A ::= ( • A) (
A ::= ( • )
A ::= • ( ) ( A ::= • (A)
s3
A ::= (A • )
A ::= • ( )
A
) )
s5 s4
A ::= ( ) • A ::= (A) • 20
Parsing with an LR Table
If action is
shift sn : advance input one token,
push sn on stack
reduce X ::= α : pop stack 2* |α| times (grammar symbols
are paired with states). In the state
now on top of stack,
use goto table to get next
state sn,
push it on top of stack
accept : stop and accept
error : weep (actually, produce a good error
message)
21
Building Parse Table
Parsing, Example
again…
ACTION Goto
(G10) State ( ) $ A
• S ::= s0 shift to s2 goto s1
A$ s1 accept
• A : := (A s2 shift to s2 shift to s5 goto s3
) s3 shift to s4
• A : := ( s4 reduce (2) reduce (2) reduce (2)
) s5 reduce (3) reduce (3) reduce (3)
s0 (())$ shift s2
s0 ( s2 ())$ shift s2
s0 ( s2 ( s2 ))$ shift s5
s0 ( s2 ( s2 ) s5 )$ reduce A ::= ()
s0 ( s2 A )$ goto s3
s0 ( s2 A s3 )$ shift s4
s0 ( s2 A s3 ) s4 $ reduce A::= (A)
s0 A $ goto s1
s0 A s1 $ ACCEPT! 22
LR Parsing Algorithm
Stack of
a1 ... ai ... an $ input
states and
grammar symbols
sm
Ym LR Parsing output
Algorithm
sm-1
Ym-1
. Action Table Goto Table
terminals and $ non-terminal
. s
t four different
s
t each item is
a actions a a state
s1 t t number
e e
Y1 s s
23
s0
Compiler Construction
Lecture 05
LR Parsing --- PART II
Computer Laboratory
University of Cambridge
1
Problem With LR(0) Parsing
• No lookahead
• Vulnerable to unnecessary
conflicts
– Shift/Reduce Conflicts (may reduce
too soon in some cases)
– Reduce/Reduce Conflicts
• Solutions:
– LR(1) parsing - systematic lookahead
2
LR(1) Items
Closure(Items) =
repeat
for each [X ::= α.Yβ, a] in Items
for each production Y ::= γ
for each b in First(βa)
add [Y ::=.γ, b] to Items
until Items is unchanged
4
Constructing the Parsing DFA (2)
Transition(s, Y)
Items ={}
for each [X ::= α.Yβ, b] in s
add [X ! αY.β, b] to Items
return Closure(Items) 6
LR(1)-the parse table
7
LR(1)-DFA
(G11)
S’ ::= S$
S ::= V = E
|E
E ::= V
V ::= x
| *E
x * = $ S E V x * = $ S E V
1 s8 s6 g2 g5 g3 8 r4 r4
2 acc 9 r1
3 s4 r3 10 r5 r5
4 s11 s13 g9 g7 11 r4
5 r2 12 r3 r3
7 r3 14 r5
9
LALR States
11
LALR(1)-parse-table
x * = $ S E V
1 s8 s6 g2 g5 g3
2 acc
3 s4 r3
4 s8 s6 g9 g7
5
6 s8 s6 g10 g7
7 r3 r3
8 r4 r4
9 r1
10 r5 r5
12
LALR vs. LR Parsing
http://catalog.compilertools.net/lexparse.html
ACCENT HAPPY
AFLEX AYACC HOLUB
ALE LEX
ANAGRAM LLGEN
BISON PCYACC
BISON/EIFFEL PRECC
BTYACC PROGRAMMAR
BYACC RDP
COGENCEE VISUALPARSE++
COCO YACC
DEPOT4 YACC++
FLEX …
15
parser.mly
%token <int> INT
%token <string> IDENT
%token PLUS MINUS TIMES DIV
%token LPAREN RPAREN
%token EOF
%left PLUS MINUS /* lowest precedence */
%left TIMES DIV /* medium precedence */
%nonassoc UMINUS /* highest precedence */
%start parse_it /* the entry point */
%type <ast> parse_it
%%
parse_it:
expr EOF { $1 }
;
expr:
INT { Number($1) }
| IDENT { Ident($1) }
| LPAREN expr RPAREN { $2 }
| expr PLUS expr { Binary(PlusOp, $1, $3) }
| expr MINUS expr { Binary(MinusOp, $1, $3) }
| expr TIMES expr { Binary(TimesOp, $1, $3) }
| expr DIV expr { Binary(DivOp, $1, $3) }
| MINUS expr %prec UMINUS { Unary(UnaryMinusOp, $2) }
;
ocamlyacc parser.mly parser.ml 16
(in this case producing a 21-state DFA)
lexer.mll
let ast_of_string s =
let lexbuf = Lexing.from_string s in
parse_it tokenize lexbuf
18
Concrete vs. Abstract Syntax Trees
parse tree = S
derivation tree =
S + E
concrete syntax
tree E 5 Abstract Syntax Tree (AST)
( S ) +
+ 5
S + E
+ +
S+E (S)
E 2 S+E 1 2 3 4
1 E 4 An AST contains only the
information needed to generate an
3 intermediate representation
Computer Laboratory
University of Cambridge
1
LL(k) vs. LR(k) reductions
A β ⇒ w ' β ∈ T ∪N , w '∈T
¿ ¿ ¿
LLk LRk
w' w'
k token look
k token look ahead
ahead
A β (left-most
symbol at
(right-most
symbol at
β A
top) top)
Stack Stack
with
βa1 a2 ⋯ak ⇒ w ' ¿
3
Compiler Construction, Revised
• Overvi ew
• Le xical An alys is
• The ory of Con te xt Fr ee
January 2007 Gra mma rs ( CF Gs) and P red ictive front-end
M T W T F S S (re cur siv e d esce nt ) P ar sing
1 2 3 4 5 6 7 • LR P arsi ng I
• LR P arsi ng I I
8 9 10 11 12 13 14
• LR P arsi ng I II
15 16 17 18 19 20 21 • Var iab les, S cop e, T ypes
22 23 24 25 26 27 28 • Sta ck Mac hin e
29 30 31 • Pro ce dur es , F un ct ions I middle-end
• Pro ce dur es , F un ct ions I I
February 2007 • Reg is te r Ma chine & Min Ca ml
mid dle-e nd
M T W T F S S
1 2 3 4 • Assemb ly c ode , lin ke r, loa de r back-end
5 6 7 8 9 10 11 • Cod e Gen er at ion
12 13 14 15 16 17 18 • Min Ca ml ba ck -en d
19 20 21 22 23 24 25
26 27 28 • Garb ag e Co llec tio n Special
• Objec t O rien ta tion topics
• Inte rp re te rs , By te Co de
inte rp re te rs, vir tu al ma ch in es
• Revi ew
4
Names, binding, scope, type checking
static int x = 17;
(in C) x = x + 3;
An L-values may be
determined at run-time:
A[j*2] = j + 3;
7
Binding
8
Dynamic binding is just a BAD IDEA
let a = 1
let f() = a
let g(a) = f()
print g(2)
1 2
Although dynamic scoping is easier to implement, reading and
understanding code can be nearly impossible.
9
Types and Type Errors
x = “this” + 3;
If we can prove that g(x) is always true, then is will never go wrong!
But that might be too much to ask for a (static) type checking system, since
This looks like a undecidable problem…
11
Type Systems
• A language’s type system specifies how to construct
types and which operations are valid for which types
• Type systems provide a concise formalization of the
semantic checking rules
• Type systems can be thought of as a logic in which
some very weak assertions can be proved automatically.
12
Another way to think of types as a logic…
Logic Typing
H |- A H |- a : A
axioms
------------- --------------------
H, A |- A H, x:A |- x : A
13
Conjunction and Pairing
Typing rules
Logical rules
H |- a : A H |- b : B
H |- A H |- B --------------------------------------
-------------------------------------- H |- (a, b) : A * B
H |- A * B
H |- p : A*B H |- p : A*B
H |- A*B H |- A*B -------------------- --------------------
-------------------- -------------------- H |- fst(p) : A H |- snd(p) : B
H |- A H |- B
14
Implication and function types.
Typing rules
Logical rules
H, A |- B
---------------- H, x:A |- e:B
H |- A B --------------------------------
H |- fun x:A.e :A B
H |- AB H |- A
--------------------------------- H |- f: AB H |- a: A
H |- B ---------------------------------------
H |- f(a) : B
15
Disjunction and Case Switch.
Logical rules
Typing rules
H |- a:A H |- b:A
-------------------------- --------------------------
H |- inr(a) : A || B H |- inl(b) : A || B
Has type
((A C) || (B C)) (A*B) C
This is a generalization of De Morgan’s rule Think of ¬A
¬A∨¬B ¬ A∧B as
A false
and then replace
false by C
Can this same thing be done with all of De Morgan’s
other three rules? Yes? No?
17
Compiler Construction
Lecture 08
Stack Machine
Computer Laboratory
University of Cambridge
1
SLANG: A (S)imple (LANG)uage (v0.1)
type name = string
2
SLANG example, with AST
fun f(y, x)
{
let z = 17;
return z * (y + x);
}
let x = 19;
let y = 10;
Slang
([Fun ("f", ["y"; "x"], [Var ("z", Number 17)],
Return
(Binary (TimesOp, Ident "z",
Binary (PlusOp, Ident "y", Ident "x"))));
Let ("x", Number 19); Let ("y", Number 10)],
Binary (TimesOp, Number 20,
Binary (MinusOp, Apply ("f", [Ident "x"; Ident "y"]),
Apply ("f", [Ident "y"; Ident "x"]))))
3
We will translate SLANG to JARGON
Intermediate
Representation
Jargon is my own
Invented abstract STACK
machine…
4
Jargon Virtual Machine (v0.1)
grows
stack sp shrinks
pointer
frame fp Stack
pointer
Four
special-purpose
“registers”
Code cp
pointer
Instructions
Status sr status
register
5
Stack Instructions: pop, popto
sp FREE
pop
value
sp FREE
stack
stack
sp FREE
value For local vars sp FREE
popto j
value Stack[fp+j]
6
fp fp
Stack Instructions: push, pushfrom
push value
sp FREE
sp FREE value
stack stack
sp FREE
sp FREE value
For local vars
pushfrom j
fp fp 7
Top-of-Stack swap and
Top-of-Stack arithmetic
sp FREE sp FREE
value 2 swap value 1
value 1 value 2
stack stack
sp FREE
result = (value 1) op (value 2)
goto k
cp j : goto k
k : …….. cp k : ……..
skip
cp j : skip j : skip
j+1 : …….. cp j+1 : ……..
9
test
If VALUE
test k cp j+1 : … is not 0
cp j : test k
j+1 : …
k : ……..
If VALUE
cp k : …….. is 0
sp FREE
VALUE sp FREE
stack stack
10
stop
cp cp j : stop
j : stop
stop
sr 0 sr 1
Status codes
0 = running
1 = stopped (program answer should be on top of stack)
2 = store index out of bounds
3 = call out of bounds
4 = stack overflow
5 = fp offset out of bounds
11
6 = return cp out of bounds
7 = arith error (div by 0)
JARGON Initial State
sp = 2 FREE
dummy return 0
fp = 0 0
Stack
cp = 0
Code
status = 0
12
Translation of expressions
pushfrom offest
pushfrom -offest
c push c x
(formal parameter)
load index
(global variable) 13
Translation of expressions
code for e1
e1 op e2
code for e2
arith op
0 : push 3
1 : push 8
2 : push 17
3 * ((8 + 17) * (2 - 6)) 3 : arith +
4 : push 2
5 : push 6
6 : arith -
7 : arith * 14
8 : arith *
Translation of commands
popto offest
assignment (local variable)
code for e
x = e;
“update x”
pop
store index
(global variable) 15
Translation of commands
16
Conditionals, Loops
test k test k
goto m goto m
m: skip
17
0: push 0 ; slot for x
Conditional Example 1: push 0 ; slot for y
2: push 19 ;
3: popto 2 ; store x
fun f(x, y) { 4: push 10 ;
let a = 0; 5: popto 3 ; store y
6: load 2 ; load x
if x < y 7: load 3 ; load y
then a = 100; 8: call 14 ; call f
9: swap ; remove arg 2
else a = 500;
10 : pop ; ...
11 : swap ; remove arg 1
return a; 12 : pop ; ...
} 13 : stop ; that's all folks!
14 : push 0 ; slot for a
let x = 19; 15 : push 0 ;
let y = 10; 16 : popto 2 ; store a
17 : pushfrom -2 ; load x
18 : pushfrom -1 ; load y
f(x, y) 19 : arith < ;
20 : test 24 ; if (x < y)
21 : push 100 ;
22 : popto 2 ; store a
23 : goto 26 ; jump over else clause
24 : push 500 ;
If then else.. 25 : popto 2 ; store a
26 : skip ; end if
27 : pushfrom 2 ; load a
28 : return ;
18
Example, While loop 0:
1:
push 4
call 5
;
; call sum
2: swap ; remove arg 1
3: pop ; ...
4: stop ; that's all folks!
5: push 0 ; slot for k
6: push 0 ; slot for s
fun sum(x) { 7: pushfrom -1 ; load x
let k = x; 8: popto 2 ; store k
let s = 0; 9: push 0 ;
while 0 < k { 10 : popto 3 ; store s
s = s + k; 11 : push 0 ; begin while loop
k = k - 1; 12 : pushfrom 2 ; load k
} 13 : arith < ;
return s; 14 : test 24 ; check (0 < k)
} 15 : pushfrom 3 ; load s
16 : pushfrom 2 ; load k
sum(4) 17 : arith + ;
18 : popto 3 ; store s
19 : pushfrom 2 ; load k
20 : push 1 ;
21 : arith - ;
22 : popto 2 ; store k
23 : goto 11 ; while loop iterate
While loop 24 : skip ; end while
25 : pushfrom 3 ; load s 19
26 : return ;
Compiler Construction
Lecture 09
Functions I
Computer Laboratory
University of Cambridge
1
Jargon Stack Frame
Stack[fp - 1] to Stack[fp - n]
are arguments passed by caller
Previous stack frame
(of caller)
2
call
cp j : call k j : call k
k : …….. cp k : ……..
Code
Code call k
sp FREE
j+1
sp FREE fp
caller’s
frame
fp 3
return
cp j : return j : return
m : …….. cp m : ……..
Code Code
sp FREE
value return
m: sp FREE
fp value
fp 4
Translation of expressions
swap
pop Take n args off
the stack, always
: : leaving return
: : value at top
swap 5
pop
SLANG to JARGON 0:
1:
push 0
push 0
; slot for x
; slot for y
example 2:
3:
push 19
popto 2
;
; store x
4: push 10 ;
5: popto 3 ; store y
6: push 20 ;
7: pushfrom 2 ; load x
fun f(y, x) 8: pushfrom 3 ; load y
{ 9: call 24 ; call f
10 : swap ; remove arg 2
let z = 17; 11 : pop ; ...
return z * (y + x); 12 : swap ; remove arg 1
} 13 : pop ; ...
14 : pushfrom 3 ; load y
15 : pushfrom 2 ; load x
let x = 19; 16 : call 24 ; call f
let y = 10; 17 : swap ; remove arg 2
18 : pop ; ...
19 : swap ; remove arg 1
20 * (f(x, y) - f(y, x)) 20 : pop ; ...
21 : arith - ;
22 : arith * ;
23 : stop ; that's all folks!
24 : push 0 ; f entry, slot for z
25 : push 17 ;
26 : popto 2 ; store z
f 27 : pushfrom 2 ; load z
28 : pushfrom -2 ; load y
29 : pushfrom -1 ; load x
30 : arith + ;
31 : arith * ;
32 : return ; return from f
6
Q:Did we do something wrong?
fun fact(x) {
if x = 0
then return 1; 0: push 4 ;
else return x * fact(x-1); 1: call 5 ; call fact
} 2: swap ; remove arg 1
3: pop ; ...
fact(4) 4: stop ; that's all folks!
5: pushfrom -1 ; load x
6: push 0 ;
Implementation of 7: arith = ;
conditional contains 8: test 12 ; if (x = 0)
“dead code” at lines 11 9: push 1 ;
and 21 10 : return ;
11 : goto 21 ; jump over else clause
12 : pushfrom -1 ; load x
13 : pushfrom -1 ; load x
14 : push 1 ;
15 : arith - ;
A: Probably not. It might be better to 16 : call 5 ; call fact
keep the code generation phase clean, 17 : swap ; remove arg 1
and leave optimizations to another pass 18 : pop ; ...
19 : arith * ;
20 : return ; 7
21 : skip ; end if
Nested functions, procedures
fun f(x) {
let a = …; How this call to h
fun h(y) { b access the value of
let b = …; a and x?
h’s frame
fun g(w) {
let c = …;
if .. c
then return a;
else return h(c) g’s frame
}
return b + g(y); b
} h’s frame
return x + h(a);
}
a
f’s frame
f(17)
x 17 8
Alternative 1: Dijkstra Displays
fun f(x) {
let a = …;
Depth 0
Static frame pointer
h F[0]
fun h(y) { Depth 1
let b = …;
fun g(w) { Depth 2 : :
let c = …;
if .. g F[0]
then return a;
(+) at run-time F[1]
else return h(c)
} only need a fixed
return b + g(y); number of indirections
} to find the value of a
: :
}
return x + h(a); non-local variable
h
(-) can use a lot of space
b
on the stack, and slows F[0]
down function calls
fun f(x) {
let a = …;
Depth 0
Static frame pointer
h
fun h(y) { Depth 1
let b = …;
fun g(w) { Depth 2
let c = …; c
if .. g : :
then return a;
else return h(c) (+) uses less space, takes
} less time to set up and
return b + g(y); tear down.
} y
}
return x + h(a); (-) At run-time, need to
“chase pointers” to find
h : :
the value of a non-local
b
variable.
a
f : :
If function g is at static nesting depth i, a
then use a single static link to the most
recent frame for nesting depth i-1.
x 10
Single Static Link vs. Dijkstra Displays
: : : :
Frame for Frame for
f(…) f(…) 11
Add commands to JARGON for non-local
variables, using single static links
fetch d j sp FREE
sp FREE
value
static-fp Stack[ fp + 2 ]
fp fp
get(0, fp) = fp
get(d + 1, fp) = get(d, Stack[fp+2])
x 14
Problem: a lot
h’
of
Duplication! a
x
c
fun g’(w, x, a, y, b) {
: : g’
let c = …;
if ..
then return a;
else return h’(c, x, a) b
} y
fun h’(y, x, a) { a
let b = …; x
return b + g’(y, x, a, y, b) y
} : : h’
fun f’(x) {
b
let a = …;
return x + h’(a, x, a);
} a
x
f’(17) a f’
: :
a
x 15
A Classic Trade Off
Static Pointer
Chains
Displays
16
Compiler Construction
Lecture 10
Functions II
Computer Laboratory
University of Cambridge
1
What about functions-as-values?
add17(3) + add21(-1)
2
Idea --- function values as “closures”
add17(3) + add21(-1)
add17 g address
a 17
Code cp frame 0
pointer
Stack
(really array) Code
(array of instructions)
Status sr status 4
register
set
k : …….. k : value
set
heap heap
sp FREE
k
value sp FREE
fp fp 5
get
k : value
heap get
sp FREE sp FREE
k value
fp fp 6
SLANG Implementation Convention
stack heap
free
space
f17(3) + f21(-1)
8
Closure conversion (similar to “lambda lifting”)
fun f(a)
{
fun g(x) {return a + x;}
fun h(x) {return a * x;}
if a < 20 then return g else return h;
}
cp j : calla j : calla
cp k : ……..
Code
Code calla
sp FREE
j+1
sp FREE
k fp
caller’s
frame
fp 10
How to translate Application…
k
e (e1, e2 … en) vn
: :
v1
code for e v closure k: code
code for e1 for for
function function
: : :
code for en
code to extract Stack Heap
Code
address of function
Situation just before calla
from heap, leaving
it on top of stack NB: code for function must treat v as
An implicit parameter in order to access
calla Non-local variables on heap.
11
This works for functions-as-arguments
12
Similar problem with reference cell
lifetimes…
!z
13
References
14
Translation of references..
x := e; !x
15
Compiler Construction
Lecture 11
Register Machines and the
Min-Caml Middle-End
Computer Laboratory
University of Cambridge
1
Register Machines
Basic (Abstract) Operations
2
Stack Machine to Register Machine
SP SP - 1
R2 [SP]
arith op
SP SP - 1
R3 [SP]
R1 R2 op R3
[SP] R1
But this defeats the whole point of registers ---
they are FAST local memory that should SP SP + 1
be used to reduce CPU to memory traffic.
4
Let’s look at the MinCaml Middle-End!
type t =
| Unit
| Bool of bool syntax.ml
| Int of int
| Float of float
| Not of t
| Neg of t
| Add of t * t
| Sub of t * t
| FNeg of t
| FAdd of t * t
| FSub of t * t
| FMul of t * t
| FDiv of t * t
| Eq of t * t
| LE of t * t
| If of t * t * t
| Let of (Id.t * Type.t) * t * t
| Var of Id.t
| LetRec of fundef * t
| App of t * t list
| Tuple of t list
| LetTuple of (Id.t * Type.t) list * t * t
| Array of t * t
| Get of t * t
| Put of t * t * t
and fundef =
{ name : Id.t * Type.t;
args : (Id.t * Type.t) list;
body : t }
5
http://min-caml.sourceforge.net/
MinCaml Compiler Roadmap
Const
Elim Inline Assoc Beta
Fold
34 46 33 18 38
Reg
Closure Virtual Simm13 Emit
Alloc
104 163 42 256
262
6
Putting it all together…
let rec iter n e =
if n = 0 then e else
let e' = Elim.f (ConstFold.f (Inline.f (Assoc.f (Beta.f e)))) in
if e = e' then e else iter (n - 1) e‘
Clean code!! 7
K-Normalization
a+b+c*d
⇓
let tmp1 = a + b in
let tmp2 = c * d in
tmp1 + tmp2
• Nesting is allowed
let x = (let y = M1 in M2) in M3
8
Example.
let x = 17
in
let rec f y =
let rec g z = ((x + y) + z)
in g
in
let first = (f 21)
in
let second = (f 88)
in
let result = ((first 99) + (second 44))
in (print_int result)
Typing
let x : int = 17
in
let rec f : (int) -> (int) -> int y : int =
let rec g : (int) -> int z : int = ((x + y) + z)
in g
in
let first : (int) -> int = (f 21)
in
let second : (int) -> int = (f 88)
in
let result : int = ((first 99) + (second 44))
in (print_int result)
9
Knormalization
let x : int = 17
in
let rec f : (int) -> (int) -> int y : int =
let rec g : (int) -> int z : int = ((x + y) + z)
in g
in
let first : (int) -> int = (f 21)
in
let second : (int) -> int = (f 88)
in
let result : int = ((first 99) + (second 44))
in (print_int result)
let x : int = 17 in
let result : int = let Ti4 : int = let Ti3 : int = 99 in (first Ti3) in
let Ti6 : int = let Ti5 : int = 44 in (second Ti5) in
(Ti4 + Ti6)
in
EXTERN(print_int result)
10
KNormalization
type t = type t =
| Unit
| Bool of bool syntax.ml | Unit
| Int of int knormal.ml
| Int of int | Float of float
| Float of float | Neg of Id.t
| Not of t | Add of Id.t * Id.t
| Neg of t | Sub of Id.t * Id.t
| Add of t * t | FNeg of Id.t
| Sub of t * t | FAdd of Id.t * Id.t
| FNeg of t | FSub of Id.t * Id.t
| FAdd of t * t | FMul of Id.t * Id.t
| FSub of t * t | FDiv of Id.t * Id.t
| FMul of t * t | IfEq of Id.t * Id.t * t * t
| FDiv of t * t | IfLE of Id.t * Id.t * t * t
| Eq of t * t | Let of (Id.t * Type.t) * t * t
| LE of t * t | Var of Id.t
| If of t * t * t | LetRec of fundef * t
| Let of (Id.t * Type.t) * t * t | App of Id.t * Id.t list
| Var of Id.t | Tuple of Id.t list
| LetRec of fundef * t | LetTuple of (Id.t * Type.t) list * Id.t * t
| App of t * t list | Get of Id.t * Id.t
| Tuple of t list | Put of Id.t * Id.t * Id.t
| LetTuple of (Id.t * Type.t) list * t * t | ExtArray of Id.t
| Array of t * t | ExtFunApp of Id.t * Id.t list
| Get of t * t
| Put of t * t * t and fundef =
and fundef = { name : Id.t * Type.t;
{ name : Id.t * Type.t; args : (Id.t * Type.t) list;
args : (Id.t * Type.t) list; body : t }
body : t }
let x = y in M ⇒ [y/x]M
13
Simplification: Constant Folding and
Unused Variable Elimination
let x = 3 in let y = 7 in x + y
⇓
let x = 3 in let y = 7 in 10
⇓
10
let result : int = let Ti4 : int = let Ti3 : int = 99 in (first Ti3) in
let Ti6 : int = let Ti5 : int = 44 in (second Ti5) in
(Ti4 + Ti6)
in
EXTERN(print_int result)
let x = 3 in
let rec f y = x + y in
f7
⇓
let rec ftop [x] y = x + y in
let x = 3 in
make_closure f = (ftop, [x]) in
apply_closure f 7
17
Example 2: Known Function Call
let rec f x = x + 3 in
(f, f 7)
⇓
let rec ftop [] x = x + 3 ;;
let rec f x = x + 3 in
f7
⇓
let rec ftop [] x = x + 3 ;;
apply_direct f 7
19
let x.8 : int = 17 in
let f.9 : (int) -> (int) -> in ty.10 : int =
Closure let g.20 : (int) -> int z.21 : int =
let Ti7.22 : int = (x.8 + y.10) in
closure.ml
| Neg of Id.t | Neg of Id.t
| Add of Id.t * Id.t | Add of Id.t * Id.t
| Sub of Id.t * Id.t | Sub of Id.t * Id.t
| FNeg of Id.t | FNeg of Id.t
| FAdd of Id.t * Id.t | FAdd of Id.t * Id.t
| FSub of Id.t * Id.t | FSub of Id.t * Id.t
| FMul of Id.t * Id.t | FMul of Id.t * Id.t
| FDiv of Id.t * Id.t | FDiv of Id.t * Id.t
| IfEq of Id.t * Id.t * t * t | IfEq of Id.t * Id.t * t * t
| IfLE of Id.t * Id.t * t * t | IfLE of Id.t * Id.t * t * t
| Let of (Id.t * Type.t) * t * t | Let of (Id.t * Type.t) * t * t
| Var of Id.t | Var of Id.t
| LetRec of fundef * t | MakeCls of (Id.t * Type.t) * closure * t
| App of Id.t * Id.t list | AppCls of Id.t * Id.t list
| Tuple of Id.t list | AppDir of Id.l * Id.t list
| LetTuple of (Id.t * Type.t) list * Id.t * t | Tuple of Id.t list
| Get of Id.t * Id.t | LetTuple of (Id.t * Type.t) list * Id.t * t
| Put of Id.t * Id.t * Id.t | Get of Id.t * Id.t
| ExtArray of Id.t | Put of Id.t * Id.t * Id.t
| ExtFunApp of Id.t * Id.t list | ExtArray of Id.l
type fundef = { name : Id.l * Type.t;
and fundef = args : Id.t * Type.t) list;
{ name : Id.t * Type.t; formal_fv : (Id.t * Type.t) list;
args : (Id.t * Type.t) list; body : t }
body : t } type prog = Prog of fundef list * t
let x = 17
in
let rec f y =
let rec g z = ((x + y) + z)
• Lexing in g
• in
Parsing let first = (f 21)
• Typing in
• K-normalization let second = (f 88)
in
• Simplification let result = ((first 99) + (second 44))
• Closure conversion in (print_int result)
Typing
24
KNormalization
25
After Simplification
let ack.15 : (int, int) -> int x.16 : int y.17 : int =
let Ti4.21 : int = 0
in
if x.16 <= Ti4.21
then
let Ti5.31 : int = 1
in (y.17 + Ti5.31)
else
let Ti6.22 : int = 0
in
if y.17 <= Ti6.22
then
let Ti7.30 : int = 1 in
let Ti8.28 : int = (x.16 - Ti7.30) in
let Ti9.29 : int = 1
in (ack.15 Ti8.28 Ti9.29)
else
let Ti10.27 : int = 1 in
let Ti11.23 : int = (x.16 - Ti10.27) in
let Ti12.26 : int = 1 in
let Ti13.25 : int = (y.17 - Ti12.26) in
let Ti14.24 : int = (ack.15 x.16 Ti13.25)
in (ack.15 Ti11.23 Ti14.24)
in
let Ti1.19 : int = 3 in
let Ti2.20 : int = 10 in
let Ti3.18 : int = (ack.15 Ti1.19 Ti2.20)
in EXTERN(print_int Ti3.18)
26
Closure Conversion
let ack.15 : (int, int) -> int x.16 : int, y.17 : int =
let Ti4.21 : int = 0
in
if x.16 <= Ti4.21
then
let Ti5.31 : int = 1
in (y.17 + Ti5.31)
else
let Ti6.22 : int = 0
in
if y.17 <= Ti6.22
then
let Ti7.30 : int = 1 in
let Ti8.28 : int = (x.16 - Ti7.30) in
let Ti9.29 : int = 1
in APPLY_DIRECT(ack.15 Ti8.28 Ti9.29)
else
let Ti10.27 : int = 1 in
let Ti11.23 : int = (x.16 - Ti10.27) in
let Ti12.26 : int = 1 in
let Ti13.25 : int = (y.17 - Ti12.26) in
let Ti14.24 : int = APPLY_DIRECT(ack.15 x.16 Ti13.25)
in APPLY_DIRECT(ack.15 Ti11.23 Ti14.24)
In
let Ti1.19 : int = 3 in
let Ti2.20 : int = 10 in
let Ti3.18 : int = APPLY_DIRECT(ack.15 Ti1.19 Ti2.20)
in APPLY_DIRECT(min_caml_print_int Ti3.18)
27
Yet another example : funcomp.ml
28
Compiler Construction
Lectures 12 & 13
Assembler, Linker, Loader.
MinCaml Back-End
Computer Laboratory
University of Cambridge
1
Compiler, Assembler, Linker, Loader
Executable
Libraries Linker File
Object/Executable File =
Machine Code +
Bookkeeping Information (dynamic)
Grinding Machine 2
Assembler
• Early Unix
– a.out format
• System V
– COFF = Common Object File Format
• Modern Unix
– UNIX ELF (executable and linking format)
• Windows NT
– PE (Portable Executable) format, a variant of COFF
• ….
5
ELF Summary
6
Linker and Loader Tasks
.
• Program Loading
- This refers to copying a program image from hard disk to the main
memory in order to put the program in a ready-to-run state. In some
cases, program loading also might involve allocating storage space or
mapping virtual addresses to disk pages.
• Symbol Resolution
– A program is made up of multiple subprograms; reference of one
subprogram to another is made through symbols. A linker's job is to
resolve the reference by noting the symbol's location and patching the
caller's object code
• Relocation
– Compilers and assemblers generate the object code for each input
module with a starting address of zero. Relocation is the process of
assigning load addresses to different parts of the program by merging
all sections of the same type into one section. The code and data
section also are adjusted so they point to the correct runtime addresses.
Const
Elim Inline Assoc Beta
Fold
34 46 33 18 38
Reg
Closure Virtual Simm13 Emit
Alloc
104 163 42 256
262
Back-End
9
SPARC Registers
WINDOW
10
MinCaml Code Generation for Sparc
11
SPARC Addressing Modes
12
Some SPARC Instructions…
13
… more SPARC Instructions…
14
Delayed Branching
call f
Space on stack is allocated
add %i0, 8, %i0 ! delay slot
BEFORE function call
sub %i0, 8, %i0
let k = e + f in
let l = e + g in
of registers!!
let o = e + j in
let p = f + g in
let q = f + h in
let r = f + i in
let s = f + j in
let t = g + h in
let u = g + i in
let v = g + j in
let w = h + i in
let x = h + j in
let y = i + j in
let z = a + b + c + d +
e + f + g + h + i + j +
k + l + m + n + o + p + q + r + s + t + u + v + w + x + y in
-z in
print_int (f 1 2 3 4)
16
Never Fear! Use the Stack!
f.29:
add %i2, %i3, %l0 add %i2, %l4, %i2
add %i2, %i4, %l1 add %i2, %l5, %i2
add %i2, %i5, %l2 add %i2, %l6, %i2
add %i3, %i4, %l3 add %i2, %l7, %i2
add %i3, %i5, %l4 add %i2, %o0, %i2
add %i4, %i5, %l5 add %i2, %o1, %i2
add %l0, %l1, %l6 add %i2, %o2, %i2
add %l0, %l2, %l7 add %i2, %o3, %i2
add %l0, %l3, %o0 add %i2, %o4, %i2
add %l0, %l4, %o1 ld [%i0 + 0], %i3
add %l0, %l5, %o2 add %i2, %i3, %i2
add %l1, %l2, %o3 ld [%i0 + 4], %i3
add %l1, %l3, %o4 add %i2, %i3, %i2
add %l1, %l4, %o5 ld [%i0 + 8], %i3
st %o5, [%i0 + 0] Retrieve add %i2, %i3, %i2
add %l1, %l5, %o5 the ld [%i0 + 12], %i3
st %o5, [%i0 + 4] add %i2, %i3, %i2
add %l2, %l3, %o5
values ld [%i0 + 16], %i3
st %o5, [%i0 + 8] add %i2, %i3, %i2
add %l2, %l4, %o5 Use stack to ld [%i0 + 20], %i3
st %o5, [%i0 + 12] add %i2, %i3, %i2
add %l2, %l5, %o5
store ld [%i0 + 24], %i3
st %o5, [%i0 + 16] intermediate add %i2, %i3, %i2
add %l3, %l4, %o5 values add %i2, %o5, %i2
st %o5, [%i0 + 20] (“register neg %i2, %i2
add %l3, %l5, %o5 spilling”) retl
st %o5, [%i0 + 24] nop
add %l4, %l5, %o5
add %i2, %i3, %i2
17
Simm13: 13-Bit Immediate Optimization
• Specific to SPARC
• “Inlining” or "constant folding"
for integers from -4096 to 4095
20
Simm13
f: f:
add ARG1, 10, RV add %i2, 10, %i2
retl retl
nop nop
g: g: st %i2, [%i0 + 0]
add ARG1, 1, TMP3 add %i2, 1, %i2
mov TMP3, ARG1
st RT, [SP + 4] st %o7, [%i0 + 4]
call f {{RV TMP4}} call f
DELAY SLOT DELAY SLOT
ld [SP + 4], RT ld [%i0 + 4], %o7
Store TMP4 on stack
st %i2, [%i0 + 4]
ld [%i0 + 0], %i2
add ARG1, ARG1, TMP5 add %i2, %i2, %i2 Fetch ARG1 from stack
mov TMP5, ARG1
st RT, [SP + 4] st %o7, [%i0 + 12]
call f call f
DELAY SLOT DELAY SLOT
ld [SP + 4], RT ld [%i0 + 12], %o7 Fetch TMP4 from stack
ld [%i0 + 4], %i3
sub TMP4, RV, RV sub %i3, %i2, %i2
retl retl
nop nop
.global min_caml_start .global min_caml_start
min_caml_start: min_caml_start:
save %sp, -112, %sp save %sp, -112, %sp
set 17, TMP7 set 17, %i2
mov TMP7, ARG1
st RT, [SP + 4] st %o7, [%i0 + 4]
call g call g
DELAY SLOT DELAY SLOT
ld [SP + 4], RT ld [%i0 + 4], %o7
mov RV, ARG1
st RT, [SP + 4] st %o7, [%i0 + 4]
call min_caml_print_int call min_caml_print_int
DELAY SLOT DELAY SLOT
ld [SP + 4], RT ld [%i0 + 4], %o7
KEY
ret ret SP %i0 = stack pointer
restore restore RT %o7 = return address
RV %i2 = return value
ARG1 %i2 = first argument (same as RV!)
Register allocation TMP3 %i2 21
: so must save ARG1 on stack!
TMP4 %i3 and stack
TMP5 %i2 : so must save TMP3 on stack!
Return to our Favorite Example:
let rec compose f g =
let rec composed x = g (f x) in
composed in
let rec dbl x = x + x in
let rec inc x = x + 1 in
let rec dec x = x - 1 in
let h = compose inc (compose dbl dec) in
print_int (h 123)
let LABEL(dbl) [] x = (x + x) in
let LABEL(inc) [] x = let TMP1 = 1 in (x + TMP1) in
let LABEL(dec) [] x = let TMP1 = 1 in (x – TMP1) in
To
virtual compose: compose:
SPARC mov HP, cl mov %i1, %i4
add HP, 16, HP add %i1, 16, %i1
set composed, TMP1 set composed, %i5
Allocate st TMP1, [cl + 0] st %i5, [%i4 + 0]
a closure st ARG2, [cl + 8] st %i3, [%i4 + 8]
on the st ARG1, [cl+ 4] st %i2, [%i4 + 4]
heap mov cl, RV mov %i4, %i2
retl retl
Register allocation
composed: composed:
ld [CLP + 8], g ld [%o5 + 8], %i3
st %i3, [%i0 + 0] save g on stack
ld [CLP + 4], f ld [%o5 + 4], %o5
mov x, ARG1
mov f, CLP
st RT, [SP + 4] st %o7, [%i0 + 4]
ld [CLP + 0], TMP2 ld [%o5 + 0], %o4
call TMP2 call %o4
STACK MAGIC STACK MAGIC
ld [SP + 4], RT ld [%i0 + 4], %o7
mov RV, ARG1
mov g, CLP ld [%i0 + 0], %o5 fetch g from stack
ld [CLP + 0], TMP2 ld [%o5 + 0], %o4
jmp TMP2 jmp %o4
Register allocation
Register allocation
26
sum.7:
Example:
cmp %i2, 0
bg ble_else.18
nop
sum.ml set
retl
0, %i2
nop
ble_else.18:
st %i2, [%i0 + 0]
sub %i2, 1, %i2
st %o7, [%i0 + 4]
call sum.7
add %i0, 8, %i0 ! delay slot
let rec sum x = sub %i0, 8, %i0
ld [%i0 + 4], %o7
if x <= 0 then 0 else ld [%i0 + 0], %i3
sum (x - 1) + x in add
retl
%i2, %i3, %i2
sum-tail.ml bg
nop
ble_else.19
retl
nop
ble_else.19:
add %i2, %i3, %i2
sub %i3, 1, %i3
b sum.8
let rec sum acc x = nop
if x <= 0 then acc else .global min_caml_start
sum (acc + x) (x - 1) in min_caml_start:
save %sp, -112, %sp
print_int (sum 0 10000)
set 0, %i2
set 10000, %i3
st %o7, [%i0 + 4]
call sum.8
add %i0, 8, %i0 ! delay slot
Tail-recursion is sub %i0, 8, %i0
identified and implemented ld [%i0 + 4], %o7
st %o7, [%i0 + 4]
with a loop --- stack not call min_caml_print_int
used!! add %i0, 8, %i0 ! delay slot
sub %i0, 8, %i0
ld [%i0 + 4], %o7
ret
restore 28
Compiler Construction
Lecture 14
Garbage
Collection
Lent Term 2007
Timothy G. Griffin
Computer Laboratory
University of Cambridge
1
What is Garbage?
3
Restrict Languages? NO WAY!
4
Explicit MM
5
Automation…
ROOT SET
stack
r1
r2 -------------------- HEAP ----------------------------------------
registers 6
… Identify Cells Reachable From Root Set…
stack
r1
r2
registers 7
… reclaim unreachable cells, and repeat …
stack
r1
r2
registers 8
Reference Counting, basic idea:
9
Reference counting can’t detect cycles!
r1
stack
r2
10
Pros and Cons
• Cons
• Space/time overhead to maintain count.
• Memory leakage when cycles in data.
• Pros
• Incremental (no long pauses to collect…)
• Has many useful applications
• UNIX File System - Symbolic Links
• Java’s RMI management of Strings
• Pure Functional Languages
11
Mark and Sweep
• A two-phase algorithm
– Mark phase: Depth first traversal of object
graph from the roots to mark live data
– Sweep phase: iterate over entire heap,
adding the unmarked data back onto the free
list
12
Cost of Mark Sweep
• Cost of mark phase:
– O(R) where R is the # of reachable words
– Assume cost is c1 * R (c1 may be 10 instr’s)
• Cost of sweep phase:
– O(H) where H is the # of words in entire heap
– Assume cost is c2 * H (c2 may be 3 instr’s)
• Analysis
– The “good” = each collection returns H - R words reclaimed
– Amortized cost = time-collecting/amount-reclaimed
• ((c1 * R) + (c2 * H)) / (H - R)
• If R is close to H, then each collection reclaims little space..
– R / H must be sufficiently small or GC cost is high.
Could dynamically adjust. Say, if R / H is larger than .5, increase
heap size
13
Other Problems
14
Copying Collection
15
Copying Collection
from-space to-space
roots
16
Copying GC
• Pros
– Simple & collects cycles
– Run-time proportional to # live objects
– Automatic compaction eliminates fragmentation
• Cons
– Precise type information required (pointer or not)
• Tag bits take extra space; normally use header word
– Twice as much memory used as program requires
• Usually, we anticipate live data will only be a small fragment
of store
• Allocate until 70% full
• From-space = 70% heap; to-space = 30%
– Long GC pauses = bad for interactive, real-time apps
17
OBSERVATION: for a copying garbage
collector
18
IDEA: Generational garbage collection
20
Compiler Construction
Lecture 15
Object Orientation
Lent Term, 2007
Lecturer: Timothy G. Griffin
Computer Laboratory
University of Cambridge
3
Static & Dynamic Methods
An A object
class A { C++
public:
int a1, a2; a1
object data
a2
void m1(int i) {
a1 = i;
}
void m2(int i) {
a2 = a1 + i; m1_A method table
} m2_A
}
5
Inheritance (“pointer polymorphism”)
class B : public A {
public:
A B object
int b1;
a1
void m3(void) {
b1 = a1 + a2;
a2 object data
} b1
}
method table
m1_A
(code entry
m2_A
points =
m3_B
memory locations)
A C object
class C : public A {
public: a1
int c1; a2 object data
c1
void m3(void) {
b1 = a1 + a2;
}
m1_A_A method table
void m2(int i) {
m2_A_C
a2 = c1 + i;
} m3_C_C
}
declared defined
7
Example
Method table for
Rectangle
IsShape_Shape_Shape
abstract class Shape {
boolean IsShape() {return true;} IsRectangle_Shape_Rectangle
boolean IsRectangle() {return false;}
boolean IsSquare() {return false;} IsSquare_Shape_Shape
abstract double SurfaceArea();
} SurfaceArea_Shape_Rectangle
class Rectangle extends Shape {
double SurfaceArea { ... }
boolean IsRectangle() {return true;}
} Method table for Square
class Squrae extends Rectangle {
boolean IsSquare() {return true;} IsShape_Shape_Shape
}
IsRectangle_Shape_Rectangle
9
Dynamic dispatch
ptr to C
Is also a ptr to A m1_A_A
a1 m2_A_C
a2 m3_C_C
b1
class C *c = ...;
class A *a = c; *(a->dispatch_table[1])(a, 3);
a->m2(3); 10
Dynamic typing:implementation
requires pointer subtyping
void m2(int i) {
a2 = c1 + i;
}
this->a2 = this->c1 + i;
}
11
Multiple inheritance
class C { class D {
public: public:
int c1, c2; int d1;
void m1() {...} void m3() {...}
void m2() {...} void m4() {...}
} }
class E : public C, D {
public:
int e1;
void m2() {...}
void m4() {...}
void m5() {...}
}
12
Multiple inheritance
ptr to E
m1_C_C
ptr to C inside E
c1 m2_C_E
c2 m3_D_D
ptr to D inside E
m4_D_E
d1 m5_E_E
e1
supertyping E-object E-class
convert_ptrE_to_ptrC(e) ≈ e
convert_ptrE_to_ptrD(e) ≈ e + sizeof(Class_C)
subtyping
convert_ptrC_to_ptrE(c) ≈ c
13
convert_ptrD_to_ptrE(d) ≈ d - sizeof(Class_C)
given an object e of class E
e.m1() (*(e->dispatch_table[0]))((Class_C *) e)
e.m3() (*(e->dispatch_table[2]))(
(class_D *)((char *)e + sizeof(Class_C)))
e.m4() (*(e->dispatch_table[3]))(
(class_D *)((char *)e + sizeof(Class_C)))
14
Another OO Feature
• Protection mechanisms
– to encapsulate local state within an object,
Java has “private” “protected” and “public”
qualifiers
• private methods/fields can’t be called/used outside
of the class in which they are defined
– This is really a scope/visibility issue! Front-
end during semantic analysis (type checking
and so on), the compiler maintains this
information in the symbol table for each class
and enforces visibility rules.
15
Compiler Construction
Lecture 16
Continuation Passing Style (CPS)
OPTIONAL TOPIC:
WILL NOT BE EXAMINED
Computer Laboratory
University of Cambridge
1
Continuation Passing Style
2
CPS on Lambda Terms
e::=c∣x∣ee∣λx.e
c = λk .kc
x = λk .kx
λx.e=λk .k λx.e
e1 e2=λk .e1 λm.e2 λn.mnk
e⇒ c e λx . x ⇒ c
¿ ¿
3
Can use CPS as intermediate form in a
Compiler!
Code
Main advantages:
CPS
Can avoid using a stack!
Compile
4
callcc and throw in SML of NJ
5
CPS on Extended Lambda Terms
e::=c∣x∣ee∣λx.e∣callcc e∣throw k e
Has type
((A C) || (B C)) (A*B) C
This is a generalization of De Morgan’s rule Think of ¬A
¬A∨¬B ¬ A∧B as
A false
and then replace
false by C
Can this same thing be done with all of De Morgan’s
other three rules? Yes? No?
7
Propositions as Types, in SML
(*
first : ('a,'b) And -> 'a
*)
fun first (Pair(a,b)) = a ;
(*
second : ('a,'b) And -> 'b
*)
fun second (Pair(a,b)) = b;
(*
dm1 : ('a -> 'b,'c -> 'b) Or -> ('a,'c) And -> 'b
*)
fun dm1 d p = case d of
Left f => f(first p)
| Right g => g(second p)
(*
dm2: (('a,'b) Or -> 'c) -> ('a -> 'c,'b -> 'c) And
*)
fun dm2 f = Pair(fn a => f(Left a), fn b => f(Right b))
(*
dm3 : ('a -> 'b,'c -> 'b) And -> ('a,'c) Or -> 'b
*)
fun dm3 p d = case d of
Left a => ((first p) a)
| Right b => ((second p) b)
9
dm4? This is a “classical” result!
(*
dm4 : : (('a,'b) And -> 'c) -> ('a -> ‘c,'b -> 'c) Or
*)
val callcc = SMLofNJ.Cont.callcc;
val throw = SMLofNJ.Cont.throw;
Operational interpretation:
10
Compiler Construction
Lecture 17
Java Virtual Machine
Computer Laboratory
University of Cambridge
1
Java system overview
Machine Independent
OS independent
2
What Is in the JVM Spec?
4
Instruction set: kinds of operands
Operand stack manipulation
pop, pop2, dup, dup2, dup_x1, swap, …
Control transfer
Unconditional : goto, goto_w, jsr, ret, …
Conditional: ifeq, iflt, ifgt, … 6
…Instruction-set …
Method invocation:
invokevirtual: usual instruction for calling a method on an object.
invokeinterface: same as invokevirtual, but used when the called
method is declared in an interface. (requires different kind of method lookup)
invokespecial: for calling things such as constructors. These are not
dynamically dispatched (this instruction is also known as
invokenonvirtual)
invokestatic: for calling methods that have the “static” modifier (these
methods “belong” to a class, rather an object)
Returning from methods:
return, ireturn, lreturn, areturn, freturn, …
PC goto PC goto_w
branchbyte1 branchbyte1
branchbyte2 branchbyte2
branchbyte3
branchbyte4
BYTE CODES: 0a 3f 0a 41 0a 37 04 le 20 61 37 04 20 3f 16 04 41 a7 ff f6
lstore 4 lstore 4 goto 7
(“assembles” to goto -10)
9
Organization of JVM
Class Area
Class Information
Native
Heap Stack
Constant Pool Stack
Method Area
Interne
t PC, FP, SP
*.class Registers Native
Class Interface
Loader Execution
Engine
File System Native
*.class Methods
10
Class Loader
• Loading: finding and importing the binary data for
a class
• Linking:
• Verification: ensuring the correctness of the imported
type
• Preparation: allocating memory for class variables and
initializing the memory to default values
• Resolution: transforming symbolic references from the
type into direct references.
• Initialization: invoking Java code that initializes
class variables to their proper starting values
11
Class File
• Table of constants. ClassFile {
• Tables describing the u4 magic;
class u2 minor_version;
u2 major_version;
– name, superclass, u2 constant_pool_count;
interfaces cp_info constant_pool[constant_pool_count-1];
– attributes, constructor u2 access_flags;
u2 this_class;
• Tables describing fields u2 super_class;
and methods u2 interfaces_count;
– name, type/signature u2 interfaces[interfaces_count];
u2 fields_count;
– attributes (private, field_info fields[fields_count];
public, etc) u2 methods_count;
method_info methods[methods_count];
• The code for methods. u2 attributes_count;
attribute_info attributes[attributes_count];
}
12
Stack Frame
SP→
Inter-
public class A Mediate Operand
{ Data Stack
... ...
Values
void f(int x)
{
int i; i Local
for(i=0; i<x; i++) Variable
{
... ...
x Array
} Caller’s SP
... ...
} Caller’s FP
FP→Return PC
13
Stack – Each Thread Has its own Stack
Heap
Thread 1 Thread 2 Thread 3
Frame Frame
Stack
14
Heap
15
Java Objects in the Heap
clazz
Fields 1
Fields 2
……
class Object
Fields n
class A
class B clazz
……
clazz
Class Area
……
Heap 16
Bytecode Interpreter
17
Just-In-Time Compiler
• Dynamically compiles bytecode into native code at runtime, usually in
method granularity
• Execution of native code is much faster than interpretation of
bytecode
• Compilation is time consuming and may slow down the application
• Tradeoffs between execution time and compilation time
CPU CPU 18
Adaptive Compiler
19
How Adaptive Compiler Works
• Set three thresholds T1, T2 (T1<T2)
• Each method has a counter that is initialized to 0.
Whenever the method is invoked, increase its
counter by 1
• The methods with counter lower than T1 are
executed using interpreter
• When a method’s counter reaches T1, compile this
method with simple optimizations
• When a method’s counter reaches T2, recompile
this method with advanced optimizations
20