(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.(** ** Definitions *)

Inductive RegExp : Set :=
| Empty : RegExp
| Eps : RegExp
| Char : ascii -> RegExp
| Cat : RegExp -> RegExp -> RegExp
| Or : RegExp -> RegExp -> RegExp
| Star : RegExp -> RegExp
| Not : RegExp -> RegExp
| And : RegExp -> RegExp -> RegExp.Notation "a ++ b" := (Cat a b).Notation "a || b" := (Or a b).(** [nu re = true] iff [re:RegExp] accepts empty string. *)

Fixpoint nu(re:RegExp):bool :=
match re with
| Empty => false
| Eps => true
| Char c => false
| Cat r s => (nu r && nu s)%bool
| Or r s => (nu r || nu s)%bool
| Star r => true
| Not r => negb (nu r)
| And r s => (nu r && nu s)%bool
end.(** Derivation of [re:RegExp] by [a:ascii]. *)

Fixpoint derive(a:ascii)(re:RegExp):RegExp :=
match re with
| Empty => Empty
| Eps => Empty
| Char c => match (ascii_dec c a) with
 | left _ => Eps
 | right _ => Empty
 end
| Cat r s => match (nu r) with
  | true => ((derive a r) ++ s) || (derive a s)
  | false => (derive a r) ++ s
  end
| Or r s => (derive a r) || (derive a s)
| Star r => (derive a r) ++ (Star r) 
| Not r => Not (derive a r)
| And r s => And (derive a r) (derive a s)
end.Notation "re / a" := (derive a re).(** [matches re s = true] iff [re:RegExp] matches [s:string]. *)

Fixpoint matches (re:RegExp)(s:string) : bool :=
match s with
| EmptyString => nu re
| String a w => matches (re / a) w
end.Notation "re ~= s" := (matches re s) (at level 60).Notation "re ~== s" := (matches re s = true) (at level 60).Notation "re ~!= s" := (matches re s = false) (at level 60).Notation "a =R= b" := (re_eq a b) (at level 70).

(* Specifications: *)
Lemma re_eq_refl : reflexive RegExp re_eq.
Lemma re_eq_sym : symmetric RegExp re_eq.
Lemma re_eq_trans : transitive RegExp re_eq.