home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / online / source / c / compilers / Bison.sit.hqx / Bison / Source / conflicts.c < prev    next >
Text File  |  1992-08-21  |  16KB  |  788 lines

  1. /***********************************************************
  2.  *
  3.  * Macintosh/MPW version of GNU Bison 1.18
  4.  * Please read the README_MPW file for more information
  5.  *
  6.  ***********************************************************/
  7.  
  8. /* Find and resolve or report look-ahead conflicts for bison,
  9.    Copyright (C) 1984, 1989 Free Software Foundation, Inc.
  10.  
  11. This file is part of Bison, the GNU Compiler Compiler.
  12.  
  13. Bison is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Public License as published by
  15. the Free Software Foundation; either version 2, or (at your option)
  16. any later version.
  17.  
  18. Bison is distributed in the hope that it will be useful,
  19. but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. GNU General Public License for more details.
  22.  
  23. You should have received a copy of the GNU General Public License
  24. along with Bison; see the file COPYING.  If not, write to
  25. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  26.  
  27. #ifdef _AIX
  28.  #pragma alloca
  29. #endif
  30. #include <stdio.h>
  31. #include "system.h"
  32. #include "machine.h"
  33. #include "new.h"
  34. #include "files.h"
  35. #include "gram.h"
  36. #include "state.h"
  37.  
  38. #ifdef macintosh
  39. #pragma segment bison
  40. #endif
  41.  
  42.  
  43. #if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
  44. #define bcopy(s, d, n) memcpy ((d), (s), (n))
  45. #else
  46. #ifdef USG
  47. #include <memory.h>
  48. #define bcopy(src, dst, num) memcpy((dst), (src), (num))
  49. #endif
  50. #endif
  51.  
  52. #ifdef __GNUC__
  53. #define alloca __builtin_alloca
  54. #else
  55. #ifdef sparc
  56. #include <alloca.h>
  57. #else
  58. #ifdef macintosh
  59. #define alloca malloc
  60. #ifndef _AIX
  61. extern char *alloca ();
  62. #endif
  63. #endif
  64. #endif
  65. #endif
  66.  
  67. extern char **tags;
  68. extern int tokensetsize;
  69. extern char *consistent;
  70. extern short *accessing_symbol;
  71. extern shifts **shift_table;
  72. extern unsigned *LA;
  73. extern short *LAruleno;
  74. extern short *lookaheads;
  75. extern int verboseflag;
  76.  
  77. void set_conflicts();
  78. void resolve_sr_conflict();
  79. void flush_shift();
  80. void log_resolution();
  81. void total_conflicts();
  82. void count_sr_conflicts();
  83. void count_rr_conflicts();
  84.  
  85. char any_conflicts;
  86. char *conflicts;
  87. errs **err_table;
  88. int expected_conflicts;
  89.  
  90.  
  91. static unsigned *shiftset;
  92. static unsigned *lookaheadset;
  93. static int src_total;
  94. static int rrc_total;
  95. static int src_count;
  96. static int rrc_count;
  97.  
  98.  
  99. void
  100. initialize_conflicts()
  101. {
  102.   register int i;
  103. /*  register errs *sp; JF unused */
  104.  
  105.   conflicts = NEW2(nstates, char);
  106.   shiftset = NEW2(tokensetsize, unsigned);
  107.   lookaheadset = NEW2(tokensetsize, unsigned);
  108.  
  109.   err_table = NEW2(nstates, errs *);
  110.  
  111.   any_conflicts = 0;
  112.  
  113.   for (i = 0; i < nstates; i++)
  114.     set_conflicts(i);
  115. }
  116.  
  117.  
  118. void
  119. set_conflicts(state)
  120. int state;
  121. {
  122.   register int i;
  123.   register int k;
  124.   register shifts *shiftp;
  125.   register unsigned *fp2;
  126.   register unsigned *fp3;
  127.   register unsigned *fp4;
  128.   register unsigned *fp1;
  129.   register int symbol;
  130.  
  131.   if (consistent[state]) return;
  132.  
  133.   for (i = 0; i < tokensetsize; i++)
  134.     lookaheadset[i] = 0;
  135.  
  136.   shiftp = shift_table[state];
  137.   if (shiftp)
  138.     {
  139.       k = shiftp->nshifts;
  140.       for (i = 0; i < k; i++)
  141.     {
  142.       symbol = accessing_symbol[shiftp->shifts[i]];
  143.       if (ISVAR(symbol)) break;
  144.       SETBIT(lookaheadset, symbol);
  145.     }
  146.     }
  147.  
  148.   k = lookaheads[state + 1];
  149.   fp4 = lookaheadset + tokensetsize;
  150.  
  151.   /* loop over all rules which require lookahead in this state */
  152.   /* first check for shift-reduce conflict, and try to resolve using precedence  */
  153.  
  154.   for (i = lookaheads[state]; i < k; i++)
  155.     if (rprec[LAruleno[i]])
  156.       {
  157.     fp1 = LA + i * tokensetsize;
  158.     fp2 = fp1;
  159.     fp3 = lookaheadset;
  160.   
  161.     while (fp3 < fp4)
  162.       {
  163.         if (*fp2++ & *fp3++)
  164.           {
  165.         resolve_sr_conflict(state, i);
  166.         break;
  167.           }
  168.       }
  169.       }
  170.  
  171.   /* loop over all rules which require lookahead in this state */
  172.   /* Check for conflicts not resolved above.  */
  173.  
  174.   for (i = lookaheads[state]; i < k; i++)
  175.     {
  176.       fp1 = LA + i * tokensetsize;
  177.       fp2 = fp1;
  178.       fp3 = lookaheadset;
  179.  
  180.       while (fp3 < fp4)
  181.     {
  182.       if (*fp2++ & *fp3++)
  183.         {
  184.           conflicts[state] = 1;
  185.           any_conflicts = 1;
  186.         }
  187.     }
  188.  
  189.       fp2 = fp1;
  190.       fp3 = lookaheadset;
  191.  
  192.       while (fp3 < fp4)
  193.     *fp3++ |= *fp2++;
  194.     }
  195. }
  196.  
  197.  
  198.  
  199. /* Attempt to resolve shift-reduce conflict for one rule
  200. by means of precedence declarations.
  201. It has already been checked that the rule has a precedence.
  202. A conflict is resolved by modifying the shift or reduce tables
  203. so that there is no longer a conflict.  */
  204.  
  205. void
  206. resolve_sr_conflict(state, lookaheadnum)
  207. int state;
  208. int lookaheadnum;
  209. {
  210.   register int i;
  211.   register int mask;
  212.   register unsigned *fp1;
  213.   register unsigned *fp2;
  214.   register int redprec;
  215.   errs *errp = (errs *) alloca (sizeof(errs) + ntokens * sizeof(short));
  216.   short *errtokens = errp->errs;
  217.  
  218.   /* find the rule to reduce by to get precedence of reduction  */
  219.   redprec = rprec[LAruleno[lookaheadnum]];
  220.  
  221.   mask = 1;
  222.   fp1 = LA + lookaheadnum * tokensetsize;
  223.   fp2 = lookaheadset;
  224.   for (i = 0; i < ntokens; i++)
  225.     {
  226.       if ((mask & *fp2 & *fp1) && sprec[i])
  227.     /* Shift-reduce conflict occurs for token number i
  228.        and it has a precedence.
  229.        The precedence of shifting is that of token i.  */
  230.     {
  231.       if (sprec[i] < redprec)
  232.         {
  233.           if (verboseflag) log_resolution(state, lookaheadnum, i, "reduce");
  234.           *fp2 &= ~mask;  /* flush the shift for this token */
  235.           flush_shift(state, i);
  236.         }
  237.       else if (sprec[i] > redprec)
  238.         {
  239.           if (verboseflag) log_resolution(state, lookaheadnum, i, "shift");
  240.           *fp1 &= ~mask;  /* flush the reduce for this token */
  241.         }
  242.       else
  243.         {
  244.           /* Matching precedence levels.
  245.          For left association, keep only the reduction.
  246.          For right association, keep only the shift.
  247.          For nonassociation, keep neither.  */
  248.  
  249.           switch (sassoc[i])
  250.         {
  251.  
  252.         case RIGHT_ASSOC:
  253.               if (verboseflag) log_resolution(state, lookaheadnum, i, "shift");
  254.           break;
  255.  
  256.         case LEFT_ASSOC:
  257.               if (verboseflag) log_resolution(state, lookaheadnum, i, "reduce");
  258.           break;
  259.  
  260.         case NON_ASSOC:
  261.               if (verboseflag) log_resolution(state, lookaheadnum, i, "an error");
  262.           break;
  263.         }
  264.  
  265.           if (sassoc[i] != RIGHT_ASSOC)
  266.         {
  267.           *fp2 &= ~mask;  /* flush the shift for this token */
  268.           flush_shift(state, i);
  269.         }
  270.           if (sassoc[i] != LEFT_ASSOC)
  271.             {
  272.           *fp1 &= ~mask;  /* flush the reduce for this token */
  273.         }
  274.           if (sassoc[i] == NON_ASSOC)
  275.         {
  276.           /* Record an explicit error for this token.  */
  277.           *errtokens++ = i;
  278.         }
  279.         }
  280.     }
  281.  
  282.       mask <<= 1;
  283.       if (mask == 0)
  284.     {
  285.       mask = 1;
  286.       fp2++;  fp1++;
  287.     }
  288.     }
  289.   errp->nerrs = errtokens - errp->errs;
  290.   if (errp->nerrs)
  291.     {
  292.       /* Some tokens have been explicitly made errors.  Allocate
  293.      a permanent errs structure for this state, to record them.  */
  294.       i = (char *) errtokens - (char *) errp;
  295.       err_table[state] = (errs *) mallocate ((unsigned int)i);
  296.       bcopy (errp, err_table[state], i);
  297.     }
  298.   else
  299.     err_table[state] = 0;
  300. }
  301.  
  302.  
  303.  
  304. /* turn off the shift recorded for the specified token in the specified state.
  305. Used when we resolve a shift-reduce conflict in favor of the reduction.  */
  306.  
  307. void
  308. flush_shift(state, token)
  309. int state;
  310. int token;
  311. {
  312.   register shifts *shiftp;
  313.   register int k, i;
  314. /*  register unsigned symbol; JF unused */
  315.  
  316.   shiftp = shift_table[state];
  317.  
  318.   if (shiftp)
  319.     {
  320.       k = shiftp->nshifts;
  321.       for (i = 0; i < k; i++)
  322.     {
  323.       if (shiftp->shifts[i] && token == accessing_symbol[shiftp->shifts[i]])
  324.         (shiftp->shifts[i]) = 0;
  325.     }
  326.     }
  327. }
  328.  
  329.  
  330. void
  331. log_resolution(state, LAno, token, resolution)
  332. int state, LAno, token;
  333. char *resolution;
  334. {
  335.   fprintf(foutput,
  336.       "Conflict in state %d between rule %d and token %s resolved as %s.\n",
  337.       state, LAruleno[LAno], tags[token], resolution);
  338. }
  339.  
  340.  
  341. void
  342. conflict_log()
  343. {
  344.   register int i;
  345.  
  346.   src_total = 0;
  347.   rrc_total = 0;
  348.  
  349.   for (i = 0; i < nstates; i++)
  350.     {
  351.       if (conflicts[i])
  352.     {
  353.       count_sr_conflicts(i);
  354.       count_rr_conflicts(i);
  355.       src_total += src_count;
  356.       rrc_total += rrc_count;
  357.     }
  358.     }
  359.  
  360.   total_conflicts();
  361. }
  362.   
  363.  
  364. void
  365. verbose_conflict_log()
  366. {
  367.   register int i;
  368.  
  369.   src_total = 0;
  370.   rrc_total = 0;
  371.  
  372.   for (i = 0; i < nstates; i++)
  373.     {
  374.       if (conflicts[i])
  375.     {
  376.       count_sr_conflicts(i);
  377.       count_rr_conflicts(i);
  378.       src_total += src_count;
  379.       rrc_total += rrc_count;
  380.  
  381.       fprintf(foutput, "State %d contains", i);
  382.  
  383.       if (src_count == 1)
  384.         fprintf(foutput, " 1 shift/reduce conflict");
  385.       else if (src_count > 1)
  386.         fprintf(foutput, " %d shift/reduce conflicts", src_count);
  387.  
  388.       if (src_count > 0 && rrc_count > 0)
  389.         fprintf(foutput, " and");
  390.  
  391.       if (rrc_count == 1)
  392.         fprintf(foutput, " 1 reduce/reduce conflict");
  393.       else if (rrc_count > 1)
  394.         fprintf(foutput, " %d reduce/reduce conflicts", rrc_count);
  395.  
  396.       putc('.', foutput);
  397.       putc('\n', foutput);
  398.     }
  399.     }
  400.  
  401.   total_conflicts();
  402. }
  403.  
  404.  
  405. void
  406. total_conflicts()
  407. {
  408.   extern int fixed_outfiles;
  409.  
  410.   if (src_total == expected_conflicts && rrc_total == 0)
  411.     return;
  412.  
  413.   if (fixed_outfiles)
  414.     {
  415.       /* If invoked under the name `yacc', use the output format
  416.      specified by POSIX.  */
  417.       fprintf(stderr, "conflicts: ");
  418.       if (src_total > 0)
  419.     fprintf(stderr, " %d shift/reduce", src_total);
  420.       if (src_total > 0 && rrc_total > 0)
  421.     fprintf(stderr, ",");
  422.       if (rrc_total > 0)
  423.     fprintf(stderr, " %d reduce/reduce", rrc_total);
  424.       putc('\n', stderr);
  425.     }
  426.   else
  427.     {
  428.       fprintf(stderr, "%s contains", infile);
  429.  
  430.       if (src_total == 1)
  431.     fprintf(stderr, " 1 shift/reduce conflict");
  432.       else if (src_total > 1)
  433.     fprintf(stderr, " %d shift/reduce conflicts", src_total);
  434.  
  435.       if (src_total > 0 && rrc_total > 0)
  436.     fprintf(stderr, " and");
  437.  
  438.       if (rrc_total == 1)
  439.     fprintf(stderr, " 1 reduce/reduce conflict");
  440.       else if (rrc_total > 1)
  441.     fprintf(stderr, " %d reduce/reduce conflicts", rrc_total);
  442.  
  443.       putc('.', stderr);
  444.       putc('\n', stderr);
  445.     }
  446. }
  447.  
  448.  
  449. void
  450. count_sr_conflicts(state)
  451. int state;
  452. {
  453.   register int i;
  454.   register int k;
  455.   register int mask;
  456.   register shifts *shiftp;
  457.   register unsigned *fp1;
  458.   register unsigned *fp2;
  459.   register unsigned *fp3;
  460.   register int symbol;
  461.  
  462.   src_count = 0;
  463.  
  464.   shiftp = shift_table[state];
  465.   if (!shiftp) return;
  466.  
  467.   for (i = 0; i < tokensetsize; i++)
  468.     {
  469.       shiftset[i] = 0;
  470.       lookaheadset[i] = 0;
  471.     }
  472.  
  473.   k = shiftp->nshifts;
  474.   for (i = 0; i < k; i++)
  475.     {
  476.       if (! shiftp->shifts[i]) continue;
  477.       symbol = accessing_symbol[shiftp->shifts[i]];
  478.       if (ISVAR(symbol)) break;
  479.       SETBIT(shiftset, symbol);
  480.     }
  481.  
  482.   k = lookaheads[state + 1];
  483.   fp3 = lookaheadset + tokensetsize;
  484.  
  485.   for (i = lookaheads[state]; i < k; i++)
  486.     {
  487.       fp1 = LA + i * tokensetsize;
  488.       fp2 = lookaheadset;
  489.  
  490.       while (fp2 < fp3)
  491.     *fp2++ |= *fp1++;
  492.     }
  493.  
  494.   fp1 = shiftset;
  495.   fp2 = lookaheadset;
  496.  
  497.   while (fp2 < fp3)
  498.     *fp2++ &= *fp1++;
  499.  
  500.   mask = 1;
  501.   fp2 = lookaheadset;
  502.   for (i = 0; i < ntokens; i++)
  503.     {
  504.       if (mask & *fp2)
  505.     src_count++;
  506.  
  507.       mask <<= 1;
  508.       if (mask == 0)
  509.     {
  510.       mask = 1;
  511.       fp2++;
  512.     }
  513.     }
  514. }
  515.  
  516.  
  517. void
  518. count_rr_conflicts(state)
  519. int state;
  520. {
  521.   register int i;
  522.   register int j;
  523.   register int count;
  524.   register unsigned mask;
  525.   register unsigned *baseword;
  526.   register unsigned *wordp;
  527.   register int m;
  528.   register int n;
  529.  
  530.   rrc_count = 0;
  531.  
  532.   m = lookaheads[state];
  533.   n = lookaheads[state + 1];
  534.  
  535.   if (n - m < 2) return;
  536.  
  537.   mask = 1;
  538.   baseword = LA + m * tokensetsize;
  539.   for (i = 0; i < ntokens; i++)
  540.     {
  541.       wordp = baseword;
  542.  
  543.       count = 0;
  544.       for (j = m; j < n; j++)
  545.     {
  546.       if (mask & *wordp)
  547.         count++;
  548.  
  549.       wordp += tokensetsize;
  550.     }
  551.  
  552.       if (count >= 2) rrc_count++;
  553.  
  554.       mask <<= 1;
  555.       if (mask == 0)
  556.     {
  557.       mask = 1;
  558.       baseword++;
  559.     }
  560.     }
  561. }
  562.  
  563.  
  564. void
  565. print_reductions(state)
  566. int state;
  567. {
  568.   register int i;
  569.   register int j;
  570.   register int k;
  571.   register unsigned *fp1;
  572.   register unsigned *fp2;
  573.   register unsigned *fp3;
  574.   register unsigned *fp4;
  575.   register int rule;
  576.   register int symbol;
  577.   register unsigned mask;
  578.   register int m;
  579.   register int n;
  580.   register int default_LA;
  581.   register int default_rule;
  582.   register int cmax;
  583.   register int count;
  584.   register shifts *shiftp;
  585.   register errs *errp;
  586.   int nodefault = 0;
  587.  
  588.   for (i = 0; i < tokensetsize; i++)
  589.     shiftset[i] = 0;
  590.  
  591.   shiftp = shift_table[state];
  592.   if (shiftp)
  593.     {
  594.       k = shiftp->nshifts;
  595.       for (i = 0; i < k; i++)
  596.     {
  597.       if (! shiftp->shifts[i]) continue;
  598.       symbol = accessing_symbol[shiftp->shifts[i]];
  599.       if (ISVAR(symbol)) break;
  600.       /* if this state has a shift for the error token,
  601.          don't use a default rule.  */
  602.       if (symbol == error_token_number) nodefault = 1;
  603.       SETBIT(shiftset, symbol);
  604.     }
  605.     }
  606.  
  607.   errp = err_table[state];
  608.   if (errp)
  609.     {
  610.       k = errp->nerrs;
  611.       for (i = 0; i < k; i++)
  612.     {
  613.       if (! errp->errs[i]) continue;
  614.       symbol = errp->errs[i];
  615.       SETBIT(shiftset, symbol);
  616.     }
  617.     }
  618.  
  619.   m = lookaheads[state];
  620.   n = lookaheads[state + 1];
  621.  
  622.   if (n - m == 1 && ! nodefault)
  623.     {
  624.       default_rule = LAruleno[m];
  625.  
  626.       fp1 = LA + m * tokensetsize;
  627.       fp2 = shiftset;
  628.       fp3 = lookaheadset;
  629.       fp4 = lookaheadset + tokensetsize;
  630.  
  631.       while (fp3 < fp4)
  632.     *fp3++ = *fp1++ & *fp2++;
  633.  
  634.       mask = 1;
  635.       fp3 = lookaheadset;
  636.  
  637.       for (i = 0; i < ntokens; i++)
  638.     {
  639.       if (mask & *fp3)
  640.         fprintf(foutput, "    %-4s\t[reduce using rule %d (%s)]\n",
  641.             tags[i], default_rule, tags[rlhs[default_rule]]);
  642.  
  643.       mask <<= 1;
  644.       if (mask == 0)
  645.         {
  646.           mask = 1;
  647.           fp3++;
  648.         }
  649.     }
  650.  
  651.       fprintf(foutput, "    $default\treduce using rule %d (%s)\n\n",
  652.           default_rule, tags[rlhs[default_rule]]);
  653.     }
  654.   else if (n - m >= 1)
  655.     {
  656.       cmax = 0;
  657.       default_LA = -1;
  658.       fp4 = lookaheadset + tokensetsize;
  659.  
  660.       if (! nodefault)
  661.     for (i = m; i < n; i++)
  662.       {
  663.         fp1 = LA + i * tokensetsize;
  664.         fp2 = shiftset;
  665.         fp3 = lookaheadset;
  666.   
  667.         while (fp3 < fp4)
  668.           *fp3++ = *fp1++ & ( ~ (*fp2++));
  669.   
  670.         count = 0;
  671.         mask = 1;
  672.         fp3 = lookaheadset;
  673.         for (j = 0; j < ntokens; j++)
  674.           {
  675.         if (mask & *fp3)
  676.           count++;
  677.   
  678.         mask <<= 1;
  679.         if (mask == 0)
  680.           {
  681.             mask = 1;
  682.             fp3++;
  683.           }
  684.           }
  685.   
  686.         if (count > cmax)
  687.           {
  688.         cmax = count;
  689.         default_LA = i;
  690.         default_rule = LAruleno[i];
  691.           }
  692.   
  693.         fp2 = shiftset;
  694.         fp3 = lookaheadset;
  695.   
  696.         while (fp3 < fp4)
  697.           *fp2++ |= *fp3++;
  698.       }
  699.  
  700.       for (i = 0; i < tokensetsize; i++)
  701.         shiftset[i] = 0;
  702.  
  703.       if (shiftp)
  704.         {
  705.           k = shiftp->nshifts;
  706.           for (i = 0; i < k; i++)
  707.         {
  708.           if (! shiftp->shifts[i]) continue;
  709.           symbol = accessing_symbol[shiftp->shifts[i]];
  710.           if (ISVAR(symbol)) break;
  711.           SETBIT(shiftset, symbol);
  712.         }
  713.         }
  714.  
  715.       mask = 1;
  716.       fp1 = LA + m * tokensetsize;
  717.       fp2 = shiftset;
  718.       for (i = 0; i < ntokens; i++)
  719.     {
  720.       int defaulted = 0;
  721.  
  722.       if (mask & *fp2)
  723.         count = 1;
  724.       else
  725.         count = 0;
  726.  
  727.       fp3 = fp1;
  728.       for (j = m; j < n; j++)
  729.         {
  730.           if (mask & *fp3)
  731.         {
  732.           if (count == 0)
  733.             {
  734.               if (j != default_LA)
  735.             {
  736.               rule = LAruleno[j];
  737.               fprintf(foutput, "    %-4s\treduce using rule %d (%s)\n",
  738.                   tags[i], rule, tags[rlhs[rule]]);
  739.             }
  740.               else defaulted = 1;
  741.  
  742.               count++;
  743.             }
  744.           else
  745.             {
  746.               if (defaulted)
  747.             {
  748.               rule = LAruleno[default_LA];
  749.               fprintf(foutput, "    %-4s\treduce using rule %d (%s)\n",
  750.                   tags[i], rule, tags[rlhs[rule]]);
  751.               defaulted = 0;
  752.             }
  753.               rule = LAruleno[j];
  754.               fprintf(foutput, "    %-4s\t[reduce using rule %d (%s)]\n",
  755.                   tags[i], rule, tags[rlhs[rule]]);
  756.             }
  757.         }
  758.  
  759.           fp3 += tokensetsize;
  760.         }
  761.  
  762.       mask <<= 1;
  763.       if (mask == 0)
  764.         {
  765.           mask = 1;
  766.           fp1++;
  767.         }
  768.     }
  769.  
  770.       if (default_LA >= 0)
  771.     {
  772.       fprintf(foutput, "    $default\treduce using rule %d (%s)\n",
  773.           default_rule, tags[rlhs[default_rule]]);
  774.     }
  775.  
  776.       putc('\n', foutput);
  777.     }
  778. }
  779.  
  780.  
  781. void
  782. finalize_conflicts()
  783. {
  784.   FREE(conflicts);
  785.   FREE(shiftset);
  786.   FREE(lookaheadset);
  787. }
  788.