Lecture notes 20190521

More Semantics 1 Control Flow

Require Import PL.Imp9.

The language

Now, let's consider a programming language with break and continue commands.
The majority of our definition remains the same with the language in Imp. We only add two kinds of commands to the definition of com:
Inductive com : Type :=
  | CSkip
  | CAss (X: var) (a : aexp)
  | CSeq (c1 c2 : com)
  | CIf (b : bexp) (c1 c2 : com)
  | CWhile (b : bexp) (c : com)
  | CBreak (* <--- new *)
  | CCont (* <--- new *)
  .
In this lecture, we discover how to defines its Hoare logic, denotational semantics and small step semantics.
Obviously, the functionalities of Break and Skip are different. But they look the same if only considering their modification on program states: neither of them modify program states. The difference between them is about determining which command will be executed next. This is called control flow.

Denotational Semantics

We start from denotational semantics.
Module Denotation_With_ControlFlow.
Program's denotation is defined as a ternary relation. Specifically, st1, ek, st2 belongs to the denotation of program c if and only if executing c from st1 may terminate at state st2 with exit kind ek.
Inductive exit_kind: Type :=
  | EK_Normal
  | EK_Break
  | EK_Cont.

Definition skip_sem: stateexit_kindstateProp :=
  fun st1 ek st2
    st1 = st2ek = EK_Normal.

Definition asgn_sem (X: var) (E: aexp): stateexit_kindstateProp :=
  fun st1 ek st2
    st2 X = aeval E st1
    Y, XYst1 Y = st2 Y
    ek = EK_Normal.
Obviously, skip commands and assignment commands can only terminate normally.
Definition break_sem: stateexit_kindstateProp :=
  fun st1 ek st2
    st1 = st2ek = EK_Break.

Definition cont_sem: stateexit_kindstateProp :=
  fun st1 ek st2
    st1 = st2ek = EK_Cont.
In contrast, CBreak and CCont will never terminate will normal exit.
Definition seq_sem (d1 d2: stateexit_kindstateProp)
  : stateexit_kindstateProp
:=
  fun st1 ek st3
    (st2, d1 st1 EK_Normal st2d2 st2 ek st3) ∨
    (d1 st1 ek st3ekEK_Normal).
For sequential composition, the second command will be executed if and only if the first one terminates normally.
Definition if_sem (b: bexp) (d1 d2: stateexit_kindstateProp)
  : stateexit_kindstateProp
:=
  fun st1 ek st2
    (d1 st1 ek st2beval b st1) ∨
    (d2 st1 ek st2 ∧ ¬beval b st1).
The semantics of if commands is trivial. Next, we define the semantics of loops. Remember, a loop itself will never terminate by break or continue although a loop body may break and terminates whole loop's execution.
Fixpoint iter_loop_body
  (b: bexp)
  (loop_body: stateexit_kindstateProp)
  (n: nat)
  : statestateProp
:=
  match n with
  | O
     fun st1 st2
       st1 = st2 ∧ ¬beval b st1
  | S n'
     fun st1 st3
      ((st2,
         (loop_body) st1 EK_Normal st2
         (iter_loop_body b loop_body n') st2 st3) ∨
       (loop_body) st1 EK_Break st3
       (st2,
         (loop_body) st1 EK_Cont st2
         (iter_loop_body b loop_body n') st2 st3)) ∧
       beval b st1
  end.

Definition loop_sem (b: bexp) (loop_body: stateexit_kindstateProp)
  : stateexit_kindstateProp
:=
  fun st1 ek st2
    n, (iter_loop_body b loop_body n) st1 st2ek = EK_Normal.

Fixpoint ceval (c: com): stateexit_kindstateProp :=
  match c with
  | CSkipskip_sem
  | CAss X Easgn_sem X E
  | CSeq c1 c2seq_sem (ceval c1) (ceval c2)
  | CIf b c1 c2if_sem b (ceval c1) (ceval c2)
  | CWhile b cloop_sem b (ceval c)
  | CBreakbreak_sem
  | CContcont_sem
  end.

End Denotation_With_ControlFlow.

Hoare Logic

A Hoare logic for Imp with break and continue has multiple postconditions.
Module Hoare_logic.

Import Assertion_S.

Notation "d [ X ⟼ a ]" := (assn_sub X a ((d)%assert)) (at level 10, X at next level) : assert_scope.
Notation "a0 [ X ⟼ a ]" := (aexp_sub X a ((a0)%imp)) (at level 10, X at next level) : imp_scope.

Parameter hoare_triple: Assertion
                         com
                         Assertion * (* Normal Postcondition *)
                         Assertion * (* Break  Postcondition *)
                         Assertion(* Continue Condition *)
                         Prop.

Notation "{{ P }} c {{ Q }} {{ QB }} {{ QC }}" :=
  (hoare_triple
     P
     c
     (Q%assert: Assertion, QB%assert: Assertion, QC%assert: Assertion))
  (at level 90, c at next level).
This Hoare triple says: if command c is started in a state satisfying assertion P, and if c eventually terminates normally / by break / by continue in some final state, then this final state will satisfy assertion Q / QB / QC.
All proof rules need to be slightly modified:
Axiom hoare_seq : (P Q R RB RC: Assertion) (c1 c2: com),
  {{P}} c1 {{Q}} {{RB}} {{RC}} →
  {{Q}} c2 {{R}} {{RB}} {{RC}} →
  {{P}} CSeq c1 c2 {{R}} {{RB}} {{RC}}.

Axiom hoare_skip : P,
  {{P}} CSkip {{P}} {{False}} {{False}}.

Axiom hoare_break : P,
  {{P}} CSkip {{False}} {{P}} {{False}}.

Axiom hoare_cont : P,
  {{P}} CSkip {{False}} {{False}} {{P}}.

Axiom hoare_if : P Q QB QC b c1 c2,
  {{ P AND [[b]] }} c1 {{Q}} {{QB}} {{QC}} →
  {{ P AND NOT [[b]] }} c2 {{Q}} {{QB}} {{QC}} →
  {{ P }} CIf b c1 c2 {{Q}} {{QB}} {{QC}}.

Axiom hoare_while : I P b c,
  {{ I AND [[b]] }} c {{I}} {{P}} {{I}} →
  {{ I }} CWhile b c {{ P OR (I AND NOT [[b]]) }} {{False}} {{False }}.

Axiom hoare_asgn_fwd : P (X: var) E,
  {{ P }}
  CAss X E
  {{ EXISTS x, P [Xx] AND
               [[AId X]] == [[ E [Xx] ]] }}
  {{False}}
  {{False}}.

Axiom hoare_asgn_bwd : P (X: var) E,
  {{ P [ XE] }} CAss X E {{ P }} {{False}} {{False}}.

Axiom hoare_consequence : (P P' Q Q' QB QB' QC QC' : Assertion) c,
  PP'
  {{P'}} c {{Q'}} {{QB'}} {{QC'}}→
  Q'Q
  QB'QB
  QC'QC
  {{P}} c {{Q}} {{QB}} {{QC}}.

End Hoare_logic.

Small Step Semantics


Module Small_Step_Semantics.
The small step semantics for break and continue is based on control stack. Specifically, every element in control stack describe a loop (loop condition and loop body) and a command after loop.
Definition cstack: Type := list (bexp * com * com).
In order to define a small step for control flow, it is useful to define the following properties:
  • a command c starts with break: start_with_break c;
  • a command c starts with continue: start_with_break c;
  • a command c is equivalent with a sequential composition of loop CWhile b c1 and another command c2: start_with_loop c b c1 c2.
Inductive start_with_break: comProp :=
| SWB_Break: start_with_break CBreak
| SWB_Seq: c1 c2,
             start_with_break c1
             start_with_break (CSeq c1 c2).

Inductive start_with_cont: comProp :=
| SWC_Cont: start_with_cont CCont
| SWC_Seq: c1 c2,
             start_with_cont c1
             start_with_cont (CSeq c1 c2).

Inductive start_with_loop: combexpcomcomProp :=
| SWL_While: b c, start_with_loop (CWhile b c) b c CSkip
| SWL_Seq: c1 b c11 c12 c2,
             start_with_loop c1 b c11 c12
             start_with_loop (CSeq c1 c2) b c11 (CSeq c12 c2).
Now, we are ready to define a small step semantics with control stack.
Inductive com': Type :=
| CNormal (s: cstack) (c: com): com'
| CLoopCond (s: cstack) (b: bexp): com'.

Inductive cstep : (com' * state) → (com' * state) → Prop :=
  | CS_AssStep : st s X a a',
      astep st a a'
      cstep
        (CNormal s (CAss X a), st)
        (CNormal s (CAss X a'), st)
  | CS_Ass : st1 st2 s X n,
      st2 X = n
      (Y, XYst1 Y = st2 Y) →
      cstep
        (CNormal s (CAss X (ANum n)), st1)
        (CNormal s CSkip, st2)
  | CS_SeqStep : st s c1 c1' st' c2,
      cstep
        (CNormal s c1, st)
        (CNormal s c1', st') →
      cstep
        (CNormal s (CSeq c1 c2), st)
        (CNormal s (CSeq c1' c2), st')
  | CS_Seq : st s c2,
      cstep
        (CNormal s (CSeq CSkip c2), st)
        (CNormal s c2, st)
  | CS_IfStep : st s b b' c1 c2,
      bstep st b b'
      cstep
        (CNormal s (CIf b c1 c2), st)
        (CNormal s (CIf b' c1 c2), st)
  | CS_IfTrue : st s c1 c2,
      cstep
        (CNormal s (CIf BTrue c1 c2), st)
        (CNormal s c1, st)
  | CS_IfFalse : st s c1 c2,
      cstep
        (CNormal s (CIf BFalse c1 c2), st)
        (CNormal s c2, st)
  | CS_While : st s c b c1 c2, (* <-- new *)
      start_with_loop c b c1 c2
      cstep
        (CNormal s c, st)
        (CLoopCond (cons (b, c1, c2) s) b, st)
  | CS_WhileStep : st s b b' b'' c1 c2, (* <-- new *)
      bstep st b' b''
      cstep
        (CLoopCond (cons (b, c1, c2) s) b', st)
        (CLoopCond (cons (b, c1, c2) s) b'', st)
  | CS_WhileTrue : st s b c1 c2, (* <-- new *)
      cstep
        (CLoopCond (cons (b, c1, c2) s) BTrue, st)
        (CNormal (cons (b, c1, c2) s) c1, st)
  | CS_WhileFalse : st s b c1 c2, (* <-- new *)
      cstep
        (CLoopCond (cons (b, c1, c2) s) BFalse, st)
        (CNormal s c2, st)
  | CS_Skip : st s b c1 c2, (* <-- new *)
      cstep
        (CNormal (cons (b, c1, c2) s) CSkip, st)
        (CLoopCond (cons (b, c1, c2) s) b, st)
  | CS_Break : st s b c1 c2 c, (* <-- new *)
      start_with_break c
      cstep
        (CNormal (cons (b, c1, c2) s) c, st)
        (CNormal s c2, st)
  | CS_Cont : st s b c1 c2 c, (* <-- new *)
      start_with_cont c
      cstep
        (CNormal (cons (b, c1, c2) s) c, st)
        (CLoopCond (cons (b, c1, c2) s) b, st)
.

End Small_Step_Semantics.

(* Thu May 23 18:25:50 UTC 2019 *)