Date post: | 31-Dec-2015 |
Category: |
Documents |
Upload: | nathaniel-reeves |
View: | 220 times |
Download: | 0 times |
Programming Language PrinciplesLecture 26
Prepared byManuel E. Bermúdez, Ph.D.
Associate ProfessorUniversity of Florida
Denotational Semantics
Semantic Descriptions
• In general, three approaches to describing semantics of a programming language:
1. Axiomatic approach:• Good formalizing type systems. Skipped.
2. Operational approach:• Describe semantics by giving a process.• The “meaning” of a program is the result of
the process.• Program behavior gleaned from process.• RPAL: scan, parse, standardize, evaluate.
Denotational Semantics
3. Denotational approach:
• Describe semantics by “denoting” constructs, usually with functions.
• The “meaning” of a program is given by a collection of semantic functions, on a construct-by-construct basis.
• Program behavior gleaned from behavior of semantic functions.
• We will specify Tiny.
Denotation Descriptions
• A denotational semantic description has three parts:
1. A set of syntactic domains (usually AST’s).2. A set of semantic domains.
• Usually, objects and/or states.3. A set of semantic functions.
• Functions describe how PL constructs manipulate/change values in the semantic domains.
We will use RPAL notation to describe functions
Sample Denotational Description
Let’s describe the behavior of an ‘add’ instruction in a fictitious machine.
1. Syntactic domain: ASTs of the form
<Opcode Operand1 Operand2>
2. Semantic domains:Register: {0,1,2,3,4,5,6,7}Value: {16-bit number}Address: {16-bit number}Memory: Address → ValueRegValues: Address → Value
Sample Denotational Description
3. Semantic function: EE (for EEvaluate).
EE: AST → (RegValues x Memory) → (RegValues x Memory)
EE takes an AST, and returns a function that• takes a (registers,memory) pair, and
returns a new (registers,memory) pair.• EE shows how the “state” is changed by
the construct in the AST.• “state”: current register contents, and
current memory contents.
Sample Denotational Description
Description of the ‘add’ operation:
EE[<+ r m>] = λ(R,M). let Result = R r + M m
in (R, (λa. a eq m → Result | M a))
1. Get contents of register r, add to contents of memory location m (yielding Result).
2. Build new “state”:• Registers (mapping) R unchanged.• New memory, maps m to Result, otherwise
maps as M does.
Sample Denotational Description
A different ‘add’ operation:
EE[<+ r m>] = λ(R,M). let Result = R r + M m
in ((λp. p eq r → Result | R p), M)
1. Get contents of register r, add to contents of memory location m (yielding Result).
2. Build new “state”:• New registers: register r contains Result.• Memory M unchanged.
Sample Denotational Description
Clearly, the denotational description specifies the semantics of the <+ r m> instruction.
– Behavior depends on (is function of) R and M.– Add contents of register r and memory m.– We specified two versions:
1. Store result in memory location m.2. Store result in register r.
Functions as “Storage”
Where do R and M come from ?
Consider
R0 = (λ().0) all registers contain zero.
R1= (λp. p eq 2 → 3 | R0 p) register 2 contains 3, others zero.
R2= (λp. p eq 4 → 7 | R1 p) register 2 contains 3, 4 contains 7, others zero.
R3= (λp. p eq 2 → 5 | R2 p) register 2 contains 5 ! (3 forgotten) register 4 contains 7, others zero.
Some Useful Notation
The “pipeline” operator (=>):
x => f denotes
x eq error → error | f(x)
Before applying a function f to an argument:• Check whether it’s error.• If it is, cancel application of f, return error.
x f
Some Useful Notation (cont’d)
The “o” (composition) operator is defined as
o = λf. λg. λx. f x eq error → error | g(f x)
• The “o” function takes two functions, f and g, and an argument x.
– Evaluate f(x):
• If f(x) is error, return error (cancel application of g)
• Otherwise, return g(f(x)).
Some Useful Notation (cont’d)
We will use “o” as an infix operator, writing f o g instead of o f g.
• Advantage:(f o g o h) x means calculate
h(g(f(x))), but cancel all applications ifthe result is ‘error’ anywhere along the way.
x f g h
Some Useful Notation (cont’d)
• In our expressions, o has higher precedence than =>
• Example:x => f o g o h means
(f o g o h) x which is
h(g(f(x) unless any value (including x) is ‘error’ along the way.
Also, both => and o are left associative.
Tiny’s Denotational Semantics
Tiny’s syntactic domains:
AST = E + C + P, whereE = 0 | 1 | 2 ... | true | false | read | Id |
<not E> | < ≤ E E> | <+ E E>C = <:= I E> | <print E> | <if E C C> |
<while E C> | <; C C>P = <program C>
Tiny’s Denotational Semantics (cont’d)
Tiny’s Semantic Domains.
State: Mem x Input x Output
Mem: Id → Val
Input: Val* (zero or more values)Output: Val*Val: Num + Bool
Tiny’s Denotational Semantics (cont’d)
Tiny’s semantic functions.
EE: E → State → (Val x State)
CC: C → State → State
PP: P → Input → Output
Some Auxiliary FunctionsReturn: Val → State → (Val x State)
λv. λs. (v,s)
Check: Domain → (Val x State) → (Val x State) λD. λ(v,s). v D → (v,s) | error
Dummy: State → State λs. s
Cond: (State → State) λF1.
→ (State → State) λF2. → (Val x State) λ(v,s). → State s => (v → F1 | F2)
Replace: Mem → Id → Val → Mem λm. λi. λv. (λi'. i' eq i → v | m i')
Now, for EE, CC, and PP
EE[0] = Return 0; EE[1] = Return 1; EE[2] = Return 2; ... etc.
EE[true] = Return true; EE[false] = Return false
EE[read] = λ(m,i,o). Null i → error
| (Head i, (m, Tail i, o))
EE[I] = λ(m,i,o). m I eq → error | (m I, (m,i,o))
The EE Semantic Function (cont’d)
EE[<not E>] = EE[E]o (Check Bool)o (λ(v,s).((not v),s) )
EE[<≤ E1 E2>] = EE[E1]o (Check Num)o (λ(v1,s1). s1 => EE[E2]
=> (Check Num)=> (λ(v2,s2).(v1 ≤ v2,s2)
)
The EE Semantic Function (cont’d)
EE[<+ E1 E2>] = EE[E1]o (Check Num)o (λ(v1,s1). s1 => EE[E2]
=> (Check Num)=> (λ(v2,s2).(v1 + v2,s2)
)
The CC Semantic Function
CC[<:= I E>] = EE[E] o (λ(v,(m,i,o)). (Replace m I v, i, o))
CC[<print E>] = EE[E] o (λ(v,(m,i,o)). (m,i,o aug v))
CC[<if E C1 C2>] = EE[E] o (Check Bool) o (Cond CC[C1] CC[C2])
The CC and PP Semantic Functions
CC[<while E C>] = EE[E] o (Check Bool) o (Cond (CC[<; C <while E C>>]) Dummy)
CC[<; C1 C2>] = CC[C1] o CC[C2]
PP[<program C>] = (λi. CC[C] ((λ().), i, nil)) o (λ(m,i,o).o)
The meaning of a Tiny program <program C> is PP[<program C>]
Semantics of Tiny
• Issues enforced:– true, false, read not, if, while, print
treated as reserved words.– Can’t read from empty input.– Can’t use undefined variable values.– Argument of ‘not’ must be Bool.– ≤ comparison allowed only on Nums.– ‘+’ allowed only on Nums.– ‘If’ control expression must be Bool.– ‘while’ control expression must be Bool.
Semantics of Tiny (cont’d)
• Issues not enforced:
– Can store Bools ? Yes, even in a variable currently holding a Num !
– Legal values to print ? Anything.– No type checking on input values.– Typing issues difficult to enforce:
• Tiny has no declarations.