/// <summary> /// Creates an FA that will match any one of a set of a characters /// </summary> /// <param name="ranges">The set ranges of characters that will be matched</param> /// <param name="accept">The symbol to accept</param> /// <returns>An FA that will match the specified set</returns> public static CharFA <TAccept> Set(IEnumerable <CharRange> ranges, TAccept accept = default(TAccept)) { var result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); foreach (var ch in CharRange.ExpandRanges(ranges)) { result.Transitions.Add(ch, final); } return(result); }
static IEnumerable <CharRange> _ParseRanges(IEnumerable <char> charRanges, bool normalize) { if (!normalize) { return(_ParseRanges(charRanges)); } else { var result = new List <CharRange>(_ParseRanges(charRanges)); CharRange.NormalizeRangeList(result); return(result); } }
/// <summary> /// Returns a <see cref="IDictionary{FA,IList{KeyValuePair{Char,Char}}}"/>, keyed by state, that contains all of the outgoing local input transitions, expressed as a series of ranges /// </summary> /// <param name="result">The <see cref="IDictionary{FA,IList{CharRange}}"/> to fill, or null to create one.</param> /// <returns>A <see cref="IDictionary{FA,IList{CharRange}}"/> containing the result of the query</returns> public IDictionary <FA <char, TAccept>, IList <CharRange> > FillInputTransitionRangesGroupedByState(IDictionary <FA <char, TAccept>, IList <CharRange> > result = null) { if (null == result) { result = new Dictionary <FA <char, TAccept>, IList <CharRange> >(); } // using the optimized dictionary we have little to do here. foreach (var trns in (IDictionary <FA <char, TAccept>, ICollection <char> >)Transitions) { result.Add(trns.Key, new List <CharRange>(CharRange.GetRanges(trns.Value))); } return(result); }
public static void _AppendRangeTo(StringBuilder builder, CharRange range) { _AppendRangeCharTo(builder, range.First); if (0 == range.Last.CompareTo(range.First)) { return; } if (range.Last == range.First + 1) // spit out 1 length ranges as two chars { _AppendRangeCharTo(builder, range.Last); return; } builder.Append('-'); _AppendRangeCharTo(builder, range.Last); }
public new CharDfaEntry[] ToDfaTable(IDictionary <TAccept, int> symbolLookup = null) { var dfa = ToDfa(); var closure = dfa.FillClosure(); if (null == symbolLookup) { symbolLookup = new ListDictionary <TAccept, int>(); var i = 0; for (int jc = closure.Count, j = 0; j < jc; ++j) { var fa = closure[j]; if (fa.IsAccepting && !symbolLookup.ContainsKey(fa.AcceptSymbol)) { symbolLookup.Add(fa.AcceptSymbol, i); ++i; } } } var result = new CharDfaEntry[closure.Count]; for (var i = 0; i < result.Length; i++) { var fa = closure[i]; var trgs = ((CharFA <TAccept>)fa).FillInputTransitionRangesGroupedByState(); var trns = new KeyValuePair <string, int> [trgs.Count]; var j = 0; foreach (var trg in trgs) { trns[j] = new KeyValuePair <string, int>( CharRange.ToPackedString(trg.Value), closure.IndexOf(trg.Key)); ++j; } result[i] = new CharDfaEntry( fa.IsAccepting ? symbolLookup[fa.AcceptSymbol] : -1, trns); } return(result); }
static CharFA <TAccept> _Parse(ParseContext pc, TAccept accept) { CharFA <TAccept> result = new CharFA <TAccept>(true, accept); CharFA <TAccept> f, next; int ch; pc.EnsureStarted(); var current = result; while (true) { switch (pc.Current) { case -1: return(result); case '.': pc.Advance(); f = current.FirstAcceptingState as CharFA <TAccept>; current = Set(new CharRange[] { new CharRange(char.MinValue, char.MaxValue) }, accept); switch (pc.Current) { case '*': current = Kleene(current, accept); pc.Advance(); break; case '+': current = Repeat(current, accept); pc.Advance(); break; case '?': current = Optional(current, accept); pc.Advance(); break; } f.IsAccepting = false; f.EpsilonTransitions.Add(current); break; case '\\': if (-1 != (ch = _ParseEscape(pc))) { next = null; switch (pc.Current) { case '*': next = new CharFA <TAccept>(); next.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); next = Kleene(next, accept); pc.Advance(); break; case '+': next = new CharFA <TAccept>(); next.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); next = Repeat(next, accept); pc.Advance(); break; case '?': next = new CharFA <TAccept>(); next.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); next = Optional(next, accept); pc.Advance(); break; default: current = current.FirstAcceptingState as CharFA <TAccept>; current.IsAccepting = false; current.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); break; } if (null != next) { current = current.FirstAcceptingState as CharFA <TAccept>; current.IsAccepting = false; current.EpsilonTransitions.Add(next); current = next; } } else { pc.Expecting(); // throw an error return(null); // doesn't execute } break; case ')': return(result); case '(': pc.Advance(); pc.Expecting(); f = current.FirstAcceptingState as CharFA <TAccept>; current = _Parse(pc, accept); pc.Expecting(')'); pc.Advance(); switch (pc.Current) { case '*': current = Kleene(current, accept); pc.Advance(); break; case '+': current = Repeat(current, accept); pc.Advance(); break; case '?': current = Optional(current, accept); pc.Advance(); break; } var ff = f.FirstAcceptingState; ff.EpsilonTransitions.Add(current); ff.IsAccepting = false; break; case '|': if (-1 != pc.Advance()) { current = _Parse(pc, accept); result = Or(new CharFA <TAccept>[] { result as CharFA <TAccept>, current as CharFA <TAccept> }, accept); } else { current = current.FirstAcceptingState as CharFA <TAccept>; result = Optional(result, accept); } break; case '[': pc.ClearCapture(); pc.Advance(); pc.Expecting(); bool not = false; if ('^' == pc.Current) { not = true; pc.Advance(); pc.Expecting(); } pc.TryReadUntil(']', '\\', false); pc.Expecting(']'); pc.Advance(); var r = (!not && "." == pc.Capture) ? new CharRange[] { new CharRange(char.MinValue, char.MaxValue) } : _ParseRanges(pc.Capture, true); if (not) { r = CharRange.NotRanges(r); } f = current.FirstAcceptingState as CharFA <TAccept>; current = Set(r, accept); switch (pc.Current) { case '*': current = Kleene(current, accept); pc.Advance(); break; case '+': current = Repeat(current, accept); pc.Advance(); break; case '?': current = Optional(current, accept); pc.Advance(); break; } f.IsAccepting = false; f.EpsilonTransitions.Add(current); break; default: ch = pc.Current; pc.Advance(); next = null; switch (pc.Current) { case '*': next = new CharFA <TAccept>(); next.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); next = Kleene(next, accept); pc.Advance(); break; case '+': next = new CharFA <TAccept>(); next.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); next = Repeat(next, accept); pc.Advance(); break; case '?': next = new CharFA <TAccept>(); next.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); next = Optional(next, accept); pc.Advance(); break; default: current = current.FirstAcceptingState as CharFA <TAccept>; current.IsAccepting = false; current.Transitions.Add((char)ch, new CharFA <TAccept>(true, accept)); break; } if (null != next) { current = current.FirstAcceptingState as CharFA <TAccept>; current.IsAccepting = false; current.EpsilonTransitions.Add(next); current = next; } break; } } }