anchor.diff:  
   //Правила контекстно-свободной грамматики в нормальной форме Хомского
   type Rule = 
  -   |ToBranch of string*string*string//А->BC, A,B,C - нетерминалы
  -   |ToLeaf of string*char//A->a, а - терминал 
  +   |ToBranch of string*string*string*Option<string> //А->BC, A,B,C - нетерминалы
  +   |ToLeaf of string*char*Option<string> //A->a, а - терминал 
   
   //Вывод правил
   let printRules =
      (function
  -   | ToBranch(a,b,c) -> System.Console.WriteLine(String.concat "" [a;"->";b;c])                 
  -   | ToLeaf(a,b)     -> System.Console.WriteLine(String.concat "" [a;"->";b.ToString()]))
  +   | ToBranch(a,b,c,l) -> System.Console.WriteLine(String.concat "" [a; "->"; b; c; "  "; (match l with | Some t -> t | None -> "")])
  +   | ToLeaf(a,b,l)     -> System.Console.WriteLine(String.concat "" [a;"->";b.ToString();"  "; (match l with | Some t -> t | None -> "") ]))
      |> List.iter
   
   //Последовательное применение правил rs, начиная с первого левого нетерминала start                             
   let printOutput rs start =
      //последовательно строит сентенциальные формы вывода
  -   let rec sentForm current rules =  
  +   let rec sentForm current rules =
         match rules with
         |x::xs -> //первый левый нетерминал
                   let leftNonTerminal = List.find (fun (y:string) -> (y = (y.ToUpper()))&&((y.ToUpper()) <> (y.ToLower()))) current
  
positive.code: 
  
  //грамматика, допускающая операции +, * и позволяющая группировать их с помощью скобок, преобразованная в НФХ
  let testGrammar1 = (Array.ofList <| (List.map ToBranch [("E","T","N1");("N1","N2","E");("E","F","N3");("N3","N4","T");("E","N5","N6");("N6","E","N7");("E1","N2","E");("T","F","N3");("T","N5","N6");("T1","N4","T");("F","N5","N6")]) @ (List.map ToLeaf [("N2",'+');("N4",'*');("E",'a');("N5",'(');("N7",')');("T",'a');("F",'a')]),"E")
  let testGrammar2 = ((List.map ToBranch [("S","A","B");("B","N1","N2");("N1","D1","D2")])@(List.map ToLeaf [("A",'a');("D2",'c');("B",'a');("D1",'b');("N2",'d')]),"S")
  //System.Console.WriteLine("Test1:")
  //recognize testGrammar1 "a*a+a"
  
  
  let str = List.init 20 (fun i -> "(a+a)*a") |> String.concat "+"
  System.Console.WriteLine("Test2:")
  let start = System.DateTime.Now
  recognize testGrammar1 str
  printfn "Time = %A" (System.DateTime.Now - start)
  
  //System.Console.WriteLine("Test3:")
  //recognize testGrammar2 "abcd"
  
negative.code:                                                                        
  let recognitionTable (rules,_) (s:string) = 
             
     let recTable = Microsoft.FSharp.Collections.Array2D.create s.Length s.Length ([],(0,0),(0,0),None,[])
     //recTable(i,l), для l > 0
  
     let inline processRule rule i k l =
          match rule with
          |ToBranch(a,b,c,rule_lbl) ->
              let nonTerminals1,_,_,lbl,_ = recTable.[i,k]
              let nonTerminals2,_,_,lbl,_ = recTable.[k+i+1,l-k-1]
              let nonTerminals,_,_,lbl,rules = recTable.[i,l]
              if (List.exists ((=)b) nonTerminals1) && (List.exists ((=)c) nonTerminals2)
              then recTable.[i,l] <- (a::nonTerminals),(i,k),(k+i+1,l-k-1),rule_lbl,(rule::rules)
          |_               -> ()   
  
     let elem i l = rules |>  Array.iter (fun rule -> for k in 0..(l-1) do processRule rule i k l)
  