/// <summary>
        /// Output the ANTLR translation of the specified character value node
        /// </summary>
        protected override void WriteCharValNode(ITree node)
        {
            var isCaseSensitive = IsCaseSensitive(node);
            var text            = GetStringValue(node);

            var length = text.Length;

            if (isCaseSensitive && length > 0)
            {
                Write("'");
                Write(text);
                Write("'");
            }
            else
            {
                if (length > 1)
                {
                    Write("(");
                }

                for (int index = 0; index < length; index++)
                {
                    if (index > 0)
                    {
                        Write(" ");
                    }

                    var upperCharacter = char.ToUpperInvariant(text[index]);
                    var lowerCharacter = char.ToLowerInvariant(text[index]);

                    if (upperCharacter == lowerCharacter)
                    {
                        Write("'");
                        Write(AntlrHelper.CharEscape(lowerCharacter));
                        Write("'");
                    }
                    else
                    {
                        Write("(");

                        Write("'");
                        Write(AntlrHelper.CharEscape(upperCharacter));
                        Write("'");

                        Write(" | ");

                        Write("'");
                        Write(AntlrHelper.CharEscape(lowerCharacter));
                        Write("'");

                        Write(")");
                    }
                }

                if (length > 1)
                {
                    Write(")");
                }
            }
        }
        void OutputLiteralRules(IDictionary<char, NamedCharacter> literals, TextWriter writer, INamedCharacterLookup lookup)
        {
            var knownValues = 
                literals.Values
                .Where(x => lookup.IsKnownCharacter(x.Character))
                .OrderBy(x => x.Character)
                .Select(x => x);

            var unknownValues = 
                literals.Values
                .Where(x => !(lookup.IsKnownCharacter(x.Character)))
                .OrderBy(x => x.Character)
                .Select(x => x);

            if (literals.Count > 0)
            {
                writer.WriteLine("");
                writer.WriteLine("");
                writer.WriteLine(@"////////////////////////////////////////////////////////////////////////////////////////////");
                writer.WriteLine(@"// Lexer rules generated for each distinct character in original grammar");
                writer.WriteLine(@"// " + lookup.Description);
                writer.WriteLine(@"////////////////////////////////////////////////////////////////////////////////////////////");
                writer.WriteLine("");
            }

            // output known (named) literals first
            foreach (var value in knownValues)
            {
                writer.Write(value.Name);
                writer.Write(" : ");

                writer.Write("'");

                var character = value.Character;

                writer.Write(AntlrHelper.CharEscape(character));

                writer.Write("'");

                writer.WriteLine(";");
            }

            // output unknown literals
            foreach (var value in unknownValues)
            {
                writer.Write(value.Name);
                writer.Write(" : ");

                int number = value.Character;

                writer.Write(@"'\u");
                writer.Write(number.ToString("X4"));
                writer.Write("'");

                writer.WriteLine(";");
            }
        }
        Dictionary<char, NamedCharacter> LiteralsCollection; // literals collection

        /// <summary>
        /// Translate ABNF grammar to ANTLR grammar
        /// </summary>
        /// <param name="input">TextReader which reads the ABNF grammar</param>
        /// <param name="output">TextWriter which writes the ANTLR grammar</param>
        public void Translate(TextReader input, TextWriter writer, bool performDirectTranslation)
        {
            // force single threaded operation
            lock (SyncLock)
            {
                this.LiteralsCollection = new Dictionary<char, NamedCharacter>();

                // open input stream
                var stream = new Antlr.Runtime.ANTLRReaderStream(input);

                // create lexer
                var lexer = new AbnfAstLexer(stream);

                // get token stream from input stream
                var tokens = new CommonTokenStream(lexer);

                // create parser
                var parser = new AbnfAstParser(tokens);

                // parse token stream
                var results = parser.start();

                if (parser.RecognitionExceptions.Count > 0 || lexer.RecognitionExceptions.Count > 0)
                {
                    var message =
                        AntlrHelper.GetErrorMessages(parser.RecognitionExceptions)
                        + AntlrHelper.GetErrorMessages(lexer.RecognitionExceptions)
                        ;

                    throw new TranslationException(message, parser.RecognitionExceptions, lexer.RecognitionExceptions);
                }

                // get parse tree
                var tree = results.Tree;

                // Use simplified named characters for indirect translation
                var lookup = new NamedCharacterLookupSimple();

                // enable this line to use Unicode named characters for indirect translation
                // var lookup = new NamedCharacterLookupUnicode();

                var ruleStatistics = new RuleStatistics();
                var statisticsVisitor = new TreeVisitor_GatherRuleStatistics(ruleStatistics);
                statisticsVisitor.Visit(tree);

                // output translated grammar
                if (performDirectTranslation)
                {
                    OutputDirectTranslation(writer, tokens, tree, lookup, ruleStatistics);
                }
                else
                {
                    OutputIndirectTranslation(writer, tokens, tree, lookup, ruleStatistics);
                }
            }
        }
        public void GatherIncrementalAliases()
        {
            foreach (var ruleName in _ruleStatistics.LhsRawRuleNames)
            {
                var ruleDetail = _ruleStatistics.RuleDetails[ruleName];

                var countOfIncrementalAlternatives = ruleDetail.CountOfIncrementalAlternatives;

                if (countOfIncrementalAlternatives > 0)
                {
                    var incrementalAliases = new string[countOfIncrementalAlternatives];

                    var lastIndex = countOfIncrementalAlternatives - 1;

                    for (int index = 0; index < countOfIncrementalAlternatives; index++)
                    {
                        // determine alias
                        var parserRuleName = AntlrHelper.GetParserRuleName(ruleName);

                        var alias = parserRuleName;

                        int counter = 0;

                        while (AntlrHelper.IsReservedKeyWord(alias) || _ruleStatistics.Aliases.Contains(alias) || _allIncrementalAliases.Contains(alias))
                        {
                            counter++;
                            alias = parserRuleName + "_" + counter;

                            while (_ruleStatistics.AllParserRuleNames.Contains(alias))
                            {
                                counter++;
                                alias = parserRuleName + "_" + counter;
                            }
                        }

                        _allIncrementalAliases.Add(alias);

                        if (index == lastIndex)
                        {
                            if (ruleDetail.IsLexerRule)
                            {
                                alias = GetLexerRuleName(alias);
                            }
                        }

                        incrementalAliases[index] = alias;
                    }

                    _mapRuleNameToIncrementalAliases.Add(ruleName, incrementalAliases);
                    _lhsIncrementalRuleCounters[ruleName] = 0;
                }
            }
        }