/// <summary>
        ///     Parses terminal symbols - like string constants
        /// </summary>
        static void ParseTerminals(ParseContext context)
        {
            for (var i = context.NonterminalStartPos; i <= context.Pos; i++)
            {
                var scanChar = context.Input[i];

                var lastTerm = context.PreviousTag?.Value as TerminalTag;
                if (lastTerm == null || lastTerm.AcceptsLetter(context, scanChar) == false)
                {
                    foreach (var tt in terminalTags)
                    {
                        if (tt.AcceptsLetter(context, scanChar) != false)
                        {
                            context.AddTag(((TerminalTag)tt.Create()).AppendChar(scanChar));
                            break;
                        }
                    }
                }
                else
                {
                    lastTerm.AppendChar(scanChar);
                }
            }
        }
        /// <summary>
        ///     Parses terminal symbols - like string constants
        /// </summary>
        static void ParseTerminals(ParseContext context) {
            for (var i = context.NonterminalStartPos; i <= context.Pos; i++)
            {
                var scanChar = context.Input[i];

                var lastTerm = context.PreviousTag?.Value as TerminalTag;
                if (lastTerm == null || lastTerm.AcceptsLetter(context, scanChar) == false)
                {
                    foreach (var tt in terminalTags)
                    {
                        if (tt.AcceptsLetter(context, scanChar) != false)
                        {
                            context.AddTag(((TerminalTag)tt.Create()).AppendChar(scanChar));
                            break;
                        }
                    }
                } else lastTerm.AppendChar(scanChar);
            }
        }
        LinkedList <Tag> SplitIntoTags(string input)
        {
            var candidates = new List <Tag>();

            if (string.IsNullOrEmpty(input))
            {
                return(new LinkedList <Tag>());
            }

            context.Setup(input);

            while (context.Pos < input.Length)
            {
                var letter = context.CurrentChar;

                var mc = 0;

                if (candidates.Count > 0)
                {
                    for (var ci = candidates.Count - 1; ci >= 0; ci--)
                    {
                        var c   = candidates[ci];
                        var ret = c.AcceptsLetter(context, letter);
                        if (ret == true)
                        {
                            context.AddTag(c.Create().Init(context.MatchedString));
                            candidates.Clear();
                            context.ResetNonterminalPos();
                            mc = 1;
                            break;
                        }
                        if (ret == null)
                        {
                            mc++;
                        }
                        else
                        {
                            candidates.RemoveAt(ci);
                        }
                    }
                }
                else
                {
                    for (var ci = nonterminalTags.Count - 1; ci >= 0; ci--)
                    {
                        var c   = nonterminalTags[ci];
                        var ret = c.AcceptsLetter(context, letter);
                        if (ret == true)
                        {
                            context.AddTag(c.Create().Init(context.MatchedString));
                            context.ResetNonterminalPos();
                            mc = 1;
                            break;
                        }
                        if (ret == null)
                        {
                            mc++;
                            candidates.Add(c);
                        }
                    }
                }

                if (mc == 0 || context.Pos == input.Length - 1) // we are not matching any nonterminal tags
                {
                    ParseTerminals(context);
                    context.ResetNonterminalPos();
                }

                context.AdvancePos();
            }

            return(context.Tags);
        }