Attribute Grammars

18 downloads 111 Views 67KB Size Report
Chapter 3. 1. Attribute Grammars. An attribute grammar is a context-free grammar that has been extended to provide context- sensitive information by appending ...
Attribute Grammars

An Example

An attribute grammar is a context-free grammar that has been extended to provide contextsensitive information by appending attributes to some of its nonterminals. Each distinct symbol in the grammar has associated with it a finite, possibly empty, set of attributes.

Recall the context-sensitive language from Chapter 1: L = { anbncn | n≥1 } Important result from computation theory: No context-free grammar generates L.

• Each attribute has a domain of possible values. • An attribute may be assigned values from its domain during parsing. • Attributes can be evaluated in assignments or conditions.

An attempt: ::= ::= a | a ::= b | b ::= c | c

Two Classes of Attributes • Synthesized attribute : An attribute that gets its values from the attributes attached to the children of its nonterminal.

This context-free grammar generates the language a+b+c+ = { akbmcn | k≥1, m≥1, n≥1 }

• Inherited attribute : An attribute that gets its values from the attributes attached to the parent (or siblings) of its nonterminal. 2

Chapter 3

3

Chapter 3

b

Size =

c

Size =

c a

b a



Size =



Size =

c Size =

Size =

b

Size =

b

Size =

::= c Size() ← 1 | 2 c Size() ←Size(2)+1

a

::= b Size() ← 1 | 2 b Size() ← Size(2)+1



::= a Size() ← 1 | 2 a Size() ← Size(2)+1

a

condition: Size(
)=Size()=Size()

Size =

::=




Impose a condition on the first production.



Domain of Size = Positive Integers



Attach a synthesized attribute, Size, to each of the nonterminals:
, , and .

Size =

condition: Size (
) = Size () = Size ()

Using an Attribute Grammar

c

Chapter 3

Size =

1

Size =

Chapter 3

4

Attach a synthesized attribute Size to
and inherited attributes InSize to and . c



::=
InSize() ← Size() InSize() ← Size()

b

Size =

::= a Size() ← 1 | 2 a Size() ← Size(2)+1 ::= b condition: InSize() = 1 | 2 b InSize(2) ← InSize()-1 Size =

a

condition: InSize() = 1 | 2 c InSize(2) ← InSize()-1 Chapter 3

6

Definition

InSize = condition: InSize =1

InSize = condition: InSize =1

Let G = be a context-free grammar. Write a production p ∈P in the form: X0 ::= X1 X2 … Xnp where np ≥ 1, X0 ∈ N, and Xk ∈ N ∪ Σ for 1 ≤ k ≤ np.

A derivation treefor a sentence in a context-free language has the properties: a) Each of its leaf nodes is labeled with a symbol from Σ, and

b



b

c

An attribute grammaris a context-free grammar augmented with attributes, semantic rules, and conditions.

b) Each interior node t corresponds to a production p ∈ P such that t is labeled with X0 and t has np children labeled with X1, X2, …, Xnp in left-to-right order. a

Size =



a



b a InSize =
Size =

InSize =
Size =



c

5

InSize =

Chapter 3

Chapter 3

::= c a





Size =

a

b

Size =

Size =

c

Size =

Size =



condition: Size (
) = Size () = Size ()

Using an Inherited Attribute

7

Chapter 3

8

Consider again a production p ∈ P of the form:

For each syntactic category X ∈ N in the grammar, there are two finite disjoint sets:

X0 ::= X1 X2 … Xnp

I(X) of inherited attributes , and

Derivation Tree: X0

S(X) of synthesized attributes . I(S) = ∅ where S is the start symbol. Let A(X) = I(X) ∪ S(X) be the set of attributes of X. Each attribute Atb ∈ A(X) takes a value from some semantic domain associated with that attribute e.g. integers, strings of characters, structures of some type

X1

X2

X3



Xn p

Each synthesized attribute Atb ∈ S(X0) has its value defined in terms of the attributes in A(X1) ∪ A(X2) ∪ … ∪ A(Xnp) ∪ I(X0).

The values of attributes are defined by semantic functionsor semantic rulesassociated with the productions in P.

Each inherited attribute Atb ∈ I(Xk) for 1 ≤ k ≤ np has its value defined in terms of the attributes in A(X0) ∪ S(X1) ∪ … ∪ S(Xnp).

Chapter 3

Chapter 3

9

10

Calculating Attribute Values for Binary Numerals

Each production may also have a set of conditions on the values of the attributes in A(X0) ∪ A(X1) ∪ … ∪ A(Xnp) that further constrain an application of the production.

Synthesized Inherited Nonterminals Attributes Attributes

The parse of a sentence in the attribute grammar is satisfied



Val

---



Val

Pos



Val, Len

---



Val

Pos

if only if the context-free grammar is satisfied and all conditions in the attribute grammar are true.

The Attribute Grammar ::= . Val() ← Val()+Val() Pos() ← 0

The semantics of a nonterminal can be considered to be a distinguished attribute evaluated at the root node of the derivation tree of that nonterminal.

::= 2 Val() ← Val(2) + Val() Pos(2) ← Pos() + 1 Pos() ← Pos() Chapter 3

11

Chapter 3

12

1

Val : Pos :

1

0 Val : Pos : Val : Len :

Val : Pos : Val : Len : 1

Val : Len : Val : Pos :

1

1

::= 1 Val() ← 2Pos ()

Val : Pos :

::= 0 Val() ← 0

Val : Pos :

Val : Len :

::= Val() ← Val() Len() ← 1 Pos() ← – 1

Val : Pos :

Val :

::= 2 Val() ← Val(2) + Val() Len() ← Len(2) + 1 Pos() ← – Len()

Val : Pos :

Binary Numeral Semantics: 11.1101

::= Val() ← Val() Pos() ← Pos()

Observe the order of evaluation of the attributes. Chapter 3

13

Checking Context Constraints in Wren

Chapter 3

Attribute Type

Augment the context-free grammar (concrete syntax) for Wren with attributes whose conditions check the context conditions of Wren.

2. All identifiers that appear in a block must be declared in that block. 3. No identifier may be declared more than once in a block. 4. The identifier on the left side of an assignment command must be declared as a variable, and the expression on the right must be of the same type.

{ integer, boolean, program, undefined }

inheritedfor , , , , , , and Name

String of letters or digits

synthesizedfor , , , and Var-list

Sequence of Name values

synthesizedfor Symbol-table

5. An identifier occurring as an (integer) element must be integer variable.

Set of pairs of the form [Name, Type]

synthesizedfor and inheritedfor , , , , , , ,, , , and

6. An identifier occurring as a boolean element must be boolean variable. 7. An identifier occurring in a read command must be integer variable. 15

Value Types

synthesizedfor

1. The program name identifier may not be declared elsewhere in the program.

Chapter 3

14

Chapter 3

16

Declarations

::= Var-list() ← cons(Name(), empty-list)

var x,y : integer;

::= , 2

Symbol-table: S1 = [['x', integer],['y', integer]]

var

Var-list: ['x','y'] condition: true

:

Type: integer

Var-list() ← cons(Name(),Var-list(2))

;

condition: if Name() is not a member of Var-list(2) then error(“”) else error(“Duplicate variable in declaration list”)

integer Name: 'x'

,

Var-list: ['y']

Name: 'x'

Name: 'y'

Name: 'x'

Name: 'y'

x

Name: 'y'

Auxiliary Functions build-symbol-table(var-list, type) 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) = if empty(table1) then table2 else if lookup-type(first-name(table1),table2) = undefined then cons(head(table1), table-union(tail(table1), table2)) else table-union(tail(table1), table2)).

Declaration Sequences

table-intersection(table1, table2) = if empty(table1) then empty else if lookup-type(first-name(table1),table2) ≠ undefined then nonempty else table-intersection(tail(table1), table2).

::= ε Symbol-table() ← empty-table

Chapter 3

19

var x,y : integer; var a : boolean; Symbol-table: S1 ∪ S2 = [['x', integer],['y', integer],['a', boolean]] condition: true Symbol-table: S1 = [['x', integer],['y', integer]]

Symbol-table: S2 = [['a', boolean]]

::= 2 Symbol-table() ← table-union(Symbol-table(), Symbol-table(2)) condition: if table-intersection( Symbol-table(), Symbol-table(2 )) = empty then error(“”) else error(“Duplicate declaration of an identifier”) Chapter 3

20

Commands

::= var : ; Symbol-table() ← build-symbol-table( Var-list(),Type()).

::= :=

Passing Context from Declarations to Commands ::= program is Symbol-table() ← add-item( (Name(), program), empty-table) ::= begin end Symbol-table() ← table-union( Symbol-table(), Symbol-table()) condition: if table-intersection( Symbol-table(), Symbol-table()) = empty then error(“”) else error(“Program name used as a variable”) Chapter 3

21

::= write Symbol-table() ← Symbol-table() Type() ← integer

Symbol-table() ← Symbol-table() Type() ← lookup-type( Name(), Symbol-table()) condition: case lookup-type(Name(), Symbol-table()) is integer, boolean : error(“”) undefined : error(“Target variable not declared”) program : error(“Target variable same as program name”) ::= read condition: case lookup-type(Name(), Symbol-table()) is integer : error(“”) undefined : error(“Variable not declared”) boolean, program : error(“Integer var expected for read”) Chapter 3

22

Expressions Symbol-table is inherited down into the derivation trees for expressions.

::= while do end while Symbol-table() ← Symbol-table() Symbol-table() ← Symbol-table()

Need to check when expecting an integer expression or a boolean expression.

::= if then 1 else 2 end if Symbol-table() ← Symbol-table() Symbol-table( 1) ← Symbol-table() Symbol-table( 2) ← Symbol-table()

condition:Type() ∉ { boolean }

Chapter 3

23

::= Symbol-table() ← Symbol-table() Type() ← Type()

::= Symbol-table() ← Symbol-table() Type() ← Type() condition:Type() ∉ { integer }

Chapter 3

24

::=

::=

Symbol-table() ← Symbol-table() Type() ← Type()

::= 2 or

Symbol-table() ← Symbol-table() Type() ← Type()

::= 2 and

Symbol-table(2) ← Symbol-table()

Symbol-table(2) ← Symbol-table()

Symbol-table() ← Symbol-table() Type(2) ← Type()

Symbol-table() ← Symbol-table() Type(2) ← Type()

Type() ← Type()

Type() ← Type()

Chapter 3

25

Chapter 3

26

::= true ::= false ::= condition: case lookup-type(Name(), Symbol-table()) is boolean : error(“”) undefined : error(“Variable not declared”) integer, program : if Type() = undefined then error(“”) else error(“Bool variable expected”)

::= 1 2 Symbol-table(1) ← Symbol-table() Symbol-table(2) ← Symbol-table() Type(1) ← integer Type(2) ← integer

::= ( ) Symbol-table() ← Symbol-table() Type() ← Type() ::= not( ) Symbol-table() ← Symbol-table() Type() ← Type() Chapter 3

27

Chapter 3

28

Block

Implementing Attribute Grammars

::= begin end

Parser produces a modified token list, not an abstract syntax tree.

Program ::= program is Symbol-table() ← add-item((Name(), program), empty-table) program(TokenList) --> [program],[ide(I)],[is], { addItem(I,program,[ ],InitialSymbolTable) }, block(Block, InitialSymbolTable), { flattenplus([program, ide(I), is, Block], TokenList) }. Chapter 3

29

Symbol-table() ← table-union(Symbol-table(), Symbol-table()) condition: if table-intersection(Symbol-table(), Symbol-table()) = empty then error(“”) else error(“Program name used as a var”)

block([ErrorMsg, Decs, begin, Cmds, end], InitialSymbolTable) --> decs(Decs,DecsSymbolTable), { tableIntersection(InitialSymbolTable, DecsSymbolTable,Result), tableUnion(InitialSymbolTable, DecsSymbolTable, SymbolTable), ( Result=nonEmpty, ErrorMsg='ERROR: Program name used as variable' ; Result=empty, ErrorMsg=noError) }, [begin], cmds(Cmds,SymbolTable), [end].

Chapter 3

30

Command Sequence Read Command ::= Symbol-table() ← Symbol-table() ::= ; 2 Symbol-table() ← Symbol-table() Symbol-table(2) ← Symbol-table() cmds(Cmds,SymbolTable) --> command(Cmd,SymbolTable), restcmds(Cmd,Cmds,SymbolTable). restcmds(Cmd, [Cmd, semicolon|Cmds], SymbolTable) --> [semicolon], cmds(Cmds,SymbolTable). restcmds(Cmd,[Cmd],SymbolTable) --> [ ].

::= read condition: case lookup-type(Name(), Symbol-table()) is integer : error(“”) undefined : error(“Variable not declared”) boolean, program : error(“Integer var expected for read”) command([read, ide(V), ErrorMsg], SymbolTable) --> [read], [ide(V)], { lookupType(V,SymbolTable,VarType), (VarType = integer, ErrorMsg=noError ; VarType = undefined, ErrorMsg='ERROR: Variable not delcared' ; (VarType = boolean ; VarType = program), ErrorMsg='ERROR: Integer variable expected for read') }.

Chapter 3

31

Chapter 3

32

Write Command

Assignment Command

::= write Symbol-table() ← Symbol-table() Type() ←integer command([write,E],SymbolTable) --> [write], expr(E,SymbolTable,integer). While Command ::= while do end while Symbol-table() ← Symbol-table() Symbol-table() ← Symbol-table() Type() ←boolean

::= := Symbol-table() ← Symbol-table() Type() ← lookup-type(Name(), Symbol-table()) condition: case lookup-type(Name(), Symbol-table()) is integer, boolean : error(“”) undefined : error(“Target variable not declared”) program : error(“Target variable same 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

command([ide(V),assign,E,ErrorMsg], Symtab) --> [ide(V)], [assign], { lookupType(V,SymbolTable,VarType) }, ({ VarType = integer }, (expr(E,Symtab,integer), { ErrorMsg=noError } ; expr(E,Symtab,boolean), { ErrorMsg='ERROR: Int expr expected' }) ; { VarType = boolean }, (expr(E,Symtab,boolean), { ErrorMsg=noError } ; expr(E,Symtab,integer), { ErrorMsg='ERROR: Bool expr expected' }) ; { VarType = undefined, ErrorMsg='ERR: Target of asgn not decd' ; VarType = program, ErrorMsg='ERR: Prog name used as var' } expr(E,Symtab,undefined)).

Chapter 3

34

Expressions ::= Symbol-table() ← Symbol-table() Type() ← Type() condition: Type() ∉ { boolean } ::= Symbol-table() ← Symbol-table() Type() ← Type() condition: Type() ∉ { integer } expr(E,SymbolTable,integer) --> intexpr(E,SymbolTable,integer). expr(E,SymbolTable,boolean) --> boolexpr(E,SymbolTable,boolean). expr(E,SymbolTable,undefined) --> intexpr(E,SymbolTable,undefined). expr(E,SymbolTable,undefined) --> boolexpr(E,SymbolTable,undefined).

Chapter 3

35

Chapter 3

36

Integer Expressions

Terms

::= Symbol-table() ← Symbol-table() Type() ← Type()

::= Symbol-table() ← Symbol-table() Type() ← Type()

::= 2 Symbol-table(2) ← Symbol-table() Symbol-table() ← Symbol-table() Type(2) ← Type() Type() ← Type()

::= 2 Symbol-table( 2 ) ← Symbol-table() Symbol-table() ← Symbol-table() Type(2) ← Type() Type() ← Type()

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

term(T,SymbolTable,Type) --> element(El,SymbolTable,Type), restterm(El,T,SymbolTable,Type).

restintexpr(T,E,SymbolTable,Type) --> weakop(Op), term(T1, SymbolTable,Type), restintexpr([T,Op,T1], E, SymbolTable,Type).

restterm(El,T,SymbolTable,Type) --> strongop(Op), element(El1, SymbolTable,Type), restterm([El,Op,El1], T, SymbolTable,Type).

restintexpr(E,E,SymbolTable,Type) --> [ ]. Chapter 3

restterm(T,T,SymbolTable,Type) --> [ ]. 37

Chapter 3

38

Element

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

::=

element([ide(I),ErrorMsg],Symtab,Type) -->

::=

[ide(I)],

condition: case lookup-type (Name(), Symbol-table()) is integer : error(“”) undefined : error(“Var not declared”) boolean, program : if Type() = undefined then error(“”) else error(“Int var expected”) ::= ( ) Symbol-table() ← Symbol-table() Type() ← Type() ::= - 2 Symbol-table( 2) ← Symbol-table() Type(2) ← Type()

{ lookupType(I,Symtab,VarType), (VarType = int, Type = int, ErrorMsg=noError ; VarType = undefined, ErrorMsg= 'ERROR: Variable not declared' ; Type = undefined, ErrorMsg=noError ; (VarType = boolean ; VarType = program), ErrorMsg='ERROR: Int var expected') }. element([lparen, E, rparen], Symtab,Type) --> [lparen], intexpr(E,Symtab,Type), [rparen]. element([minus|E],Symtab,Type) --> [minus], element(E,Symtab,Type).

Try It Chapter 3

39

Chapter 3

cp ~slonnegr/public/plf/context . 40