(** * Imp: Simple Imperative Programs *)
(** In this chapter, we'll take a more serious look at how to use Coq to study interesting things outside of itself.  Our case study is a _simple imperative programming language_ called Imp, embodying a tiny core fragment of conventional mainstream languages such as C and Java.  Here is a familiar mathematical function written in Imp.  Z ::= X;; Y ::= 1;; WHILE not (Z = 0) DO Y ::= Y * Z;; Z ::= Z - 1 END *)
(** This chapter looks at how to define the _syntax_ and _semantics_ of Imp; further chapters in _Programming Language Foundations_ (_Software Foundations_, volume 2) develop a theory of _program equivalence_ and introduce _Hoare Logic_, a widely used logic for reasoning about imperative programs. *)
(* IMPORTS *)
Set Warnings "-notation-overridden,-parsing".
(* /IMPORTS *)
(* ################################################################# *)
(** * Arithmetic and Boolean Expressions *)
(** We'll present Imp in three parts: first a core language of _arithmetic and boolean expressions_, then an extension of these expressions with _variables_, and finally a language of _commands_ including assignment, conditions, sequencing, and loops. *)
(* ================================================================= *)
(** ** Syntax *)
Module AExp.
(** These two definitions specify the _abstract syntax_ of arithmetic and boolean expressions. *)
Inductive aexp : Type :=
| ANum : nat -> aexp
| APlus : aexp -> aexp -> aexp
| AMinus : aexp -> aexp -> aexp
| AMult : aexp -> aexp -> aexp.
Inductive bexp : Type :=
| BTrue : bexp
| BFalse : bexp
| BEq : aexp -> aexp -> bexp
| BLe : aexp -> aexp -> bexp
| BNot : bexp -> bexp
| BAnd : bexp -> bexp -> bexp.
(** In this chapter, we'll elide the translation from the concrete syntax that a programmer would actually write to these abstract syntax trees -- the process that, for example, would translate the string ["1+2*3"] to the AST  APlus (ANum 1) (AMult (ANum 2) (ANum 3)).  The optional chapter [ImpParser] develops a simple implementation of a lexical analyzer and parser that can perform this translation.  You do _not_ need to understand that chapter to understand this one, but if you haven't taken a course where these techniques are covered (e.g., a compilers course) you may want to skim it. *)
(** For comparison, here's a conventional BNF (Backus-Naur Form) grammar defining the same abstract syntax:  a ::= nat | a + a | a - a | a * a  b ::= true | false | a = a | a <= a | not b | b and b *)
(** Compared to the Coq version above...  - The BNF is more informal -- for example, it gives some suggestions about the surface syntax of expressions (like the fact that the addition operation is written [+] and is an infix symbol) while leaving other aspects of lexical analysis and parsing (like the relative precedence of [+], [-], and [*], the use of parens to explicitly group subexpressions, etc.) unspecified.  Some additional information (and human intelligence) would be required to turn this description into a formal definition, for example when implementing a compiler.  The Coq version consistently omits all this information and concentrates on the abstract syntax only.  - On the other hand, the BNF version is lighter and easier to read.  Its informality makes it flexible, a big advantage in situations like discussions at the blackboard, where conveying general ideas is more important than getting every detail nailed down precisely.  Indeed, there are dozens of BNF-like notations and people switch freely among them, usually without bothering to say which form of BNF they're using because there is no need to: a rough-and-ready informal understanding is all that's important.  It's good to be comfortable with both sorts of notations: informal ones for communicating between humans and formal ones for carrying out implementations and proofs. *)
(* ================================================================= *)
(** ** Evaluation *)
(** _Evaluating_ an arithmetic expression produces a number. *)
Fixpoint aeval (a : aexp) : nat :=
match a with
| ANum n => n
| APlus a1 a2 => (aeval a1) + (aeval a2)
| AMinus a1 a2  => (aeval a1) - (aeval a2)
| AMult a1 a2 => (aeval a1) * (aeval a2)
end.
Example test_aeval1:
aeval (APlus (ANum 2) (ANum 2)) = 4.
(** There is no real reason to use [try] in completely manual proofs like these, but it is very useful for doing automated proofs in conjunction with the [;] tactical, which we show next. *)
(* ----------------------------------------------------------------- *)
(** *** The [;] Tactical (Simple Form) *)
(** In its most common form, the [;] tactical takes two tactics as arguments.  The compound tactic [T;T'] first performs [T] and then performs [T'] on _each subgoal_ generated by [T]. *)
(** For example, consider the following trivial lemma: *)

(** Using [try] and [;] together, we can get rid of the repetition in the proof that was bothering us a little while ago. *)
Theorem optimize_0plus_sound': forall a,
aeval (optimize_0plus a) = aeval a.