/// <summary> /// Build DFAs for multiple languages simultaneously. /// /// Each language is specified as a subset of available <typeparamref name="TResult"/>s, and will include /// patterns for each result in its set. /// /// Languages built simultaneously will be globally minimized and will share as many states as possible. /// </summary> /// <param name="languages">Sets defining the languages to build</param> /// <param name="ambiguityResolver">When patterns for multiple results match the same string, this is called to /// combine the multiple results into one. If this is null, then a DfaAmbiguityException will be thrown in that /// case.</param> /// <returns>Start states for DFAs that match the given languages. This will have the same length as languages, /// with corresponding start states in corresponding positions.</returns> public IList <DfaState <TResult> > Build(IList <ISet <TResult> > languages, DfaAmbiguityResolver <TResult> ambiguityResolver) { if (languages.Count < 1) { return(new List <DfaState <TResult> >()); } SerializableDfa <TResult> serializableDfa; if (cache == null) { serializableDfa = _build(languages, ambiguityResolver); } else { var cacheKey = GetCacheKey(DfaTypeMatcher, languages, ambiguityResolver); serializableDfa = (SerializableDfa <TResult>)cache.GetCachedItem(cacheKey); if (serializableDfa == null) { serializableDfa = _build(languages, ambiguityResolver); cache.MaybeCacheItem(cacheKey, serializableDfa); } } return(serializableDfa.GetStartStates()); }
/// <summary> /// Build DFAs from a provided NFA /// /// This method is used when you want to build the NFA yourself instead of letting this class do it. /// /// Languages built simultaneously will be globally minimized and will share as many states as possible. /// </summary> /// <param name="nfa">The NFA</param> /// <param name="nfaStartStates">The return value will include the DFA states corresponding to these NFA states, in the same order</param> /// <param name="ambiguityResolver">When patterns for multiple results match the same string, this is called to /// combine the multiple results into one. If this is null, then a DfaAmbiguityException will be thrown in that case.</param> /// <param name="cache">If this cache is non-null, it will be checked for a memoized result for this NFA, and will be populated /// with a memoized result when the call is complete.</param> /// <returns>DFA start states that are equivalent to the given NFA start states. This will have the same length as nfaStartStates, with /// corresponding start states in corresponding positions.</returns> public static IList <DfaState <TResult> > BuildFromNfa(Nfa <TResult> nfa, int[] nfaStartStates, DfaAmbiguityResolver <TResult> ambiguityResolver, IBuilderCache cache) { string cacheKey = null; SerializableDfa <TResult> serializableDfa = null; if (cache != null) { var hashAlg = new SHA256Managed(); using (var ms = new MemoryStream()) { using var cs = new CryptoStream(ms, hashAlg, CryptoStreamMode.Write); var bf = new BinaryFormatter(); bf.Serialize(ms, nfaStartStates); bf.Serialize(ms, nfa); bf.Serialize(ms, ambiguityResolver); ms.Flush(); cs.FlushFinalBlock(); cacheKey = Base32.GetDigest(hashAlg.Hash); } serializableDfa = (SerializableDfa <TResult>)cache.GetCachedItem(cacheKey); } if (serializableDfa == null) { var rawDfa = new DfaFromNfa <TResult>(nfa, nfaStartStates, ambiguityResolver).GetDfa(); var minimalDfa = new DfaMinimizer <TResult>(rawDfa).GetMinimizedDfa(); serializableDfa = new SerializableDfa <TResult>(minimalDfa); if (cacheKey != null) { cache.MaybeCacheItem(cacheKey, serializableDfa); } } return(serializableDfa.GetStartStates()); }