You are on page 1of 10

Attribute Grammars An Example

An attribute grammar is a context-free grammar Recall the context-sensitive language from


that has been extended to provide context- Chapter 1:
sensitive information by appending attributes L = { anbncn | n1 }
to some of its nonterminals.
Each distinct symbol in the grammar has
associated with it a finite, possibly empty, Important result from computation theory:
set of attributes. No context-free grammar generates L.
Each attribute has a domain of possible values.
An attribute may be assigned values from its An attempt:
domain during parsing. <string> ::= <a seq> <b seq> <c seq>
Attributes can be evaluated in assignments <a seq> ::= a | <a seq> a
or conditions. <b seq> ::= b | <b seq> b
<c seq> ::= c | <c seq> c
Two Classes of Attributes
Synthesized attribute : An attribute that This context-free grammar generates the
gets its values from the attributes attached language
to the children of its nonterminal. a+b+c+ = { akbmcn | k1, m1, n1 }
Inherited attribute : An attribute that gets
its values from the attributes attached to the
parent (or siblings) of its nonterminal.
Chapter 3 1 Chapter 3 2

Using an Attribute Grammar Size =

c
Size (<a seq>) = Size (<b seq>) = Size (<c seq>)

Attach a synthesized attribute, Size, to each of the


Size =
<c seq>

nonterminals: <a seq>, <b seq>, and <c seq>.

c
Size =
<c seq>

Domain of Size = Positive Integers

c
Size =
Impose a condition on the first production.
<c seq>
Size =

<c seq>
<string>

<string> ::= <a seq> <b seq> <c seq>


<b seq>

c
Size =

condition:
b

Size(<a seq>)=Size(<b seq>)=Size(<c seq>)


a <b seq>

Size =

<a seq> ::= a


b

Size(<a seq>) 1
<b seq>
Size =

| <a seq>2 a
condition:

Size =

Size(<a seq>) Size(<a seq>2)+1


<a seq>

<b seq>
Size =

<b seq> ::= b


b

Size(<b seq>) 1
a
<a seq>

| <b seq>2 b
Size =

Size(<b seq>) Size(<b seq>2)+1


a
<a seq>

<c seq> ::= c


Size =

Size(<c seq>) 1
| <c seq>2 c
<a seq>

Size(<c seq>) Size(<c seq>2)+1


a

Chapter 3 3 Chapter 3 4
Using an Inherited Attribute

Size =
Attach a synthesized attribute Size to <a seq>

c
and inherited attributes InSize to <b seq> and
Size (<a seq>) = Size (<b seq>) = Size (<c seq>)

<c seq>
<c seq>.

Size =
<c seq>
<string> ::= <a seq> <b seq> <c seq>

c
InSize(<b seq>) Size(<a seq>)
InSize(<c seq>) Size(<a seq>)
Size =
<string>

b
<a seq> ::= a
<b seq>

Size(<a seq>) 1

Size =
a <b seq> | <a seq>2 a
Size(<a seq>) Size(<a seq>2)+1
b
<b seq> ::= b
Size =
condition:

condition:
<a seq>

InSize(<b seq>) = 1
Size =

| <b seq>2 b
InSize(<b seq>2) InSize(<b seq>)-1
a
<a seq>

Size =

<c seq> ::= c


condition:
<a seq>

InSize(<c seq>) = 1
a

| <c seq>2 c
InSize(<c seq>2) InSize(<c seq>)-1
Chapter 3 5 Chapter 3 6

Definition
condition: InSize =1

An attribute grammaris a context-free


InSize =

grammar augmented with attributes, semantic


rules, and conditions.
c
<c seq>

InSize =

Let G = <N,,P,S> be a context-free grammar.


<c seq>

Write a production p P in the form:


X0 ::= X1 X2 Xnp where np 1, X0 N,
condition: InSize =1
c
InSize =

and Xk N for 1 k np.


b
<string>

<b seq>

InSize =

A derivation treefor a sentence in a


InSize =
a <b seq>

context-free language has the properties:


<b seq>

a) Each of its leaf nodes is labeled with a


Size =

symbol from , and


b
<a seq>

b) Each interior node t corresponds to a


production p P such that t is labeled
Size =

with X0 and t has np children labeled with


<a seq>

X1, X2, , Xnp in left-to-right order.


Size =
<a seq>

Chapter 3 7 Chapter 3 8
For each syntactic category X N in the Consider again a production p P of the form:
grammar, there are two finite disjoint sets: X0 ::= X1 X2 Xnp
I(X) of inherited attributes
, and Derivation Tree:
S(X) of synthesized attributes
. X0
I(S) = where S is the start symbol.

Let A(X) = I(X) S(X) be the set of attributes of X.


X1 X2 X3 Xn
p

Each attribute Atb A(X) takes a value from


some semantic domain associated with that
Each synthesized attribute Atb S(X0) has its
attribute
value defined in terms of the attributes in
e.g. integers, strings of characters, A(X1) A(X2) A(Xnp) I(X0).
structures of some type

The values of attributes are defined by semantic Each inherited attribute Atb I(Xk) for 1 k np
functionsor semantic rulesassociated with the has its value defined in terms of the attributes in
productions in P. A(X0) S(X1) S(Xnp).

Chapter 3 9 Chapter 3 10

Calculating Attribute Values for


Each production may also have a set of Binary Numerals
conditions on the values of the attributes in
A(X0) A(X1) A(Xnp)
Synthesized Inherited
that further constrain an application of the Nonterminals Attributes Attributes
production.
<binary numeral> Val ---
<binary digits> Val Pos
The parse of a sentence in the attribute
grammar is satisfied <fraction digits> Val, Len ---
if only if <bit> Val Pos
the context-free grammar is satisfied and all
conditions in the attribute grammar are true.
The Attribute Grammar
<binary numeral> ::= <binary digits> . <fraction digits>
The semantics of a nonterminal can be Val(<binary numeral>)
considered to be a distinguished attribute Val(<binary digits>)+Val(<fraction digits>)
evaluated at the root node of the derivation Pos(<binary digits>) 0
tree of that nonterminal.
<binary digits> ::= <binary digits>2 <bit>
Val(<binary digits>)
Val(<binary digits>2) + Val(<bit>)
Pos(<binary digits>2) Pos(<binary digits>) + 1
Pos(<bit>) Pos(<binary digits>)
Chapter 3 11 Chapter 3 12
<binary digits> ::= <bit> Binary Numeral Semantics: 11.1101
Val(<binary digits>) Val(<bit>)
Pos(<bit>) Pos(<binary digits>)

<bit>

Pos :
Val :

1
<fraction digits>
<fraction digits> ::= <fraction digits>2 <bit>
Val(<fraction digits>)
Val(<fraction digits>2) + Val(<bit>)

<bit>

Pos :
Len :

Val :
Val :

0
Len(<fraction digits>)

<fraction digits>
Len(<fraction digits>2) + 1

<bit>

Pos :
Val :
<binary numeral>

1
<fraction digits>
Pos(<bit>) Len(<fraction digits>)

Len :
Val :
<fraction digits> ::= <bit>

<fraction digits>
Len :
Val :
Val(<fraction digits>) Val(<bit>)

Val :
Len(<fraction digits>) 1

<bit>

Pos :
Val :

1
<binary digits>

Len :
Pos(<bit>) 1

Val :
<bit>

Pos :
Val :

1
<bit> ::= 0

Pos :
Val :

<binary digits>
Val(<bit>) 0

<bit> ::= 1

Pos :
Val :

<bit>

Pos :
Val :

1
Val(<bit>) 2Pos (<bit>)

Observe the order of evaluation of the attributes.


Chapter 3 13 Chapter 3 14

Checking Context Attribute Value Types


Constraints in Wren Type { integer, boolean,
program, undefined }
Augment the context-free grammar (concrete synthesizedfor <type>
syntax) for Wren with attributes whose
conditions check the context conditions of Wren. inheritedfor <expr>, <int expr>, <term>,
<element>, <bool expr>, <bool term>,
1. The program name identifier may not be and <bool element>
declared elsewhere in the program.
2. All identifiers that appear in a block must be Name String of letters or digits
declared in that block. synthesizedfor <variable>, <identifier>,
3. No identifier may be declared more than once <letter>, and <digit>
in a block.
Var-list Sequence of Name values
4. The identifier on the left side of an assignment
command must be declared as a variable, and synthesizedfor <variable list>
the expression on the right must be of the
same type. Symbol-table Set of pairs of the
form [Name, Type]
5. An identifier occurring as an (integer) element
must be integer variable. synthesizedfor <dec seq> and <dec>
6. An identifier occurring as a boolean element inheritedfor <block>, <cmd seq>,
must be boolean variable. <cmd>, <expr>, <int expr>, <term>,
<element>,<bool expr>, <bool term>,
7. An identifier occurring in a read command
<bool element>, and <comparison>
must be integer variable.
Chapter 3 15 Chapter 3 16
Declarations <var list> ::= <variable>
Var-list(<var list>)
var x,y : integer;
cons(Name(<variable>), empty-list)

<declaration> <var list> ::= <variable> , <var list>2


Symbol-table: S1 = [['x', integer],['y', integer]]
Var-list(<var list>)
var <variable list> : ;
cons(Name(<variable>),Var-list(<var list>2))
<type>
Var-list: ['x','y'] Type: integer
condition: true condition:
if Name(<variable>) is not a
integer
<variable> , <variable list>
member of Var-list(<var list>2)
Name: 'x' Var-list: ['y'] then error()
else error(Duplicate variable in
<identifier> <variable>
Name: 'x' Name: 'y' declaration list)
<letter> <identifier>
Name: 'x' Name: 'y'
Auxiliary Functions
x <letter> build-symbol-table(var-list, type)
Name: 'y'
add-item(name, type, table)
y
table-union(table1, table2)
table-intersection(table1, table2)
lookup-type(name, table)
Chapter 3 17 Chapter 3 18

table-union(table1, table2) = Declaration Sequences


if empty(table1)
then table2 var x,y : integer; var a : boolean;
else
<declaration sequence>
if lookup-type(first-name(table1),table2) = Symbol-table: S1 S2 = [['x', integer],['y', integer],['a', boolean]]
undefined condition: true
then cons(head(table1),
table-union(tail(table1), table2)) <declaration> <declaration sequence>
Symbol-table:
Symbol-table:
else table-union(tail(table1), table2)). S1 = [['x', integer],['y', integer]] S2 = [['a', boolean]]

table-intersection(table1, table2) = <dec seq> ::=


if empty(table1) Symbol-table(<dec seq>) empty-table
then empty
else <dec seq> ::= <dec> <dec seq>2
if lookup-type(first-name(table1),table2) Symbol-table(<dec seq>)
undefined table-union(Symbol-table(<dec>),
then nonempty Symbol-table(<dec seq>2))
else condition:
table-intersection(tail(table1), table2). if table-intersection(
Symbol-table(<dec>),
Symbol-table(<dec seq>2 )) = empty
then error()
else error(Duplicate declaration of
an identifier)
Chapter 3 19 Chapter 3 20
Commands
<declaration> ::= var <variable list> : <type>;
Symbol-table(<declaration>) <cmd> ::= <variable> := <expr>
build-symbol-table(
Var-list(<var list>),Type(<type>)). Symbol-table(<expr>)
Symbol-table(<cmd>)
Passing Context from Type(<expr>)
Declarations to Commands lookup-type( Name(<variable >),
Symbol-table(<cmd>))
<program> ::= program<identifier> is <block> condition:
case
Symbol-table(<block>) lookup-type(Name(<variable>),
add-item( (Name(<identifier>), program), Symbol-table(<cmd>)) is
empty-table) integer, boolean : error()
undefined : error(Target variable
<block> ::= <dec seq> begin <cmd seq> end not declared)
program : error(Target variable same
Symbol-table(<cmd seq>) as program name)
table-union( Symbol-table(<block>),
Symbol-table(<dec seq>)) <cmd> ::= read <variable>
condition:
condition: case lookup-type(Name(<variable>),
if table-intersection(
Symbol-table(<block>), Symbol-table(<cmd>)) is
Symbol-table(<dec seq>)) = empty integer : error()
then error() undefined : error(Variable not declared)
else error(Program name used as boolean, program : error(Integer var
a variable) expected for read)
Chapter 3 21 Chapter 3 22

<command> ::= write <expr>


Symbol-table(<expr>)
Expressions
Symbol-table(<command>) Symbol-table is inherited down into the derivation
Type(<expr>) integer trees for expressions.

<command> ::= Need to check <variable> when expecting an


while <boolean expr> do integer expression or a boolean expression.
<command sequence> end while
Symbol-table(<boolean expr>) <expr> ::= <int expr>
Symbol-table(<command>) Symbol-table(<int expr>)
Symbol-table(<command sequence>) Symbol-table(<expr>)
Symbol-table(<command>)
Type(<int expr>) Type(<expr>)
<command> ::= condition:Type(<expr>) { boolean }
if <boolean expr>
then <command sequence>1
else <command sequence>2 <expr> ::= <bool expr>
end if Symbol-table(<boolean expr>)
Symbol-table(<boolean expr>) Symbol-table(<expr>)
Symbol-table(<command>) Type(<bool expr>) Type(<expr>)
Symbol-table(<command sequence> 1) condition:Type(<expr>) { integer }
Symbol-table(<command>)
Symbol-table(<command sequence> 2)
Symbol-table(<command>)
Chapter 3 23 Chapter 3 24
<bool expr> ::= <bool term> <bool term> ::= <bool elem>
Symbol-table(<bool term>) Symbol-table(<bool elem>)
Symbol-table(<bool expr>) Symbol-table(<bool term>)
Type(<bool term>) Type(<bool expr>) Type(<bool elem>) Type(<bool term>)

<bool expr> ::= <bool expr>2 or <bool term> <bool term> ::= <bool term>2 and <bool elem>
Symbol-table(<bool expr>2) Symbol-table(<bool term>2)
Symbol-table(<bool expr>) Symbol-table(<bool term>)
Symbol-table(<bool term>) Symbol-table(<bool elem>)
Symbol-table(<bool expr>) Symbol-table(<bool term>)
Type(<bool expr>2) Type(<bool expr>) Type(<bool term>2) Type(<bool term>)
Type(<bool term>) Type(<bool expr>) Type(<bool elem>) Type(<bool term>)

Chapter 3 25 Chapter 3 26

<bool elem> ::= true


<bool elem> ::= false <comparison> ::=
<integer expr>1 <relation> <integer expr>2
<bool elem> ::= <variable>
condition: Symbol-table(<integer expr>1)
case Symbol-table(<comparison>)
lookup-type(Name(<variable>),
Symbol-table(<bool elem>)) is Symbol-table(<integer expr>2)
boolean : error() Symbol-table(<comparison>)
undefined : error(Variable not declared)
integer, program : Type(<integer expr>1) integer
if Type(<bool elem>) = undefined
then error() Type(<integer expr>2) integer
else error(Bool variable expected)
<bool elem> ::= ( <bool expr> )
Symbol-table(<bool expr>)
Symbol-table(<bool elem>)
Type(<bool expr>) Type(<bool elem>)

<bool elem> ::= not( <bool expr> )


Symbol-table(<bool expr>)
Symbol-table(<bool elem>)
Type(<bool expr>) Type(<bool elem>)
Chapter 3 27 Chapter 3 28
Block
Implementing
<block> ::= <dec seq> begin <cmd seq> end
Attribute Grammars
Symbol-table(<cmd seq>)
Parser produces a modified token list, not an table-union(Symbol-table(<block>),
abstract syntax tree. Symbol-table(<dec seq>))
condition:
if table-intersection(Symbol-table(<block>),
Program Symbol-table(<dec seq>)) = empty
then error()
else error(Program name used as a var)
<program> ::= program<identifier> is <block>
block([ErrorMsg, Decs, begin, Cmds, end],
Symbol-table(<block>) InitialSymbolTable) -->
add-item((Name(<identifier>), program), decs(Decs,DecsSymbolTable),
empty-table) { tableIntersection(InitialSymbolTable,
DecsSymbolTable,Result),
program(TokenList) --> tableUnion(InitialSymbolTable,
DecsSymbolTable, SymbolTable),
[program],[ide(I)],[is], ( Result=nonEmpty,
{ addItem(I,program,[ ],InitialSymbolTable) }, ErrorMsg='ERROR: Program name
used as variable'
block(Block, InitialSymbolTable),
; Result=empty, ErrorMsg=noError) },
{ flattenplus([program, ide(I), is, Block], [begin], cmds(Cmds,SymbolTable), [end].
TokenList) }.

Chapter 3 29 Chapter 3 30

Command Sequence
Read Command
<cmd seq> ::= <command>
Symbol-table(<cmd>) <cmd> ::= read <variable>
Symbol-table(<cmd seq>) condition:
case lookup-type(Name(<variable>),
<cmd seq> ::= <command> ; <cmd seq>2 Symbol-table(<cmd>)) is
Symbol-table(<cmd>) integer : error()
Symbol-table(<cmd seq>) undefined : error(Variable not declared)
Symbol-table(<cmd seq>2) boolean, program : error(Integer var
Symbol-table(<cmd seq>) expected for read)

command([read, ide(V), ErrorMsg],


cmds(Cmds,SymbolTable) --> SymbolTable) -->
command(Cmd,SymbolTable),
restcmds(Cmd,Cmds,SymbolTable). [read], [ide(V)],
restcmds(Cmd, [Cmd, semicolon|Cmds], { lookupType(V,SymbolTable,VarType),
SymbolTable) --> (VarType = integer, ErrorMsg=noError ;
[semicolon], cmds(Cmds,SymbolTable).
VarType = undefined,
restcmds(Cmd,[Cmd],SymbolTable) --> [ ]. ErrorMsg='ERROR: Variable not delcared' ;
(VarType = boolean ; VarType = program),
ErrorMsg='ERROR: Integer variable
expected for read') }.
Chapter 3 31 Chapter 3 32
Write Command

<command> ::= write <expr>


Assignment Command
Symbol-table(<expr>)
Symbol-table(<command>) <command> ::= <variable> := <expr>
Type(<expr>) integer Symbol-table(<expr>)
Symbol-table(<cmd>)
command([write,E],SymbolTable) -->
[write], expr(E,SymbolTable,integer). Type(<expr>)
lookup-type(Name(<variable>),
Symbol-table(<cmd>))
While Command
condition:
<command> ::= case
while <boolean expr> do lookup-type(Name(<variable>),
<command sequence> end while Symbol-table(<cmd>)) is
Symbol-table(<boolean expr>) integer, boolean : error()
Symbol-table(<command>) undefined : error(Target variable
Symbol-table(<command sequence>) not declared)
Symbol-table(<command>) program : error(Target variable same
Type(<boolean expr>) boolean as program name)
command([while,Test,do,Body,end,while],
SymbolTable) -->
[while],
boolexpr(Test,SymbolTable,boolean), [do],
cmds(Body,SymbolTable), [end], [while].
Chapter 3 33 Chapter 3 34

command([ide(V),assign,E,ErrorMsg], Expressions
Symtab) -->
[ide(V)], [assign], <expr> ::= <integer expr>
{ lookupType(V,SymbolTable,VarType) }, Symbol-table(<int expr>)
({ VarType = integer }, Symbol-table(<expr>)
(expr(E,Symtab,integer), Type(<int expr>) Type(<expr>)
{ ErrorMsg=noError } condition: Type(<expr>) { boolean }
; expr(E,Symtab,boolean),
{ ErrorMsg='ERROR: Int expr expected' }) <expr> ::= <boolean expr>
; Symbol-table(<bool expr>)
{ VarType = boolean }, Symbol-table(<expr>)
(expr(E,Symtab,boolean), Type(<int expr>) Type(<expr>)
{ ErrorMsg=noError }
; expr(E,Symtab,integer), condition: Type(<expr>) { integer }
{ ErrorMsg='ERROR: Bool expr expected' })
;
{ VarType = undefined, expr(E,SymbolTable,integer) -->
ErrorMsg='ERR: Target of asgn not decd' intexpr(E,SymbolTable,integer).
; expr(E,SymbolTable,boolean) -->
VarType = program, boolexpr(E,SymbolTable,boolean).
ErrorMsg='ERR: Prog name used as var' }
expr(E,SymbolTable,undefined) -->
expr(E,Symtab,undefined)).
intexpr(E,SymbolTable,undefined).
expr(E,SymbolTable,undefined) -->
boolexpr(E,SymbolTable,undefined).
Chapter 3 35 Chapter 3 36
Integer Expressions Terms

<int expr> ::= <term> <term> ::= <element>


Symbol-table(<element>)
Symbol-table(<term>)
Symbol-table(<term>)
Symbol-table(<int expr>)
Type(<term>) Type(<int expr>) Type(<element>) Type(<term>)

<int expr> ::= <int expr>2 <weak op> <term> <term> ::= <term>2 <strong op> <element>
Symbol-table(<int expr>2) Symbol-table(<term> 2 )
Symbol-table(<term>)
Symbol-table(<int expr>)
Symbol-table(<term>) Symbol-table(<element>)
Symbol-table(<int expr>) Symbol-table(<term>)
Type(<int expr>2) Type(<int expr>) Type(<term>2) Type(<term>)
Type(<term>) Type(<int expr>) Type(<element>) Type(<term>)

intexpr(E,SymbolTable,Type) --> term(T,SymbolTable,Type) -->


term(T,SymbolTable,Type), element(El,SymbolTable,Type),
restintexpr(T,E,SymbolTable,Type). restterm(El,T,SymbolTable,Type).

restintexpr(T,E,SymbolTable,Type) --> restterm(El,T,SymbolTable,Type) -->


weakop(Op), term(T1, SymbolTable,Type), strongop(Op),
restintexpr([T,Op,T1], E, SymbolTable,Type). element(El1, SymbolTable,Type),
restterm([El,Op,El1], T, SymbolTable,Type).
restintexpr(E,E,SymbolTable,Type) --> [ ].
restterm(T,T,SymbolTable,Type) --> [ ].
Chapter 3 37 Chapter 3 38

Element element([num(N)],SymTab,Type) --> [num(N)].

<element> ::= <numeral> element([ide(I),ErrorMsg],Symtab,Type) -->


<element> ::= <variable> [ide(I)],
condition: { lookupType(I,Symtab,VarType),
case lookup-type (Name(<variable>),
Symbol-table(<element>)) is (VarType = int, Type = int, ErrorMsg=noError
integer : error() ; VarType = undefined, ErrorMsg=
undefined : error(Var not declared) 'ERROR: Variable not declared'
boolean, program :
if Type(<element>) = undefined ; Type = undefined, ErrorMsg=noError
then error() ; (VarType = boolean ; VarType = program),
else error(Int var expected) ErrorMsg='ERROR: Int var expected') }.
<element> ::= ( <expr> )
Symbol-table(<expr>)
Symbol-table(<element>) element([lparen, E, rparen], Symtab,Type) -->
[lparen], intexpr(E,Symtab,Type), [rparen].
Type(<expr>) Type(<element>)
<element> ::= - <element>2
element([minus|E],Symtab,Type) -->
Symbol-table(<element> 2) [minus], element(E,Symtab,Type).
Symbol-table(<element>)
Type(<element>2) Type(<element>)
Try It cp ~slonnegr/public/plf/context .
Chapter 3 39 Chapter 3 40

You might also like