コード例 #1
0
        public static CodeCompileUnit GenerateCompileUnit(XbnfGenerationInfo genInfo, string codeclass, string codenamespace, bool fast)
        {
            var result = new CodeCompileUnit();
            var ns     = new CodeNamespace();

            if (!string.IsNullOrEmpty(codenamespace))
            {
                ns.Name = codenamespace;
            }
            result.Namespaces.Add(ns);
            ns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
            var td = C.Class(codeclass, false);

            td.CustomAttributes.Add(GeneratedCodeAttribute);
            td.BaseTypes.Add(C.Type("GlrTableParser"));
            // GlrTableParser(int[][][][] parseTable,string[] symbolTable, ParseAttribute[][] attributes,int[] errorSentinels, IEnumerable<Token> tokenizer,int maxErrorCount)
            td.Members.Add(C.Field(C.Type(typeof(int[][][][])), "ParseTable", MemberAttributes.FamilyAndAssembly | MemberAttributes.Static));
            td.Members.Add(C.Field(C.Type(typeof(string[])), "SymbolTable", MemberAttributes.FamilyAndAssembly | MemberAttributes.Static));
            td.Members.Add(C.Field(C.Type(C.Type("ParseAttribute", 1), 1), "ParseAttributes", MemberAttributes.FamilyAndAssembly | MemberAttributes.Static));
            td.Members.Add(C.Field(C.Type(typeof(int[])), "ErrorSentinels", MemberAttributes.FamilyAndAssembly | MemberAttributes.Static));
            //td.Members.Add(C.Field(C.Type(typeof(int[])), "NodeFlags", MemberAttributes.FamilyAndAssembly | MemberAttributes.Static));

            var et = C.Type("IEnumerable");

            et.TypeArguments.Add(C.Type("Token"));
            var ctor = C.Ctor(MemberAttributes.Public, C.Param(et, "tokenizer"));

            ctor.BaseConstructorArgs.AddRange(new CodeExpression[] {
                C.FieldRef(C.TypeRef(codeclass), "ParseTable"),
                C.FieldRef(C.TypeRef(codeclass), "SymbolTable"),
                C.FieldRef(C.TypeRef(codeclass), "ParseAttributes"),
                C.FieldRef(C.TypeRef(codeclass), "ErrorSentinels"),
                //C.FieldRef(C.TypeRef(codeclass), "NodeFlags"),
                C.ArgRef("tokenizer"),
                C.FieldRef(C.TypeRef(typeof(int)), "MaxValue")
            });
            td.Members.Add(ctor);
            ctor = C.Ctor(MemberAttributes.Public, C.Param(et, "tokenizer"), C.Param(typeof(int), "maxErrorCount"));
            ctor.BaseConstructorArgs.AddRange(new CodeExpression[] {
                C.FieldRef(C.TypeRef(codeclass), "ParseTable"),
                C.FieldRef(C.TypeRef(codeclass), "SymbolTable"),
                C.FieldRef(C.TypeRef(codeclass), "ParseAttributes"),
                C.FieldRef(C.TypeRef(codeclass), "ErrorSentinels"),
                //C.FieldRef(C.TypeRef(codeclass), "NodeFlags"),
                C.ArgRef("tokenizer"),
                C.ArgRef("maxErrorCount")
            });
            td.Members.Add(ctor);
            ns.Types.Add(td);
            CfgGlrParseTable pt;

            genInfo.Cfg.TryToGlrParseTable(out pt);
            int ts;
            var syms = XbnfConvert.GetSymbolTable(genInfo, out ts);

            (C.GetByName("ParseTable", td.Members) as CodeMemberField).InitExpression      = C.Literal(pt.ToArray(syms));
            (C.GetByName("SymbolTable", td.Members) as CodeMemberField).InitExpression     = C.Literal(syms.ToArray());
            (C.GetByName("ParseAttributes", td.Members) as CodeMemberField).InitExpression = _SerializeParseAttributes(genInfo, syms);
            (C.GetByName("ErrorSentinels", td.Members) as CodeMemberField).InitExpression  = _SerializeErrorSentinels(genInfo, syms);
            //(C.GetByName("NodeFlags", td.Members) as CodeMemberField).InitExpression = _SerializeNodeFlags(genInfo,syms);
            foreach (var code in genInfo.Xbnf.Code)
            {
                td.Members.AddRange(SlangParser.ParseMembers(code.Value, code.Line, code.Column, code.Position));
            }
            var hasChangeType = false;
            var hasEvalAny    = false;

            foreach (var prod in genInfo.Xbnf.Productions)
            {
                if (null != prod.Action)
                {
                    var hasEA = false;
                    var hasCT = false;
                    _GenerateAction(genInfo, syms, td, prod, fast, out hasCT, out hasEA);
                    if (hasCT)
                    {
                        hasChangeType = true;
                    }
                    if (hasEA)
                    {
                        hasEvalAny = true;
                    }
                }
            }
            var consts = new string[syms.Count];

            for (int ic = syms.Count, i = 0; i < ic; ++i)
            {
                var s = syms[i];
                if ("#ERROR" == s)
                {
                    s = "ErrorSymbol";
                }
                else if ("#EOS" == s)
                {
                    s = "EosSymbol";
                }
                s         = _MakeSafeName(s);
                s         = _MakeUniqueMember(td, s);
                consts[i] = s;
                td.Members.Add(C.Field(typeof(int), s, MemberAttributes.Const | MemberAttributes.Public, C.Literal(i)));
            }
            if (hasChangeType)
            {
                var m = C.Method(C.Type(typeof(object)), "_ChangeType", MemberAttributes.Static | MemberAttributes.Private, C.Param(typeof(object), "obj"), C.Param(typeof(Type), "type"));
                m.Statements.Add(C.Var(typeof(TypeConverter), "typeConverter", C.Invoke(C.TypeRef(typeof(TypeDescriptor)), "GetConverter", C.ArgRef("obj"))));
                // if(null!=typeConverter || !typeConverter.CanConvertTo(type))
                m.Statements.Add(C.If(C.Or(C.IdentEq(C.Null, C.VarRef("typeConverter")), C.Not(C.Invoke(C.VarRef("typeConverter"), "CanConvertTo", C.ArgRef("type")))),
                                      C.Return(C.Invoke(C.TypeRef(typeof(Convert)), "ChangeType", C.ArgRef("obj"), C.ArgRef("type")))
                                      ));
                m.Statements.Add(C.Return(C.Invoke(C.VarRef("typeConverter"), "ConvertTo", C.ArgRef("obj"), C.ArgRef("type"))));
                td.Members.Add(m);
            }
            if (hasEvalAny)
            {
                var sid = C.PropRef(C.ArgRef("node"), "SymbolId");
                var m   = C.Method(typeof(object), "_EvaluateAny", MemberAttributes.Private | MemberAttributes.Static, C.Param(C.Type("ParseNode"), "node"), C.Param(typeof(object), "state"));
                for (int ic = genInfo.Xbnf.Productions.Count, i = 0; i < ic; ++i)
                {
                    var p = genInfo.Xbnf.Productions[i];
                    if (!p.IsCollapsed && !p.IsHidden)
                    {
                        var sidcmp = syms.IndexOf(p.Name);
                        var sidcf  = C.FieldRef(C.TypeRef(td.Name), consts[sidcmp]);
                        var cnd    = C.If(C.Eq(sid, sidcf));
                        if (!p.IsTerminal)
                        {
                            cnd.TrueStatements.Add(C.Return(C.Invoke(C.TypeRef(td.Name), string.Concat("Evaluate", p.Name), C.ArgRef("node"), C.ArgRef("state"))));
                        }
                        else
                        {
                            cnd.TrueStatements.Add(C.Return(C.PropRef(C.ArgRef("node"), "Value")));
                        }
                        m.Statements.Add(cnd);
                    }
                }
                m.Statements.Add(C.Return(C.Null));
                td.Members.Add(m);
            }

            return(result);
        }
コード例 #2
0
        /*static int Test()
         * {
         *      string input;
         *      using (var sr = new StreamReader(@"..\..\data2.json"))
         *              input = sr.ReadToEnd();
         *      var tokenizer = new JsonTokenizer(input);
         *      var xbnf = XbnfDocument.ReadFrom(@"..\..\json.xbnf");
         *      XbnfGenerationInfo info;
         *      XbnfConvert.TryCreateGenerationInfo(xbnf, out info);
         *      int ts;
         *      var symbols =XbnfConvert.GetSymbolTable(info, out ts);
         *      CfgGlrParseTable parseTable;
         *      info.Cfg.RebuildCache();
         *      info.Cfg.TryToGlrParseTable(out parseTable, LRTableKind.Lalr1);
         *      var errorSentinels = new List<int>();
         *      var i = 0;
         *      var parseAttributes = new ParseAttribute[symbols.Count][];
         *      foreach(var attrs in info.Cfg.AttributeSets)
         *      {
         *              var id = symbols.IndexOf(attrs.Key);
         *              int jc = attrs.Value.Count;
         *              parseAttributes[id] = new ParseAttribute[jc];
         *              for(var j=0;j<jc;++j)
         *              {
         *                      var attr = attrs.Value[j];
         *                      parseAttributes[id][j] = new ParseAttribute(attr.Name, attr.Value);
         *                      if ("errorSentinel" == attr.Name && attr.Value is bool && ((bool)attr.Value))
         *                              errorSentinels.Add(id);
         *
         *              }
         ++i;
         *      }
         *      for (i = 0; i < parseAttributes.Length; i++)
         *              if (null == parseAttributes[i])
         *                      parseAttributes[i] = new ParseAttribute[0];
         *
         *      var parser = new GlrTableParser(parseTable.ToArray(symbols), symbols.ToArray(), parseAttributes, errorSentinels.ToArray(),tokenizer);
         *      foreach (var pt in parser.ParseReductions(false, true, false))
         *      {
         *              Console.WriteLine(pt.ToString("t"));
         *      }
         *      return 0;
         * }*/
        public static int Run(string[] args, TextReader stdin, TextWriter stdout, TextWriter stderr)
        {
            int        result = 0;
            TextWriter output = null;

            string inputfile     = null;
            string outputfile    = null;
            string rolexfile     = null;
            string codenamespace = null;
            string codelanguage  = null;
            string codeclass     = null;
            string yaccfile      = null;
            bool   verbose       = false;
            bool   noshared      = false;
            bool   ifstale       = false;
            bool   fast          = false;
            bool   noparser      = false;

            try
            {
                if (0 == args.Length)
                {
                    _PrintUsage(stderr);
                    return(-1);
                }
                if (args[0].StartsWith("/"))
                {
                    throw new ArgumentException("Missing input file.");
                }

                // process the command line args
                inputfile = args[0];
                for (var i = 1; i < args.Length; ++i)
                {
                    switch (args[i])
                    {
                    case "/namespace":
                        if (args.Length - 1 == i)                                 // check if we're at the end
                        {
                            throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1)));
                        }
                        ++i;                                 // advance
                        codenamespace = args[i];
                        break;

                    case "/class":
                        if (args.Length - 1 == i)                                 // check if we're at the end
                        {
                            throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1)));
                        }
                        ++i;                                 // advance
                        codeclass = args[i];
                        break;

                    case "/language":
                        if (args.Length - 1 == i)                                 // check if we're at the end
                        {
                            throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1)));
                        }
                        ++i;                                 // advance
                        codelanguage = args[i];
                        break;

                    case "/output":
                        if (args.Length - 1 == i)                                 // check if we're at the end
                        {
                            throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1)));
                        }
                        ++i;                                 // advance
                        outputfile = args[i];
                        break;

                    case "/yacc":
                        if (args.Length - 1 == i)                                 // check if we're at the end
                        {
                            throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1)));
                        }
                        ++i;                                 // advance
                        yaccfile = args[i];
                        break;

                    case "/ifstale":
                        ifstale = true;
                        break;

                    case "/fast":
                        fast = true;
                        break;

                    case "/noparser":
                        noparser = true;
                        break;

                    case "/noshared":
                        noshared = true;
                        break;

                    case "/verbose":
                        verbose = true;
                        break;

                    case "/rolex":
                        if (args.Length - 1 == i)                                 // check if we're at the end
                        {
                            throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1)));
                        }
                        ++i;                                 // advance
                        rolexfile = args[i];
                        break;

                    default:
                        throw new ArgumentException(string.Format("Unknown switch {0}", args[i]));
                    }
                }
                if (null != outputfile && noparser)
                {
                    throw new ArgumentException("<noparser> and <ouputfile> cannot both be specified.", "outputfile");
                }

                if (null == codeclass)
                {
                    if (null != outputfile)
                    {
                        codeclass = Path.GetFileNameWithoutExtension(outputfile);
                    }
                    else
                    {
                        codeclass = Path.GetFileNameWithoutExtension(inputfile);
                    }
                }


                // override the options with our document's options
                var doc = XbnfDocument.ReadFrom(inputfile);
                var oi  = -1;
                oi = doc.Options.IndexOf("outputfile");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        outputfile = s;
                        if ("" == outputfile)
                        {
                            outputfile = null;
                        }
                    }
                    // if it's specified in the doc we need to make it doc relative
                    if (null != outputfile)
                    {
                        if (!Path.IsPathRooted(outputfile))
                        {
                            var dir = Path.GetDirectoryName(Path.GetFullPath(inputfile));
                            outputfile = Path.GetFullPath(Path.Combine(dir, outputfile));
                        }
                    }
                }
                oi = doc.Options.IndexOf("rolexfile");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        rolexfile = s;
                        if ("" == rolexfile)
                        {
                            rolexfile = null;
                        }
                    }
                    // if it's specified in the doc we need to make it doc relative
                    if (null != rolexfile)
                    {
                        if (!Path.IsPathRooted(rolexfile))
                        {
                            var dir = Path.GetDirectoryName(Path.GetFullPath(inputfile));
                            rolexfile = Path.GetFullPath(Path.Combine(dir, rolexfile));
                        }
                    }
                }

                oi = doc.Options.IndexOf("yaccfile");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        rolexfile = s;
                        if ("" == yaccfile)
                        {
                            yaccfile = null;
                        }
                    }
                    // if it's specified in the doc we need to make it doc relative
                    if (null != yaccfile)
                    {
                        if (!Path.IsPathRooted(yaccfile))
                        {
                            var dir = Path.GetDirectoryName(Path.GetFullPath(inputfile));
                            rolexfile = Path.GetFullPath(Path.Combine(dir, yaccfile));
                        }
                    }
                }


                oi = doc.Options.IndexOf("codenamespace");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        codenamespace = s;
                    }
                }
                oi = doc.Options.IndexOf("codelanguage");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (!string.IsNullOrEmpty(s))
                    {
                        codelanguage = s;
                    }
                }
                oi = doc.Options.IndexOf("codeclass");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        codeclass = s;
                        if ("" == codeclass)
                        {
                            if (null != outputfile)
                            {
                                codeclass = Path.GetFileNameWithoutExtension(outputfile);
                            }
                            else
                            {
                                codeclass = Path.GetFileNameWithoutExtension(inputfile);
                            }
                        }
                    }
                }
                oi = doc.Options.IndexOf("verbose");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    if (o is bool)
                    {
                        verbose = (bool)o;
                    }
                }
                oi = doc.Options.IndexOf("fast");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    if (o is bool)
                    {
                        fast = (bool)o;
                    }
                }
                if (fast && null != codelanguage)
                {
                    throw new ArgumentException("<codelanguage> and <fast> cannot both be specified. The <fast> option is C# only.");
                }

                var stale = true;
                if (ifstale)
                {
                    stale = false;
                    if (!stale && null != rolexfile)
                    {
                        if (_IsStale(inputfile, rolexfile))
                        {
                            stale = true;
                        }
                    }
                    if (!stale && null != yaccfile)
                    {
                        if (_IsStale(inputfile, yaccfile))
                        {
                            stale = true;
                        }
                    }

                    if (!stale)
                    {
                        var files = XbnfDocument.GetResources(inputfile);
                        foreach (var s in files)
                        {
                            if (_IsStale(s, outputfile))
                            {
                                stale = true;
                                break;
                            }
                        }
                    }
                    // see if our exe has changed
                    if (!stale && null != outputfile && _IsStale(CodeBase, outputfile))
                    {
                        stale = true;
                    }
                }

                if (!stale)
                {
                    stderr.WriteLine("Skipped building of the following because they were not stale:");
                    if (null != outputfile)
                    {
                        stderr.WriteLine("Output file: " + outputfile);
                    }
                    if (null != rolexfile)
                    {
                        stderr.WriteLine("Rolex file: " + rolexfile);
                    }
                    if (null != yaccfile)
                    {
                        stderr.WriteLine("YACC file: " + yaccfile);
                    }
                }
                else
                {
                    stderr.WriteLine("{0} is building the following:", Name);
                    if (null != outputfile)
                    {
                        stderr.WriteLine("Output file: " + outputfile);
                    }
                    if (null != rolexfile)
                    {
                        stderr.WriteLine("Rolex file: " + rolexfile);
                    }
                    if (null != yaccfile)
                    {
                        stderr.WriteLine("YACC file: " + yaccfile);
                    }
                    if (string.IsNullOrEmpty(codelanguage))
                    {
                        if (!string.IsNullOrEmpty(outputfile))
                        {
                            codelanguage = Path.GetExtension(outputfile);
                            if (codelanguage.StartsWith("."))
                            {
                                codelanguage = codelanguage.Substring(1);
                            }
                        }
                        if (string.IsNullOrEmpty(codelanguage))
                        {
                            codelanguage = "cs";
                        }
                    }

                    var isLexerOnly = true;
                    if (doc.HasNonTerminalProductions)
                    {
                        isLexerOnly = false;
                    }
                    else
                    {
                        foreach (var include in doc.Includes)
                        {
                            if (include.Document.HasNonTerminalProductions)
                            {
                                isLexerOnly = false;
                                break;
                            }
                        }
                    }
                    // we need to prepare it by marking every terminal
                    // with an attribute if it isn't already. we use
                    // "terminal" because it doesn't impact terminals
                    // in any way, but this way the CfgDocument can
                    // "see" them.
                    for (int ic = doc.Productions.Count, i = 0; i < ic; ++i)
                    {
                        var p = doc.Productions[i];
                        if (p.IsTerminal && 0 == p.Attributes.Count)
                        {
                            p.Attributes.Add(new XbnfAttribute("terminal", true));
                        }
                    }

                    XbnfGenerationInfo genInfo;
                    var msgs = XbnfConvert.TryCreateGenerationInfo(doc, out genInfo);

                    foreach (var msg in msgs)
                    {
                        if (verbose || ErrorLevel.Information != msg.ErrorLevel)
                        {
                            stderr.WriteLine(msg);
                        }
                    }
                    foreach (var msg in msgs)
                    {
                        if (msg.ErrorLevel == ErrorLevel.Error)
                        {
                            throw new Exception(msg.ToString());
                        }
                    }
                    CfgDocument primaryCfg = genInfo.Cfg;
                    doc = genInfo.Xbnf;
                    if (!isLexerOnly)
                    {
                        if (verbose)
                        {
                            stderr.WriteLine("Final grammar:");
                            stderr.WriteLine(primaryCfg.ToString());
                            stderr.WriteLine();
                        }
                        foreach (var msg in msgs)
                        {
                            if (msg.ErrorLevel == ErrorLevel.Error)
                            {
                                throw new Exception(msg.ToString());
                            }
                        }
                        if (!noparser)
                        {
                            var ccu = CodeGenerator.GenerateCompileUnit(genInfo, codeclass, codenamespace, fast);
                            ccu.Namespaces.Add(new CodeNamespace(codenamespace ?? ""));
                            var ccuNS     = ccu.Namespaces[ccu.Namespaces.Count - 1];
                            var ccuShared = CodeGenerator.GenerateSharedCompileUnit(codenamespace);
                            ccu.ReferencedAssemblies.Add(typeof(TypeConverter).Assembly.GetName().ToString());

                            if (fast)
                            {
                                CD.CodeDomVisitor.Visit(ccu, (ctx) =>
                                {
                                    var vd = ctx.Target as CodeVariableDeclarationStatement;
                                    if (null != vd && CD.CodeDomResolver.IsNullOrVoidType(vd.Type))
                                    {
                                        vd.Type = C.Type("var");
                                    }
                                }, CD.CodeDomVisitTargets.All & ~(CD.CodeDomVisitTargets.Expressions | CD.CodeDomVisitTargets.Comments | CD.CodeDomVisitTargets.Attributes | CD.CodeDomVisitTargets.Directives | CD.CodeDomVisitTargets.Types | CD.CodeDomVisitTargets.TypeRefs));
                                CD.CodeDomVisitor.Visit(ccuShared, (ctx) =>
                                {
                                    var vd = ctx.Target as CodeVariableDeclarationStatement;
                                    if (null != vd && CD.CodeDomResolver.IsNullOrVoidType(vd.Type))
                                    {
                                        vd.Type = C.Type("var");
                                    }
                                }, CD.CodeDomVisitTargets.All & ~(CD.CodeDomVisitTargets.Expressions | CD.CodeDomVisitTargets.Comments | CD.CodeDomVisitTargets.Attributes | CD.CodeDomVisitTargets.Directives | CD.CodeDomVisitTargets.Types | CD.CodeDomVisitTargets.TypeRefs));
                            }
                            else
                            {
                                SlangPatcher.Patch(ccu, ccuShared);
                                var co = SlangPatcher.GetNextUnresolvedElement(ccu);
                                if (null != co)
                                {
                                    stderr.WriteLine("Warning: Not all of the elements could be resolved. The generated code may not be correct in all languages.");
                                    stderr.WriteLine("  Next unresolved: {0}", C.ToString(co).Trim());
                                }
                            }
                            if (!noshared)
                            {
                                CodeGenerator.ImportCompileUnit(ccuNS, ccuShared);
                            }

                            var prov = CodeDomProvider.CreateProvider(codelanguage);

                            if (null != outputfile)
                            {
                                var sw = new StreamWriter(outputfile);
                                sw.BaseStream.SetLength(0);
                                output = sw;
                            }
                            else
                            {
                                output = stdout;
                            }
                            var opts = new CodeGeneratorOptions();
                            opts.VerbatimOrder            = true;
                            opts.BlankLinesBetweenMembers = false;
                            prov.GenerateCodeFromCompileUnit(ccu, output, opts);
                            output.Flush();
                            output.Close();
                            output = null;
                        }
                    }
                    else
                    {
                        stderr.WriteLine("{0} skipped parser generation because there are no non-terminals and no imports defined.", Name);
                    }

                    if (null != rolexfile)
                    {
                        var sw = new StreamWriter(rolexfile);
                        sw.BaseStream.SetLength(0);
                        output = sw;
                        output.WriteLine(XbnfConvert.ToRolexSpec(genInfo));
                        output.Flush();
                        output.Close();
                        output = null;
                    }
                    if (null != yaccfile)
                    {
                        var sw = new StreamWriter(yaccfile);
                        sw.BaseStream.SetLength(0);
                        output = sw;
                        output.WriteLine(genInfo.Cfg.ToString("y"));
                        output.Flush();
                        output.Close();
                        output = null;
                    }
                }
            }
#if !DEBUG
            catch (Exception ex)
            {
                result = _ReportError(ex, stderr);
            }
#endif
            finally
            {
                stderr.Close();
                stdout.Close();
                if (outputfile != null && null != output)
                {
                    output.Close();
                }
            }
            return(result);
        }