home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / n / nuweb / Source / src / scraps_c < prev    next >
Encoding:
Text File  |  1997-03-13  |  21.2 KB  |  749 lines

  1.  
  2. #line 648 "nuweb.w"
  3. #include "global.h"
  4.  
  5. #line 2497 "nuweb.w"
  6. #define SLAB_SIZE 500
  7.  
  8. typedef struct slab {
  9.   struct slab *next;
  10.   char chars[SLAB_SIZE];
  11. } Slab;
  12.  
  13. #line 2508 "nuweb.w"
  14. typedef struct {
  15.   char *file_name;
  16.   int file_line;
  17.   int page;
  18.   char letter;
  19.   Slab *slab;
  20. } ScrapEntry;
  21.  
  22. #line 2519 "nuweb.w"
  23. static ScrapEntry *SCRAP[256];
  24.  
  25. #define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
  26.  
  27. static int scraps;
  28.  
  29. #line 2540 "nuweb.w"
  30. void init_scraps(void)
  31. {
  32.   scraps = 1;
  33.   SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  34. }
  35.  
  36. #line 2550 "nuweb.w"
  37. void write_scrap_ref(FILE *file, int num, int first, int *page)
  38. {
  39.   if (scrap_array(num).page >= 0) {
  40.     if (first)
  41.       fprintf(file, "%d", scrap_array(num).page);
  42.     else if (scrap_array(num).page != *page)
  43.       fprintf(file, ", %d", scrap_array(num).page);
  44.     if (scrap_array(num).letter > 0)
  45.       putc(scrap_array(num).letter, file);
  46.   }
  47.   else {
  48.     if (first)
  49.       putc('?', file);
  50.     else
  51.       fputs(", ?", file);
  52.     
  53. #line 2583 "nuweb.w"
  54.     {
  55.       if (!already_warned) {
  56.         fprintf(stderr, "%s: you'll need to rerun nuweb after running LaTeX\n",
  57.                 command_name);
  58.         already_warned = TRUE;
  59.       }
  60.     }
  61.     
  62. #line 2565 "nuweb.w"
  63.  
  64.   }
  65.   *page = scrap_array(num).page;
  66. }
  67.  
  68. #line 2573 "nuweb.w"
  69. void write_single_scrap_ref(FILE *file, int num)
  70. {
  71.   int page;
  72.   write_scrap_ref(file, num, TRUE, &page);
  73. }
  74.  
  75. #line 2602 "nuweb.w"
  76. typedef struct {
  77.   Slab *scrap;
  78.   Slab *prev;
  79.   int index;
  80. } Manager;
  81.  
  82. #line 2613 "nuweb.w"
  83. static void push(char c, Manager *manager)
  84. {
  85.   Slab *scrap = manager->scrap;
  86.   int index = manager->index;
  87.   scrap->chars[index++] = c;
  88.   if (index == SLAB_SIZE) {
  89.     Slab *new = (Slab *) arena_getmem(sizeof(Slab));
  90.     scrap->next = new;
  91.     manager->scrap = new;
  92.     index = 0;
  93.   }
  94.   manager->index = index;
  95. }
  96.  
  97. #line 2630 "nuweb.w"
  98. static void pushs(char *s, Manager *manager)
  99. {
  100.   while (*s)
  101.     push(*s++, manager);
  102. }
  103.  
  104. #line 2640 "nuweb.w"
  105. int collect_scrap(void)
  106. {
  107.   Manager writer;
  108.   
  109. #line 2650 "nuweb.w"
  110.   {
  111.     Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
  112.     if ((scraps & 255) == 0)
  113.       SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  114.     scrap_array(scraps).slab = scrap;
  115.     scrap_array(scraps).file_name = save_string(source_name);
  116.     scrap_array(scraps).file_line = source_line;
  117.     scrap_array(scraps).page = -1;
  118.     scrap_array(scraps).letter = 0;
  119.     writer.scrap = scrap;
  120.     writer.index = 0;
  121.   }
  122.   
  123. #line 2643 "nuweb.w"
  124.  
  125.   
  126. #line 2667 "nuweb.w"
  127.   {
  128.     int c = source_get();
  129.     while (1) {
  130.       switch (c) {
  131.         case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
  132.                           command_name, scrap_array(scraps).file_name,
  133.                           scrap_array(scraps).file_line);
  134.                   exit(-1);
  135.         case '@': 
  136. #line 2688 "nuweb.w"
  137.                   {
  138.                     c = source_get();
  139.                     switch (c) {
  140.                       case '@': pushs("@@", &writer);
  141.                                 c = source_get();
  142.                                 break;
  143.                       case '|': 
  144. #line 2709 "nuweb.w"
  145.                                 {
  146.                                   do {
  147.                                     char new_name[256];
  148.                                     char *p = new_name;
  149.                                     do
  150.                                       c = source_get();
  151.                                     while (isspace(c));
  152.                                     if (c != '@') {
  153.                                       Name *name;
  154.                                       do {
  155.                                         *p++ = c;
  156.                                         c = source_get();
  157.                                       } while (c != '@' && !isspace(c));
  158.                                       *p = '\0';
  159.                                       name = name_add(&user_names, new_name);
  160.                                       if (!name->defs || name->defs->scrap != scraps) {
  161.                                         Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  162.                                         def->scrap = scraps;
  163.                                         def->next = name->defs;
  164.                                         name->defs = def;
  165.                                       }
  166.                                     }
  167.                                   } while (c != '@');
  168.                                   c = source_get();
  169.                                   if (c != '}') {
  170.                                     fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  171.                                             command_name, c, source_name, source_line);
  172.                                     exit(-1);
  173.                                   }
  174.                                 }
  175.                                 
  176. #line 2694 "nuweb.w"
  177.                   
  178.                       case '}': push('\0', &writer);
  179.                                 return scraps++;
  180.                       case '<': 
  181. #line 2744 "nuweb.w"
  182.                                 {
  183.                                   Name *name = collect_scrap_name();
  184.                                   
  185. #line 2755 "nuweb.w"
  186.                                   {
  187.                                     char *s = name->spelling;
  188.                                     int len = strlen(s) - 1;
  189.                                     pushs("@<", &writer);
  190.                                     while (len > 0) {
  191.                                       push(*s++, &writer);
  192.                                       len--;
  193.                                     }
  194.                                     if (*s == ' ')
  195.                                       pushs("...", &writer);
  196.                                     else
  197.                                       push(*s, &writer);
  198.                                     pushs("@>", &writer);
  199.                                   }
  200.                                   
  201. #line 2746 "nuweb.w"
  202.                                 
  203.                                   
  204. #line 2774 "nuweb.w"
  205.                                   {
  206.                                     if (!name->uses || name->uses->scrap != scraps) {
  207.                                       Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  208.                                       use->scrap = scraps;
  209.                                       use->next = name->uses;
  210.                                       name->uses = use;
  211.                                     }
  212.                                   }
  213.                                   
  214. #line 2747 "nuweb.w"
  215.                                 
  216.                                   c = source_get();
  217.                                 }
  218.                                 
  219. #line 2697 "nuweb.w"
  220.                   
  221.                                 break;
  222.                       default : fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  223.                                         command_name, c, source_name, source_line);
  224.                                 exit(-1);
  225.                     }
  226.                   }
  227.                   
  228. #line 2675 "nuweb.w"
  229.   
  230.                   break;
  231.         default:  push(c, &writer);
  232.                   c = source_get();
  233.                   break;
  234.       }
  235.     }
  236.   }
  237.   
  238. #line 2644 "nuweb.w"
  239.  
  240. }
  241.  
  242. #line 2787 "nuweb.w"
  243. static char pop(Manager *manager)
  244. {
  245.   Slab *scrap = manager->scrap;
  246.   int index = manager->index;
  247.   char c = scrap->chars[index++];
  248.   if (index == SLAB_SIZE) {
  249.     manager->prev = scrap;
  250.     manager->scrap = scrap->next;
  251.     index = 0;
  252.   }
  253.   manager->index = index;
  254.   return c;
  255. }
  256.  
  257. #line 2806 "nuweb.w"
  258. static Name *pop_scrap_name(Manager *manager)
  259. {
  260.   char name[256];
  261.   char *p = name;
  262.   int c = pop(manager);
  263.   while (TRUE) {
  264.     if (c == '@')
  265.       
  266. #line 2825 "nuweb.w"
  267.       {
  268.         c = pop(manager);
  269.         if (c == '@') {
  270.           *p++ = c;
  271.           c = pop(manager);
  272.         }
  273.         else if (c == '>') {
  274.           if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
  275.             p[-3] = ' ';
  276.             p -= 2;
  277.           }
  278.           *p = '\0';
  279.           return prefix_add(¯o_names, name);
  280.         }
  281.         else {
  282.           fprintf(stderr, "%s: found an internal problem\n", command_name);
  283.           exit(-1);
  284.         }
  285.       }
  286.       
  287. #line 2813 "nuweb.w"
  288.  
  289.     else {
  290.       *p++ = c;
  291.       c = pop(manager);
  292.     }
  293.   }
  294. }
  295.  
  296. #line 2849 "nuweb.w"
  297. int write_scraps(FILE *file, Scrap_Node *defs, int global_indent,
  298.      char *indent_chars, char debug_flag, char tab_flag, char indent_flag)
  299. {
  300.   int indent = 0;
  301.   while (defs) {
  302.     
  303. #line 2864 "nuweb.w"
  304.     {
  305.       char c;
  306.       Manager reader;
  307.       int line_number = scrap_array(defs->scrap).file_line;
  308.       
  309. #line 2895 "nuweb.w"
  310.       if (debug_flag) {
  311.         fprintf(file, "\n#line %d \"%s\"\n",
  312.                 line_number, scrap_array(defs->scrap).file_name);
  313.         
  314. #line 2905 "nuweb.w"
  315.         {
  316.           if (indent_flag) {
  317.             if (tab_flag)
  318.               for (indent=0; indent<global_indent; indent++)
  319.                 putc(' ', file);
  320.             else
  321.               for (indent=0; indent<global_indent; indent++)
  322.                 putc(indent_chars[indent], file);
  323.           }
  324.           indent = 0;
  325.         }
  326.         
  327. #line 2898 "nuweb.w"
  328.       
  329.       }
  330.       
  331. #line 2868 "nuweb.w"
  332.     
  333.       reader.scrap = scrap_array(defs->scrap).slab;
  334.       reader.index = 0;
  335.       c = pop(&reader);
  336.       while (c) {
  337.         switch (c) {
  338.           case '@':  
  339. #line 2936 "nuweb.w"
  340.                      {
  341.                        c = pop(&reader);
  342.                        switch (c) {
  343.                          case '@': putc(c, file);
  344.                                    indent_chars[global_indent + indent] = ' ';
  345.                                    indent++;
  346.                                    break;
  347.                          case '<': 
  348. #line 2955 "nuweb.w"
  349.                                    {
  350.                                      Name *name = pop_scrap_name(&reader);
  351.                                      if (name->mark) {
  352.                                        fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
  353.                                                command_name, name->spelling);
  354.                                        exit(-1);
  355.                                      }
  356.                                      if (name->defs) {
  357.                                        name->mark = TRUE;
  358.                                        indent = write_scraps(file, name->defs, global_indent + indent,
  359.                                                              indent_chars, debug_flag, tab_flag, indent_flag);
  360.                                        indent -= global_indent;
  361.                                        name->mark = FALSE;
  362.                                      }
  363.                                      else if (!tex_flag)
  364.                                        fprintf(stderr, "%s: macro never defined <%s>\n",
  365.                                                command_name, name->spelling);
  366.                                    }
  367.                                    
  368. #line 2943 "nuweb.w"
  369.                      
  370.                                    
  371. #line 2895 "nuweb.w"
  372.                                    if (debug_flag) {
  373.                                      fprintf(file, "\n#line %d \"%s\"\n",
  374.                                              line_number, scrap_array(defs->scrap).file_name);
  375.                                      
  376. #line 2905 "nuweb.w"
  377.                                      {
  378.                                        if (indent_flag) {
  379.                                          if (tab_flag)
  380.                                            for (indent=0; indent<global_indent; indent++)
  381.                                              putc(' ', file);
  382.                                          else
  383.                                            for (indent=0; indent<global_indent; indent++)
  384.                                              putc(indent_chars[indent], file);
  385.                                        }
  386.                                        indent = 0;
  387.                                      }
  388.                                      
  389. #line 2898 "nuweb.w"
  390.                                    
  391.                                    }
  392.                                    
  393. #line 2944 "nuweb.w"
  394.                      
  395.                                    break;
  396.                          default:  /* ignore, since we should already have a warning */
  397.                                    break;
  398.                        }
  399.                      }
  400.                      
  401. #line 2874 "nuweb.w"
  402.     
  403.                      break;
  404.           case '\n': putc(c, file);
  405.                      line_number++;
  406.                      
  407. #line 2905 "nuweb.w"
  408.                      {
  409.                        if (indent_flag) {
  410.                          if (tab_flag)
  411.                            for (indent=0; indent<global_indent; indent++)
  412.                              putc(' ', file);
  413.                          else
  414.                            for (indent=0; indent<global_indent; indent++)
  415.                              putc(indent_chars[indent], file);
  416.                        }
  417.                        indent = 0;
  418.                      }
  419.                      
  420. #line 2878 "nuweb.w"
  421.     
  422.                      break;
  423.           case '\t': 
  424. #line 2921 "nuweb.w"
  425.                      {
  426.                        if (tab_flag)
  427.                          
  428. #line 1382 "nuweb.w"
  429.                          {
  430.                            int delta = 8 - (indent % 8);
  431.                            indent += delta;
  432.                            while (delta > 0) {
  433.                              putc(' ', file);
  434.                              delta--;
  435.                            }
  436.                          }
  437.                          
  438. #line 2923 "nuweb.w"
  439.                      
  440.                        else {
  441.                          putc('\t', file);
  442.                          indent_chars[global_indent + indent] = '\t';
  443.                          indent++;
  444.                        }
  445.                      }
  446.                      
  447. #line 2880 "nuweb.w"
  448.     
  449.                      break;
  450.           default:   putc(c, file);
  451.                      indent_chars[global_indent + indent] = ' ';
  452.                      indent++;
  453.                      break;
  454.         }
  455.         c = pop(&reader);
  456.       }
  457.     }
  458.     
  459. #line 2854 "nuweb.w"
  460.  
  461.     defs = defs->next;
  462.   }
  463.   return indent + global_indent;
  464. }
  465.  
  466. #line 2984 "nuweb.w"
  467. void collect_numbers(char *aux_name)
  468. {
  469.   if (number_flag) {
  470.     int i;
  471.     for (i=1; i<scraps; i++)
  472.       scrap_array(i).page = i;
  473.   }
  474.   else {
  475.     FILE *aux_file = fopen(aux_name, "r");
  476.     already_warned = FALSE;
  477.     if (aux_file) {
  478.       char aux_line[500];
  479.       while (fgets(aux_line, 500, aux_file)) {
  480.         int scrap_number;
  481.         int page_number;
  482.         char dummy[50];
  483.         if (3 == sscanf(aux_line, "\\newlabel{scrap%d}{%[^}]}{%d}",
  484.                         &scrap_number, dummy, &page_number)) {
  485.           if (scrap_number < scraps)
  486.             scrap_array(scrap_number).page = page_number;
  487.           else
  488.             
  489. #line 2583 "nuweb.w"
  490.             {
  491.               if (!already_warned) {
  492.                 fprintf(stderr, "%s: you'll need to rerun nuweb after running LaTeX\n",
  493.                         command_name);
  494.                 already_warned = TRUE;
  495.               }
  496.             }
  497.             
  498. #line 3005 "nuweb.w"
  499.  
  500.         }
  501.       }
  502.       fclose(aux_file);
  503.       
  504. #line 3017 "nuweb.w"
  505.       {
  506.         int scrap;
  507.         for (scrap=2; scrap<scraps; scrap++) {
  508.           if (scrap_array(scrap-1).page == scrap_array(scrap).page) {
  509.             if (!scrap_array(scrap-1).letter)
  510.               scrap_array(scrap-1).letter = 'a';
  511.             scrap_array(scrap).letter = scrap_array(scrap-1).letter + 1;
  512.           }
  513.         }
  514.       }
  515.       
  516. #line 3009 "nuweb.w"
  517.  
  518.     }
  519.   }
  520. }
  521.  
  522. #line 3523 "nuweb.w"
  523. typedef struct name_node {
  524.   struct name_node *next;
  525.   Name *name;
  526. } Name_Node;
  527.  
  528. #line 3531 "nuweb.w"
  529. typedef struct goto_node {
  530.   Name_Node *output;            /* list of words ending in this state */
  531.   struct move_node *moves;      /* list of possible moves */
  532.   struct goto_node *fail;       /* and where to go when no move fits */
  533.   struct goto_node *next;       /* next goto node with same depth */
  534. } Goto_Node;
  535.  
  536. #line 3541 "nuweb.w"
  537. typedef struct move_node {
  538.   struct move_node *next;
  539.   Goto_Node *state;
  540.   char c;
  541. } Move_Node;
  542.  
  543. #line 3550 "nuweb.w"
  544. static Goto_Node *root[CHAR_MAX];
  545. static int max_depth;
  546. static Goto_Node **depths;
  547.  
  548. #line 3558 "nuweb.w"
  549. static Goto_Node *goto_lookup(char c, Goto_Node *g)
  550. {
  551.   Move_Node *m = g->moves;
  552.   while (m && m->c != c)
  553.     m = m->next;
  554.   if (m)
  555.     return m->state;
  556.   else
  557.     return NULL;
  558. }
  559.  
  560. #line 3579 "nuweb.w"
  561. static void build_gotos(Name *tree);
  562. static int reject_match(Name *name, char post, Manager *reader);
  563.  
  564. void search(void)
  565. {
  566.   int i;
  567.   for (i=0; i<CHAR_MAX; i++)
  568.     root[i] = NULL;
  569.   max_depth = 16;
  570.   depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
  571.   for (i=0; i<max_depth; i++)
  572.     depths[i] = NULL;
  573.   build_gotos(user_names);
  574.   
  575. #line 3667 "nuweb.w"
  576.   {
  577.     int depth;
  578.     for (depth=1; depth<max_depth; depth++) {
  579.       Goto_Node *r = depths[depth];
  580.       while (r) {
  581.         Move_Node *m = r->moves;
  582.         while (m) {
  583.           char a = m->c;
  584.           Goto_Node *s = m->state;
  585.           Goto_Node *state = r->fail;
  586.           while (state && !goto_lookup(a, state))
  587.             state = state->fail;
  588.           if (state)
  589.             s->fail = goto_lookup(a, state);
  590.           else
  591.             s->fail = root[a];
  592.           if (s->fail) {
  593.             Name_Node *p = s->fail->output;
  594.             while (p) {
  595.               Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
  596.               q->name = p->name;
  597.               q->next = s->output;
  598.               s->output = q;
  599.               p = p->next;
  600.             }
  601.           }
  602.           m = m->next;
  603.         }
  604.         r = r->next;
  605.       }
  606.     }
  607.   }
  608.   
  609. #line 3592 "nuweb.w"
  610.  
  611.   
  612. #line 3706 "nuweb.w"
  613.   {
  614.     for (i=1; i<scraps; i++) {
  615.       char c;
  616.       Manager reader;
  617.       Goto_Node *state = NULL;
  618.       reader.prev = NULL;
  619.       reader.scrap = scrap_array(i).slab;
  620.       reader.index = 0;
  621.       c = pop(&reader);
  622.       while (c) {
  623.         while (state && !goto_lookup(c, state))
  624.           state = state->fail;
  625.         if (state)
  626.           state = goto_lookup(c, state);
  627.         else
  628.           state = root[c];
  629.         c = pop(&reader);
  630.         if (state && state->output) {
  631.           Name_Node *p = state->output;
  632.           do {
  633.             Name *name = p->name;
  634.             if (!reject_match(name, c, &reader) &&
  635.                 (!name->uses || name->uses->scrap != i)) {
  636.               Scrap_Node *new_use =
  637.                   (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  638.               new_use->scrap = i;
  639.               new_use->next = name->uses;
  640.               name->uses = new_use;
  641.             }
  642.             p = p->next;
  643.           } while (p);
  644.         }
  645.       }
  646.     }
  647.   }
  648.   
  649. #line 3593 "nuweb.w"
  650.  
  651. }
  652.  
  653. #line 3601 "nuweb.w"
  654. static void build_gotos(Name *tree)
  655. {
  656.   while (tree) {
  657.     
  658. #line 3613 "nuweb.w"
  659.     {
  660.       int depth = 2;
  661.       char *p = tree->spelling;
  662.       char c = *p++;
  663.       Goto_Node *q = root[c];
  664.       if (!q) {
  665.         q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  666.         root[c] = q;
  667.         q->moves = NULL;
  668.         q->fail = NULL;
  669.         q->moves = NULL;
  670.         q->output = NULL;
  671.         q->next = depths[1];
  672.         depths[1] = q;
  673.       }
  674.       while (c = *p++) {
  675.         Goto_Node *new = goto_lookup(c, q);
  676.         if (!new) {
  677.           Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
  678.           new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  679.           new->moves = NULL;
  680.           new->fail = NULL;
  681.           new->moves = NULL;
  682.           new->output = NULL;
  683.           new_move->state = new;
  684.           new_move->c = c;
  685.           new_move->next = q->moves;
  686.           q->moves = new_move;
  687.           if (depth == max_depth) {
  688.             int i;
  689.             Goto_Node **new_depths =
  690.                 (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
  691.             max_depth = 2 * depth;
  692.             for (i=0; i<depth; i++)
  693.               new_depths[i] = depths[i];
  694.             depths = new_depths;
  695.             for (i=depth; i<max_depth; i++)
  696.               depths[i] = NULL;
  697.           }
  698.           new->next = depths[depth];
  699.           depths[depth] = new;
  700.         }
  701.         q = new;
  702.         depth++;
  703.       }
  704.       q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
  705.       q->output->next = NULL;
  706.       q->output->name = tree;
  707.     }
  708.     
  709. #line 3604 "nuweb.w"
  710.  
  711.     build_gotos(tree->rlink);
  712.     tree = tree->llink;
  713.   }
  714. }
  715.  
  716. #line 3754 "nuweb.w"
  717. #define sym_char(c) (isalnum(c) || (c) == '_')
  718.  
  719. static int op_char(char c)
  720. {
  721.   switch (c) {
  722.     case '!': case '@': case '#': case '%': case '$': case '^':
  723.     case '&': case '*': case '-': case '+': case '=': case '/':
  724.     case '|': case '~': case '<': case '>':
  725.       return TRUE;
  726.     default:
  727.       return FALSE;
  728.   }
  729. }
  730.  
  731. #line 3771 "nuweb.w"
  732. static int reject_match(Name *name, char post, Manager *reader)
  733. {
  734.   int len = strlen(name->spelling);
  735.   char first = name->spelling[0];
  736.   char last = name->spelling[len - 1];
  737.   char prev = '\0';
  738.   len = reader->index - len - 2;
  739.   if (len >= 0)
  740.     prev = reader->scrap->chars[len];
  741.   else if (reader->prev)
  742.     prev = reader->scrap->chars[SLAB_SIZE - len];
  743.   if (sym_char(last) && sym_char(post)) return TRUE;
  744.   if (sym_char(first) && sym_char(prev)) return TRUE;
  745.   if (op_char(last) && op_char(post)) return TRUE;
  746.   if (op_char(first) && op_char(prev)) return TRUE;
  747.   return FALSE;
  748. }
  749.