Require Automaton.
Require Import Alphabet.
Require Import List.
Require Import Syntax.
Module Make(
Import A:
Automaton.T).
The singleton predicate for states *
Definition singleton_state_pred (
state:
state) :=
(
fun state' =>
match compare state state'
with Eq =>
true |
_ =>
false end).
past_state_of_non_init_state, extended for all states. *
Definition past_state_of_state (
state:
state) :=
match state with
|
Init _ => []
|
Ninit nis =>
past_state_of_non_init_state nis
end.
Concatenations of last and past *
Definition head_symbs_of_state (
state:
state) :=
match state with
|
Init _ => []
|
Ninit s =>
last_symb_of_non_init_state s::
past_symb_of_non_init_state s
end.
Definition head_states_of_state (
state:
state) :=
singleton_state_pred state::
past_state_of_state state.
Validation for correctness *
Prefix predicate between two lists of symbols. *
Inductive prefix:
list symbol ->
list symbol ->
Prop :=
|
prefix_nil:
forall l,
prefix []
l
|
prefix_cons:
forall l1 l2 x,
prefix l1 l2 ->
prefix (
x::
l1) (
x::
l2).
Fixpoint is_prefix (
l1 l2:
list symbol):=
match l1,
l2 with
| [],
_ =>
true
|
t1::
q1,
t2::
q2 => (
compare_eqb t1 t2 &&
is_prefix q1 q2)%
bool
|
_::
_, [] =>
false
end.
Property is_prefix_correct (
l1 l2:
list symbol):
is_prefix l1 l2 =
true ->
prefix l1 l2.
Proof.
If we shift, then the known top symbols of the destination state is
a prefix of the known top symbols of the source state, with the new
symbol added. *
Definition shift_head_symbs :=
forall s,
match action_table s with
|
Lookahead_act awp =>
forall t,
match awp t with
|
Shift_act s2 _ =>
prefix (
past_symb_of_non_init_state s2) (
head_symbs_of_state s)
|
_ =>
True
end
|
_ =>
True
end.
Definition is_shift_head_symbs (
_:
unit) :=
forallb (
fun s:
state =>
match action_table s with
|
Lookahead_act awp =>
forallb (
fun t =>
match awp t with
|
Shift_act s2 _ =>
is_prefix (
past_symb_of_non_init_state s2) (
head_symbs_of_state s)
|
_ =>
true
end)
all_list
|
_ =>
true
end)
all_list.
Property is_shift_head_symbs_correct:
is_shift_head_symbs () =
true ->
shift_head_symbs.
Proof.
When a goto happens, then the known top symbols of the destination state
is a prefix of the known top symbols of the source state, with the new
symbol added. *
Definition goto_head_symbs :=
forall s nt,
match goto_table s nt with
|
Some (
exist _ s2 _) =>
prefix (
past_symb_of_non_init_state s2) (
head_symbs_of_state s)
|
None =>
True
end.
Definition is_goto_head_symbs (
_:
unit) :=
forallb (
fun s:
state =>
forallb (
fun nt =>
match goto_table s nt with
|
Some (
exist _ s2 _) =>
is_prefix (
past_symb_of_non_init_state s2) (
head_symbs_of_state s)
|
None =>
true
end)
all_list)
all_list.
Property is_goto_head_symbs_correct:
is_goto_head_symbs () =
true ->
goto_head_symbs.
Proof.
We have to say the same kind of checks for the assumptions about the
states stack. However, theses assumptions are predicates. So we define
a notion of "prefix" over predicates lists, that means, basically, that
an assumption entails another *
Inductive prefix_pred:
list (
state->
bool) ->
list (
state->
bool) ->
Prop :=
|
prefix_pred_nil:
forall l,
prefix_pred []
l
|
prefix_pred_cons:
forall l1 l2 f1 f2,
(
forall x,
implb (
f2 x) (
f1 x) =
true) ->
prefix_pred l1 l2 ->
prefix_pred (
f1::
l1) (
f2::
l2).
Fixpoint is_prefix_pred (
l1 l2:
list (
state->
bool)) :=
match l1,
l2 with
| [],
_ =>
true
|
f1::
q1,
f2::
q2 =>
(
forallb (
fun x =>
implb (
f2 x) (
f1 x))
all_list
&&
is_prefix_pred q1 q2)%
bool
|
_::
_, [] =>
false
end.
Property is_prefix_pred_correct (
l1 l2:
list (
state->
bool)) :
is_prefix_pred l1 l2 =
true ->
prefix_pred l1 l2.
Proof.
The assumptions about state stack is conserved when we shift *
Definition shift_past_state :=
forall s,
match action_table s with
|
Lookahead_act awp =>
forall t,
match awp t with
|
Shift_act s2 _ =>
prefix_pred (
past_state_of_non_init_state s2)
(
head_states_of_state s)
|
_ =>
True
end
|
_ =>
True
end.
Definition is_shift_past_state (
_:
unit) :=
forallb (
fun s:
state =>
match action_table s with
|
Lookahead_act awp =>
forallb (
fun t =>
match awp t with
|
Shift_act s2 _ =>
is_prefix_pred
(
past_state_of_non_init_state s2) (
head_states_of_state s)
|
_ =>
true
end)
all_list
|
_ =>
true
end)
all_list.
Property is_shift_past_state_correct:
is_shift_past_state () =
true ->
shift_past_state.
Proof.
The assumptions about state stack is conserved when we do a goto *
Definition goto_past_state :=
forall s nt,
match goto_table s nt with
|
Some (
exist _ s2 _) =>
prefix_pred (
past_state_of_non_init_state s2)
(
head_states_of_state s)
|
None =>
True
end.
Definition is_goto_past_state (
_:
unit) :=
forallb (
fun s:
state =>
forallb (
fun nt =>
match goto_table s nt with
|
Some (
exist _ s2 _) =>
is_prefix_pred
(
past_state_of_non_init_state s2) (
head_states_of_state s)
|
None =>
true
end)
all_list)
all_list.
Property is_goto_past_state_correct :
is_goto_past_state () =
true ->
goto_past_state.
Proof.
What states are possible after having popped these symbols from the
stack, given the annotation of the current state ? *
Inductive state_valid_after_pop (
s:
state):
list symbol ->
list (
state ->
bool) ->
Prop :=
|
state_valid_after_pop_nil1:
forall p pl,
p s =
true ->
state_valid_after_pop s [] (
p::
pl)
|
state_valid_after_pop_nil2:
forall sl,
state_valid_after_pop s sl []
|
state_valid_after_pop_cons:
forall st sq p pl,
state_valid_after_pop s sq pl ->
state_valid_after_pop s (
st::
sq) (
p::
pl).
Fixpoint is_state_valid_after_pop
(
state:
state) (
to_pop:
list symbol)
annot :=
match annot,
to_pop with
| [],
_ =>
true
|
p::
_, [] =>
p state
|
p::
pl,
s::
sl =>
is_state_valid_after_pop state sl pl
end.
Property is_state_valid_after_pop_complete state sl pl :
state_valid_after_pop state sl pl ->
is_state_valid_after_pop state sl pl =
true.
Proof.
intro.
induction H; intuition.
destruct sl; intuition.
Qed.
A state is valid for reducing a production when :
- The assumptions on the state are such that we will find the right hand
side of the production on the stack.
- We will be able to do a goto after having popped the right hand side.
*
Definition valid_for_reduce (
state:
state)
prod :=
prefix (
prod_rhs_rev prod) (
head_symbs_of_state state) /\
forall state_new,
state_valid_after_pop state_new
(
prod_rhs_rev prod) (
head_states_of_state state) ->
goto_table state_new (
prod_lhs prod) =
None ->
match state_new with
|
Init i =>
prod_lhs prod =
start_nt i
|
Ninit _ =>
False
end.
Definition is_valid_for_reduce (
state:
state)
prod:=
(
is_prefix (
prod_rhs_rev prod) (
head_symbs_of_state state) &&
forallb (
fun state_new =>
if is_state_valid_after_pop state_new (
prod_rhs_rev prod)
(
head_states_of_state state)
then
match goto_table state_new (
prod_lhs prod)
with
|
Some _ =>
true
|
None =>
match state_new with
|
Init i =>
compare_eqb (
prod_lhs prod) (
start_nt i)
|
Ninit _ =>
false
end
end
else
true)
all_list)%
bool.
Property is_valid_for_reduce_correct (
state:
state)
prod:
is_valid_for_reduce state prod =
true ->
valid_for_reduce state prod.
Proof.
All the states that does a reduce are valid for reduction *
Definition reduce_ok :=
forall s,
match action_table s with
|
Lookahead_act awp =>
forall t,
match awp t with
|
Reduce_act p =>
valid_for_reduce s p
|
_ =>
True
end
|
Default_reduce_act p =>
valid_for_reduce s p
end.
Definition is_reduce_ok (
_:
unit) :=
forallb (
fun s =>
match action_table s with
|
Lookahead_act awp =>
forallb (
fun t =>
match awp t with
|
Reduce_act p =>
is_valid_for_reduce s p
|
_ =>
true
end)
all_list
|
Default_reduce_act p =>
is_valid_for_reduce s p
end)
all_list.
Property is_reduce_ok_correct :
is_reduce_ok () =
true ->
reduce_ok.
Proof.
The automaton is safe *
Definition safe :=
shift_head_symbs /\
goto_head_symbs /\
shift_past_state /\
goto_past_state /\
reduce_ok.
Definition is_safe (
_:
unit) :=
(
is_shift_head_symbs () &&
is_goto_head_symbs () &&
is_shift_past_state () &&
is_goto_past_state () &&
is_reduce_ok ())%
bool.
Property is_safe_correct:
is_safe () =
true ->
safe.
Proof.
End Make.