home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / VSLLib.C < prev    next >
C/C++ Source or Header  |  1998-11-23  |  16KB  |  797 lines

  1. // $Id: VSLLib.C,v 1.15 1998/11/23 17:43:44 zeller Exp $
  2. // The VSL Library
  3.  
  4. // Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char VSLLib_rcsid[] = 
  30.     "$Id: VSLLib.C,v 1.15 1998/11/23 17:43:44 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36.  
  37. #include "assert.h"
  38. #include "hash.h"
  39.  
  40. #include "VSEFlags.h"
  41.  
  42. #include "VSLLib.h"
  43. #include "VSLDef.h"
  44. #include "VSLDefList.h"
  45. #include "VSLBuiltin.h"
  46.  
  47. #include "VSLNode.h"
  48. #include "DefCallN.h"
  49. #include "BuiltinCN.h"
  50. #include "ArgNode.h"
  51. #include "ListNode.h"
  52. #include "TrueNode.h"
  53. #include "StringBox.h"
  54.  
  55. DEFINE_TYPE_INFO_0(VSLLib)
  56.  
  57. // VSLLib
  58.  
  59. // Data
  60.  
  61. void (*VSLLib::background)() = 0;   // Background proc
  62.  
  63. #define BACKGROUND() do { if (background) background(); } while (false)
  64. #define ASSERT_OK() \
  65. do { \
  66.     if (VSEFlags::assert_library_ok) \
  67.     { \
  68.         bool ok = OK(); \
  69.         assert(ok); \
  70.     if (!ok) \
  71.         abort(); \
  72.     } \
  73. } while (false)
  74.  
  75.  
  76. // Initialization
  77.  
  78. // Init hash table
  79. void VSLLib::initHash()
  80. {
  81.     for (int i = 0; i < hashSize; i++)
  82.     defs[i] = 0;
  83. }
  84.  
  85. // Init VSL library
  86. VSLLib::VSLLib()
  87.     : _lib_name(""), _first(0), _last(0)
  88. {
  89.     initHash();
  90. }
  91.  
  92.  
  93. // Init VSL library and read from file
  94. VSLLib::VSLLib(const string& lib_name, unsigned optimize)
  95.     : _lib_name(lib_name), _first(0), _last(0)
  96. {
  97.     initHash();
  98.     read(lib_name, optimize);
  99. }
  100.  
  101.  
  102. // Init VSL library and read from stream
  103. VSLLib::VSLLib(istream& i, unsigned optimize)
  104.     : _lib_name(""), _first(0), _last(0)
  105. {
  106.     initHash();
  107.     read(i, optimize);
  108. }
  109.  
  110.  
  111. // Return list of defs for FUNC_NAME; 0 if not found
  112. VSLDefList* VSLLib::deflist(const string& func_name) const
  113. {
  114.     unsigned hashcode = hashpjw(func_name) % hashSize;
  115.  
  116.     VSLDefList *d;
  117.     for (d = defs[hashcode];
  118.      d != 0 && d->func_name() != func_name; d = d->next())
  119.     ;
  120.  
  121.     return d;
  122. }
  123.  
  124.  
  125. // Add definition to library
  126. VSLDef *VSLLib::add(const string& func_name,
  127.     VSLNode *pattern, VSLNode *expr, 
  128.     bool global, const string& filename, int lineno)
  129. {
  130.     BACKGROUND();
  131.  
  132.     // Find DefList for function name
  133.     VSLDefList *d = deflist(func_name);
  134.     
  135.     if (d == 0)
  136.     {
  137.     // Not found?  Create a new DefList...
  138.     unsigned hashcode = hashpjw(func_name) % hashSize;
  139.  
  140.     d = defs[hashcode];
  141.     defs[hashcode] = new VSLDefList(this, hashcode, func_name, global);
  142.     defs[hashcode]->next() = d;
  143.  
  144.     // ...and return it
  145.     d = defs[hashcode];
  146.     }
  147.  
  148.     // Append new def to DefList
  149.     bool newFlag;
  150.     VSLDef* newdef = d->add(newFlag, pattern, expr, filename, lineno);
  151.  
  152.     if (newFlag)
  153.     {
  154.     // Insert def into global list
  155.     if (_last == 0)
  156.         _first = newdef;
  157.     else
  158.     {
  159.         _last->libnext() = newdef;
  160.         newdef->libprev() = _last;
  161.     }
  162.     _last = newdef;
  163.     }
  164.  
  165.     // Setup scope: Scope is global if any def is global.
  166.     d->global() = d->global() || global;
  167.  
  168.     return newdef;
  169. }
  170.  
  171.  
  172. // Rename function name
  173. int VSLLib::override(const string& func_name)
  174. {
  175.     VSLDefList *d = deflist(func_name);
  176.  
  177.     if (d == 0)
  178.     return -1;
  179.  
  180.     d->override();
  181.     return 0;
  182. }
  183.  
  184. // Delete function def
  185. int VSLLib::replace(const string& func_name)
  186. {
  187.     VSLDefList *d = deflist(func_name);
  188.  
  189.     if (d == 0)
  190.     return -1;
  191.  
  192.     d->replace();
  193.     return 0;
  194. }
  195.  
  196.     
  197.  
  198.  
  199.  
  200. // Return definition for given function name and argument
  201. VSLDef *VSLLib::def(const string& func_name, Box *a) const
  202. {
  203.     VSLDefList *d = deflist(func_name);
  204.     return d ? d->def(a) : 0;
  205. }
  206.  
  207.  
  208. // Evaluate call
  209. const Box *VSLLib::eval(const string& func_name, ListBox *a) const
  210. {
  211.     VSLDefList *d = deflist(func_name);
  212.     if (d == 0)
  213.     eval_error("'" + func_name + "(...)' undefined");
  214.  
  215.     return d ? d->eval(a) : 0;
  216. }
  217.  
  218. // Custom functions
  219. const Box *VSLLib::eval(const string& func_name, VSLArg args[]) const
  220. {
  221.     ListBox *arg = new ListBox;
  222.     for (int i = 0; args[i].box() != 0; i++)
  223.     *arg += args[i].box();
  224.     
  225.     const Box *result = eval(func_name, arg);
  226.     arg->unlink();
  227.  
  228.     return result;
  229. }
  230.  
  231. const Box *VSLLib::eval(const string& func_name,
  232.             VSLArg arg0,
  233.             VSLArg arg1,
  234.             VSLArg arg2,
  235.             VSLArg arg3,
  236.             VSLArg arg4,
  237.             VSLArg arg5,
  238.             VSLArg arg6,
  239.             VSLArg arg7,
  240.             VSLArg arg8,
  241.             VSLArg arg9) const
  242. {
  243.     VSLArg args[11];
  244.  
  245.     args[0] = arg0;
  246.     args[1] = arg1;
  247.     args[2] = arg2;
  248.     args[3] = arg3;
  249.     args[4] = arg4;
  250.     args[5] = arg5;
  251.     args[6] = arg6;
  252.     args[7] = arg7;
  253.     args[8] = arg8;
  254.     args[9] = arg9;
  255.     args[10] = (Box *)0;
  256.  
  257.     return eval(func_name, args);
  258. }
  259.  
  260. // Prepare expression for output
  261. void VSLLib::output(Box *&a)
  262. {
  263.     if (a == 0)
  264.     return;
  265.  
  266.     VSLDefList *d = deflist("__output");
  267.     if (d == 0)
  268.     return;
  269.  
  270.     ListBox *args = new ListBox(a, new ListBox);
  271.     a->unlink();
  272.     a = (Box *)d->eval(args);
  273.     args->unlink();
  274. }
  275.     
  276.  
  277. // Destructor
  278. VSLLib::~VSLLib()
  279. {
  280.     for (int i = 0; i < hashSize; i++)
  281.     if (defs[i]) delete defs[i];
  282. }
  283.  
  284.  
  285. // Binder
  286. // Add definitions of builtin functions;
  287. // assign default value to still undefined functions
  288. int VSLLib::bind()
  289. {
  290.     int changes = 0;
  291.     for (VSLDef *cdef = _first; cdef != 0; cdef = cdef->libnext())
  292.     if (cdef->expr() == 0)
  293.     {
  294.         BACKGROUND();
  295.  
  296.         // Deklaration without definition? Find suitable builtin function
  297.         int idx = VSLBuiltin::resolve(cdef->deflist->func_name());
  298.  
  299.         if (idx < 0)
  300.         {
  301.         eval_error("function declared, but not defined", cdef);
  302.         
  303.         // Replace missing def by "__undef()" call
  304.         cdef->expr() = call("__undef");
  305.         if (cdef->expr() == 0)
  306.             cdef->expr() = new ConstNode(new StringBox("???"));
  307.         }
  308.         else
  309.         {
  310.         // All args passed to the declaration must be passed
  311.         // to the builtin function as well
  312.         cdef->expr() = new BuiltinCallNode(idx, 
  313.             cdef->node_pattern()->dup());
  314.         }
  315.  
  316.         changes++;
  317.     }
  318.  
  319.     return changes;
  320. }
  321.  
  322.  
  323. // Bind names to variables
  324. int VSLLib::resolveNames()
  325. {
  326.     int changes = 0;
  327.     for (VSLDef *cdef = _first; cdef != 0; cdef = cdef->libnext())
  328.     {
  329.     BACKGROUND();
  330.  
  331.     changes += cdef->resolveNames();
  332.     ASSERT_OK();
  333.     }
  334.  
  335.     return changes;
  336. }
  337.  
  338.  
  339. // (Re)create all function patterns
  340. int VSLLib::compilePatterns()
  341. {
  342.     int changes = 0;
  343.  
  344.     // First, delete all patterns
  345.     VSLDef *cdef;
  346.     for (cdef = _first; cdef != 0; cdef = cdef->libnext())
  347.     {
  348.     BACKGROUND();
  349.  
  350.     // Function pattern
  351.     cdef->uncompilePattern();
  352.     ASSERT_OK();
  353.  
  354.     // LET and WHERE patterns
  355.     cdef->expr()->uncompilePatterns(cdef);
  356.     ASSERT_OK();
  357.     }
  358.  
  359.     // Now recreate all patterns
  360.     for (cdef = _first; cdef != 0; cdef = cdef->libnext())
  361.     {
  362.     BACKGROUND();
  363.  
  364.     // Function pattern
  365.     cdef->compilePattern();
  366.     ASSERT_OK();
  367.  
  368.     // LET and WHERE patterns
  369.     cdef->expr()->compilePatterns(cdef);
  370.     ASSERT_OK();
  371.  
  372.     changes++;
  373.     }
  374.  
  375.     return changes;
  376. }
  377.  
  378.  
  379. // Make function calls unambiguous
  380. int VSLLib::resolveDefs()
  381. {
  382.     int changes = 0;
  383.     for (VSLDef *cdef = _first; cdef != 0; cdef = cdef->libnext())
  384.     {
  385.     BACKGROUND();
  386.  
  387.     changes += cdef->expr()->resolveDefs(cdef);
  388.     ASSERT_OK();
  389.     }
  390.  
  391.     return changes;
  392. }
  393.  
  394. // Resolve synonyms
  395. int VSLLib::resolveSynonyms()
  396. {
  397.     int changes = 0;
  398.     for (VSLDef *cdef = _first; cdef != 0; cdef = cdef->libnext())
  399.     {
  400.     BACKGROUND();
  401.  
  402.     changes += cdef->expr()->resolveSynonyms(cdef, &cdef->expr());
  403.     ASSERT_OK();
  404.     }
  405.  
  406.     return changes;
  407. }
  408.  
  409. // Make big operands
  410. int VSLLib::foldOps()
  411. {
  412.     int changes = 0;
  413.     for (VSLDef *cdef = _first; cdef != 0; cdef = cdef->libnext())
  414.     {
  415.     BACKGROUND();
  416.  
  417.     changes += cdef->expr()->foldOps(cdef, &cdef->expr());
  418.     ASSERT_OK();
  419.     }
  420.  
  421.     return changes;
  422. }
  423.  
  424.  
  425. // Build constants
  426. int VSLLib::foldConsts()
  427. {
  428.     int changes = 0;
  429.     for (VSLDef *cdef = _first; cdef != 0; cdef = cdef->libnext())
  430.     if (VSEFlags::optimize_globals || !cdef->deflist->global())
  431.     {
  432.         BACKGROUND();
  433.  
  434.         changes += cdef->expr()->foldConsts(cdef, &cdef->expr());
  435.         ASSERT_OK();
  436.     }
  437.  
  438.     return changes;
  439. }
  440.  
  441.  
  442. // Perform function inlining
  443. int VSLLib::inlineFuncs()
  444. {
  445.     int changes = 0;
  446.     for (VSLDef *cdef = _first; cdef != 0; cdef = cdef->libnext())
  447.     {
  448.     BACKGROUND();
  449.  
  450.     changes += cdef->expr()->inlineFuncs(cdef, &cdef->expr());
  451.     ASSERT_OK();
  452.     }
  453.  
  454.     return changes;
  455. }
  456.  
  457. // Detect self references
  458. int VSLLib::countSelfReferences()
  459. {
  460.     int changes = 0;
  461.  
  462.     // Set all self_references to zero
  463.     VSLDef *cdef;
  464.     for (cdef = _first; cdef != 0; cdef = cdef->libnext())
  465.     {
  466.     VSLDefList *dflist = cdef->deflist;
  467.     dflist->self_references = 0;
  468.     }
  469.  
  470.     // Now go and count the self_references
  471.     for (cdef = _first; cdef != 0; cdef = cdef->libnext())
  472.     {
  473.     BACKGROUND();
  474.  
  475.     changes += cdef->expr()->countSelfReferences(cdef, cdef->deflist);
  476.     ASSERT_OK();
  477.     }
  478.  
  479.     return changes;
  480. }
  481.  
  482. // Delete unused local defs
  483. int VSLLib::cleanup()
  484. {
  485.     int changes = 0;
  486.  
  487.     VSLDef *d = _last;
  488.     while (d != 0)
  489.     {
  490.     BACKGROUND();
  491.  
  492.     VSLDefList *dflist = d->deflist;
  493.     if (!dflist->global() && 
  494.         (dflist->references == 0 || 
  495.          dflist->references == dflist->self_references))
  496.     {   
  497.         // Function is unused except its def: delete it
  498.  
  499.         // move D until it is beyond DFLIST
  500.         while (d != 0 && d->deflist == dflist)
  501.         d = d->libprev();
  502.  
  503.         if (VSEFlags::show_optimize)
  504.         {
  505.         for (VSLDef *e = dflist->first(); e != 0; e = e->listnext())
  506.             cout << "\n" << e->longname() << ": removed";
  507.         cout.flush();
  508.         }
  509.  
  510.         // Find pointer from predecessor and have it point to the successor
  511.         if (defs[dflist->hashcode] == dflist)
  512.         defs[dflist->hashcode] = dflist->next();
  513.         else
  514.         {
  515.         VSLDefList *prev;
  516.         for (prev = defs[dflist->hashcode];
  517.             prev != 0 && prev->next() != dflist; prev = prev->next())
  518.             ;
  519.         assert (prev->next() == dflist);
  520.         prev->next() = dflist->next();
  521.         }
  522.  
  523.         // Delete VSLDefs
  524.         dflist->replace();
  525.  
  526.         // Delete VSLDeflist
  527.         dflist->next() = 0; delete dflist;
  528.         changes++;
  529.     }
  530.     else
  531.     {
  532.         // Check next definition
  533.         d = d->libprev();
  534.     }
  535.  
  536.     ASSERT_OK();
  537.     }
  538.  
  539.     return changes;
  540. }
  541.  
  542.  
  543. // Optimization
  544.  
  545. // Processor
  546. void VSLLib::process(unsigned mode)
  547. {
  548.     /* 
  549.     The sequence of optimizations is:
  550.  
  551.     1. resolveDefs
  552.     2. resolveSynonyms
  553.     3. foldOps     <--------+
  554.     4. foldConsts           | (*)
  555.     5. inlineFuncs ---------+
  556.     6. countSelfReferences
  557.  
  558.     ((*): until no more changes occur)
  559.  
  560.     Between two optimization steps, unused functions are deleted
  561.     (cleanup).  This speeds up optimization.
  562.  
  563.     In general, the sequence of optimization steps is arbitrary.
  564.     In practice, we have the following constraints:
  565.  
  566.     * resolveDefs is precondition for inlineFuncs and resolveSynonyms.
  567.  
  568.     * resolveSynonyms does a subset of inlineFuncs, but much
  569.       faster and less resource-intensive.  Thus, it should be
  570.       called before inlineFuncs.
  571.  
  572.     * foldOps und foldConsts work best on large, complex
  573.       expressions, as resulting from inlineFuncs.
  574.  
  575.     * foldConsts is quite time-consuming and should profit
  576.       from all earlier optimizations.
  577.  
  578.     These constraints determine the sequence as shown above.
  579.  
  580.     If only single optimizations are chosen: resolveSynonyms and
  581.     foldOps require the least time, but also have the least
  582.     effects; the library shrinks slightly and evaluation speeds up
  583.     slightly.
  584.  
  585.     foldConsts requires much time; the library may become much
  586.     smaller (constants are shared); evaluation time shrinks a lot.
  587.  
  588.     inlineFuncs also requires much time; the library
  589.     becomes much larger and evaluation speeds up slightly.
  590.     */
  591.  
  592.     bind();
  593.     resolveNames();
  594.     compilePatterns();
  595.  
  596.     if (mode & _Cleanup)
  597.     cleanup();
  598.  
  599.     if (mode & _ResolveDefs)
  600.     if (resolveDefs() > 0)
  601.         if (mode & _Cleanup)
  602.         cleanup();
  603.  
  604.     if (mode & _ResolveSynonyms)
  605.     if (resolveSynonyms() > 0)
  606.         if (mode & _Cleanup)
  607.         cleanup();
  608.     
  609.     for (unsigned loop = 0; loop < (mode & loopMask); loop++)
  610.     {
  611.     int sum = 0;
  612.     int changes;
  613.  
  614.     if (mode & _FoldOps)
  615.         if ((changes = foldOps()) > 0)
  616.         {
  617.         sum += changes;
  618.         compilePatterns();
  619.         }
  620.  
  621.     if (mode & _FoldConsts)
  622.         if ((changes = foldConsts()) > 0)
  623.         {
  624.         sum += changes;
  625.         if (mode & _Cleanup)
  626.             cleanup();
  627.         }
  628.  
  629.     if (mode & _InlineFuncs)
  630.         if ((changes = inlineFuncs()) > 0)
  631.         {
  632.         sum += changes;
  633.         if (mode & _Cleanup)
  634.             cleanup();
  635.         }
  636.  
  637.     if (sum == 0)
  638.         break;      // No more changes
  639.     }
  640.  
  641.     if (mode & _CountSelfReferences)
  642.     if (countSelfReferences() > 0)
  643.         if (mode & _Cleanup)
  644.         cleanup();
  645. }
  646.  
  647.  
  648.  
  649.  
  650. // Debugging
  651.  
  652. // Dump
  653. ostream& operator << (ostream& s, const VSLLib& lib)
  654. {
  655.     s << "// " << lib._lib_name << "\n\n";
  656.  
  657.     VSLDef *d = lib._first;
  658.     if (VSEFlags::dump_last)
  659.     d = lib._last;
  660.  
  661.     for (; d != 0; d = d->libnext())
  662.     {
  663.     // Dump comment
  664.     s << "// " << d->longname() << " (hashcode: "
  665.         << d->deflist->hashcode << ") ";
  666.         
  667.     if (d->deflist->references == 0)
  668.         s << "(unused) ";
  669.     else
  670.         s << "(used " << d->deflist->references << " times) ";
  671.  
  672.     if (d->straight())
  673.         s << "(straight)\n";
  674.     else
  675.         s << "(not straight)\n";
  676.  
  677.     // Function name (with args)
  678.     s << d->f_name();
  679.  
  680.     if (d->expr() != 0)
  681.     {
  682.         if (d->deflist->global())
  683.         s << " -> ";
  684.         else
  685.         s << " = ";
  686.         s.flush();
  687.  
  688.         // Definition
  689.         s << *(d->expr());
  690.     }
  691.  
  692.     s << ";\n\n"; 
  693.     s.flush();
  694.     }
  695.  
  696.     return s;
  697. }
  698.  
  699.  
  700. // ...as tree
  701. void VSLLib::dumpTree(ostream& s) const
  702. {
  703.     bool old = StringBox::quoted;
  704.     StringBox::quoted = true;
  705.  
  706.     s << "#!vsl\n\n// " << _lib_name << "\n\n";
  707.     s << "#include <vsl.vsl>\n\n";
  708.  
  709.     s << "main(_...) -> VSLLib(\"" << _lib_name << "\",\n\n";
  710.  
  711.     VSLDef *d = _first;
  712.     if (VSEFlags::dump_last)
  713.     d = _last;
  714.  
  715.     for (; d != 0; d = d->libnext())
  716.     {
  717.     // Comment
  718.     s << "// " << d->longname() << " (hashcode: "
  719.         << d->deflist->hashcode << ") ";
  720.         
  721.     if (d->deflist->references == 0)
  722.         s << "(unused) ";
  723.     else
  724.         s << "(used " << d->deflist->references << " times) ";
  725.  
  726.     if (d->straight())
  727.         s << "(straight)\n";
  728.     else
  729.         s << "(not straight)\n";
  730.  
  731.  
  732.     // Header
  733.     s << "VSLDef(";
  734.     
  735.     // 1st parameter: name and location (as text)
  736.     s << "\"" << d->longname() << "\"";
  737.     s << ", ";
  738.  
  739.     // 2nd parameter: pattern (as text)
  740.     if (d->node_pattern() != 0)
  741.         s << "\"" << *d->node_pattern() << "\"";
  742.     else
  743.         s << "NoPatternText()";
  744.     s << ", ";
  745.  
  746.     // 3rd parameter: definition (as text)
  747.     if (d->expr() != 0)
  748.         s << "\"" << *d->expr() << "\"";
  749.     else
  750.         s << "NoDefText()";
  751.     s << ", ";
  752.  
  753.     // 4th parameter: pattern (as VSL expr)
  754.     if (d->node_pattern() != 0)
  755.         d->node_pattern()->dumpTree(s);
  756.     else
  757.         s << "NoPatternTree()";
  758.     s << ", ";
  759.  
  760.     // 5th parameter: definition (as VSL expr)
  761.     if (d->expr() != 0)
  762.         d->expr()->dumpTree(s);
  763.     else
  764.         s << "NoDefTree()";
  765.     s << ")";
  766.  
  767.     if (d->libnext() != 0)
  768.         s << ",\n\n";
  769.     }
  770.  
  771.     s << "\n);\n";
  772.  
  773.     StringBox::quoted = old;
  774. }
  775.  
  776.  
  777. // Representation invariant
  778. bool VSLLib::OK() const
  779. {
  780.     // Loop #1: over hash table
  781.     for (int i = 0; i < hashSize; i++)
  782.     if (defs[i] != 0)
  783.     {
  784.         // Check pointer to lib
  785.         assert (defs[i]->lib == this);
  786.  
  787.         // Check Deflist
  788.         assert (defs[i]->OK());
  789.     }
  790.  
  791.     // Loop #2: over internal list
  792.     for (VSLDef *d = _first; d != 0; d = d->libnext())
  793.     assert (d->OK());
  794.  
  795.     return true;
  796. }
  797.