home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / languages / ami_nuweb0.87c.lha / scraps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-12  |  19.9 KB  |  598 lines

  1. #include "global.h"
  2. #define SLAB_SIZE 500
  3.  
  4. typedef struct slab {
  5.   struct slab *next;
  6.   char chars[SLAB_SIZE];
  7. } Slab;
  8. typedef struct {
  9.   char *file_name;
  10.   int file_line;
  11.   int page;
  12.   char letter;
  13.   Slab *slab;
  14. } ScrapEntry;
  15. static ScrapEntry *SCRAP[256];
  16.  
  17. #define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
  18.  
  19. static int scraps;
  20. void init_scraps(void)
  21. {
  22.   scraps = 1;
  23.   SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  24. } void write_scrap_ref(FILE *file, int num, int first, int *page)
  25. {
  26.   if (scrap_array(num).page >= 0) {
  27.     if (first)
  28.       fprintf(file, "%d", scrap_array(num).page);
  29.     else if (scrap_array(num).page != *page)
  30.       fprintf(file, ", %d", scrap_array(num).page);
  31.     if (scrap_array(num).letter > 0)
  32.       fputc(scrap_array(num).letter, file);
  33.   }
  34.   else {
  35.     if (first)
  36.       putc('?', file);
  37.     else
  38.       fputs(", ?", file);
  39.     {
  40.       if (!already_warned) {
  41.     #ifdef _AMIGA
  42.         fprintf(stderr, get_string(MSG_WARNING_45C),
  43.     #else
  44.         fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",
  45.     #endif
  46.                 command_name);
  47.         already_warned = TRUE;
  48.       }
  49.     }
  50.   }
  51.   *page = scrap_array(num).page;
  52. } void write_single_scrap_ref(FILE *file, int num)
  53. {
  54.   int page;
  55.   write_scrap_ref(file, num, TRUE, &page);
  56. } typedef struct {
  57.   Slab *scrap;
  58.   Slab *prev;
  59.   int index;
  60. } Manager;
  61. static void push(char c, Manager *manager)
  62. {
  63.   Slab *scrap = manager->scrap;
  64.   int index = manager->index;
  65.   scrap->chars[index++] = c;
  66.   if (index == SLAB_SIZE) {
  67.     Slab *new = (Slab *) arena_getmem(sizeof(Slab));
  68.     scrap->next = new;
  69.     manager->scrap = new;
  70.     index = 0;
  71.   }
  72.   manager->index = index;
  73. } static void pushs(char *s, Manager *manager)
  74. {
  75.   while (*s)
  76.     push(*s++, manager);
  77. } int collect_scrap(void)
  78. {
  79.   Manager writer;
  80.   {
  81.     Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
  82.     if ((scraps & 255) == 0)
  83.       SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  84.     scrap_array(scraps).slab = scrap;
  85.     scrap_array(scraps).file_name = save_string(source_name);
  86.     scrap_array(scraps).file_line = source_line;
  87.     scrap_array(scraps).page = -1;
  88.     scrap_array(scraps).letter = 0;
  89.     writer.scrap = scrap;
  90.     writer.index = 0;
  91.   }
  92.   {
  93.     int c = source_get();
  94.     while (1) {
  95.       switch (c) {
  96.   #ifdef _AMIGA
  97.         case EOF: fprintf(stderr, get_string(MSG_ERROR_47B),
  98.                           command_name, scrap_array(scraps).file_name,
  99.                           scrap_array(scraps).file_line);
  100.   #else
  101.         case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
  102.                           command_name, scrap_array(scraps).file_name,
  103.                           scrap_array(scraps).file_line);
  104.   #endif
  105.                   exit(EXIT_FAILURE);
  106.         case '@': {
  107.                     c = source_get();
  108.                     switch (c) {
  109.                       case '@': pushs("@@", &writer);
  110.                                 c = source_get();
  111.                                 break;
  112.                       case '|': {
  113.                                   do {
  114.                                     char new_name[100];
  115.                                     char *p = new_name;
  116.                                     do
  117.                                       c = source_get();
  118.                                     while (isspace(c));
  119.                                     if (c != '@') {
  120.                                       Name *name;
  121.                                       do {
  122.                                         *p++ = c;
  123.                                         c = source_get();
  124.                                       } while (c != '@' && !isspace(c));
  125.                                       *p = '\0';
  126.                                       name = name_add(&user_names, new_name);
  127.                                       if (!name->defs || name->defs->scrap != scraps) {
  128.                                         Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  129.                                         def->scrap = scraps;
  130.                                         def->next = name->defs;
  131.                                         name->defs = def;
  132.                                       }
  133.                                     }
  134.                                   } while (c != '@');
  135.                                   c = source_get();
  136.                                   if (c != '}') {
  137.                                     fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  138.                                             command_name, c, source_name, source_line);
  139.                                     exit(EXIT_FAILURE);
  140.                                   }
  141.                                 }
  142.                       case '}': push('\0', &writer);
  143.                                 return scraps++;
  144.                       case '<': {
  145.                                   Name *name = collect_scrap_name();
  146.                                   {
  147.                                     char *s = name->spelling;
  148.                                     int len = strlen(s) - 1;
  149.                                     pushs("@<", &writer);
  150.                                     while (len > 0) {
  151.                                       push(*s++, &writer);
  152.                                       len--;
  153.                                     }
  154.                                     if (*s == ' ')
  155.                                       pushs("...", &writer);
  156.                                     else
  157.                                       push(*s, &writer);
  158.                                     pushs("@>", &writer);
  159.                                   }
  160.                                   {
  161.                                     if (!name->uses || name->uses->scrap != scraps) {
  162.                                       Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  163.                                       use->scrap = scraps;
  164.                                       use->next = name->uses;
  165.                                       name->uses = use;
  166.                                     }
  167.                                   }
  168.                                   c = source_get();
  169.                                 }
  170.                                 break;
  171.                   #ifdef _AMIGA
  172.                       default : fprintf(stderr, get_string(MSG_ERROR_47C),
  173.                                         command_name, c, source_name, source_line);
  174.                   #else
  175.                       default : fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  176.                                         command_name, c, source_name, source_line);
  177.                   #endif
  178.                                 exit(EXIT_FAILURE);
  179.                     }
  180.                   }
  181.                   break;
  182.         default:  push(c, &writer);
  183.                   c = source_get();
  184.                   break;
  185.       }
  186.     }
  187.   }
  188. } static char pop(Manager *manager)
  189. {
  190.   Slab *scrap = manager->scrap;
  191.   int index = manager->index;
  192.   char c = scrap->chars[index++];
  193.   if (index == SLAB_SIZE) {
  194.     manager->prev = scrap;
  195.     manager->scrap = scrap->next;
  196.     index = 0;
  197.   }
  198.   manager->index = index;
  199.   return c;
  200. } static Name *pop_scrap_name(Manager *manager)
  201. {
  202.   char name[100];
  203.   char *p = name;
  204.   int c = pop(manager);
  205.   while (TRUE) {
  206.     if (c == '@')
  207.       {
  208.         c = pop(manager);
  209.         if (c == '@') {
  210.           *p++ = c;
  211.           c = pop(manager);
  212.         }
  213.         else if (c == '>') {
  214.           if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
  215.             p[-3] = ' ';
  216.             p -= 2;
  217.           }
  218.           *p = '\0';
  219.           return prefix_add(¯o_names, name);
  220.         }
  221.         else {
  222.       #ifdef _AMIGA
  223.           fprintf(stderr, get_string(MSG_ERROR_50A), command_name);
  224.       #else
  225.           fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
  226.       #endif
  227.           exit(EXIT_FAILURE);
  228.         }
  229.       }
  230.     else {
  231.       *p++ = c;
  232.       c = pop(manager);
  233.     }
  234.   }
  235. } int write_scraps(FILE *file, Scrap_Node *defs, int global_indent,
  236.   char *indent_chars, char debug_flag, char tab_flag, char indent_flag)
  237. {
  238.   int indent = 0;
  239.   while (defs) {
  240.     {
  241.       char c;
  242.       Manager reader;
  243.       int line_number = scrap_array(defs->scrap).file_line;
  244.       if (debug_flag) {
  245.         fprintf(file, "\n#line %d \"%s\"\n",
  246.                 line_number, scrap_array(defs->scrap).file_name);
  247.         {
  248.           if (indent_flag) {
  249.             if (tab_flag)
  250.               for (indent=0; indent<global_indent; indent++)
  251.                 putc(' ', file);
  252.             else
  253.               for (indent=0; indent<global_indent; indent++)
  254.                 putc(indent_chars[indent], file);
  255.           }
  256.           indent = 0;
  257.         }
  258.       }
  259.       reader.scrap = scrap_array(defs->scrap).slab;
  260.       reader.index = 0;
  261.       c = pop(&reader);
  262.       while (c) {
  263.         switch (c) {
  264.           case '@':  {
  265.                        c = pop(&reader);
  266.                        switch (c) {
  267.                          case '@': putc(c, file);
  268.                                    indent_chars[global_indent + indent] = ' ';
  269.                                    indent++;
  270.                                    break;
  271.                          case '<': {
  272.                                      Name *name = pop_scrap_name(&reader);
  273.                                      if (name->mark) {
  274.                                    #ifdef _AMIGA
  275.                                        fprintf(stderr, get_string(MSG_ERROR_52C1),
  276.                                                command_name, name->spelling);
  277.                                    #else
  278.                                        fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
  279.                                                command_name, name->spelling);
  280.                                    #endif
  281.                                        exit(EXIT_FAILURE);
  282.                                      }
  283.                                      if (name->defs) {
  284.                                        name->mark = TRUE;
  285.                                        indent = write_scraps(file, name->defs, global_indent + indent,
  286.                                                              indent_chars, debug_flag, tab_flag, indent_flag);
  287.                                        indent -= global_indent;
  288.                                        name->mark = FALSE;
  289.                                      }
  290.                                      else if (!tex_flag)
  291.                                    #ifdef _AMIGA
  292.                                        fprintf(stderr, get_string(MSG_WARNING_52C2),
  293.                                    #else
  294.                                        fprintf(stderr, "%s: macro never defined <%s>\n",
  295.                                    #endif
  296.                                                command_name, name->spelling);
  297.                                    }
  298.                                    if (debug_flag) {
  299.                                      fprintf(file, "\n#line %d \"%s\"\n",
  300.                                              line_number, scrap_array(defs->scrap).file_name);
  301.                                      {
  302.                                        if (indent_flag) {
  303.                                          if (tab_flag)
  304.                                            for (indent=0; indent<global_indent; indent++)
  305.                                              putc(' ', file);
  306.                                          else
  307.                                            for (indent=0; indent<global_indent; indent++)
  308.                                              putc(indent_chars[indent], file);
  309.                                        }
  310.                                        indent = 0;
  311.                                      }
  312.                                    }
  313.                                    break;
  314.                          default:  /* ignore, since we should already have a warning */
  315.                                    break;
  316.                        }
  317.                      }
  318.                      break;
  319.           case '\n': putc(c, file);
  320.                      line_number++;
  321.                      {
  322.                        if (indent_flag) {
  323.                          if (tab_flag)
  324.                            for (indent=0; indent<global_indent; indent++)
  325.                              putc(' ', file);
  326.                          else
  327.                            for (indent=0; indent<global_indent; indent++)
  328.                              putc(indent_chars[indent], file);
  329.                        }
  330.                        indent = 0;
  331.                      }
  332.                      break;
  333.           case '\t': {
  334.                        if (tab_flag)
  335.                          {
  336.                            int delta = 8 - (indent % 8);
  337.                            indent += delta;
  338.                            while (delta > 0) {
  339.                              putc(' ', file);
  340.                              delta--;
  341.                            }
  342.                          }
  343.                        else {
  344.                          putc('\t', file);
  345.                          indent_chars[global_indent + indent] = '\t';
  346.                          indent++;
  347.                        }
  348.                      }
  349.                      break;
  350.           default:   putc(c, file);
  351.                      indent_chars[global_indent + indent] = ' ';
  352.                      indent++;
  353.                      break;
  354.         }
  355.         c = pop(&reader);
  356.       }
  357.     }
  358.     defs = defs->next;
  359.   }
  360.   return indent + global_indent;
  361. } void collect_numbers(char *aux_name)
  362. {
  363.   if (number_flag) {
  364.     int i;
  365.     for (i=1; i<scraps; i++)
  366.       scrap_array(i).page = i;
  367.   }
  368.   else {
  369.     FILE *aux_file = fopen(aux_name, "r");
  370.     already_warned = FALSE;
  371.     if (aux_file) {
  372.       char aux_line[500];
  373.       while (fgets(aux_line, 500, aux_file)) {
  374.         int scrap_number;
  375.         int page_number;
  376.         char dummy[50];
  377.         if (3 == sscanf(aux_line, "\\newlabel{scrap%d}{%[^}]}{%d}",
  378.                         &scrap_number, dummy, &page_number)) {
  379.           if (scrap_number < scraps)
  380.             scrap_array(scrap_number).page = page_number;
  381.           else
  382.             {
  383.               if (!already_warned) {
  384.             #ifdef _AMIGA
  385.                 fprintf(stderr, get_string(MSG_WARNING_45C),
  386.             #else
  387.                 fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",
  388.             #endif
  389.                         command_name);
  390.                 already_warned = TRUE;
  391.               }
  392.             }
  393.         }
  394.       }
  395.       fclose(aux_file);
  396.       {
  397.         int scrap;
  398.         for (scrap=2; scrap<scraps; scrap++) {
  399.           if (scrap_array(scrap-1).page == scrap_array(scrap).page) {
  400.             if (!scrap_array(scrap-1).letter)
  401.               scrap_array(scrap-1).letter = 'a';
  402.             scrap_array(scrap).letter = scrap_array(scrap-1).letter + 1;
  403.           }
  404.         }
  405.       }
  406.     }
  407.   }
  408. } typedef struct name_node {
  409.   struct name_node *next;
  410.   Name *name;
  411. } Name_Node;
  412. typedef struct goto_node {
  413.   Name_Node *output;            /* list of words ending in this state */
  414.   struct move_node *moves;      /* list of possible moves */
  415.   struct goto_node *fail;       /* and where to go when no move fits */
  416.   struct goto_node *next;       /* next goto node with same depth */
  417. } Goto_Node;
  418. typedef struct move_node {
  419.   struct move_node *next;
  420.   Goto_Node *state;
  421.   char c;
  422. } Move_Node;
  423. static Goto_Node *root[128];
  424. static int max_depth;
  425. static Goto_Node **depths;
  426. static Goto_Node *goto_lookup(char c, Goto_Node *g)
  427. {
  428.   Move_Node *m = g->moves;
  429.   while (m && m->c != c)
  430.     m = m->next;
  431.   if (m)
  432.     return m->state;
  433.   else
  434.     return NULL;
  435. } static void build_gotos(Name *);
  436. static int reject_match(Name *, char, Manager *);
  437.  
  438. void search(void)
  439. {
  440.   int i;
  441.   for (i=0; i<128; i++)
  442.     root[i] = NULL;
  443.   max_depth = 10;
  444.   depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
  445.   for (i=0; i<max_depth; i++)
  446.     depths[i] = NULL;
  447.   build_gotos(user_names);
  448.   {
  449.     int depth;
  450.     for (depth=1; depth<max_depth; depth++) {
  451.       Goto_Node *r = depths[depth];
  452.       while (r) {
  453.         Move_Node *m = r->moves;
  454.         while (m) {
  455.           char a = m->c;
  456.           Goto_Node *s = m->state;
  457.           Goto_Node *state = r->fail;
  458.           while (state && !goto_lookup(a, state))
  459.             state = state->fail;
  460.           if (state)
  461.             s->fail = goto_lookup(a, state);
  462.           else
  463.             s->fail = root[a];
  464.           if (s->fail) {
  465.             Name_Node *p = s->fail->output;
  466.             while (p) {
  467.               Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
  468.               q->name = p->name;
  469.               q->next = s->output;
  470.               s->output = q;
  471.               p = p->next;
  472.             }
  473.           }
  474.           m = m->next;
  475.         }
  476.         r = r->next;
  477.       }
  478.     }
  479.   }
  480.   {
  481.     for (i=1; i<scraps; i++) {
  482.       char c;
  483.       Manager reader;
  484.       Goto_Node *state = NULL;
  485.       reader.prev = NULL;
  486.       reader.scrap = scrap_array(i).slab;
  487.       reader.index = 0;
  488.       c = pop(&reader);
  489.       while (c) {
  490.         while (state && !goto_lookup(c, state))
  491.           state = state->fail;
  492.         if (state)
  493.           state = goto_lookup(c, state);
  494.         else
  495.           state = root[c];
  496.         c = pop(&reader);
  497.         if (state && state->output) {
  498.           Name_Node *p = state->output;
  499.           do {
  500.             Name *name = p->name;
  501.             if (!reject_match(name, c, &reader) &&
  502.                 (!name->uses || name->uses->scrap != i)) {
  503.               Scrap_Node *new_use =
  504.                   (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  505.               new_use->scrap = i;
  506.               new_use->next = name->uses;
  507.               name->uses = new_use;
  508.             }
  509.             p = p->next;
  510.           } while (p);
  511.         }
  512.       }
  513.     }
  514.   }
  515. } static void build_gotos(Name *tree)
  516. {
  517.   while (tree) {
  518.     {
  519.       int depth = 2;
  520.       char *p = tree->spelling;
  521.       char c = *p++;
  522.       Goto_Node *q = root[c];
  523.       if (!q) {
  524.         q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  525.         root[c] = q;
  526.         q->moves = NULL;
  527.         q->fail = NULL;
  528.         q->moves = NULL;
  529.         q->output = NULL;
  530.         q->next = depths[1];
  531.         depths[1] = q;
  532.       }
  533.       while (c = *p++) {
  534.         Goto_Node *new = goto_lookup(c, q);
  535.         if (!new) {
  536.           Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
  537.           new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  538.           new->moves = NULL;
  539.           new->fail = NULL;
  540.           new->moves = NULL;
  541.           new->output = NULL;
  542.           new_move->state = new;
  543.           new_move->c = c;
  544.           new_move->next = q->moves;
  545.           q->moves = new_move;
  546.           if (depth == max_depth) {
  547.             int i;
  548.             Goto_Node **new_depths =
  549.                 (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
  550.             max_depth = 2 * depth;
  551.             for (i=0; i<depth; i++)
  552.               new_depths[i] = depths[i];
  553.             depths = new_depths;
  554.             for (i=depth; i<max_depth; i++)
  555.               depths[i] = NULL;
  556.           }
  557.           new->next = depths[depth];
  558.           depths[depth] = new;
  559.         }
  560.         q = new;
  561.         depth++;
  562.       }
  563.       q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
  564.       q->output->next = NULL;
  565.       q->output->name = tree;
  566.     }
  567.     build_gotos(tree->rlink);
  568.     tree = tree->llink;
  569.   }
  570. } #define sym_char(c) (isalnum(c) || (c) == '_')
  571.  
  572. static int op_char(char c)
  573. {
  574.   switch (c) {
  575.     case '!': case '@': case '#': case '%': case '$': case '^':
  576.     case '&': case '*': case '-': case '+': case '=': case '/':
  577.     case '|': case '~': case '<': case '>':
  578.       return TRUE;
  579.     default:
  580.       return FALSE;
  581.   }
  582. } static int reject_match(Name *name, char post, Manager *reader)
  583. {
  584.   int len = strlen(name->spelling);
  585.   char first = name->spelling[0];
  586.   char last = name->spelling[len - 1];
  587.   char prev = '\0';
  588.   len = reader->index - len - 2;
  589.   if (len >= 0)
  590.     prev = reader->scrap->chars[len];
  591.   else if (reader->prev)
  592.     prev = reader->scrap->chars[SLAB_SIZE - len];
  593.   if (sym_char(last) && sym_char(post)) return TRUE;
  594.   if (sym_char(first) && sym_char(prev)) return TRUE;
  595.   if (op_char(last) && op_char(post)) return TRUE;
  596.   if (op_char(first) && op_char(prev)) return TRUE;
  597.   return FALSE;