void ParseProtoStatements()
        {
            // protoStatement | protoStatement protoStatements | empty

            for (; ;)
            {
                object token = PeekNextToken();
                if (token == null)
                {
                    ErrorUnexpectedEndOfStream();
                }

                VRMLTokenIdKeywordOrFieldType idToken = token as VRMLTokenIdKeywordOrFieldType;
                if (idToken == null)
                {
                    ErrorParsingToken("statement keyword or node id", "", "proto statements");
                }

                switch (idToken.id)
                {
                case "PROTO":
                case "EXTERNPROTO":
                    string nodeTypeId;
                    X3DPrototypeInstance proto = ParseProtoStatement(out nodeTypeId);
                    protoDefinitions.Add(nodeTypeId, proto);
                    break;

                default: return;
                }
            }
        }
        X3DPrototypeInstance ParseProto(out string nodeTypeId)
        {
            // PROTO nodeTypeId [ interfaceDeclarations ] { protoBody }

            PushNameState();

            inPROTO = true;

            string tokenPROTO = GetNextIDToken();

            if (tokenPROTO != "PROTO")
            {
                ErrorParsingToken("PROTO", tokenPROTO, "PROTO statement");
            }

            nodeTypeId = GetNextIDToken();

            char ts = GetNextTerminalSymbolToken();

            if (ts != '[')
            {
                ErrorParsingToken("[", ts.ToString(), "PROTO statement '" + nodeTypeId + "'");
            }

            List <InterfaceDeclaration> interfaceDeclarations = ParseInterfaceDeclarations();

            ts = GetNextTerminalSymbolToken();
            if (ts != ']')
            {
                ErrorParsingToken("]", ts.ToString(), "PROTO statement '" + nodeTypeId + "'");
            }

            ts = GetNextTerminalSymbolToken();
            if (ts != '{')
            {
                ErrorParsingToken("{", ts.ToString(), "PROTO statement '" + nodeTypeId + "'");
            }

            ParseProtoBody();

            ts = GetNextTerminalSymbolToken();
            if (ts != '}')
            {
                ErrorParsingToken("}", ts.ToString(), "PROTO statement '" + nodeTypeId + "'");
            }

            // Proto node of the type of the first node
            X3DPrototypeInstance ret = nodes[0].GetProto();

            ret.InterfaceDeclarations = interfaceDeclarations;
            ret.ProtoNodeName         = nodeTypeId;
            ret.Nodes = nodes;

            PopNameState();

            return(ret);
        }
        void ParseStatement()
        {
            // nodeStatement | protoStatement | exportStatement | importStatement | routeStatement

            object token = PeekNextToken();

            if (token == null)
            {
                ErrorUnexpectedEndOfStream();
            }

            VRMLTokenIdKeywordOrFieldType idToken = token as VRMLTokenIdKeywordOrFieldType;

            if (idToken == null)
            {
                ErrorParsingToken("statement keyword or node id", "", "statement");
            }

            switch (idToken.id)
            {
            case "PROTO":
            case "EXTERNPROTO":
                string nodeTypeId;
                int    lineOfProtoStart    = line;
                X3DPrototypeInstance proto = ParseProtoStatement(out nodeTypeId);
                if (protoDefinitions.ContainsKey(nodeTypeId))
                {
                    ErrorParsing(VRMLReaderError.PROTOAlreadyDefined, lineOfProtoStart);
                }
                else
                {
                    protoDefinitions.Add(nodeTypeId, proto);
                }
                break;

            case "EXPORT": ParseExportStatement(); break;

            case "IMPORT": ParseImportStatement(); break;

            case "ROUTE": ParseRouteStatement(); break;

            default:
                X3DNode node = ParseNodeStatement();
                if (node != null)
                {
                    nodes.Add(node);
                }
                break;
            }
        }