/// <summary> /// Creates a state machine representing this expression /// </summary> /// <typeparam name="TAccept">The type of accept symbol to use for this expression</typeparam> /// <param name="accept">The accept symbol to use for this expression</param> /// <returns>A new <see cref="CharFA{TAccept}"/> finite state machine representing this expression</returns> public override CharFA <TAccept> ToFA <TAccept>(TAccept accept) { var left = (null != Left) ? Left.ToFA(accept) : null; var right = (null != Right) ? Right.ToFA(accept) : null; return(CharFA <TAccept> .Or(new CharFA <TAccept>[] { left, right }, accept)); }
/// <summary> /// Creates a state machine representing this expression /// </summary> /// <typeparam name="TAccept">The type of accept symbol to use for this expression</typeparam> /// <param name="accept">The accept symbol to use for this expression</param> /// <returns>A new <see cref="CharFA{TAccept}"/> finite state machine representing this expression</returns> public override CharFA <TAccept> ToFA <TAccept>(TAccept accept) { var ranges = new List <CharRange>(); for (int ic = Entries.Count, i = 0; i < ic; ++i) { var entry = Entries[i]; var crc = entry as RegexCharsetCharEntry; if (null != crc) { ranges.Add(new CharRange(crc.Value, crc.Value)); } var crr = entry as RegexCharsetRangeEntry; if (null != crr) { ranges.Add(new CharRange(crr.First, crr.Last)); } var crcl = entry as RegexCharsetClassEntry; if (null != crcl) { ranges.AddRange(CharFA <TAccept> .CharacterClasses[crcl.Name]); } } if (HasNegatedRanges) { return(CharFA <TAccept> .Set(CharRange.NotRanges(ranges), accept)); } return(CharFA <TAccept> .Set(ranges, accept)); }
/// <summary> /// Returns a duplicate state machine, except one that only goes from this state to any state specified in <paramref name="to"/>. Any state that does not lead to one of those states is eliminated from the resulting graph. /// </summary> /// <param name="to">The collection of destination states</param> /// <returns>A new state machine that only goes from this state to the states indicated by <paramref name="to"/></returns> public CharFA <TAccept> ClonePathToAny(IEnumerable <CharFA <TAccept> > to) { var closure = FillClosure(); var nclosure = new CharFA <TAccept> [closure.Count]; for (var i = 0; i < nclosure.Length; i++) { nclosure[i] = new CharFA <TAccept>(closure[i].IsAccepting, closure[i].AcceptSymbol); nclosure[i].Tag = closure[i].Tag; } for (var i = 0; i < nclosure.Length; i++) { var t = nclosure[i].InputTransitions; var e = nclosure[i].EpsilonTransitions; foreach (var trns in closure[i].InputTransitions) { if (_ContainsAny(trns.Value.FillClosure(), to)) { var id = closure.IndexOf(trns.Value); t.Add(trns.Key, nclosure[id]); } } foreach (var trns in closure[i].EpsilonTransitions) { if (_ContainsAny(trns.FillClosure(), to)) { var id = closure.IndexOf(trns); e.Add(nclosure[id]); } } } return(nclosure[0]); }
/// <summary> /// Creates a new FA that matches the specified FA expression or empty /// </summary> /// <param name="expr">The expression to make optional</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that will match the specified expression or empty</returns> public static CharFA <TAccept> Optional(CharFA <TAccept> expr, TAccept accept = default(TAccept)) { var result = expr.Clone(); var f = result.FirstAcceptingState; f.AcceptSymbol = accept; result.EpsilonTransitions.Add(f); return(result); }
static void _Concat(CharFA <TAccept> lhs, CharFA <TAccept> rhs) { //Debug.Assert(lhs != rhs); var f = lhs.FirstAcceptingState; //Debug.Assert(null != rhs.FirstAcceptingState); f.IsAccepting = false; f.EpsilonTransitions.Add(rhs); //Debug.Assert(null!= lhs.FirstAcceptingState); }
public void Add(CharRange inputRange, CharFA <TAccept> fa) { _rangeTransitions.Add(new RangeWithFa(inputRange, fa)); if (!_charactersByState.TryGetValue(fa, out var chars)) { chars = new CharactersAndRanges(new List <char>(), new List <CharRange>()); _charactersByState[fa] = chars; } chars.ranges.Add(inputRange); }
public void Add(char input, CharFA <TAccept> fa) { _charactersTransitions.Add(input, fa); if (!_charactersByState.TryGetValue(fa, out var chars)) { chars = new CharactersAndRanges(new List <char>(), new List <CharRange>()); _charactersByState[fa] = chars; } chars.characters.Add(input); }
static bool _TryForwardNeutral(CharFA <TAccept> fa, out CharFA <TAccept> result) { if (!fa.IsNeutral) { result = fa; return(false); } result = fa.EpsilonTransitions[0]; return(fa != result); // false if circular }
/// <summary> /// Creates a lexer out of the specified FSM "expressions" /// </summary> /// <param name="exprs">The expressions to compose the lexer with</param> /// <returns>An FSM representing the lexer.</returns> public static CharFA <TAccept> ToLexer(params CharFA <TAccept>[] exprs) { var result = new CharFA <TAccept>(); for (var i = 0; i < exprs.Length; i++) { result.EpsilonTransitions.Add(exprs[i]); } return(result); }
public void Add(CharFA <TAccept> fa, CharactersAndRanges inputs) { foreach (var input in inputs.characters) { Add(input, fa); } foreach (var inputsRange in inputs.ranges) { Add(inputsRange, fa); } }
/// <summary> /// Creates an FA that will match any one of a set of a characters /// </summary> /// <param name="set">The set 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 <char> set, TAccept accept = default(TAccept)) { var result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); foreach (var ch in set) { result.InputTransitions[ch] = final; } return(result); }
/// <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.InputTransitions[ch] = final; } return(result); }
/// <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 charRange in ranges) { result.InputTransitions.Add(charRange, final); } return(result); }
/// <summary> /// Creates an FA that matches a literal string /// </summary> /// <param name="string">The string to match</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA machine that will match this literal</returns> public static CharFA <TAccept> Literal(IEnumerable <char> @string, TAccept accept = default(TAccept)) { var result = new CharFA <TAccept>(); var current = result; foreach (var ch in @string) { current.IsAccepting = false; var fa = new CharFA <TAccept>(true, accept); current.InputTransitions.Add(ch, fa); current = fa; } return(result); }
static CharFA <TAccept> _ForwardNeutrals(CharFA <TAccept> fa) { if (null == fa) { throw new ArgumentNullException(nameof(fa)); } var result = fa; while (_TryForwardNeutral(result, out result)) { ; } return(result); }
public void Remove(CharFA <TAccept> fa) { _charactersByState.Remove(fa); var keys = _charactersTransitions.Where(x => x.Value == fa).ToList(); foreach (var key in keys) { _charactersTransitions.Remove(key.Key); } var rangeKeys = _rangeTransitions.Where(x => x.fa == fa).Select((x, i) => i).ToList(); foreach (var i in rangeKeys.OrderByDescending(x => x)) { _rangeTransitions.RemoveAt(i); } }
public bool TryGetValue(char input, out CharFA <TAccept> fa) { if (_charactersTransitions.TryGetValue(input, out fa)) { return(true); } foreach (var rangeTransition in _rangeTransitions) { if (rangeTransition.range.First <= input && input <= rangeTransition.range.Last) { fa = rangeTransition.fa; return(true); } } return(false); }
/// <summary> /// Creates a new FA that is a concatenation of two other FA expressions /// </summary> /// <param name="exprs">The FAs to concatenate</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that is the concatenation of the specified FAs</returns> public static CharFA <TAccept> Concat(IEnumerable <CharFA <TAccept> > exprs, TAccept accept = default(TAccept)) { CharFA <TAccept> left = null; var right = left; foreach (var val in exprs) { if (null == val) { continue; } //Debug.Assert(null != val.FirstAcceptingState); var nval = val.Clone(); //Debug.Assert(null != nval.FirstAcceptingState); if (null == left) { left = nval; //Debug.Assert(null != left.FirstAcceptingState); continue; } else if (null == right) { right = nval; //Debug.Assert(null != right.FirstAcceptingState); } else { //Debug.Assert(null != right.FirstAcceptingState); _Concat(right, nval); //Debug.Assert(null != right.FirstAcceptingState); } //Debug.Assert(null != left.FirstAcceptingState); _Concat(left, right.Clone()); //Debug.Assert(null != left.FirstAcceptingState); } if (null != right) { right.FirstAcceptingState.AcceptSymbol = accept; } else { left.FirstAcceptingState.AcceptSymbol = accept; } return(left); }
/// <summary> /// Makes all accepting states transition to a new accepting final state, and sets them as non-accepting /// </summary> /// <param name="accept">The symbol to accept</param> public void Finalize(TAccept accept = default(TAccept)) { var asc = FillAcceptingStates(); var ascc = asc.Count; if (1 == ascc) { return; // don't need to do anything } var final = new CharFA <TAccept>(true, accept); for (var i = 0; i < ascc; ++i) { var fa = asc[i]; fa.IsAccepting = false; fa.EpsilonTransitions.Add(final); } }
/// <summary> /// Creates a state machine representing this expression /// </summary> /// <typeparam name="TAccept">The type of accept symbol to use for this expression</typeparam> /// <param name="accept">The accept symbol to use for this expression</param> /// <returns>A new <see cref="CharFA{TAccept}"/> finite state machine representing this expression</returns> public override CharFA <TAccept> ToFA <TAccept>(TAccept accept) { if (null == Left) { return((null != Right) ? Right.ToFA(accept) : null); } else if (null == Right) { return(Left.ToFA(accept)); } var result = CharFA <TAccept> .Concat(new CharFA <TAccept>[] { Left.ToFA(accept), Right.ToFA(accept) }, accept); if (null != Left as RegexConcatExpression || null != Right as RegexConcatExpression) { result.TrimNeutrals(); } return(result); }
/// <summary> /// Creates a new FA that matches any one of the FA expressions passed /// </summary> /// <param name="exprs">The expressions to match</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that will match the union of the FA expressions passed</returns> public static CharFA <TAccept> Or(IEnumerable <CharFA <TAccept> > exprs, TAccept accept = default(TAccept)) { var result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); foreach (var fa in exprs) { if (null != fa) { var nfa = fa.Clone(); result.EpsilonTransitions.Add(nfa); var nffa = nfa.FirstAcceptingState; nffa.IsAccepting = false; nffa.EpsilonTransitions.Add(final); } else if (!result.EpsilonTransitions.Contains(final)) { result.EpsilonTransitions.Add(final); } } return(result); }
/// <summary> /// Deep copies the finite state machine to a new state machine /// </summary> /// <returns>The new machine</returns> public CharFA <TAccept> Clone() { var closure = FillClosure(); var nclosure = new CharFA <TAccept> [closure.Count]; for (var i = 0; i < nclosure.Length; i++) { nclosure[i] = new CharFA <TAccept>(closure[i].IsAccepting, closure[i].AcceptSymbol); nclosure[i].Tag = closure[i].Tag; } for (var i = 0; i < nclosure.Length; i++) { var t = nclosure[i].InputTransitions; var e = nclosure[i].EpsilonTransitions; foreach (var trns in closure[i].InputTransitions.RangesTransitions) { var id = closure.IndexOf(trns.fa); if (id != -1) { t.Add(trns.range, nclosure[id]); } } foreach (var trns in closure[i].InputTransitions.CharactersTransitions) { var id = closure.IndexOf(trns.Value); if (id != -1) { t.Add(trns.Key, nclosure[id]); } } foreach (var trns in closure[i].EpsilonTransitions) { var id = closure.IndexOf(trns); e.Add(nclosure[id]); } } return(nclosure[0]); }
/// <summary> /// Makes the specified expression case insensitive /// </summary> /// <param name="expr">The target expression</param> /// <param name="accept">The accept symbol</param> /// <returns>A new expression that is the case insensitive equivelent of <paramref name="expr"/></returns> public static CharFA <TAccept> CaseInsensitive(CharFA <TAccept> expr, TAccept accept = default(TAccept)) { var fa = expr.Clone(); var closure = fa.FillClosure(); for (int ic = closure.Count, i = 0; i < ic; ++i) { var ffa = closure[i]; if (ffa.IsAccepting) { ffa.AcceptSymbol = accept; } foreach (var trns in ffa.InputTransitions as IDictionary <CharFA <TAccept>, ICollection <char> > ) { foreach (var ch in new List <char>(trns.Value)) { if (char.IsLower(ch)) { var cch = char.ToUpperInvariant(ch); if (!trns.Value.Contains(cch)) { ffa.InputTransitions.Add(cch, trns.Key); } } else if (char.IsUpper(ch)) { var cch = char.ToLowerInvariant(ch); if (!trns.Value.Contains(cch)) { ffa.InputTransitions.Add(cch, trns.Key); } } } } } return(fa); }
public bool Remove(CharFA <TAccept> item) { _ThrowReadOnly(); return(false); }
public bool Contains(CharFA <TAccept> item) { return(_inner.Keys.Contains(item)); }
public void Add(CharFA <TAccept> item) { _ThrowReadOnly(); }
} = -1; // kleene by default /// <summary> /// Creates a state machine representing this expression /// </summary> /// <typeparam name="TAccept">The type of accept symbol to use for this expression</typeparam> /// <param name="accept">The accept symbol to use for this expression</param> /// <returns>A new <see cref="CharFA{TAccept}"/> finite state machine representing this expression</returns> public override CharFA <TAccept> ToFA <TAccept>(TAccept accept) => null != Expression ? CharFA <TAccept> .Repeat(Expression.ToFA(accept), MinOccurs, MaxOccurs, accept) : null;
/// <summary> /// Indicates whether this state is a duplicate of another state. /// </summary> /// <param name="rhs">The state to compare with</param> /// <returns>True if the states are duplicates (one can be removed without changing the language of the machine)</returns> public bool IsDuplicate(CharFA <TAccept> rhs) { return(null != rhs && IsAccepting == rhs.IsAccepting && _SetComparer.Default.Equals(EpsilonTransitions, rhs.EpsilonTransitions) && _SetComparer.Default.Equals((IDictionary <CharFA <TAccept>, ICollection <char> >)InputTransitions, (IDictionary <CharFA <TAccept>, ICollection <char> >)rhs.InputTransitions)); }
/// <summary> /// Creates a state machine representing this expression /// </summary> /// <typeparam name="TAccept">The type of accept symbol to use for this expression</typeparam> /// <param name="accept">The accept symbol to use for this expression</param> /// <returns>A new <see cref="CharFA{TAccept}"/> finite state machine representing this expression</returns> public override CharFA <TAccept> ToFA <TAccept>(TAccept accept) => CharFA <TAccept> .Literal(new char[] { Value }, accept);
/// <summary> /// Creates a new FA that will match a repetition of the specified FA expression /// </summary> /// <param name="expr">The expression to repeat</param> /// <param name="minOccurs">The minimum number of times to repeat or -1 for unspecified (0)</param> /// <param name="maxOccurs">The maximum number of times to repeat or -1 for unspecified (unbounded)</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that matches the specified FA one or more times</returns> public static CharFA <TAccept> Repeat(CharFA <TAccept> expr, int minOccurs = -1, int maxOccurs = -1, TAccept accept = default(TAccept)) { expr = expr.Clone(); if (minOccurs > 0 && maxOccurs > 0 && minOccurs > maxOccurs) { throw new ArgumentOutOfRangeException(nameof(maxOccurs)); } CharFA <TAccept> result; switch (minOccurs) { case -1: case 0: switch (maxOccurs) { case -1: case 0: result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); final.EpsilonTransitions.Add(result); foreach (var afa in expr.FillAcceptingStates()) { afa.IsAccepting = false; afa.EpsilonTransitions.Add(final); } result.EpsilonTransitions.Add(expr); result.EpsilonTransitions.Add(final); //Debug.Assert(null != result.FirstAcceptingState); return(result); case 1: result = Optional(expr, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); default: var l = new List <CharFA <TAccept> >(); expr = Optional(expr); l.Add(expr); for (int i = 1; i < maxOccurs; ++i) { l.Add(expr.Clone()); } result = Concat(l, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } case 1: switch (maxOccurs) { case -1: case 0: result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); final.EpsilonTransitions.Add(result); foreach (var afa in expr.FillAcceptingStates()) { afa.IsAccepting = false; afa.EpsilonTransitions.Add(final); } result.EpsilonTransitions.Add(expr); //Debug.Assert(null != result.FirstAcceptingState); return(result); case 1: //Debug.Assert(null != expr.FirstAcceptingState); return(expr); default: result = Concat(new[] { expr, Repeat(expr.Clone(), 0, maxOccurs - 1) }, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } default: switch (maxOccurs) { case -1: case 0: result = Concat(new[] { Repeat(expr, minOccurs, minOccurs, accept), Repeat(expr, 0, 0, accept) }, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); case 1: throw new ArgumentOutOfRangeException(nameof(maxOccurs)); default: if (minOccurs == maxOccurs) { var l = new List <CharFA <TAccept> >(); l.Add(expr); //Debug.Assert(null != expr.FirstAcceptingState); for (int i = 1; i < minOccurs; ++i) { var e = expr.Clone(); //Debug.Assert(null != e.FirstAcceptingState); l.Add(e); } result = Concat(l, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } result = Concat(new[] { Repeat(expr.Clone(), minOccurs, minOccurs, accept), Repeat(Optional(expr.Clone()), maxOccurs - minOccurs, maxOccurs - minOccurs, accept) }, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } } }