You are on page 1of 53

Part 4

Semantic analysis

Semantic analysis 231


Structure of a compiler
character stream

Lexical analysis
token stream

Syntax analysis
syntax tree

Semantic analysis
syntax tree

Intermediate code generation


intermediate representation

Intermediate code optimization


intermediate representation

Code generation
machine code

Code optimization
machine code

Semantic analysis 232


if (Pa
Token == =
Semantic
tream
if ( analysis
b == 0 ) Abstract
a = b syntax
;
b 0 a b
tree (AST)
Input: syntax tree ) Output: decorated syntax tree
Syntax Analysis
if
if Semant
== = Decorated
(Parsing)
boolean
== =
int
stract syntax
b 0 a b AST int b int 0 int a int b
tree (AST)
lvalue
if Semantic Analysis
boolean int 412/413
ecorated Context-free
== grammar = CScan not Spring 2008
represent Introduction
all language to Compilers
constraints,
AST e.g. int
non
b local/context-dependent
int 0 int a int b relations. Errors
lvalue (incorrect
program)
Semantic analysis checks the source program for semantic
S 412/413 Spring 2008 Introduction to Compilers
consistency with the language definition. 2

I A variable can not be used without having been defined


I The same variable/function/class/method can not be defined twice
I The number of arguments of a function should match its definition
I One can not multiply a number and a string
I ...
Last compiler phase that can report errors to the user.
Also, figures out useful information for later compiler phases (e.g.,
types of all expressions)
Semantic analysis 233
Outline

1. Syntax-directed translation

2. Abstract syntax tree

3. Type and scope checking

Semantic analysis 234


Syntax-directed definition

A general way to associate actions (i.e., programs) to production


rules of a context-free grammar
Used for carrying out most semantic analyses as well as code
translation

A syntax-directed definition associates:


I With each grammar symbol, a set of attributes, and
I With each production, a set of semantic rules for computing the
values of the attributes associated with the symbols appearing in the
production
A grammar with attributes and semantic rules is called an attributed
grammar
A parse tree augmented with the attribute values at each node is
called an annotated parse tree.

Semantic analysis 235


Example
Grammar:
4S 2

S ! aSb|aS|cSacS|✏ a 3 S2 b

Semantic rules: c 1S0 a c 1 S 0

Production Semantic rules


a 0 S 0 a 0S 0 b
S ! aS1 b S.nba := S1 .nba + 1
S.nbc := S1 .nbc
S ! aS1 S.nba := S1 .nba + 1
S.nbc := S1 .nbc
S ! cS1 acS2 S.nba := S1 .nba + S2 .nba + 1 acaacabb
S.nbc := S1 .nbc + S2 .nbc + 2
S!✏ S.nba := 0
S.nbc := 0
S0 ! S Final result is in S.nba and S.nbc

(subscripts allow to distinguish di↵erent instances of the same symbol in a rule)

Semantic analysis 236


Attributes

Two kinds of attributes


I Synthesized: Attribute value for the LHS nonterminal is computed
from the attribute values of the symbols at the RHS of the rule.
I Inherited: Attribute value of a RHS nonterminal is computed from
the attribute values of the LHS nonterminal and some other RHS
nonterminals.
Terminals can have synthesized attributes, computed by the lexer
(e.g., id.lexeme), but no inherited attributes.

Semantic analysis 237


Example: Example:
Example: synth
synthe
synthesized att
Example: synthesized attributes to evaluate
Example:expressions
synthesiz
Example: synthesized attrib
Example: synthesized at
Left-recursive expression grammar Production Semantic rules
L!E L.val = E .val
E ! E1Production
Production + Production
Semantic
T E .val rules = Semantic.val + Tr
E1Semantic
L
L !RE ! E1 LL.val ! !
T E
15 E= .val L.val
= E1L.val
E .val .val= = ET.v
E
E !EE!
Production Production
1 +T
E
T EE! !
Semantic E +
.valE1Erules
1+
.val
= Semantic
T
E1=T E
.val .val
TE.val
+.val rules
=
T .valE1
=
Production Semantic rules
L!E L.val = E .val L !RE !TE! 1L !TT1RE⇤R!
L.val EF15
! EE
.val
= T =.val
1 E
1E.val L.val
T1T= ET=
.val .val ET.val
E1 .val
.val= EF1
=
.val
Production E ! E
! FE .val ESemantic
! +T T E rules
.val E =
.val E = .val
T.
E ! E1 + T E .val = E1 .val + T .val E !EE! 1T +TT =T
EE1 !
.val ET1=.val =+ FTE
T .val
.val .val
.val
.val1 =
L !
R !TE! E
F
1 TT ! R !
(E
1 ⇤E T)
F.valEL.val
3TT1 !
! TFT*T= ⇤
.val
11= E
FE 5
=.val
.val TE =
.val E = .val
T1
E !T E .val = T .val .valE
= ⇤TF
1.val 1 .valTT.val F1.val
.val =
ET !
! FEF! +
E T
!
digit
T TE
!
T .val
F
.valF =
.val
= EE
F = .val
.val
.valT = + T T
digit.lexval
.val = .va
.valF.
T ! T1 ⇤ F T .val = T1 .val ⇥ F .val E ! T E .val = TF.val
1 1
T ! T .val =
T !RF T!
! ⇤E
(EF
1 T
)3 T
!
T F T
.valE
F
! ⇤1
.val
.val
F *1!=(EF T =
)= T5
E
E
.val
(E1table
) 5 .val
.val
.val
1 F =
.val
F .valT T
=
F .val1tree
.va
.val
E
= .E
T !F T .val = F .val
T !EF F!
1
! Tdigit
(put
T T!F.val
F!
the
E .val
F .val
= F =
digit=T
.val T.val
.val
F
and
digit.lexval
=
.val F =.val
digd
F ! (E ) F .val = E .val F ! digit F .val =
F !T (E!) T1F⇤3! F.val
F T)=
(E 1
.val1 .val
E =FT.val 1 .val F .va
= E .val
F ! num F .val = num.lexval
F ! !F
T digit (putF the T= table
(put
.val(put and
=FFthe
digit.lexval .val tree
the=table table ina
F !.val digit .val digit.le
F ! (E )3 3 F .val = E .val
(put the
F ! digit
table
(put and
F .val the
tree inand
table
= digit.lexval
the
(put the table and tree in

Semantic analysis 238


Example: inherited attributes to evaluate expressions
Example: syn
Example: synthesized attribute to evaluate expressions

Example: synthesized
Example: attribute to evaluate
synthesized attribute expressions
to evaluate expressions
Example:
LL expression synthesized attribute to evaluate expressions
grammar
Example:
grammarsynthesized attribute to evaluate
attributeexpressions
LL expression
Example: synthesized
Example: attribute
Productionsynthesized
toExample: synthesized
evaluate expressions
Semantic rulesattribute to evaluate expressions
to evaluate expres
T ! FT 0 T 0 .inh = F .val T .val = 15 F .val = 3
Production Semantic rulesLLProduction expression grammar
Example:
LL expression
T .val =synthesized
grammar num.lexval = 3 TLL expression gr
0 .inh = 3
0
rules Semanticattribute to evaluate expressions
T .syn
Semantic
Production rules 0
0 LL 0expression grammar T ! ⇤FT T .inh = T .inh ⇥ F .val 0
T
0
.val
0
T .syn = = 15
15 F FT.val
.val =
.val
0
3==515 F .val = 3
T ! FT TProduction
.inh =Semantic
F .valrules T ! FT T .inh
T
T !
LL .val
= FFT
.syn =
expression
.val T .inh = F .val
T .syn
grammar
LL
0

expression
1 0 1
0
num.lexval
num.lexval
grammar
= 5 T
0
= 3 num.lexval
T .inh1 =3=
0
Production
0 .inh =
0
1
0
0
153 T 0 .inh = 3 Se 0
.valT ! ✏ TProduction
0 0
TT
= T .syn
==
.val 15 T .val ==T3 .syn
.inhF .val rules
0 0 0
TT.val T.val0 .syn
! FTLL expression
T .inh
=Production
T
= Fgrammar
LL
T expression
! ⇤FT T grammar
= T Semantic
.syn num TF!
F ! rules
.syn
.inh =!T⇤FT
Tnum.lexval
.valFT 0
T Semantic
.inh ⇥T
= num.lexval
0
= Production
F .val
.inh
3 T 0 .inh
= 0
T .inh
1=
0T
3 ⇥
0
1 .syn
0
T Semantic
.syn1 == 15
F .val 15 0
rules T 0 .syn
F .val = 5= T
0
15 !
T .val0 = 15 F .valT =
0 0
F .valFT
0
10 =5 0
3 = 15 F .val T
0
1
0

Production TSemantic
T 0=
.syn TrulesT .inh
.synTT
=
!
T.syn F=.val
= FT T .inh
T5F.syn 0
num.lexval = F= T .inh = 15= 5 .val
.val5 num.lexval 0
T10 .inh = 15 = 3 00 0
T 0 ! ⇤FT10 TT10 .inh 0 = TT.inh 15 = 3=
0 0 0 .syn 00
=T15 .val
F .val = .val
=T!T.syn
! ⇤FT T T .inh
FT .inh T ⇥
.inh
T
= TT .syn
.val
!!
=
F
⇥=FF.val
✏1
FT
T
.val 1
0 T
0
.valT .synT
.inh
LL expression
.syn
=
!= T✏
F
num.lexval
.inh
.val
0
.val
0
grammar T = T=
.syn
num.lexval 0
= 5=TT1 .inh
0
.syn
0
T
=T=
T
T
0
.inh .val
0 0
.val
.syn 0
3num.lexval
T.val
115 0
=
==
.inh T 0
15 3 0 T1 .syn 0
1
0
0 = 15 0
T 0 .inh
F .val01 = 3 = 3 num.lexval
num.lexval
15.syn
0
0 = 3 = 3 T 0 .in
T
0
0
1
0 0
T ! ⇤FT 1T .inh .inh ⇥ F T .syn
= 3⇥TF.inh =
10 15 F .val = 5
.val = 3 T .syn = 15 F .val =
0 0 0 0
TTF0 .syn
!✏ = T T!T.syn
00 = TTF.inh
⇤FT .syn.inh
! num F .val1= num.lexval
! num Production
0
T ! ⇤FT T T
FT
0

!
F=
.val
.val
= T .inh ⇥ FT.val
FT
!
00=num.lexval
T
1 .syn
1
.inh
num.syn F
00
Semantic
= TT=.inh1
.inh
0
T
0 .syn
T.syn
T15 ⇥=F= F
!=⇤FT
.valrules
=T 15
.val
.val
num.lexval
0
0
0 1
T .inh = T .inh
.synF .val
T0 .syn
T = 5=
.syn 0
*
=T 15 num.lexval
F .val
.syn
T .val 0= 15 = 5FT =05 =
0
.val !
1
0
T103.inh ⇤FT
num.lexval
0 = 15=0 5 TT
0 .in 0
1
1 1
0 0
1
T .syn = T .syn 0 0 010 1 1 1
Tnum.lexval = 5num.lexval
TT.syn 1 .inh== 15 0 0
T0 ! ✏ T 0 .syn = T✏ 0 .inh ! ✏ = T .syn
TT .syn .synT T= T✏ .inh T105.syn 0 0 0 0
!.syn 1 T .inh
=
num.lexvalT10 .inh
== 15=3 15
T 0T.inh
0 ==
1 .syn 3 15 0
T ! T .syn = T .inhF ! num T .val
0 0 =
0 .syn 0 1
T ! ✏ T T!.syn
! num F .val = num.lexval ⇤FT= TT.inh
FT.val
.inh1F
0
=!
= num.lexval
=
T .inhnum15
⇥ FTF.val
0
0
0.val = num.lexval
1 .syn = T 150 .syn = 15 F .val = 5
0
0
0 T
0

F ! num F .val =F num.lexval F ! num F .val = num.lexval T .syn = T .syn


1 1
0
num.lexval = 5 0T10 .inh = 15 0

Semantic analysis T0 ! ✏ T 0 .syn = T 0 .inh


1
T10 .syn = 15 T !✏ T
10
F ! num F .val = num.lexval
Semantic analysis Semantic analysis
F ! num F .
10 10

Semantic analysis 10

Semantic analysis Semantic analysis 10


Semantic analysis 10
Semantic analysis 10

Semantic analysis 10

Semantic analysis 239


Evaluation order of SDD’s
General case of synthesized and inherited attributes:
Draw a dependency graph between attributes on the parse tree
Find a topological order on the dependency graph (possible if and
only if there are no directed cycles)
If a topological order exists, it gives a working evaluation order. If
not, it is impossible to evaluate the attributes
In practice, it is difficult to predict from an attributed grammar whether
no parse tree will have cycles
Example:

(Dragonbook)
Semantic analysis 240
Evaluation order of SDD’s

Some important particular cases:


A grammar with only synthesized attributes is called a S-attributed
grammar.
Attributes can be evaluated by a bottom-up (postorder) traversal of
the parse tree

2 2

1 1

Semantic analysis 241


Evaluation order of SDD’s
Some important particular cases:
A syntax-directed definition is L-attributed if each attribute is either
1. Synthesized
2. Inherited “from the left”: if the production is A ! X1 X2 . . . Xn , then
the inherited attributes for Xj can depend only on
2.1 Inherited attributes of A
2.2 Any attributes among X1 ,. . . ,Xj 1 (symbols at the left of Xj
2.3 Attributes of Xj (provided they are not causing cycles)
To evaluate the attributes: do a depth first traversal evaluating
inherited attributes on the way down and synthesized attributes on
the way up (i.e., an Euler-tour traversal)

1 8

6 7

2 5

3 4

Semantic analysis 242


Translation of code

Syntax-directed definitions can be used to translate code


Example: translating expressions to post-fix notation

Production Semantic rules


L!E L.t = E .t
E ! E1 + T E .t = E1 .t||T .t||0 +0
E ! E1 T E .t = E1 .t||T .t||0 0
E !T E .t = T .t
T ! T1 ⇤ F T .t = T1 .t||F .t||0 ⇤0
T !F T .t = F .t
F ! (E ) F .t = E .t
F ! num F .t = num.lexval

Semantic analysis 243


Syntax-directed translation scheme

The previous solution requires to manipulate strings (concatenate,


create, store)
An alternative is to use syntax-directed translation schemes.
A syntax-directed translation scheme (SDT) is a context-free
grammar with program fragments (called semantic actions)
embedded within production bodies:

A ! {R0 }X1 {R1 }X2 . . . Xk {Rk }

Actions are performed from left-to-right when the rules is used for a
reduction
Interesting for example to generate code incrementally

Semantic analysis 244


Example: Example:
Example for code translation synthesizedsynthesized
attribute toa
Example: synthesized attrib
Production Semantic rules
Example for code translation
L!E L.val = E .val
Production ESemantic ! EProduction
1 ExampleTrules
+translation Efor.valcode =Semantic
Etranslation
1 .val + T
Example for code
Production
L!E RL.val! L !E E = ET
L1 ! .val
E E .val = E
L.val1 .val = ET 0 0
E ! E + T {print( + )}
Production E ! ESemantic
Production +Production
T EEfor
Production
1Example !.val
rules TTE=!
code Production
E1 .val
Semantic
translation E .val
1
+ Trules.val
= T.val
.val= E
ExampleL ! E forTcode
E !
L!
! T ⇤translation
E
E1 + T E
L!E L ! E R ! EL.val T=TE E.val.val
! TFR=1+⇤
F
EF! {print( ⇤ )}
1 .val TT= T.val
.val
=
0 0
.val E+T.val
)} .val
1 0 0
1L E! ! EE+ TT ! !L.val
E E + E
{print(
!E T =E
{print( + 0 0 1 1
E )} T1
{print(0 +0 )} E ! E1 +
1
E ! E1 + T Production
ET!T EE Production
.valE
!! = T T
E E Semantic
.val
!
1
F
+.val
! F
T(E =)+ ETT .valrules
.val
.val T .val
= E = .valF .val
+= T .v 0 0
num!
! ⇤ {print( ⇤
LT!!E T ⇤1F F !{print(
Production E T
TT F
⇤T)}!{print(num.lexval)} 1 E .val
0 0
)} 1
T
E !T LT + L.val )+= E 2
.val
1
R ! E1 T !T E1RLE ⇤T!
.val
! F!E=
E
! FFE+T !1.val
E1T{print(
.val(E
{print(
T =
9 )}1
ETT!.val
)} .val
F
1.val
{print( 5 F {print(
)} .val
= F2=
0 0 0 0
E .valE .val T .v
.val
)} 0 0 0 0

T ! T1 ⇤ F 0 0
{print( ⇤ )} E ! T T
E E! !E T(E
+T {print(T
1 !
+ )}F T(E )
1 ⇤ F0 0
1 T .val = T
E! !FEEE .val
E1T!
F
+
F!
!
!T= Tnum
T F
T⇤T
)
F! E.val
.val
Put
{print(=grammar
digit ⇤= F!.val
F)}
E .val
Enum
1F .val
and.val += T2.14
.val
digit.lexva
{print(num.lexval)}
=Figure
T 0 0
.val of dragon
T T!!
!
T F⇤ F {print(T= !
{print(
⇤ )} F9expressions)
{print(num.lexval)}
1
)} {print(
0 0 5 )}T{print(
.val 2 )}= F
0 0 0 0 0 0
T !F F !
T ! T1 ⇤RF! T(EET )
.val
{print(
1F!! =
T5)TT1E1⇤.val
9 F
)} .val to
.val
{print( 10 0
5 )} =E
evaluate .val
TFhandout
{print(E.val
1 .val
2 )} 0 0
T .val F .v
0 0

F ! (E ) T ! F FE !
T
digit
!F (E
)numF .val (put
FF the
(see = ! the
.val
(E
Put
digit.lexval
=table
)2.14
grammar T1and
about F.valand
Figure=
.val
syntax-directed trE
2.14
!T TTF.val
F!!
!!
=
(EPut
F
FE .val
grammar .val =
and T
Figure
{print(num.lexval)}
Tgrammars
.val
to .val
)} =with
evaluate
of dragonbook
F .val
expressions)
(and
F ! num {print(num.lexval)}
F ! (E )T ! FT
F{print(
.val
num
=
9 )}
to ET
{print(
evaluate
.val F
complex !
{print(num.lexval)}
0 0
)} {print(
5expressions) 2digit0 0
F
int).val0 0
= d
9 (put
{print(
F 1! ⇤9Put
F
the
)} {print(
(see(E )
grammar
the
5.val
0 0
table
handout andF
Post-fix =
)} {print(
andT)} .val
2(see
.val
SDT
Figure
about
0 0
tree
theall
handout
1syntax-directed
as =
2.14 E
of .val
actions Fin.val
0 0
are
dragonbook the
about syntax
performe
for a (and d
treatm
F ! digit
T !FF.valPut to
digit.lexval
=grammar
evaluate
complex Tgrammars
.val =with
and Figure
expressions) (put
complex
F 2.14
.val the table
grammars with(and
int)of dragonbook
int) po
F ! digitexpressions)
to evaluate F .val digit.lexval
=SDT
Post-fix as all actions are
(putF !
the(E )(see theFhandout = Esyntax-directed
attable and
(see
Post-fix .valastree
SDT about
all
in
.val
actions
the dragobo
syntax-directed for at
are performed a treatm
the en
(Post-fix SDT as all actions are performed the theend
complex ofabout
handout
grammarsthe (put
with productions)
int)
the for a treatme
table and
tree
F ! digit
complex F .val
grammars=withdigit.lexval
int)
Semantic analysis

Post-fix SDT as all actions are performed at the en


Post-fix SDT as all actions are performed at the end
(put the table and tree in th
Semantic analysis
Semantic analysis

Semantic analysis
Semantic analysis

Semantic analysis

Semantic analysis Semantic analysis 245


Side-e↵ects
Semantic rules and actions in SDD and SDT’s can have side-e↵ects.
E.g., for printing values or adding information into a table
Needs to ensure that the evaluation order is compatible with
side-e↵ects
Example: variable declaration in C

Production Semantic rules


D ! TL L.type = T .type (inherited)
T ! int T .type =int (synthesized)
T ! float T .type =float (synthesized)
L ! L1 , id L1 .type = L.type (inherited)
AddType(id.entry , L.type) (synthesized, side e↵ect)
L ! id AddType(id.entry , L.type) (synthesized, side e↵ect)

id.entry is an entry in the symbol table. AddType adds type


information about entry in the symbol table

Semantic analysis 246


Implementation of SDD’s: after parsing

Attributes can be computed after parsing:


By explicitely traversing the parse or syntax tree in any order
permitting the evaluation of the attributes
Depth-first for S-attributed grammars or Euler tour for L-attributed
grammar
Advantage: does not depend on the order imposed by the syntax
analysis
Drawback: requires to build (and store in memory) the syntax tree

Semantic analysis 247


Evaluation after parsing of L-attributed grammar
For L-attributed grammars, the following recursive function will do the
computation for inherited and synthesized attributes

Analyse(N, InheritedAttributes)
if leaf(N) 1 8
return SynthesizedAttributes
6 7
Attributes = InheritedAttributes
for each child C of N, from left to right 2 5

ChildAttributes = Analyse(C , Attributes) 3 4

Attributes = Attributes [ ChildAttributes


Execute semantic rules for the production at node N
return SynthesizedAttributes

Inherited attributes are passed as arguments and synthesized


attributes are returned by recursive calls
In practice, this is implemented as a big two-level switch on
nonterminals and then rules with this nonterminal at its LHS

Semantic analysis 248


Variations

Instead of a giant switch, one could have separate routines for each
nonterminal (as with recursive top-down parsing) and a switch on
productions having this nonterminal as LHS (see examples later)
Global variables can be used instead of parameters to pass inherited
attributes by side-e↵ects (with care)
Can be easily adapted to use syntax-directed translation schemes
(by interleaving child analysis and semantic actions)

In object-oriented languages, this can be implemented with:


I one class for each nonterminal symbol, or for each syntactic category
(expression, statement, etc.)
I either one ’Analyse’ method in each class (difficult to maintain,
extend) or using the visitor design pattern.

Semantic analysis 249


Implementation of SDD’s: during parsing

Attributes can be computed directly during parsing:


Attributes of a S-attributed grammar are easily computed during
bottom-up parsing
Attributes of a L-attributed grammar are easily computed during
top-down parsing
Attribute values can be stored on a stack (the same as the one for
parsing or a di↵erent one)
Advantage: one pass, does not require to store (or build) the syntax
tree, memory efficient
Drawback: the order of evaluation is constrained by the parser, not
modular

Nowadays, mostly only used to generate the abstract syntax tree

Semantic analysis 250


Bottom-up parsing and S-attributed grammar
Synthesized attributes are easily handled during bottom-up parsing.
Handling inherited attributes is possible (for a LL-grammar) but
more difficult.
Example with only synthesized attributes (stored on a stack):

Production Semantic rules Stack actions


E ! E1 + T E .val = E1 .val + T .val tmpT = pop()
tmpE = pop()
push(tmpE + tempT )
E !T E .val = T .val
T ! T1 ⇤ F T .val = T1 .val ⇥ F .val tmpT = pop()
tmpF = pop()
push(tmpT ⇤ tempF )
T !F T .val = F .val
F ! (E ) F .val = E .val
F ! num F .val = num.lexval push(num.lexval)

(Parsing tables on slide 189)


Semantic analysis 251
Bottom-up parsing and S-attributed grammar
Stack Input Action Attribute stack
$ 0 2 ⇤ (10 + 3)$ s5
$ 0 2 5 ⇤(10 + 3)$ r6: F ! num 2
$ 0 F 3 ⇤(10 + 3)$ r4: T ! F 2
$ 0 T 2 ⇤(10 + 3)$ s7 2
$ 0 T 2 ⇤ 7 (10 + 3)$ s4 2
$ 0 T 2 ⇤ 7 ( 4 10 + 3)$ s5 2
$ 0 T 2 ⇤ 7 ( 4 10 5 +3)$ r6: F ! num 2 10
$ 0 T 2 ⇤ 7 ( 4 F 3 +3)$ r4: T ! F 2 10
$ 0 T 2 ⇤ 7 ( 4 T 2 +3)$ r2: E ! T 2 10
$ 0 T 2 ⇤ 7 ( 4 E 8 +3)$ s6 2 10
$ 0 T 2 ⇤ 7 ( 4 E 8 + 6 3)$ s5 2 10
$ 0 T 2 ⇤ 7 ( 4 E 8 + 6 3 5 )$ r6: F ! num 2 10 3
$ 0 T 2 ⇤ 7 ( 4 E 8 + 6 F 3 )$ r4: T ! F 2 10 3
$ 0 T 2 ⇤ 7 ( 4 E 8 + 6 T 9 )$ r1: E ! E + T 2 13
$ 0 T 2 ⇤ 7 ( 4 E 8 )$ s11 2 13
$ 0 T 2 ⇤ 7 ( 4 E 8 ) 11 $ r5: F ! (E ) 2 13
$ 0 T 2 ⇤ 7 F 10 $ r3: T ! T ⇤ F 26
$ 0 T 2 $ r2: E ! T 26
$ 0 E 1 $ Accept 26
Semantic analysis 252
Top-down parsing of L-attributed grammar
Recursive parser: the analysis scheme of slide 248 can be
incorporated within the recursive functions of nonterminals
Table-driven parser: this is also possible but less obvious.
Example with only inherited attributes (stored on a stack):

Production Semantic rules Stack actions


S0 ! S S.nb = 0 push(0)
S ! (S1 )S2 S1 .nb = S.nb + 1 push(top() + 1)
S2 .nb = S.nb
S !✏ print(S.nb) print(pop())

(print the depth of nested parentheses)

Parsing table:
( ) $
S0 S0 ! S S0 ! S
S S ! (S)S S !✏ S !✏

Semantic analysis 253


Top-down parsing of L-attributed grammar
Stack Input Attribute stack Output
S 0$ (()(()))() 0
S$ (()(()))() 01
(S)S$ (()(()))() 01
S)S$ ()(()))() 012
(S)S)S$ ()(()))() 012
S)S)S$ )(()))() 01 2
)S)S$ )(()))() 01
S)S$ (()))() 012
(S)S)S$ (()))() 012
S)S)S$ ()))() 0123
(S)S)S)S$ ()))() 0123
S)S)S)S$ )))() 012 3
)S)S)S$ )))() 012
S)S)S$ ))() 01 2
)S)S$ ))() 01
S)S$ )() 0 1
)S$ )() 0
S$ () 01
(S)S$ () 01
S)S$ ) 0 1
)S$ ) 0
S$ 0
$
Semantic analysis 254
Comments

It is possible to transform a grammar with synthesized and inherited


attributes into a grammar with only synthesized attributes
It is usually easier to define semantic rules/actions on the original
(ambiguous) grammar, rather than the transformed one
There are techniques to transform a grammar with semantic actions
(see reference books for details)

Semantic analysis 255


Applications of SDD’s

SDD can be used at several places during compilation:


Building the syntax tree from the parse tree
Various static semantic checking (type, scope, etc.)
Code generation
Building an interpreter
...

Semantic analysis 256


Outline

1. Syntax-directed translation

2. Abstract syntax tree

3. Type and scope checking

Semantic analysis 257


rs, and the various symbols and punctuation without using recursion
Abstract
ression syntax
(expr). Note also the tree (AST)
hierarchical decomposition in the figure on the right.
ng)
parsing is somewhat arbitrary, but invariably if a recursive definition is involved,
g.
ch tokens are grouped
represented in a parse
d the syntax tree with operators as interior nodes and
rator. The syntax tree on the right corresponds to the parse

epresents ansuch
containing rules assignment
as expression not an assignment statement. In C an
The abstract
railing semicolon. syntax
That is, in treein is
C (unlike usedtheassemicolon
Algol) a basis isfor most semantic
a statement
r. analyses and for intermediate code generation (or even used as an
intermediate representation)
When the grammar has been modified for parsing, the syntax tree is
(expr). Note also the hierarchical decomposition in the figure on the right.
mply syntax. a more naturalneeds
The compiler representation
semantic information, than the parse
e.g., tree(integer,
the types
g is somewhat arbitrary, but invariably if a recursive definition is involved,
) of the objects involved. This enables checking
The abstract syntax tree can be constructed using for semantic errors and inserting
SDD (see next
yntax tree withslides)
operators as interior nodes and
he syntax tree on the right corresponds to the parse
Another SDD can then be defined on the syntax tree to perform
semantic
nts an assignment expression notchecking
an assignmentor generate
statement. In C an another intermediate code (directed
semicolon. That is, in C (unlike in Algol) the semicolon is a statement
by the syntax tree and not the parse tree)
Semantic analysis 258
Generating an abstract syntax tree
For the left-recursive expression grammar:
Production Semantic rules
E ! E1 + T E .node = new Node(0 +0 , E1 .node, T .node)
E ! E1 T E .node = new Node(0 0 , E1 .node, T .node)
E !T E .node = T .node
T ! (E ) T .node = E .node
T ! id T .node = new Leaf (id, id.entry )
T ! num T .node = new Leaf (num, num.entry )

(Dragonbook)

Semantic analysis 259


Generating an abstract syntax tree

For the LL transformed expression grammar:


Production Semantic rules
E ! TE 0 E .node = E 0 .syn; E 0 .inh = T .node
E 0 ! +TE10 E10 .inh = new Node(0 +0 , E 0 .inh, T .node); E 0 .syn = E10 .syn
E 0 ! TE10 E10 .inh = new Node(0 0 , E 0 .inh, T .node); E 0 .syn = E10 .syn
E0 ! ✏ E 0 .syn = E 0 .inh
E !T E .node = T .node
T ! (E ) T .node = E .node
T ! id T .node = new Leaf (id, id.entry )
T ! num T .node = new Leaf (num, num.entry )

(Dragonbook)

Semantic analysis 260


Syntactic sugar

Syntactic sugar: syntax within a programming language that makes


things easier to read or to express but does not a↵ect functionality
and expressive power of the language.
When building the syntax tree, it is useful to remove sugared
constructs (=“desugaring”).
It makes subsequent phases easier to implement and maintain.
Examples:
I In C: a[i] (= (a+i)*), a->x (= (*a).x)
I All loop operators (for, repeat, while) can be rewritten as while
loops.
Information should however be kept about original code for semantic
error reporting.

Semantic analysis 261


Outline

1. Syntax-directed translation

2. Abstract syntax tree

3. Type and scope checking

Semantic analysis 262


Type and scope checking

Static checkings:
I All checkings done at compilation time (versus dynamic checkings
done at run time)
I Allow to catch errors as soon as possible and ensure that the program
can be compiled
Two important checkings:
I Scope checking: checks that all variables and functions used within a
given scope have been correctly declared
I Type checking: ensures that an operator or function is applied to the
correct number of arguments of the correct types
These two checks are based on information stored in a symbol table

Semantic analysis 263


Scope
{
int x = 1;
int y = 2;
{
double x = 3.1416;
y += (int)x;
}
y += x;
}

Most languages o↵er some sort of control for scopes, constraining


the visibility of an identifier to some subsection of the program
A scope is typically a section of program text enclosed by basic
program delimiters, e.g., {} in C, begin-end in Pascal.
Many languages allow nested scopes, i.e., scopes within scopes. The
current scope (at some program position) is the innermost scope.
Global variables and functions are available everywhere
Determining if an identifier encountered in a program is accessible at
that point is called Scope checking.
Semantic analysis 264
Symbol table
w
...

{ int x; int y;
{ int w; bool y; int z; x int
..w..; ..x..; ..y..; ..z..; y int
}
..w..; ..x..; ..y..; w int
} y bool
z int

The compiler keeps track of names and their binding using a symbol
table (also called an environment)
A symbol table must implement the following operations:
I Create an empty table
I Add a binding between a name and some information
I Look up a name and retrieve its information
I Enter a new scope
I Exit a scope (and reestablish the symbol table in its state before
entering the scope)

Semantic analysis 265


Symbol table
To manage scopes, one can use a persistent or an imperative data
structure
A persistent data structure is a data structure which always
preserves the previous version of itself when it is modified
Example: lists in functional languages such as Scheme
I Binding: insert the binding at the front of the list, lookup: search the
list from head to tail
I Entering a scope: save the current list, exiting: recalling the old list
A non persistent implementation: with a stack
I Binding: push the binding on top of the stack, lookup: search the
stack from top to bottom
I Entering a scope: push a marker on the top of the stack, exiting: pop
all bindings from the stack until a marker is found, which is also
popped
I This approach destroys the symbol table when exiting the scope
(problematic in some cases)

Semantic analysis 266


More efficient data structures

Search in list or stack is O(n) for n symbols in the table


One can use more efficient data structures like hash-tables or binary
search trees
Scopes can then be handled in several ways:
I Create a new symbol table for each scope and use a stack or a linked
list to link them
I Use one big symbol table for all scopes:
I Each scope receives a number
I All variables defined within a scope are stored with their scope number
I Exiting a scope: removing all variables with the current scope number
I There exist persistent hash-tables

Semantic analysis 267


Types

Type checking is verifying that each operation executed in a


program respects the type system of the language, i.e., that all
operands in any expression are of appropriate types and number
Type systems:
I Static typing if checking is done at compilation-time (e.g., C, Java,
C++)
I Dynamic typing if checking is done at run-time (e.g., Scheme,
Javascript).
I Strong typing if all type errors are caught (e.g., Java, Scheme)
I Weak typing if operations may be performed on values of wrong types
(e.g., C, assembly)
Implicit type conversion, or coercion, is when a compiler finds a type
error and changes the type of the variable into the appropriate one
(e.g., integer!float)

Semantic analysis 268


Principle of static type checking

Identify the types of the language and the language constructs that
have types associated with them
Associate a type attribute to these constructs and semantic rules to
compute them and to check that the typing system is respected
Needs to store identifier types in the symbol table
One can use two separate tables, one for the variable names and one
for the function names
Function types is determined by the types (and number) of
arguments and return type. E.g., (int, int) ! int
Type checking can not be dissociated from scope and other
semantic checking

Semantic analysis 269


TypeId ! int id
Illustration TypeId ! bool id

TypeIds ! TypeId
We will use the following source grammarTypeIds
to illustrate type, checking
! TypeId TypeIds

Exp ! num
Program ! Funs
Exp ! id
Exp ! Exp + Exp
Funs ! Fun
Exp ! Exp = Exp
Funs ! Fun Funs
Exp ! if Exp then Exp else Exp
Exp ! id ( Exps )
Fun ! TypeId ( TypeIds ) = Exp
Exp ! let id = Exp in Exp
TypeId ! int id
Exps ! Exp
TypeId ! bool id
Exps ! Exp , Exps
TypeIds ! TypeId
TypeIds ! TypeId , TypeIds Grammar 5.1: Example language for interpretation

Exp ! num
! id5 and 6 of (Mogensen, 2010) for full details)
Exp chapter
(see
Exp ! Exp + Exp
Exp ! Exp = Exp
Exp ! if Exp then Exp else Exp
Exp analysis!
Semantic id ( Exps ) 270
Implementation on the syntax tree: expressions
Type checking of expressions:
6.5. TYPE CHECKING EXPRESSIONS 137
inherited attributes
CheckExp (Exp, vtable, f table) = case Exp of
num int filled in by lexer
id t = lookup(vtable, getname(id))
if t = unbound scope checking
then error(); int
else t
Exp1 + Exp2 t1 = CheckExp (Exp1 , vtable, f table) error recovery
t2 = CheckExp (Exp2 , vtable, f table)
if t1 = int and t2 = int
then int
type checking
else error(); int
Exp1 = Exp2 t1 = CheckExp (Exp1 , vtable, f table)
synthesized attribute
t2 = CheckExp (Exp2 , vtable, f table)
if t1 = t2
Follows the implementation
then bool of slide 249 with one function per
else error(); bool
nonterminal,
if Exp1
with a switch on production rules. Could be implemented
t1 = CheckExp (Exp1 , vtable, f table)
withthen
classes/methods
Exp2 t2 = Checkor a visitor
Exp (Exp 2 , vtable,pattern.
f table)
else Exp3 t3 = CheckExp (Exp3 , vtable, f table)
if t1 = bool and t2 = t3
Semantic analysis 271
if t1error();
else = boolbool and t2 = t3
if Exp1 t1then
= Check t2 Exp (Exp1 , vtable, f table)
Implementation on the syntax tree: function calls
then Exp2 t2else
= Check error();Exp (Exp t2 2 , vtable, f table)
else
id (TYPEExp3)
Exps t3t==Check lookup( Exp (Exp
f table, 3 , vtable, f table)
getname(id))
6.5. CHECKING EXPRESSIONS 137
if ift1t==bool unbound and t 2 = t3
then t2
then error(); int
CheckExp (Exp, vtable,
num
id ( Exps ) tint
else
f table) t=
else error(); 2 case Exp of
= lookup( f table, getname(id))
filled in by lexer
((t , . . . ,tn ) ! tgetname(id))
0) = t
id
[t
= 1unbound
tif=t lookup(vtable,
, . . . ,t ] = Check Exps (Exps, vtable, f table)
scope checking
if t =error();
then 1 unboundint m
thenif error();
else m = n and int t1 = t1 , . . . ,tn = tn
else((tthen t
1t, . . . ,t0n ) ! t0 ) = t
Exp1 + Exp2 t1 [t=1else. . . ,terror();
,Check ] = (Exp
mExp Check t01 ,Exps
vtable,
(Exps, checking function
vtable, f table)
f table)
let id = Exp1 t2tif1== m Check
Check= n Exp and (Expt(Exp
1= 11,,. vtable,
2 ,tvtable,
. . ,tnf= tfntable)
table)
in Exp2 then
t1 =tint
ifvtable
Exp
0 = bind(vtable,
and t2 = int getname(id),t1 ) arguments
thenelseint
Check error();
Exp (Exp t02 , vtable , f table)
let id = Exp1 telse 1 = Checkerror(); (Exp1 , vtable, f table)
Expint
Check
in
Exp Exp 2Exp
1 =Exps tvtable
(Exps,
2 1vtable,
= Check = fbind(vtable,
table)
Exp (Exp getname(id),t
vtable,
=1 ,case Exps
f table)
of 1 )
Exp Check
t2 = Check
[Check (Exp
Exp (Exp,
Exp vtable
2 , vtable,
Exp (Exp , ff table)]
2 , vtable, table)
f table)
Exp , Exps Check if t1 Exp = t2(Exp, vtable, f table)
CheckExps (Exps, then
vtable, bool f table) = case Exps of
:: Check Exps (Exps, vtable, f table)
Exp [Check
else Exp (Exp,
error(); vtable, f table)]
bool
Exp
if Exp , Exps
1
Check
t 1 = Check
Figure
Exp (Exp, 6.2:
Exp (Exp ≈cons
vtable,
Type f table)
1 , vtable,
checking f table)
of expressions
then Exp2 t::2 Check
= Check Exps (Exps, vtable, f table)
Exp (Exp2 , vtable, f table)
else Exp3 t3 = CheckExp (Exp3 , vtable, f table)
Figure 6.2: Type checking of expressions
if t1 = bool and t2 = t3
then t2
else error(); t2
Semantic analysis 272
id ( Exps ) t = lookup( f table, getname(id))
Implementation on the syntax tree: variable declaration
if t = unbound
then error(); int
else
((t1 , . . . ,tn ) ! t0 ) = t
[t1 , . . . ,tm ] = CheckExps (Exps, vtable, f table)
6.5. TYPE CHECKING EXPRESSIONS 137
if m = n and t1 = t1 , . . . ,tn = tn
then t0
CheckExp (Exp, vtable,else f table)
error();=t0case Exp of
num
let id = Exp1 intt1 = CheckExp (Exp1 , vtable, f table) create a new
id
in Exp2 tvtable = bind(vtable,
= lookup(vtable, getname(id),t1 )
getname(id))
Check
if t = Exp (Exp2 , vtable , f table)
unbound scope
then error(); int
CheckExps (Exps, else
vtable, t f table) = case Exps of
Exp1 + Exp2 [Check
Exp t1 = CheckExp (Exp, vtable, f table)]
Exp (Exp1 , vtable, f table)
Create
, Expsa Check
new symbol table vtable 0
Exp t2 =Exp Check(Exp, Expvtable,
(Exp 2 ,fvtable,
table) f table)with the new binding
if:: Check
t1 = int Exps (Exps,
and t2 =vtable,
int f table)
Pass it as an thenargument
int for the evaluation of Exp2 (right child)
Figure 6.2: Type checking of expressions
else error(); int
Exp1 = Exp2 t1 = CheckExp (Exp1 , vtable, f table)
t2 = CheckExp (Exp2 , vtable, f table)
if t1 = t2
then bool
else error(); bool
if Exp1 t1 = CheckExp (Exp1 , vtable, f table)
then Exp2 t2 = CheckExp (Exp2 , vtable, f table)
else Exp3 t3 = CheckExp (Exp3 , vtable, f table)
Semantic analysis if t = bool and t = t 273
Implementation on the syntax tree: function declaration
6.7. TYPE CHECKING A PROGRAM 139
synthesized attribute
CheckFun (Fun, f table) = case Fun of
TypeId ( TypeIds ) = Exp ( f ,t0 ) = GetTypeId (TypeId)
vtable = CheckTypeIds (TypeIds)
t1 = CheckExp (Exp, vtable, f table)
if t0 6= t1
then error()
6.7. TYPE CHECKING A PROGRAM
GetTypeId (TypeId) = case TypeId of
inherited attributes
int id (getname(id), int) Check f table)6.7. TYPE Fun
= case CHECKING
of A PROGRAM
Fun (Fun,
bool id (getname(id), bool)
TypeId ( TypeIds ) = Exp ( f ,t0 ) = GetTypeId (TypeI
CheckFun (Fun, f table) = case Fun of
CheckTypeIds (TypeIds) = case TypeIds of vtable = Check (Ty
TypeId ( TypeIds ) = ExpTypeIds
( f ,t0 ) =
TypeId (x,t) = GetTypeId (TypeId) t1 = CheckExp (Exp, vtab
bind(emptytable, x,t) vtable =
TypeId , TypeIds (x,t) = GetTypeId (TypeId)
if t0 6= t1 t1 = Che
vtable = CheckTypeIds (TypeIds) then error() if t0 6= t1
if lookup(vtable, x) = unbound Create a symbol table then err
GetTypeId
then bind(vtable, x,t) (TypeId) = case TypeId of
with arguments
GetTypeId (TypeId) = case TypeId of
else error(); vtable
int id (getname(id),int int)
id (getname(id), int)
bool id (getname(id), bool)
Figure 6.3: Type checking a function declaration
bool id (getname(id), bool)
Semantic analysis 274
6.8. ADVANCED TYPE CHECKING 141
GetFun (Fun) = case Fun of
Implementation on the syntax tree: program
TypeId ( TypeIds ) = Exp ( f ,t0 ) = GetTypeId (TypeId)
[t1 , . . . ,tn ] = GetTypes (TypeIds)
( f , (t1 , . . . ,tn ) ! t0 )

GetTypes (TypeIds) = case TypeIds of


Check Program (Program) = case Program of
TypeId (x,t) = GetTypeId (TypeId)
Funs f table = GetFuns (Funs)
Collect all function definitions in a
[t]
CheckFuns (Funs, f table) symbol table (to allow mutual recursion)
TypeId ifTypeIds (x1 ,t1 ) =
lookup( f table,
Get 6= (int)
main)TypeId
(TypeId)
! int
[t2 , . . . ,tn ] = GetTypes (TypeIds) Language semantic requires a main function
then error()
[t1 ,t2 , . . . ,tn ]
GetFuns (Funs) = case Funs of
CheckFuns (Funs, f table) = case Funs of
Fun ( f ,t) = GetFun (Fun)
Fun Check Fun (Fun, f table)
bind(emptytable, f ,t)
Fun
Fun Funs
Funs Check Fun
( f ,t) = f table)
(Fun,(Fun)
Get Fun
Check
f tableFuns f table)
(Funs, (Funs)
= Get Funs
if lookup( f table,
Figure 6.4:f )Type
= unbound
checking a program
then bind( f table, f ,t)
else error(); f table
Needs two passes over the function definitions to allow mutual
GetFun (Fun) = case Fun of
recursion
TypeId ( TypeIds ) = Exp ( f ,t0 ) = GetTypeId (TypeId)
See (Mogensen, [t(2010) 1 , . . . ,tn ] =forGetTypes
Get(TypeIds)(similar to CheckFuns )
f , (t1 , . . . ,tn ) ! t0 ) Funs

GetTypes (TypeIds) = case TypeIds of


TypeId (x,t) = GetTypeId (TypeId)
[t]
TypeId TypeIds (x1 ,t1 ) = GetTypeId (TypeId)
[t2 , . . . ,tn ] = GetTypes (TypeIds)
Semantic analysis 275
More on types

Compound types:
They are represented by trees (constructed by a SDD)
Example: array declarations in C
int [3][4]
Production Semantic rules
array
T ! BC T .t = C .t; C .b = B.t
B ! int B.t =int
B ! float B.t =float 3 array
C ! [ NUM ]C1 C .t = array (NUM.val, C1 .t)
C !✏ C .t = C .b
4 int

Compound types are compared by comparing their trees

Semantic analysis 276


More on types
Type coercion: 6.5. TYPE CHECKING EXPRESSIONS 137

The compiler supplies


Check implicit conversions of types
Exp (Exp, vtable, f table) = case Exp of
num
Define a hierarchy int
of types and convert each operand to their least
id t = lookup(vtable, getname(id))
upper bound (LUB) in ifthe hierarchy
t = unbound
then error(); int
Overloading: else t
Exp1 + Exp
The same name is used
2 t1 = Check
for several , vtable, f table)
Exp (Exp1di↵erent operations over several
t2 = CheckExp (Exp2 , vtable, f table)
di↵erent types (e.g., =if int1 =our int source
and t2 = intlanguage)
then int
Type must be defined at else translation
error(); int
Exp1 = Exp2 t1 = CheckExp (Exp1 , vtable, f table)
t2 = CheckExp (Exp2 , vtable, f table)
if t1 = t2
then bool
else error(); bool
if Exp1 t1 = CheckExp (Exp1 , vtable, f table)
Polymorphism/generic
then Exp2types:
t2 = CheckExp (Exp2 , vtable, f table)
else Exp t = CheckExp (Exp3 , vtable, f table)
Functions defined 3overif3at1large
= bool class
and t2 =oft3 similar types
E.g: Functions that can then t
be2 applied over all arrays no matter what
else error(); t2
the types ofidthe elements
( Exps ) are f table, getname(id))
t = lookup(
if t = unbound
Semantic analysis then error(); int 277
More on types

Dynamic typing:
Type checking is (mostly) done at run-time
Objects (values) have types, not variables
Dynamically typed languages: Scheme, Lisp, Python, Php...
The following scheme code will generate an error at run time

(defun length
(lambda (l)
(if (null? l)
0
(+ 1 (length (cdr l))))))
(length 4)

Semantic analysis 278


else error(); int
Exp1 = Exp2
t1 = CheckExp (Exp1 , vtable, f table)
More on types t2 = CheckExp (Exp2 , vtable, f table)
if t1 = t2
then bool
Implicit types and type inference: else error(); bool
if Exp1 t1 = CheckExp (Exp1 , vtable, f table)
Some languages (like ML,
then Exp2
(O)Caml, Haskell, C#) do not require to
t2 = CheckExp (Exp2 , vtable, f table)
explicitly declare
else types
Exp3 oft3 (all)
= Check functions
Exp (Exp3 , vtable,or variables
f table)
if t1 = bool and t2 = t3
Types are automatically inferred
then t2 at compile time.
else error(); t2
The followingidOCaml
( Exps ) code will generate
t = lookup( an error at compile time
f table, getname(id))
if t = unbound
let rec length = function
then error();
[] > 0 int
else
| h::t > 1 + (length t);;
((t1 , . . . ,tn ) ! t0 ) = t
[t1 , . . . ,tm ] = CheckExps (Exps, vtable, f table)
letif myf
m = n() and = t1length
= t1 , . . .4;;
,tn = tn
In our illustrative example,then there t0
else error(); t0
is inference in the let expression:
let id = Exp1 t1 = CheckExp (Exp1 , vtable, f table)
in Exp2 vtable = bind(vtable, getname(id),t1 )
CheckExp (Exp2 , vtable , f table)

The type of idCheckExps (Exps, vtable,


is inferred fromf table) case Exps
the =type of .
of Exp 1
Exp [CheckExp (Exp, vtable, f table)]
Exp , Exps CheckExp (Exp, vtable, f table)
:: CheckExps (Exps, vtable, f table)
Semantic analysis 279
Scope and type checking for object-oriented languages

Each class declaration is added to the (global) symbol table or to a


separate table for types
Each class declaration also introduces a new scope:
I that contains all declared fields and methods
I that have scopes of methods as sub-scopes
Inheritance implies a hierarchy of class scopes
I If class B extends class A, then scope of A is a parent scope for B.
Each scope can be implemented as a single symbol table, combining
fields and methods, or as two separate tables, one for fields and one
for methods.

Semantic analysis 280


Example
How To Test the SubType Relation
class A {
int x; Global symtab
int f(int z) { A obj =A=
int v; … B obj =B=
} C obj =C=
}
=A= symtab =C= symtab
class B extends A { x var int a var =A=
bool y; f fun int → int b var =B=
int t;
} =B= symtab f symtab
class C { y var bool z arg int
A a; t var int v var int
B b; …

a = b;
}
CS 412/413 Spring 2007 Introduction to Compilers 38

Semantic analysis 281


Scope checking

Resolve identifier occurrence in a method:


Starts the search from the symbol table of the current block and
then walk the symbol table hierarchy

Resolve qualified accesses: e.g., o.f , where o is of class A.


Walk the symbol table hierarchy starting with the symbol table of
class A.
this (or self) keyword starts the walk from the symbol table of
the enclosing class.

Note: multiple inheritance (Class B extends A,C) can cause


problems when the same symbol exist in two parent scopes.

Semantic analysis 282


Subtyping

If class B extends class A, then type B is a subtype of A (type A is


a supertype of B).
Subtype polymorphism: Code using class A objects can also use
class B objects.
For type checking, subtype relations can be tested from the
hierarchy of class symbol tables.

Problems with subtyping:


I The actual type of an object is unknown at compile time: it can be
the declared class or any subclass.
I Problematic for overridden fields and methods: we don’t know which
declaration to use at compile time.
I Solution is language dependent: this can be addressed statically by
imposing constraints on language and/or dynamically

Semantic analysis 283

You might also like