Langlib

Langlib.Grammars.Indexed.NormalForm.EpsilonElim

ε-Free Indexed Grammars #

This file develops the stack-sensitive nullability infrastructure used by the normal-form pipeline. Nullability for indexed grammars depends on the current stack, so ε-elimination is organized around right-hand-side sublists whose deleted symbols are nullable at the stack they receive during expansion.

References #

def IndexedGrammar.IsNullable {T : Type} (g : IndexedGrammar T) (A : g.nt) (σ : List g.flag) :

A nonterminal A with stack σ is nullable if g can derive [] from [indexed A σ].

Equations
Instances For

    Generating the empty word is exactly nullability of the initial nonterminal with the empty stack.

    theorem IndexedGrammar.isNullable_appendStackSuffix {T : Type} {g : IndexedGrammar T} {A : g.nt} {σ : List g.flag} (h : g.IsNullable A σ) (suffix : List g.flag) :
    g.IsNullable A (σ ++ suffix)
    theorem IndexedGrammar.not_isNullable_of_noEpsilon {T : Type} {g : IndexedGrammar T} (hne : g.NoEpsilon') (A : g.nt) (σ : List g.flag) :

    In a no-ε indexed grammar, no single stacked nonterminal can derive the empty sentential form.

    theorem IndexedGrammar.derives_erase_nullable {T : Type} {g : IndexedGrammar T} {A : g.nt} {σ : List g.flag} (hnullable : g.IsNullable A σ) (u v : List g.ISym) :
    g.Derives (u ++ [ISym.indexed A σ] ++ v) (u ++ v)

    A nullable stacked nonterminal can be erased in any sentential context.

    theorem IndexedGrammar.transforms_append_cases {T : Type} {g : IndexedGrammar T} {u v w : List g.ISym} (hstep : g.Transforms (u ++ v) w) :
    (∃ (u' : List g.ISym), g.Transforms u u' w = u' ++ v) ∃ (v' : List g.ISym), g.Transforms v v' w = u ++ v'

    A one-step indexed rewrite of an appended sentential form rewrites either the left side or the right side of the append.

    theorem IndexedGrammar.derives_nil_of_append_left {T : Type} {g : IndexedGrammar T} {u v : List g.ISym} (hder : g.Derives (u ++ v) []) :

    If an appended sentential form derives [], then its left component also derives [].

    theorem IndexedGrammar.derives_nil_of_append_right {T : Type} {g : IndexedGrammar T} {u v : List g.ISym} (hder : g.Derives (u ++ v) []) :

    If an appended sentential form derives [], then its right component also derives [].

    theorem IndexedGrammar.derives_nil_of_append {T : Type} {g : IndexedGrammar T} {u v w : List g.ISym} (hder : g.Derives (u ++ v ++ w) []) :

    If u ++ v ++ w derives [], then the middle component derives [].

    theorem IndexedGrammar.derivesIn_nil_of_append_left {T : Type} {g : IndexedGrammar T} {n : } {u v : List g.ISym} (hder : g.DerivesIn n (u ++ v) []) :
    mn, g.DerivesIn m u []

    Counted form: if u ++ v derives [], then u derives [] within the original budget.

    theorem IndexedGrammar.derivesIn_nil_of_append_right {T : Type} {g : IndexedGrammar T} {n : } {u v : List g.ISym} (hder : g.DerivesIn n (u ++ v) []) :
    mn, g.DerivesIn m v []

    Counted form: if u ++ v derives [], then v derives [] within the original budget.

    theorem IndexedGrammar.derivesIn_nil_of_mem {T : Type} {g : IndexedGrammar T} {n : } {w : List g.ISym} {s : g.ISym} (hder : g.DerivesIn n w []) (hs : s w) :
    mn, g.DerivesIn m [s] []

    Counted form: every symbol in a sentential form deriving [] derives [] within the original budget.

    theorem IndexedGrammar.derives_nil_of_mem {T : Type} {g : IndexedGrammar T} {w : List g.ISym} {s : g.ISym} (hder : g.Derives w []) (hs : s w) :

    Every symbol occurring in a sentential form that derives [] is nullable as a singleton sentential form.

    theorem IndexedGrammar.terminal_mem_of_transforms {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} {t : T} (hstep : g.Transforms w₁ w₂) :

    A terminal already present in a sentential form is still present after one indexed-grammar rewrite step. Indexed rules rewrite only one indexed nonterminal in its context.

    theorem IndexedGrammar.terminal_mem_of_derives {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} {t : T} (hder : g.Derives w₁ w₂) :

    A terminal already present in a sentential form is preserved by any indexed derivation.

    A sentential form containing a terminal cannot derive the empty sentential form.

    theorem IndexedGrammar.no_terminal_mem_of_derives_nil {T : Type} {g : IndexedGrammar T} {w : List g.ISym} (hder : g.Derives w []) (t : T) :

    If a sentential form derives [], it contains no terminal.

    theorem IndexedGrammar.terminal_mem_expandRhs_of_mem {T : Type} {g : IndexedGrammar T} {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} {t : T} (ht : IRhsSymbol.terminal t rhs) :

    A terminal RHS symbol appears as the corresponding terminal in any expansion.

    Terminals in an expanded RHS come exactly from terminal RHS symbols.

    theorem IndexedGrammar.no_terminal_mem_rhs_of_expandRhs_derives_nil {T : Type} {g : IndexedGrammar T} {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} (hder : g.Derives (g.expandRhs rhs σ) []) (t : T) :

    If an expanded RHS can derive [], the original RHS contains no terminal symbols.

    theorem IndexedGrammar.derives_nil_of_all_nullable_indexed {T : Type} {g : IndexedGrammar T} {w : List g.ISym} (hnullable : sw, ∃ (A : g.nt) (σ : List g.flag), s = ISym.indexed A σ g.IsNullable A σ) :

    A sentential form whose every symbol is a nullable indexed nonterminal derives the empty sentential form.

    theorem IndexedGrammar.all_nullable_indexed_of_derives_nil {T : Type} {g : IndexedGrammar T} {w : List g.ISym} (hder : g.Derives w []) (s : g.ISym) :
    s w∃ (A : g.nt) (σ : List g.flag), s = ISym.indexed A σ g.IsNullable A σ

    If a sentential form derives [], every symbol in it is a nullable indexed nonterminal.

    theorem IndexedGrammar.derives_nil_iff_all_nullable_indexed {T : Type} {g : IndexedGrammar T} {w : List g.ISym} :
    g.Derives w [] sw, ∃ (A : g.nt) (σ : List g.flag), s = ISym.indexed A σ g.IsNullable A σ

    A sentential form derives [] exactly when all of its symbols are nullable indexed nonterminals.

    theorem IndexedGrammar.expandRhs_derives_nil_iff_all_nullable_rhs {T : Type} {g : IndexedGrammar T} {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} :
    g.Derives (g.expandRhs rhs σ) [] srhs, ∃ (A : g.nt) (push : Option g.flag), s = IRhsSymbol.nonterminal A push g.IsNullable A (match push with | none => σ | some f => f :: σ)

    An expanded RHS derives [] exactly when every RHS symbol is a nonterminal nullable at the stack it receives from the expansion.

    theorem IndexedGrammar.derivesIn_nil_of_expandRhs_nonterminal_mem {T : Type} {g : IndexedGrammar T} {n : } {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} {B : g.nt} {push : Option g.flag} (hder : g.DerivesIn n (g.expandRhs rhs σ) []) (hs : IRhsSymbol.nonterminal B push rhs) :
    mn, g.DerivesIn m [ISym.indexed B (match push, hs with | none, hs => σ | some f, hs => f :: σ)] []

    Counted extraction for one nonterminal occurrence in an expanded RHS deriving [].

    inductive IndexedGrammar.NullableRhsSublist {T : Type} (g : IndexedGrammar T) (σ : List g.flag) :
    List (IRhsSymbol T g.nt g.flag)List (IRhsSymbol T g.nt g.flag)Prop

    kept is obtained from rhs by deleting only RHS nonterminals that are nullable at the stack they receive during expansion.

    Instances For
      theorem IndexedGrammar.NullableRhsSublist.sublist {T : Type} {g : IndexedGrammar T} {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : g.NullableRhsSublist σ rhs kept) :
      kept.Sublist rhs
      theorem IndexedGrammar.derives_expandRhs_of_nullableRhsSublist {T : Type} {g : IndexedGrammar T} {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : g.NullableRhsSublist σ rhs kept) :
      g.Derives (g.expandRhs rhs σ) (g.expandRhs kept σ)
      theorem IndexedGrammar.derives_context_expandRhs_of_nullableRhsSublist {T : Type} {g : IndexedGrammar T} {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : g.NullableRhsSublist σ rhs kept) (u v : List g.ISym) :
      g.Derives (u ++ g.expandRhs rhs σ ++ v) (u ++ g.expandRhs kept σ ++ v)
      theorem IndexedGrammar.NullableRhsSublist.kept_ne_nil_of_not_derives_nil {T : Type} {g : IndexedGrammar T} {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : g.NullableRhsSublist σ rhs kept) (hnot : ¬g.Derives (g.expandRhs rhs σ) []) :
      kept []
      theorem IndexedGrammar.exists_nonempty_nullableRhsSublist_of_not_derives_nil {T : Type} {g : IndexedGrammar T} {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} (hnot : ¬g.Derives (g.expandRhs rhs σ) []) :
      ∃ (kept : List (IRhsSymbol T g.nt g.flag)), g.NullableRhsSublist σ rhs kept kept []
      theorem IndexedGrammar.derives_rule_nullableRhsSublist_none {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {σ : List g.flag} {kept : List (IRhsSymbol T g.nt g.flag)} (hr : r g.rules) (hconsume : r.consume = none) (hsub : g.NullableRhsSublist σ r.rhs kept) (u v : List g.ISym) :
      g.Derives (u ++ [ISym.indexed r.lhs σ] ++ v) (u ++ g.expandRhs kept σ ++ v)
      theorem IndexedGrammar.derives_rule_nullableRhsSublist_some {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {f : g.flag} {σ : List g.flag} {kept : List (IRhsSymbol T g.nt g.flag)} (hr : r g.rules) (hconsume : r.consume = some f) (hsub : g.NullableRhsSublist σ r.rhs kept) (u v : List g.ISym) :
      g.Derives (u ++ [ISym.indexed r.lhs (f :: σ)] ++ v) (u ++ g.expandRhs kept σ ++ v)
      theorem IndexedGrammar.derives_rule_nullableRhsSublist {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {σ : List g.flag} {kept : List (IRhsSymbol T g.nt g.flag)} (hr : r g.rules) (hsub : g.NullableRhsSublist σ r.rhs kept) (u v : List g.ISym) :
      g.Derives (match r.consume with | none => u ++ [ISym.indexed r.lhs σ] ++ v | some f => u ++ [ISym.indexed r.lhs (f :: σ)] ++ v) (u ++ g.expandRhs kept σ ++ v)
      theorem IndexedGrammar.derives_empty_left_eq {T : Type} {g : IndexedGrammar T} {w : List g.ISym} (h : g.Derives [] w) :
      w = []

      A derivation whose source sentential form is empty can only end at the empty sentential form.

      theorem IndexedGrammar.exists_nullableRhsSublist_derives_to_terminals {T : Type} {g : IndexedGrammar T} {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} {w : List T} (hder : g.Derives (g.expandRhs rhs σ) (List.map (fun (a : T) => ISym.terminal a) w)) :
      ∃ (kept : List (IRhsSymbol T g.nt g.flag)), g.NullableRhsSublist σ rhs kept g.Derives (g.expandRhs kept σ) (List.map (fun (a : T) => ISym.terminal a) w) (w []kept [])

      If an expanded RHS derives a terminal word, then the same word is derived by some sublist obtained by deleting only nullable RHS nonterminals. Nonempty terminal output keeps at least one RHS symbol.

      theorem IndexedGrammar.exists_nullableRhsSublist_derives_to_terminals_parts {T : Type} {g : IndexedGrammar T} {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} {w : List T} (hder : g.Derives (g.expandRhs rhs σ) (List.map (fun (a : T) => ISym.terminal a) w)) :
      ∃ (kept : List (IRhsSymbol T g.nt g.flag)) (parts : List (List T)), g.NullableRhsSublist σ rhs kept w = parts.flatten List.Forall₂ (fun (s : IRhsSymbol T g.nt g.flag) (part : List T) => part [] g.Derives (g.expandRhs [s] σ) (List.map (fun (a : T) => ISym.terminal a) part)) kept parts

      Branch-wise strengthening of exists_nullableRhsSublist_derives_to_terminals: every kept RHS symbol is assigned a nonempty terminal yield derived from that symbol.

      theorem IndexedGrammar.exists_nullableRhsSublist_derivesIn_to_terminals_parts {T : Type} {g : IndexedGrammar T} {n : } {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} {w : List T} (hder : g.DerivesIn n (g.expandRhs rhs σ) (List.map (fun (a : T) => ISym.terminal a) w)) :
      ∃ (kept : List (IRhsSymbol T g.nt g.flag)) (parts : List ( × List T)), g.NullableRhsSublist σ rhs kept w = List.flatMap (fun (p : × List T) => p.2) parts (List.map (fun (p : × List T) => p.1) parts).sum n List.Forall₂ (fun (s : IRhsSymbol T g.nt g.flag) (p : × List T) => p.2 [] g.DerivesIn p.1 (g.expandRhs [s] σ) (List.map (fun (a : T) => ISym.terminal a) p.2)) kept parts

      Counted branch-wise RHS pruning. Besides deleting nullable RHS nonterminals, this records a counted terminal yield for every kept symbol, and the kept budgets together do not exceed the original derivation budget.

      theorem IndexedGrammar.exists_nonempty_nullableRhsSublist_derivesIn_to_terminals_parts {T : Type} {g : IndexedGrammar T} {n : } {rhs : List (IRhsSymbol T g.nt g.flag)} {σ : List g.flag} {w : List T} (hder : g.DerivesIn n (g.expandRhs rhs σ) (List.map (fun (a : T) => ISym.terminal a) w)) (hw : w []) :
      ∃ (kept : List (IRhsSymbol T g.nt g.flag)) (parts : List ( × List T)), g.NullableRhsSublist σ rhs kept kept [] w = List.flatMap (fun (p : × List T) => p.2) parts (List.map (fun (p : × List T) => p.1) parts).sum n List.Forall₂ (fun (s : IRhsSymbol T g.nt g.flag) (p : × List T) => p.2 [] g.DerivesIn p.1 (g.expandRhs [s] σ) (List.map (fun (a : T) => ISym.terminal a) p.2)) kept parts

      One epsilon-pruned step: apply an original rule, but keep only a nonempty RHS sublist whose deleted nonterminals are nullable at the stack used by the rule application.

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For

        Reflexive-transitive closure of epsilon-pruned indexed steps.

        Equations
        Instances For
          theorem IndexedGrammar.prunedTransforms_length_le {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (hstep : g.PrunedTransforms w₁ w₂) :
          w₁.length w₂.length
          theorem IndexedGrammar.prunedDerives_length_le {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (hder : g.PrunedDerives w₁ w₂) :
          w₁.length w₂.length
          theorem IndexedGrammar.derives_of_prunedTransforms {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (hstep : g.PrunedTransforms w₁ w₂) :
          g.Derives w₁ w₂
          theorem IndexedGrammar.derives_of_prunedDerives {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (hder : g.PrunedDerives w₁ w₂) :
          g.Derives w₁ w₂
          theorem IndexedGrammar.prunedTransforms_with_prefix {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (u : List g.ISym) (hstep : g.PrunedTransforms w₁ w₂) :
          g.PrunedTransforms (u ++ w₁) (u ++ w₂)
          theorem IndexedGrammar.prunedTransforms_with_suffix {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (v : List g.ISym) (hstep : g.PrunedTransforms w₁ w₂) :
          g.PrunedTransforms (w₁ ++ v) (w₂ ++ v)
          theorem IndexedGrammar.prunedDerives_with_prefix {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (u : List g.ISym) (hder : g.PrunedDerives w₁ w₂) :
          g.PrunedDerives (u ++ w₁) (u ++ w₂)
          theorem IndexedGrammar.prunedDerives_with_suffix {T : Type} {g : IndexedGrammar T} {w₁ w₂ : List g.ISym} (v : List g.ISym) (hder : g.PrunedDerives w₁ w₂) :
          g.PrunedDerives (w₁ ++ v) (w₂ ++ v)
          theorem IndexedGrammar.prunedDerives_append {T : Type} {g : IndexedGrammar T} {u₁ u₂ v₁ v₂ : List g.ISym} (hu : g.PrunedDerives u₁ u₂) (hv : g.PrunedDerives v₁ v₂) :
          g.PrunedDerives (u₁ ++ v₁) (u₂ ++ v₂)
          theorem IndexedGrammar.part_fst_le_sum_of_mem {T : Type} (parts : List ( × List T)) {p : × List T} (hp : p parts) :
          p.1 (List.map (fun (q : × List T) => q.1) parts).sum
          theorem IndexedGrammar.prunedDerives_expandRhs_to_terminals_of_forall₂_derivesIn {T : Type} {g : IndexedGrammar T} {N : } (hrec : ∀ {m : } {A : g.nt} {σ : List g.flag} {w : List T}, m < Ng.DerivesIn m [ISym.indexed A σ] (List.map (fun (a : T) => ISym.terminal a) w)w []g.PrunedDerives [ISym.indexed A σ] (List.map (fun (a : T) => ISym.terminal a) w)) {σ : List g.flag} {kept : List (IRhsSymbol T g.nt g.flag)} {parts : List ( × List T)} (hparts : List.Forall₂ (fun (s : IRhsSymbol T g.nt g.flag) (p : × List T) => p.2 [] g.DerivesIn p.1 (g.expandRhs [s] σ) (List.map (fun (a : T) => ISym.terminal a) p.2)) kept parts) (hlt : pparts, p.1 < N) :
          g.PrunedDerives (g.expandRhs kept σ) (List.map (fun (a : T) => ISym.terminal a) (List.flatMap (fun (p : × List T) => p.2) parts))
          theorem IndexedGrammar.exists_initial_rule_nullableRhsSublist_of_generates_nonempty {T : Type} {g : IndexedGrammar T} {w : List T} (hgen : g.Generates w) (hw : w []) :
          ∃ (r : IRule T g.nt g.flag) (kept : List (IRhsSymbol T g.nt g.flag)), r g.rules r.lhs = g.initial r.consume = none g.NullableRhsSublist [] r.rhs kept kept [] g.Derives (g.expandRhs kept []) (List.map (fun (a : T) => ISym.terminal a) w)

          Every nonempty generated word has a first start-rule expansion whose nullable deletions leave a nonempty RHS deriving the same word.

          theorem IndexedGrammar.prunedDerives_indexed_to_terminals_of_derivesIn_nonempty {T : Type} {g : IndexedGrammar T} {n : } {A : g.nt} {σ : List g.flag} {w : List T} (hder : g.DerivesIn n [ISym.indexed A σ] (List.map (fun (a : T) => ISym.terminal a) w)) (hw : w []) :
          g.PrunedDerives [ISym.indexed A σ] (List.map (fun (a : T) => ISym.terminal a) w)

          Every nonempty generated word has a complete derivation using only ε-pruned steps.

          A pruned derivation from the start symbol can only end in a nonempty terminal word.

          Semantic ε-elimination: pruned derivations from the start generate exactly the nonempty part of the original language.

          theorem IndexedGrammar.isNullable_cases_rule {T : Type} {g : IndexedGrammar T} {A : g.nt} {σ : List g.flag} (hnullable : g.IsNullable A σ) :
          (∃ rg.rules, r.lhs = A r.consume = none g.Derives (g.expandRhs r.rhs σ) []) ∃ (f : g.flag) (ρ : List g.flag) (r : IRule T g.nt g.flag), σ = f :: ρ r g.rules r.lhs = A r.consume = some f g.Derives (g.expandRhs r.rhs ρ) []

          First-step analysis for a nullable stacked nonterminal. Nullability is witnessed by a matching grammar rule whose expansion is nullable.

          theorem IndexedGrammar.isNullable_of_derives_nullable {T : Type} {g : IndexedGrammar T} {A B : g.nt} {σ τ : List g.flag} (hder : g.Derives [ISym.indexed A σ] [ISym.indexed B τ]) (hnullable : g.IsNullable B τ) :
          g.IsNullable A σ

          Nullability propagates backwards along a derivation.

          theorem IndexedGrammar.isNullable_of_rule_derives_empty_none {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {A : g.nt} {σ : List g.flag} (hr : r g.rules) (hlhs : r.lhs = A) (hconsume : r.consume = none) (hder : g.Derives (g.expandRhs r.rhs σ) []) :
          g.IsNullable A σ

          If a non-consuming rule expands to a nullable sentential form, then its left-hand side is nullable at the same stack.

          theorem IndexedGrammar.isNullable_of_rule_derives_empty_some {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {A : g.nt} {f : g.flag} {σ : List g.flag} (hr : r g.rules) (hlhs : r.lhs = A) (hconsume : r.consume = some f) (hder : g.Derives (g.expandRhs r.rhs σ) []) :
          g.IsNullable A (f :: σ)

          If a flag-consuming rule expands to a nullable sentential form, then its left-hand side is nullable when that flag is on top of the stack.

          theorem IndexedGrammar.isNullable_iff_rule_derives_empty {T : Type} {g : IndexedGrammar T} {A : g.nt} {σ : List g.flag} :
          g.IsNullable A σ (∃ rg.rules, r.lhs = A r.consume = none g.Derives (g.expandRhs r.rhs σ) []) ∃ (f : g.flag) (ρ : List g.flag) (r : IRule T g.nt g.flag), σ = f :: ρ r g.rules r.lhs = A r.consume = some f g.Derives (g.expandRhs r.rhs ρ) []

          Rule-level characterization of nullable stacked nonterminals.

          theorem IndexedGrammar.isNullable_cases_flagsSeparated {T : Type} {g : IndexedGrammar T} (hfs : g.FlagsSeparated) {A : g.nt} {σ : List g.flag} (hnullable : g.IsNullable A σ) :
          (∃ rg.rules, r.lhs = A r.consume = none r.rhs = []) (∃ rg.rules, r.lhs = A r.consume = none r.rhs [] sr.rhs, ∃ (B : g.nt) (push : Option g.flag), s = IRhsSymbol.nonterminal B push g.IsNullable B (match push with | none => σ | some f => f :: σ)) ∃ (f : g.flag) (ρ : List g.flag) (r : IRule T g.nt g.flag) (B : g.nt), σ = f :: ρ r g.rules r.lhs = A r.consume = some f r.rhs = [IRhsSymbol.nonterminal B none] g.IsNullable B ρ

          In a flag-separated grammar, nullability has three concrete sources: an explicit ε-rule, a non-consuming rule whose whole RHS is nullable at the inherited stack, or a pop rule whose single child is nullable after the pop.

          theorem IndexedGrammar.isNullable_of_rule_all_nullable_none {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {A : g.nt} {σ : List g.flag} (hr : r g.rules) (hlhs : r.lhs = A) (hconsume : r.consume = none) (hall : sr.rhs, ∃ (B : g.nt) (push : Option g.flag), s = IRhsSymbol.nonterminal B push g.IsNullable B (match push with | none => σ | some f => f :: σ)) :
          g.IsNullable A σ

          A non-consuming rule whose expanded RHS is entirely nullable makes its LHS nullable.

          theorem IndexedGrammar.isNullable_of_pop_rule_nullable_child {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {A B : g.nt} {f : g.flag} {σ : List g.flag} (hr : r g.rules) (hlhs : r.lhs = A) (hconsume : r.consume = some f) (hrhs : r.rhs = [IRhsSymbol.nonterminal B none]) (hB : g.IsNullable B σ) :
          g.IsNullable A (f :: σ)

          A pop rule whose unique child is nullable after the pop makes its LHS nullable with the consumed flag on top of the stack.

          theorem IndexedGrammar.isNullable_flagsSeparated_iff {T : Type} {g : IndexedGrammar T} (hfs : g.FlagsSeparated) {A : g.nt} {σ : List g.flag} :
          g.IsNullable A σ (∃ rg.rules, r.lhs = A r.consume = none r.rhs = []) (∃ rg.rules, r.lhs = A r.consume = none r.rhs [] sr.rhs, ∃ (B : g.nt) (push : Option g.flag), s = IRhsSymbol.nonterminal B push g.IsNullable B (match push with | none => σ | some f => f :: σ)) ∃ (f : g.flag) (ρ : List g.flag) (r : IRule T g.nt g.flag) (B : g.nt), σ = f :: ρ r g.rules r.lhs = A r.consume = some f r.rhs = [IRhsSymbol.nonterminal B none] g.IsNullable B ρ

          In a flag-separated grammar, nullability is exactly generated by explicit ε-rules, non-consuming all-nullable RHSs, and pop rules whose child is nullable after the pop.

          theorem IndexedGrammar.isNullable_nil_iff_flagsSeparated {T : Type} {g : IndexedGrammar T} (hfs : g.FlagsSeparated) {A : g.nt} :
          g.IsNullable A [] (∃ rg.rules, r.lhs = A r.consume = none r.rhs = []) rg.rules, r.lhs = A r.consume = none r.rhs [] sr.rhs, ∃ (B : g.nt) (push : Option g.flag), s = IRhsSymbol.nonterminal B push g.IsNullable B (match push with | none => [] | some f => [f])

          Empty-stack specialization of the flag-separated nullability equations.

          theorem IndexedGrammar.isNullable_cons_iff_flagsSeparated {T : Type} {g : IndexedGrammar T} (hfs : g.FlagsSeparated) {A : g.nt} {f : g.flag} {ρ : List g.flag} :
          g.IsNullable A (f :: ρ) (∃ rg.rules, r.lhs = A r.consume = none r.rhs = []) (∃ rg.rules, r.lhs = A r.consume = none r.rhs [] sr.rhs, ∃ (B : g.nt) (push : Option g.flag), s = IRhsSymbol.nonterminal B push g.IsNullable B (match push with | none => f :: ρ | some f' => f' :: f :: ρ)) ∃ (r : IRule T g.nt g.flag) (B : g.nt), r g.rules r.lhs = A r.consume = some f r.rhs = [IRhsSymbol.nonterminal B none] g.IsNullable B ρ

          Nonempty-stack specialization of the flag-separated nullability equations.

          theorem IndexedGrammar.isNullable_of_empty_rule_none {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {A : g.nt} (hr : r g.rules) (hlhs : r.lhs = A) (hconsume : r.consume = none) (hrhs : r.rhs = []) (σ : List g.flag) :
          g.IsNullable A σ

          An explicit rule A → ε makes A nullable at every stack.

          theorem IndexedGrammar.isNullable_of_empty_rule_some {T : Type} {g : IndexedGrammar T} {r : IRule T g.nt g.flag} {A : g.nt} {f : g.flag} (hr : r g.rules) (hlhs : r.lhs = A) (hconsume : r.consume = some f) (hrhs : r.rhs = []) (σ : List g.flag) :
          g.IsNullable A (f :: σ)

          An explicit rule Af → ε makes A nullable at every stack whose top flag is f.

          The semantic set of nullable stacked nonterminals.

          Equations
          Instances For

            One algebraic unfolding of stack-sensitive nullability for flag-separated grammars.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              theorem IndexedGrammar.nullableStep_mono {T : Type} {g : IndexedGrammar T} {X Y : Set (g.nt × List g.flag)} (hXY : X Y) :
              theorem IndexedGrammar.nullableStep_sound {T : Type} {g : IndexedGrammar T} {X : Set (g.nt × List g.flag)} (hX : ∀ (A : g.nt) (σ : List g.flag), (A, σ) Xg.IsNullable A σ) :

              Finite unfoldings of the nullability equations, starting from no nullable states.

              Equations
              Instances For
                inductive IndexedGrammar.ApproxNullableRhsSublist {T : Type} (g : IndexedGrammar T) (n : ) (σ : List g.flag) :
                List (IRhsSymbol T g.nt g.flag)List (IRhsSymbol T g.nt g.flag)Prop

                A RHS sublist whose deletions are justified by one finite nullable approximation rank.

                Instances For
                  theorem IndexedGrammar.ApproxNullableRhsSublist.toNullableRhsSublist {T : Type} {g : IndexedGrammar T} {n : } {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : g.ApproxNullableRhsSublist n σ rhs kept) :
                  g.NullableRhsSublist σ rhs kept
                  theorem IndexedGrammar.ApproxNullableRhsSublist.mono {T : Type} {g : IndexedGrammar T} {m n : } (hmn : m n) {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : g.ApproxNullableRhsSublist m σ rhs kept) :
                  g.ApproxNullableRhsSublist n σ rhs kept

                  Relative nullable summaries #

                  inductive IndexedGrammar.RelativeNullable {T : Type} (g : IndexedGrammar T) (base : Set g.nt) :
                  List g.flagg.ntProp

                  Nullability above an abstract suffix whose nullable nonterminals are given by base. RelativeNullable g base α A means that A is nullable on α ++ σ for every suffix σ whose nullable set is base.

                  Instances For
                    theorem IndexedGrammar.RelativeNullable.sound {T : Type} {g : IndexedGrammar T} {base : Set g.nt} {σ α : List g.flag} {A : g.nt} (hbase : Bbase, g.IsNullable B σ) (h : g.RelativeNullable base α A) :
                    g.IsNullable A (α ++ σ)
                    theorem IndexedGrammar.relativeNullable_complete_of_nullableApprox {T : Type} {g : IndexedGrammar T} {base : Set g.nt} {σ : List g.flag} (hbase : ∀ (B : g.nt), g.IsNullable B σB base) (n : ) (α : List g.flag) (A : g.nt) :
                    (A, α ++ σ) g.NullableApprox ng.RelativeNullable base α A
                    theorem IndexedGrammar.RelativeNullable.complete_flagsSeparated {T : Type} {g : IndexedGrammar T} (hfs : g.FlagsSeparated) {base : Set g.nt} {σ α : List g.flag} {A : g.nt} (hbase : ∀ (B : g.nt), g.IsNullable B σB base) (hnullable : g.IsNullable A (α ++ σ)) :
                    g.RelativeNullable base α A
                    theorem IndexedGrammar.relativeNullable_iff_flagsSeparated {T : Type} {g : IndexedGrammar T} (hfs : g.FlagsSeparated) {base : Set g.nt} {σ α : List g.flag} {A : g.nt} (hbase : ∀ (B : g.nt), B base g.IsNullable B σ) :
                    g.RelativeNullable base α A g.IsNullable A (α ++ σ)

                    Finite-summary ε-elimination skeleton #

                    def IndexedGrammar.stackSummaryEval {F Q : Type} (init : Q) (step : QFQ) :
                    List FQ

                    Evaluate a finite stack summary. The transition step q f is the summary after pushing flag f on top of a stack with summary q.

                    Equations
                    Instances For
                      @[simp]
                      theorem IndexedGrammar.stackSummaryEval_nil {F Q : Type} (init : Q) (step : QFQ) :
                      stackSummaryEval init step [] = init
                      @[simp]
                      theorem IndexedGrammar.stackSummaryEval_cons {F Q : Type} (init : Q) (step : QFQ) (f : F) (σ : List F) :
                      stackSummaryEval init step (f :: σ) = step (stackSummaryEval init step σ) f
                      def IndexedGrammar.annotateStackWithSummary {F Q : Type} (init : Q) (step : QFQ) :
                      List FList (F × Q)

                      Annotate every stack flag with the summary of the suffix below it.

                      Equations
                      Instances For
                        @[simp]
                        theorem IndexedGrammar.annotateStackWithSummary_nil {F Q : Type} (init : Q) (step : QFQ) :
                        @[simp]
                        theorem IndexedGrammar.annotateStackWithSummary_cons {F Q : Type} (init : Q) (step : QFQ) (f : F) (σ : List F) :
                        annotateStackWithSummary init step (f :: σ) = (f, stackSummaryEval init step σ) :: annotateStackWithSummary init step σ
                        @[simp]
                        theorem IndexedGrammar.map_fst_annotateStackWithSummary {F Q : Type} (init : Q) (step : QFQ) (σ : List F) :

                        A finite stack summary recognizes exactly the nullable stacks when nullable_sound and nullable_complete are supplied later.

                        Instances For
                          @[simp]
                          theorem IndexedGrammar.NullableStackSummary.eval_cons {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (f : g.flag) (σ : List g.flag) :
                          S.eval (f :: σ) = S.step (S.eval σ) f

                          A RHS symbol is droppable at summary state q when it is a nonterminal nullable at the stack summary it receives.

                          Equations
                          Instances For
                            Equations
                            • One or more equations did not get rendered due to their size.

                            RHS sublist pruning justified by a finite stack summary.

                            Instances For

                              Enumerate all summary-justified RHS prunings.

                              Equations
                              Instances For

                                Lift a kept RHS symbol into the summary grammar at current tail summary q. Pushed flags are annotated with the summary below the pushed flag.

                                Equations
                                Instances For
                                  theorem IndexedGrammar.summaryLiftRhs_ne_nil {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (q : S.state) {rhs : List (IRhsSymbol T g.nt g.flag)} (hne : rhs []) :
                                  def IndexedGrammar.summaryRuleForKept {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (r : IRule T g.nt g.flag) (q : S.state) (kept : List (IRhsSymbol T g.nt g.flag)) :
                                  IRule T (g.nt × S.state) (g.flag × S.state)
                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For
                                    noncomputable def IndexedGrammar.summaryRulesForRule {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (r : IRule T g.nt g.flag) :
                                    List (IRule T (g.nt × S.state) (g.flag × S.state))
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For
                                      theorem IndexedGrammar.mem_summaryRulesForRule {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) {r : IRule T g.nt g.flag} {r' : IRule T (g.nt × S.state) (g.flag × S.state)} (hr' : r' summaryRulesForRule S r) :
                                      ∃ (q : S.state) (kept : List (IRhsSymbol T g.nt g.flag)), q Finset.univ.toList kept summaryPrunedRhsList S q r.rhs kept [] r' = summaryRuleForKept S r q kept
                                      theorem IndexedGrammar.SummaryNullableRhsSublist.toNullableRhsSublist_eval {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hsound : ∀ (A : g.nt) (σ : List g.flag), S.nullable A (S.eval σ)g.IsNullable A σ) {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : SummaryNullableRhsSublist S (S.eval σ) rhs kept) :
                                      g.NullableRhsSublist σ rhs kept

                                      Semantic soundness of summary-justified RHS deletion at an actually matching stack summary.

                                      theorem IndexedGrammar.NullableRhsSublist.toSummary_eval {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hcomplete : ∀ (A : g.nt) (σ : List g.flag), g.IsNullable A σS.nullable A (S.eval σ)) {σ : List g.flag} {rhs kept : List (IRhsSymbol T g.nt g.flag)} (h : g.NullableRhsSublist σ rhs kept) :

                                      Semantic completeness of summary-justified RHS deletion at an actually matching stack summary.

                                      @[simp]
                                      theorem IndexedGrammar.summaryLiftSF_terminals {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (w : List T) :
                                      summaryLiftSF S (List.map (fun (a : T) => ISym.terminal a) w) = List.map (fun (a : T) => ISym.terminal a) w
                                      @[simp]
                                      theorem IndexedGrammar.summaryProjectSF_terminals {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (w : List T) :
                                      summaryProjectSF S (List.map (fun (a : T) => ISym.terminal a) w) = List.map (fun (a : T) => ISym.terminal a) w
                                      theorem IndexedGrammar.summaryRuleForKept_mem_summaryRulesForRule {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) {r : IRule T g.nt g.flag} {q : S.state} {kept : List (IRhsSymbol T g.nt g.flag)} (hkeptMem : kept summaryPrunedRhsList S q r.rhs) (hkept : kept []) :
                                      theorem IndexedGrammar.summaryRuleForKept_mem_epsilonElimSummary_rules {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) {r : IRule T g.nt g.flag} {q : S.state} {kept : List (IRhsSymbol T g.nt g.flag)} (hr : r g.rules) (hkeptMem : kept summaryPrunedRhsList S q r.rhs) (hkept : kept []) :

                                      The annotated summary carried by a nonterminal agrees with the summary of its stack, and each stack flag remembers the summary of the suffix below it.

                                      Equations
                                      Instances For
                                        theorem IndexedGrammar.prunedDerives_project_of_summaryDerives {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hsound : ∀ (A : g.nt) (σ : List g.flag), S.nullable A (S.eval σ)g.IsNullable A σ) {w₁ w₂ : List (epsilonElimSummary S).ISym} (hder : (epsilonElimSummary S).Derives w₁ w₂) (hwa : SummaryWellAnnotatedSF S w₁) :
                                        theorem IndexedGrammar.summaryTransforms_lift_of_prunedTransforms {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hcomplete : ∀ (A : g.nt) (σ : List g.flag), g.IsNullable A σS.nullable A (S.eval σ)) {w₁ w₂ : List g.ISym} (hstep : g.PrunedTransforms w₁ w₂) :
                                        theorem IndexedGrammar.summaryDerives_lift_of_prunedDerives {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hcomplete : ∀ (A : g.nt) (σ : List g.flag), g.IsNullable A σS.nullable A (S.eval σ)) {w₁ w₂ : List g.ISym} (hder : g.PrunedDerives w₁ w₂) :
                                        theorem IndexedGrammar.epsilonElimSummary_generates_of_generates_nonempty {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hcomplete : ∀ (A : g.nt) (σ : List g.flag), g.IsNullable A σS.nullable A (S.eval σ)) {w : List T} (hgen : g.Generates w) (hw : w []) :
                                        theorem IndexedGrammar.generates_of_epsilonElimSummary_generates {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hsound : ∀ (A : g.nt) (σ : List g.flag), S.nullable A (S.eval σ)g.IsNullable A σ) {w : List T} (hgen : (epsilonElimSummary S).Generates w) :
                                        theorem IndexedGrammar.epsilonElimSummary_generates_iff {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hsound : ∀ (A : g.nt) (σ : List g.flag), S.nullable A (S.eval σ)g.IsNullable A σ) (hcomplete : ∀ (A : g.nt) (σ : List g.flag), g.IsNullable A σS.nullable A (S.eval σ)) {w : List T} :
                                        theorem IndexedGrammar.exists_noEpsilon_of_nullableStackSummary {T : Type} {g : IndexedGrammar T} (S : g.NullableStackSummary) (hsound : ∀ (A : g.nt) (σ : List g.flag), S.nullable A (S.eval σ)g.IsNullable A σ) (hcomplete : ∀ (A : g.nt) (σ : List g.flag), g.IsNullable A σS.nullable A (S.eval σ)) :
                                        ∃ (g' : IndexedGrammar T), g'.NoEpsilon' ∀ (w : List T), w [] → (g'.Generates w g.Generates w)
                                        noncomputable def IndexedGrammar.nullableSetAt {T : Type} (g : IndexedGrammar T) (σ : List g.flag) :
                                        Equations
                                        Instances For
                                          def IndexedGrammar.relativeNullableStepSet {T : Type} (g : IndexedGrammar T) (base : Set g.nt) (f : g.flag) :
                                          Equations
                                          Instances For
                                            Equations
                                            • One or more equations did not get rendered due to their size.
                                            Instances For

                                              A grammar is ε-free exactly when no stacked nonterminal is nullable.

                                              If a grammar is already ε-free, it is an ε-free equivalent of itself.

                                              theorem IndexedGrammar.exists_noEpsilon {T : Type} (g : IndexedGrammar T) (hne : g.NoEpsilon') :
                                              ∃ (g' : IndexedGrammar T), g'.NoEpsilon' (g.StartNotOnRhs'g'.StartNotOnRhs') ∀ (w : List T), w [] → (g'.Generates w g.Generates w)