private bool AddEnumItemDef(
            ProtocolDescriptor.ProtocolDef protoDef,
            ProtocolDescriptor.EnumDef enumDef, XElement element)
        {
            // check name attr
            string name;

            {
                XAttribute attr = element.Attribute("name");
                if (attr == null)
                {
                    PrintLineError(protoDef, element,
                                   "`item` node must contain a `name` attribute");
                    return(false);
                }
                name = attr.Value;
            }
            if (Regex.IsMatch(name, @"^[a-zA-Z_]\w*$") == false)
            {
                PrintLineError(protoDef, element,
                               "`item` node `name` attribute is invalid");
                return(false);
            }
            if (enumDef.ItemNameIndex.ContainsKey(name))
            {
                PrintLineError(protoDef, element,
                               "`item` node `name` attribute duplicated");
                return(false);
            }

            // check value attr
            string val = "";

            {
                XAttribute attr = element.Attribute("value");
                if (attr != null)
                {
                    val = attr.Value;
                }
            }

            ProtocolDescriptor.EnumDef.ItemDef def =
                new ProtocolDescriptor.EnumDef.ItemDef();
            def.ParentRef  = enumDef;
            def.Name       = name;
            def.LineNumber = GetLineNumber(element);

            if (val == "")
            {
                // default
                def.Type = ProtocolDescriptor.EnumDef.ItemType.Default;
                if (enumDef.Items.Count == 0)
                {
                    def.IntValue = 0;
                }
                else
                {
                    def.IntValue =
                        enumDef.Items[enumDef.Items.Count - 1].IntValue + 1;
                }
            }
            else if (Regex.IsMatch(val, @"^(-)?[0-9]+$"))
            {
                // int
                def.Type     = ProtocolDescriptor.EnumDef.ItemType.Int;
                def.IntValue = int.TryParse(val, out def.IntValue)
                    ? def.IntValue : 0;
            }
            else
            {
                string[] parts = val.Split('.');
                if (parts.Length == 1)
                {
                    // current enum
                    string refDefName = parts[0];

                    ProtocolDescriptor.EnumDef.ItemDef refDef = null;
                    if (enumDef.ItemNameIndex.TryGetValue(
                            refDefName, out refDef) == false)
                    {
                        PrintLineError(protoDef, element,
                                       "enum item `{0}` is undefined", refDefName);
                        return(false);
                    }

                    def.Type =
                        ProtocolDescriptor.EnumDef.ItemType.CurrentEnumRef;
                    def.IntValue       = refDef.IntValue;
                    def.RefEnumItemDef = refDef;
                }
                else if (parts.Length == 2)
                {
                    // other enum in same file
                    string refEnumDefName = parts[0];
                    string refDefName     = parts[1];

                    ProtocolDescriptor.EnumDef refEnumDef = null;
                    if (protoDef.EnumNameIndex.TryGetValue(
                            refEnumDefName, out refEnumDef) == false)
                    {
                        PrintLineError(protoDef, element,
                                       "enum `{0}` is undefined", refEnumDefName);
                        return(false);
                    }
                    ProtocolDescriptor.EnumDef.ItemDef refDef = null;
                    if (refEnumDef.ItemNameIndex.TryGetValue(
                            refDefName, out refDef) == false)
                    {
                        PrintLineError(protoDef, element,
                                       "enum item `{0}` is undefined", refDefName);
                        return(false);
                    }

                    def.Type =
                        ProtocolDescriptor.EnumDef.ItemType.OtherEnumRef;
                    def.IntValue       = refDef.IntValue;
                    def.RefEnumItemDef = refDef;
                }
                else if (parts.Length == 3)
                {
                    // other enum in other file
                    string refProtoDefName = parts[0];
                    string refEnumDefName  = parts[1];
                    string refDefName      = parts[2];

                    ProtocolDescriptor.ProtocolDef refProtoDef = null;
                    if (this.descriptor.ImportedProtos.TryGetValue(
                            refProtoDefName, out refProtoDef) == false)
                    {
                        PrintLineError(protoDef, element,
                                       "protocol `{0}` is undefined", refProtoDefName);
                        return(false);
                    }
                    ProtocolDescriptor.EnumDef refEnumDef = null;
                    if (refProtoDef.EnumNameIndex.TryGetValue(
                            refEnumDefName, out refEnumDef) == false)
                    {
                        PrintLineError(protoDef, element,
                                       "enum `{0}` is undefined", refEnumDefName);
                        return(false);
                    }
                    ProtocolDescriptor.EnumDef.ItemDef refDef = null;
                    if (refEnumDef.ItemNameIndex.TryGetValue(
                            refDefName, out refDef) == false)
                    {
                        PrintLineError(protoDef, element,
                                       "enum item `{0}` is undefined", refDefName);
                        return(false);
                    }

                    def.Type =
                        ProtocolDescriptor.EnumDef.ItemType.OtherEnumRef;
                    def.IntValue       = refDef.IntValue;
                    def.RefEnumItemDef = refDef;
                }
                else
                {
                    PrintLineError(protoDef, element,
                                   "enum value `{0}` is invalid", val);
                    return(false);
                }
            }

            enumDef.Items.Add(def);
            enumDef.ItemNameIndex.Add(def.Name, def);

            return(true);
        }
        private void ProcessImportedProtocols(
            ProtocolDescriptor.ProtocolDef protoDef)
        {
            Dictionary <string, ProtocolDescriptor.ProtocolDef> usedProtos =
                new Dictionary <string, ProtocolDescriptor.ProtocolDef>();
            Dictionary <string, ProtocolDescriptor.ProtocolDef> enumRefProtos =
                new Dictionary <string, ProtocolDescriptor.ProtocolDef>();
            Dictionary <string, ProtocolDescriptor.ProtocolDef> structRefProtos =
                new Dictionary <string, ProtocolDescriptor.ProtocolDef>();
            Dictionary <string, ProtocolDescriptor.ProtocolDef> enumMapRefProtos =
                new Dictionary <string, ProtocolDescriptor.ProtocolDef>();

            // collect enum ref protocols
            for (int i = 0; i < protoDef.Enums.Count; ++i)
            {
                ProtocolDescriptor.EnumDef enumDef =
                    protoDef.Enums[i];

                for (int j = 0; j < enumDef.Items.Count; ++j)
                {
                    ProtocolDescriptor.EnumDef.ItemDef def =
                        enumDef.Items[j];
                    if (def.RefEnumItemDef != null)
                    {
                        ProtocolDescriptor.ProtocolDef refProtoDef =
                            def.RefEnumItemDef.ParentRef.ParentRef;
                        usedProtos[refProtoDef.Name]    = refProtoDef;
                        enumRefProtos[refProtoDef.Name] = refProtoDef;
                    }
                }
            }

            // collect struct ref protocols
            for (int i = 0; i < protoDef.Structs.Count; ++i)
            {
                ProtocolDescriptor.StructDef structDef =
                    protoDef.Structs[i];

                for (int j = 0; j < structDef.Fields.Count; ++j)
                {
                    ProtocolDescriptor.StructDef.FieldDef def =
                        structDef.Fields[j];
                    if (def.RefEnumDef != null)
                    {
                        ProtocolDescriptor.ProtocolDef refProtoDef =
                            def.RefEnumDef.ParentRef;
                        usedProtos[refProtoDef.Name]      = refProtoDef;
                        structRefProtos[refProtoDef.Name] = refProtoDef;
                    }
                    if (def.RefStructDef != null)
                    {
                        ProtocolDescriptor.ProtocolDef refProtoDef =
                            def.RefStructDef.ParentRef;
                        usedProtos[refProtoDef.Name]      = refProtoDef;
                        structRefProtos[refProtoDef.Name] = refProtoDef;
                    }
                }
            }

            // collect enum map ref protocols
            for (int i = 0; i < protoDef.EnumMaps.Count; ++i)
            {
                ProtocolDescriptor.EnumMapDef enumMapDef =
                    protoDef.EnumMaps[i];

                for (int j = 0; j < enumMapDef.Items.Count; ++j)
                {
                    ProtocolDescriptor.EnumMapDef.ItemDef def =
                        enumMapDef.Items[j];
                    if (def.RefEnumItemDef != null)
                    {
                        ProtocolDescriptor.ProtocolDef refProtoDef =
                            def.RefEnumItemDef.ParentRef.ParentRef;
                        usedProtos[refProtoDef.Name]       = refProtoDef;
                        enumMapRefProtos[refProtoDef.Name] = refProtoDef;
                    }
                    if (def.RefStructDef != null)
                    {
                        ProtocolDescriptor.ProtocolDef refProtoDef =
                            def.RefStructDef.ParentRef;
                        usedProtos[refProtoDef.Name]       = refProtoDef;
                        enumMapRefProtos[refProtoDef.Name] = refProtoDef;
                    }
                }
            }

            for (int i = 0; i < protoDef.Imports.Count; ++i)
            {
                ProtocolDescriptor.ImportDef importDef =
                    protoDef.Imports[i];

                // check imported protocol is used
                if (usedProtos.ContainsKey(importDef.ProtoDef.Name) == false)
                {
                    Console.Error.WriteLine(string.Format(
                                                "warning:{0}:{1}: protocol `{2}` " +
                                                "is not used but imported",
                                                protoDef.FilePath, importDef.LineNumber,
                                                importDef.Name));
                }

                if (enumRefProtos.ContainsKey(importDef.ProtoDef.Name))
                {
                    importDef.IsRefByEnum = true;
                }
                if (structRefProtos.ContainsKey(importDef.ProtoDef.Name))
                {
                    importDef.IsRefByStruct = true;
                }
                if (enumMapRefProtos.ContainsKey(importDef.ProtoDef.Name))
                {
                    importDef.IsRefByEnumMap = true;
                }
            }
        }