(** Heavily annotated for a tutorial introduction. ** See the Makefile for how to strip the annotations **)
(** First, import the entire Floyd proof automation system, which ** includes the VeriC program logic and the MSL theory of separation logic **)
(** Import the theory of list segments.  This is not, strictly speaking, ** part of the Floyd system.  In principle, any user of Floyd can build ** theories of new data structures (list segments, trees, doubly linked ** lists, trees with cross edges, etc.).  We emphasize this by putting ** list_dt in the progs directory.   "dt" stands for "dependent types", ** as the theory uses Coq's dependent types to handle user-defined ** record fields. **)
(** Import the [reverse.v] file, which is produced by CompCert's clightgen ** from reverse.c.   The file reverse.v defines abbreviations for identifiers ** (variable names, etc.) of the C program, such as _head, _reverse. ** It also defines "prog", which is the entire abstract syntax tree ** of the C program in the reverse.c file. **)
Open Scope logic.
(* The C programming language has a special namespace for struct ** and union identifiers, e.g., "struct foo {...}".  Some type-based operators ** in the program logic need access to an interpretation of this namespace, ** i.e., the meaning of each struct-identifier such as "foo".  The next ** line (which looks identical for any program) builds this ** interpretation, called "CompSpecs" *)
Instance CompSpecs : compspecs. make_compspecs prog. Defined.
Definition Vprog : varspecs. mk_varspecs prog. Defined.
(** The reverse.c program uses the linked list structure [struct list]. ** This satisfies the linked-list pattern, in that it has one self-reference ** field (in this case, called [tail]) and arbitrary other fields.  The [Instance] ** explains (and proves) how [struct list] satisfies the [listspec] pattern. **)
Instance LS: listspec _list _tail (fun _ _ => emp).
(** Here's a loop invariant for use in the body_sumlist proof *)
Definition sumlist_Inv (sh: share) (contents: list int) (p: val) : environ->mpred :=
(EX cts1: list int, EX cts2: list int, EX t: val,
PROP (contents = cts1++cts2)
LOCAL (temp _t t; temp _s (Vint (sum_int cts1)))
SEP ( lseg LS sh (map Vint cts1) p t ; lseg LS sh (map Vint cts2) t nullval)).
Definition reverse_Inv (sh: share) (contents: list val) : environ->mpred :=
(EX cts1: list val, EX cts2 : list val, EX w: val, EX v: val,
PROP (contents = rev cts1 ++ cts2)
LOCAL (temp _w w; temp _v v)
SEP (lseg LS sh cts1 w nullval;
lseg LS sh cts2 v nullval)).
(** The next lemma concerns the extern global initializer, ** struct list three[] = {{1, three+1}, {2, three+2}, {3, NULL}}; ** This is equivalent to a linked list of three elements [1,2,3]. ** The proof is not very beautiful at present; it would be helpful ** to have a nicer proof theory for reasoning about this kind of thing. **)

Lemma setup_globals:
forall Delta gv,
PTree.get _three (glob_types Delta) = Some (tarray t_struct_list 3) ->
ENTAIL Delta, PROP  ()
LOCAL  (gvars gv)
SEP
(data_at Ews tuint (Vint (Int.repr 1)) (gv _three);
mapsto Ews (tptr t_struct_list) (offset_val 4 (gv _three))
(offset_val 8 (gv _three));
mapsto Ews tuint (offset_val 8 (gv _three)) (Vint (Int.repr 2));
mapsto Ews (tptr t_struct_list) (offset_val 12 (gv _three))
(offset_val 16 (gv _three));
mapsto Ews tuint (offset_val 16 (gv _three)) (Vint (Int.repr 3));
mapsto Ews tuint (offset_val 20 (gv _three)) (Vint (Int.repr 0));
has_ext tt)
|-- PROP() LOCAL(gvars gv)
SEP (lseg LS Ews (map Vint (Int.repr 1 :: Int.repr 2 :: Int.repr 3 :: nil))
(gv _three) nullval; has_ext tt).