public static void writeParseCodeAux(TextWriter writer, ScriptParserGenerator generator, IList <SelectionSubCandidate> subCandidates, Action <SelectionSubCandidate, TextWriter, ScriptParserGenerator> returnCodeGenerate)
        {
            Debug.Assert(subCandidates.Count >= 1);
            DefinitionElement rootDefinition = subCandidates.First().RootElement;

            // 先頭のDefinitionContentが同じである選択候補の集合
            Dictionary <DefinitionContent, List <SelectionSubCandidate> > sameHeadCandidates = new Dictionary <DefinitionContent, List <SelectionSubCandidate> >(new DefinitionContentComparer());
            // 優先順位を保つために順番を覚えておく
            List <DefinitionContent> headOrder = new List <DefinitionContent>();
            // 後続の要素がない選択候補の集合
            List <SelectionSubCandidate> noElementCandidates = new List <SelectionSubCandidate>();

            // 選択候補を先頭の要素ごとに振り分け
            foreach (SelectionSubCandidate sub in subCandidates)
            {
                List <SelectionSubCandidate> list;
                if (sub.IsEmpty)
                {
                    noElementCandidates.Add(sub);
                }
                else
                {
                    if (!sameHeadCandidates.TryGetValue(sub.Head, out list))
                    {
                        sameHeadCandidates[sub.Head] = list = new List <SelectionSubCandidate>();
                        headOrder.Add(sub.Head);
                    }
                    list.Add(sub);
                }
            }
            Dictionary <string, string> usedFirsts = new Dictionary <string, string>();
            Dictionary <DefinitionContent, string[]> firstTerminals = new Dictionary <DefinitionContent, string[]>();

            foreach (DefinitionContent head in headOrder)
            {
                // 先頭が同じ候補の集合
                List <SelectionSubCandidate> list;
                bool getListFromHeadSucceeded = sameHeadCandidates.TryGetValue(head, out list);
                Debug.Assert(getListFromHeadSucceeded);
                // 現在の先頭要素の中での頭にくる可能性のある終端記号
                HashSet <string> firstsAtThisHead = new HashSet <string>();
                foreach (SelectionSubCandidate sub in list)
                {
                    IList <string> firsts = sub.GetFirstTerminals(generator);
                    foreach (string first in firsts)
                    {
                        // もう追加した場合はスルー
                        if (firstsAtThisHead.Contains(first))
                        {
                            continue;
                        }
                        firstsAtThisHead.Add(first);
                        // 他の先頭のときに使っている終端記号が頭にくる可能性がある場合は警告
                        string usingPoint;
                        if (usedFirsts.TryGetValue(first, out usingPoint))
                        {
                            string context = string.Format("'{0}' の定義", rootDefinition.DefinitionName);
                            string message = string.Format("<{1}> 内の <{0}> は <{2}> によって隠されます", first, sub.OriginalElements.ToString(), usingPoint);
                            generator.Warn(context, message);
                        }
                        else
                        {
                            usedFirsts[first] = sub.OriginalElements.ToString();
                        }
                    }
                }
                firstTerminals[head] = firstsAtThisHead.ToArray();
            }
            bool isSingleCandidate = sameHeadCandidates.Count == 1 && noElementCandidates.Count == 0;

            if (isSingleCandidate)
            {
                List <SelectionSubCandidate> list             = sameHeadCandidates.Values.First();
                string[]                     firstsAtThisHead = firstTerminals.Values.First();
                DefinitionContent            head             = list.First().Head;
                string                       headVar          = head.WriteParseCode(writer, generator);
                List <SelectionSubCandidate> next             = new List <SelectionSubCandidate>();
                foreach (SelectionSubCandidate sub in list)
                {
                    next.Add(sub.NextElement(headVar));
                }
                writeParseCodeAux(writer, generator, next, returnCodeGenerate);
                return;
            }
            bool needsBlockAtEmpty = headOrder.Count >= 1;
            bool usePeekOrThrow    = noElementCandidates.Count == 0;

            // 後続の要素があるものは再帰的に処理
            if (headOrder.Count >= 1)
            {
                string peek;
                if (usePeekOrThrow)
                {
                    IList <string> validTerminals = firstTerminals.Values.SelectMany(terminals => terminals).Distinct().ToList();
                    writer.WriteLine(generator.GetCodeOfPeekOrThrow(rootDefinition.DefinitionName, validTerminals, out peek));
                }
                else
                {
                    // 後続の要素がない場合もあるのでPeekOrThrowではなくPeek
                    writer.WriteLine(generator.GetCodeOfPeek(out peek));
                }
                // 順番通りに
                foreach (DefinitionContent head in headOrder)
                {
                    // 先頭が同じ候補の集合
                    List <SelectionSubCandidate> list;
                    bool getListFromHeadSucceeded = sameHeadCandidates.TryGetValue(head, out list);
                    Debug.Assert(getListFromHeadSucceeded);
                    // 現在の先頭要素の中での頭にくる可能性のある終端記号
                    string[] firstsAtThisHead;
                    bool     getFirstsFromHeadSucceeded = firstTerminals.TryGetValue(head, out firstsAtThisHead);
                    Debug.Assert(getFirstsFromHeadSucceeded);
                    // 頭の終端記号が対象のであるか
                    if (usePeekOrThrow)
                    {
                        writer.WriteLine(generator.GetCodeOfIfLexisIn(peek, firstsAtThisHead));
                    }
                    else
                    {
                        writer.WriteLine(generator.GetCodeOfIfOptionalLexisIn(peek, firstsAtThisHead));
                    }
                    // 先頭の要素をパース
                    string headVar = head.WriteParseCode(writer, generator);
                    // 後続を再帰的に処理
                    List <SelectionSubCandidate> next = new List <SelectionSubCandidate>();
                    foreach (SelectionSubCandidate sub in list)
                    {
                        next.Add(sub.NextElement(headVar));
                    }
                    writeParseCodeAux(writer, generator, next, returnCodeGenerate);
                    writer.Write(generator.GetCodeOfCloseBlock());
                    writer.Write(generator.GetCodeOfSingleElse());
                }
            }
            // 同じ内容なのが二つあった時は警告を出す
            if (noElementCandidates.Count >= 2)
            {
                SelectionSubCandidate oneOfCandidate = noElementCandidates.First();
                foreach (SelectionSubCandidate emptyElse in noElementCandidates.Skip(1))
                {
                    string context = string.Format("'{0}' の定義", rootDefinition.DefinitionName);
                    string message = string.Format("<{0}> は <{1}> によって隠されます", emptyElse.OriginalElements.ToString(), oneOfCandidate.OriginalElements.ToString());
                    generator.Warn(context, message);
                }
            }
            if (needsBlockAtEmpty)
            {
                writer.WriteLine(generator.GetCodeOfOpenBlock());
            }
            if (noElementCandidates.Count >= 1)
            {
                SelectionSubCandidate elements = noElementCandidates.First();
                returnCodeGenerate(elements, writer, generator);
            }
            else
            {
                IList <string> availableTerminals = new List <string>(usedFirsts.Keys);
                writer.WriteLine(generator.GetCodeOfThrowError(rootDefinition.DefinitionName, availableTerminals));
            }
            if (needsBlockAtEmpty)
            {
                writer.WriteLine(generator.GetCodeOfCloseBlock());
            }
        }
        void firstFollowing(ScriptParserGenerator gen, DefinitionElement root, TextWriter writer, DefinitionContent content)
        {
            writer.WriteLine(string.Format("   {0}: first:<{1}> following:<{2}>", content, joinStr(content.GetFirstTerminals(gen)), joinStr(content.GetFollowingTerminals(gen))));
            SelectionElement s = content as SelectionElement;

            if (s != null)
            {
                foreach (ElementsElement elems in s.Candidates)
                {
                    firstFollowing(gen, root, writer, elems);
                }
            }
            ExpressionsElement ex = content as ExpressionsElement;

            if (ex != null)
            {
                foreach (ElementsElement elems in ex.Selection.Candidates)
                {
                    firstFollowing(gen, root, writer, elems);
                }
            }
            ElementsElement es = content as ElementsElement;

            if (es != null)
            {
                foreach (ElementElement elem in es.Elements)
                {
                    firstFollowing(gen, root, writer, elem);
                }
            }
            RepeatElement r = content as RepeatElement;

            if (r != null)
            {
                firstFollowing(gen, root, writer, r.InnerExpression);
            }
            OptionElement o = content as OptionElement;

            if (o != null)
            {
                firstFollowing(gen, root, writer, o.InnerExpression);
            }
            GroupElement g = content as GroupElement;

            if (g != null)
            {
                firstFollowing(gen, root, writer, g.InnerExpression);
            }
            LiteralElement l = content as LiteralElement;
        }