static void _Concat(CharFA <TAccept> lhs, CharFA <TAccept> rhs) { var f = lhs.FirstAcceptingState; f.EpsilonTransitions.Add(rhs); f.IsAccepting = 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; } var nval = val.Clone(); if (null == left) { left = nval; continue; } else if (null == right) { right = nval; } else { _Concat(right, nval); } _Concat(left, right); } right.FirstAcceptingState.AcceptSymbol = accept; return(left); }
private void RenderTimer_Tick(object sender, EventArgs e) { RenderTimer.Enabled = false; CharFA <string> fa = null; try { fa = CharFA <string> .Parse(Regex.Text, "Accept"); } catch (Exception ex) { Status.Text = string.Format("Error Parsing Regex: {0}", ex.Message); } if (null != fa) { // mark our states for displaying the DFA later foreach (var ffa in fa.FillClosure()) { ffa.Tag = ffa; } try { var kvp = fa.Lex(Input.Text.GetEnumerator(), "#ERROR"); if (kvp.Value.Length != Input.Text.Length) { Status.Text = string.Format("Input error at {0}", kvp.Value.Length); } else { Status.Text = "Successfully Lexed."; } } catch (Exception eex) { Status.Text = string.Format("Input error: {0}", eex.Message); } var options = new CharFA <string> .DotGraphOptions(); options.DebugString = Input.Text; var dfa = fa.ToDfa(); dfa.TrimDuplicates(); try { using (var stm = fa.RenderToStream("jpg", false, options)) NfaGraph.Image = Image.FromStream(stm); } catch { } options.StatePrefix = @"Q"; options.DebugSourceNfa = fa; try { using (var stm = dfa.RenderToStream("jpg", false, options)) DfaGraph.Image = Image.FromStream(stm); } catch { } } }
/// <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); }
/// <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); }
/// <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.Transitions.Add(ch, final); } return(result); }
/// <summary> /// Creates a new FA that will match a repetition of one or more of the specified FA expression /// </summary> /// <param name="expr">The expression to repeat</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, TAccept accept = default(TAccept)) { var result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); var e = expr.Clone(); var afa = e.FirstAcceptingState; afa.IsAccepting = false; afa.EpsilonTransitions.Add(final); afa.EpsilonTransitions.Add(result); result.EpsilonTransitions.Add(e); 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.Transitions.Add(ch, fa); current = fa; } 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) { var nfa = fa.Clone(); result.EpsilonTransitions.Add(nfa); var nffa = nfa.FirstAcceptingState; nffa.IsAccepting = false; nffa.EpsilonTransitions.Add(final); } return(result); }
static void Main(string[] args) { var nfa = CharFA <string> .Parse("hello|world!", "success!"); var dfa = nfa.ToDfa(); var opts = new CharFA <string> .DotGraphOptions(); opts.DebugSourceNfa = nfa; opts.DebugString = "he"; dfa.TrimDuplicates(); dfa.RenderToFile(@"..\..\..\helloworld.jpg", opts); Console.WriteLine(dfa); var tok = dfa.Lex("helloworld".GetEnumerator(), "#ERROR"); Console.WriteLine("{0}: {1}", tok.Key, new string(tok.Value)); }
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; } } }
/// <summary> /// Creates a new FA that will match a repetition of zero or more of the specified FA expressions /// </summary> /// <param name="expr">The expression to repeat</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that matches the specified FA zero or more times</returns> public static CharFA <TAccept> Kleene(CharFA <TAccept> expr, TAccept accept = default(TAccept)) { return(Optional(Repeat(expr), accept)); }