Transcript

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.

Programming Language PrinciplesLecture 26

Prepared byManuel E. Bermúdez, Ph.D.

Associate ProfessorUniversity of Florida

Denotational Semantics


Top Related