home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / jikepg12.zip / jikespg / src / lpgutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-04  |  38.7 KB  |  1,031 lines

  1. /* $Id: lpgutil.c,v 1.2 1999/11/04 14:02:22 shields Exp $ */
  2. /*
  3.  This software is subject to the terms of the IBM Jikes Compiler
  4.  License Agreement available at the following URL:
  5.  http://www.ibm.com/research/jikes.
  6.  Copyright (C) 1983, 1999, International Business Machines Corporation
  7.  and others.  All Rights Reserved.
  8.  You must accept the terms of that agreement to use this software.
  9. */
  10. static char hostfile[] = __FILE__;
  11.  
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include "common.h"
  16. #include "header.h"
  17.  
  18. /**********************************************************************/
  19. /* The following are global variables and constants used to manage a  */
  20. /* pool of temporary space. Externally, the user invokes the function */
  21. /* "talloc" just as he would invoke "malloc".                         */
  22. /**********************************************************************/
  23. #ifdef DOS
  24. #define LOG_BLKSIZE 12
  25. #else
  26. #define LOG_BLKSIZE 14
  27. #endif
  28.  
  29. #define BLKSIZE (1 << LOG_BLKSIZE)
  30. #define BASE_INCREMENT 64
  31.  
  32. typedef long cell;
  33.  
  34. static cell **temp_base = NULL;
  35. static long temp_top = 0,
  36.             temp_size = 0,
  37.             temp_base_size = 0;
  38.  
  39. /**********************************************************************/
  40. /*                          ALLOCATE_MORE_SPACE:                      */
  41. /**********************************************************************/
  42. /* This procedure obtains more TEMPORARY space.                       */
  43. /**********************************************************************/
  44. static BOOLEAN allocate_more_space(cell ***base, long *size, long *base_size)
  45. {
  46.     int k;
  47.  
  48. /**********************************************************************/
  49. /* The variable size always indicates the maximum number of cells     */
  50. /* that has been allocated and reserved for the storage pool.         */
  51. /* Initially, size should be set to 0 to indicate that no space has   */
  52. /* yet been allocated. The pool of cells available is divided into    */
  53. /* segments of size 2**LOG_BLKSIZE each and each segment is pointer   */
  54. /* to by a slot in the array base.                                    */
  55. /*                                                                    */
  56. /* By dividing "size" by the size of the segment we obtain the        */
  57. /* index for the next segment in base. If base is already full, it is */
  58. /* reallocated.                                                       */
  59. /*                                                                    */
  60. /**********************************************************************/
  61.     k = (*size) >> LOG_BLKSIZE; /* which segment? */
  62.     if (k == (*base_size))      /* base overflow? reallocate */
  63.     {
  64.         register int i = (*base_size);
  65.  
  66.         (*base_size) += BASE_INCREMENT;
  67.         (*base) = (cell **)
  68.                   ((*base) == NULL ?
  69.                    malloc(sizeof(cell *) * (*base_size)) :
  70.                    realloc((*base), sizeof(cell *) * (*base_size)));
  71.         if ((*base) == (cell **) NULL)
  72.             return FALSE;
  73.  
  74.         for (i = i; i < (*base_size); i++)
  75.             (*base)[i] = NULL;
  76.     }
  77.  
  78. /**********************************************************************/
  79. /* If the Ast slot "k" does not already contain a segment, We try to  */
  80. /* allocate one and place its address in (*base)[k].                  */
  81. /* If the allocation was not successful, we terminate;                */
  82. /* otherwise, we adjust the address in (*base)[k] so as to allow us   */
  83. /* to index the segment directly, instead of having to perform a      */
  84. /* subtraction for each reference. Finally, we update size.           */
  85. /*                                                                    */
  86. /* Finally, we set the block to zeros.                                */
  87. /**********************************************************************/
  88.     if ((*base)[k] == NULL)
  89.     {
  90.         (*base)[k] = (cell *) malloc(sizeof(cell) << LOG_BLKSIZE);
  91.         if ((*base)[k] == (cell *) NULL)
  92.             return FALSE;
  93.         (*base)[k] -= (*size);
  94.     }
  95.  
  96.     memset((void *)((*base)[k] + (*size)), 0, sizeof(cell) << LOG_BLKSIZE);
  97.     (*size) += BLKSIZE;
  98.  
  99.     return TRUE;
  100. }
  101.  
  102.  
  103. /**********************************************************************/
  104. /*                         RESET_TEMPORARY_SPACE:                     */
  105. /**********************************************************************/
  106. /* This procedure resets the temporary space already allocated so     */
  107. /* that it can be reused before new blocks are allocated.             */
  108. /**********************************************************************/
  109. void reset_temporary_space(void)
  110. {
  111.     temp_top = 0;         /* index of next usable elemt */
  112.     temp_size = 0;
  113.  
  114.     return;
  115. }
  116.  
  117.  
  118. /**********************************************************************/
  119. /*                         FREE_TEMPORARY_SPACE:                      */
  120. /**********************************************************************/
  121. /* This procedure frees all allocated temporary space.                */
  122. /**********************************************************************/
  123. void free_temporary_space(void)
  124. {
  125.     int k;
  126.  
  127.     for (k = 0; k < temp_base_size && temp_base[k] != NULL; k++)
  128.     {
  129.         temp_base[k] += (k * BLKSIZE);
  130.         ffree(temp_base[k]);
  131.     }
  132.  
  133.     if (temp_base != NULL)
  134.     {
  135.         ffree(temp_base);
  136.         temp_base = NULL;
  137.     }
  138.  
  139.     temp_base_size = 0;
  140.     temp_top = 0;
  141.     temp_size = 0;
  142.  
  143.     return;
  144. }
  145.  
  146.  
  147. /**********************************************************************/
  148. /*                                TALLOC:                             */
  149. /**********************************************************************/
  150. /* talloc allocates an object of size "size" in temporary space and   */
  151. /* returns a pointer to it.                                           */
  152. /**********************************************************************/
  153. void *talloc(long size)
  154. {
  155.     long i;
  156.  
  157.     i = temp_top;
  158.     temp_top += ((size + sizeof(cell) - 1) / sizeof(cell));
  159.     if (temp_top > temp_size)
  160.     {
  161.         i = temp_size;
  162.         temp_top = temp_size +
  163.                    ((size + sizeof(cell) - 1) / sizeof(cell));
  164.         if (! allocate_more_space(&temp_base, &temp_size, &temp_base_size))
  165.         {
  166.             temp_top = temp_size;
  167.             return NULL;
  168.         }
  169.     }
  170.  
  171.     return ((void *) &(temp_base[i >> LOG_BLKSIZE] [i]));
  172. }
  173.  
  174.  
  175. /**********************************************************************/
  176. /*                      TEMPORARY_SPACE_ALLOCATED:                    */
  177. /**********************************************************************/
  178. /* Return the total size of temporary space allocated.                */
  179. /**********************************************************************/
  180. long temporary_space_allocated(void)
  181. {
  182.     return ((temp_base_size * sizeof(cell **)) +
  183.             (temp_size * sizeof(cell)));
  184. }
  185.  
  186.  
  187. /**********************************************************************/
  188. /*                         TEMPORARY_SPACE_USED:                      */
  189. /**********************************************************************/
  190. /* Return the total size of temporary space used.                     */
  191. /**********************************************************************/
  192. long temporary_space_used(void)
  193. {
  194.     return (((temp_size >> LOG_BLKSIZE) * sizeof(cell **)) +
  195.              (temp_top * sizeof(cell)));
  196. }
  197.  
  198.  
  199. /**********************************************************************/
  200. /*                                                                    */
  201. /* The following are global variables and constants used to manage a  */
  202. /* pool of global space. Externally, the user invokes one of the      */
  203. /* functions:                                                         */
  204. /*                                                                    */
  205. /*    ALLOCATE_NODE                                                   */
  206. /*    ALLOCATE_GOTO_MAP                                               */
  207. /*    ALLOCATE_SHIFT_MAP                                              */
  208. /*    ALLOCATE_REDUCE_MAP                                             */
  209. /*                                                                    */
  210. /* These functions allocate space from the global pool in the same    */
  211. /* using the function "galloc" below.                                 */
  212. /*                                                                    */
  213. /**********************************************************************/
  214. static cell **global_base = NULL;
  215. static long global_top = 0,
  216.             global_size = 0,
  217.             global_base_size = 0;
  218.  
  219. static struct node *node_pool = NULL;
  220.  
  221. /**********************************************************************/
  222. /*                          PROCESS_GLOBAL_WASTE:                     */
  223. /**********************************************************************/
  224. /* This function is invoked when the space left in a segment is not   */
  225. /* enough for GALLOC to allocate a requested object. Rather than      */
  226. /* waste the space, as many NODE structures as possible are allocated */
  227. /* in that space and stacked up in the NODE_POOL list.                */
  228. /**********************************************************************/
  229. static void process_global_waste(long top)
  230. {
  231.     struct node *p;
  232.     long i;
  233.  
  234.     while (TRUE)
  235.     {
  236.         i = top;
  237.         top += ((sizeof(struct node) + sizeof(cell) - 1) / sizeof(cell));
  238.         if (top > global_size)
  239.             break;
  240.         p = (struct node *) &(global_base[i >> LOG_BLKSIZE] [i]);
  241.         p -> next = node_pool;
  242.         node_pool = p;
  243.     }
  244.  
  245.     return;
  246. }
  247.  
  248. /**********************************************************************/
  249. /*                                GALLOC:                             */
  250. /**********************************************************************/
  251. /* galloc allocates an object of size "size" in global space and      */
  252. /* returns a pointer to it. It is analoguous to "talloc", but it      */
  253. /* is a local (static) routine that is only invoked in this file by   */
  254. /* other more specialized routines.                                   */
  255. /**********************************************************************/
  256. static void *galloc(long size)
  257. {
  258.     long i;
  259.  
  260.     i = global_top;
  261.     global_top += ((size + sizeof(cell) - 1) / sizeof(cell));
  262.     if (global_top > global_size)
  263.     {
  264.         process_global_waste(i);
  265.         i = global_size;
  266.         global_top = global_size +
  267.                      ((size + sizeof(cell) - 1) / sizeof(cell));
  268.         if (! allocate_more_space(&global_base,
  269.                                   &global_size, &global_base_size))
  270.         {
  271.             global_top = global_size;
  272.             return NULL;
  273.         }
  274.     }
  275.  
  276.     return ((void *) &(global_base[i >> LOG_BLKSIZE] [i]));
  277. }
  278.  
  279.  
  280. /****************************************************************************/
  281. /*                              ALLOCATE_NODE:                              */
  282. /****************************************************************************/
  283. /*   This function allocates a node structure and returns a pointer to it.  */
  284. /* it there are nodes in the free pool, one of them is returned. Otherwise, */
  285. /* a new node is allocated from the global storage pool.                    */
  286. /****************************************************************************/
  287. struct node *allocate_node(char *file, long line)
  288. {
  289.     struct node *p;
  290.  
  291.     p = node_pool;
  292.     if (p != NULL)  /* is free list not empty? */
  293.          node_pool = p -> next;
  294.     else
  295.     {
  296.         p = (struct node *) galloc(sizeof(struct node));
  297.         if (p == NULL)
  298.             nospace(file, line);
  299.     }
  300.  
  301.     return(p);
  302. }
  303.  
  304.  
  305. /****************************************************************************/
  306. /*                             FREE_NODES:                                  */
  307. /****************************************************************************/
  308. /*  This function frees a linked list of nodes by adding them to the free   */
  309. /* list.  Head points to head of linked list and tail to the end.           */
  310. /****************************************************************************/
  311. void free_nodes(struct node *head, struct node *tail)
  312. {
  313.     tail -> next = node_pool;
  314.     node_pool = head;
  315.  
  316.     return;
  317. }
  318.  
  319.  
  320. /****************************************************************************/
  321. /*                             ALLOCATE_GOTO_MAP:                           */
  322. /****************************************************************************/
  323. /*   This function allocates space for a goto map with "size" elements,     */
  324. /* initializes and returns a goto header for that map. NOTE that after the  */
  325. /* map is successfully allocated, it is offset by one element. This is      */
  326. /* to allow the array in question to be indexed from 1..size instead of     */
  327. /* 0..(size-1).                                                             */
  328. /****************************************************************************/
  329. struct goto_header_type allocate_goto_map(int size, char *file, long line)
  330. {
  331.     struct goto_header_type go_to;
  332.  
  333.     go_to.size = size;
  334.     go_to.map = (struct goto_type *)
  335.                 galloc(size * sizeof(struct goto_type));
  336.     if (go_to.map == NULL)
  337.         nospace(file, line);
  338.     go_to.map--;   /* map will be indexed in range 1..size */
  339.  
  340.     return(go_to);
  341. }
  342.  
  343.  
  344. /****************************************************************************/
  345. /*                            ALLOCATE_SHIFT_MAP:                           */
  346. /****************************************************************************/
  347. /*   This function allocates space for a shift map with "size" elements,    */
  348. /* initializes and returns a shift header for that map. NOTE that after the */
  349. /* map is successfully allocated, it is offset by one element. This is      */
  350. /* to allow the array in question to be indexed from 1..size instead of     */
  351. /* 0..(size-1).                                                             */
  352. /****************************************************************************/
  353. struct shift_header_type allocate_shift_map(int size,
  354.                                             char *file, long line)
  355. {
  356.     struct shift_header_type sh;
  357.  
  358.     sh.size = size;
  359.     sh.map = (struct shift_type *)
  360.              galloc(size * sizeof(struct shift_type));
  361.     if (sh.map == NULL)
  362.         nospace(file, line);
  363.     sh.map--;   /* map will be indexed in range 1..size */
  364.  
  365.     return(sh);
  366. }
  367.  
  368.  
  369. /****************************************************************************/
  370. /*                             ALLOCATE_REDUCE_MAP:                         */
  371. /****************************************************************************/
  372. /*   This function allocates space for a REDUCE map with "size"+1 elements, */
  373. /* initializes and returns a REDUCE header for that map. The 0th element of */
  374. /* a reduce map is used for the default reduction.                          */
  375. /****************************************************************************/
  376. struct reduce_header_type allocate_reduce_map(int size,
  377.                                               char *file, long line)
  378. {
  379.     struct reduce_header_type red;
  380.  
  381.     red.map = (struct reduce_type *)
  382.               galloc((size + 1) * sizeof(struct reduce_type));
  383.     if (red.map == NULL)
  384.         nospace(file, line);
  385.     red.size = size;
  386.  
  387.     return(red);
  388. }
  389.  
  390.  
  391. /**********************************************************************/
  392. /*                        GLOBAL_SPACE_ALLOCATED:                     */
  393. /**********************************************************************/
  394. /* Return the total size of global space allocated.                   */
  395. /**********************************************************************/
  396. long global_space_allocated(void)
  397. {
  398.     return ((global_base_size * sizeof(cell **)) +
  399.             (global_size * sizeof(cell)));
  400. }
  401.  
  402.  
  403. /**********************************************************************/
  404. /*                           GLOBAL_SPACE_USED:                       */
  405. /**********************************************************************/
  406. /* Return the total size of global space used.                        */
  407. /**********************************************************************/
  408. long global_space_used(void)
  409. {
  410.     return (((global_size >> LOG_BLKSIZE) * sizeof(cell **)) +
  411.              (global_top * sizeof(cell)));
  412. }
  413.  
  414.  
  415. /****************************************************************************/
  416. /*                           ALLOCATE_INT_ARRAY:                            */
  417. /****************************************************************************/
  418. /*   This function allocates an array of size "size" of int integers.       */
  419. /****************************************************************************/
  420. int *allocate_int_array(long size, char *file, long line)
  421. {
  422.     int *p;
  423.  
  424.     p = (int *) calloc(size, sizeof(int));
  425.     if (p == (int *) NULL)
  426.         nospace(file, line);
  427.  
  428.     return(&p[0]);
  429. }
  430.  
  431.  
  432. /****************************************************************************/
  433. /*                           ALLOCATE_SHORT_ARRAY:                          */
  434. /****************************************************************************/
  435. /*   This function allocates an array of size "size" of short integers.     */
  436. /****************************************************************************/
  437. short *allocate_short_array(long size, char *file, long line)
  438. {
  439.     short *p;
  440.  
  441.     p = (short *) calloc(size, sizeof(short));
  442.     if (p == (short *) NULL)
  443.         nospace(file, line);
  444.  
  445.     return(&p[0]);
  446. }
  447.  
  448.  
  449. /****************************************************************************/
  450. /*                           ALLOCATE_BOOLEAN_ARRAY:                        */
  451. /****************************************************************************/
  452. /*   This function allocates an array of size "size" of type boolean.       */
  453. /****************************************************************************/
  454. BOOLEAN *allocate_boolean_array(long size, char *file, long line)
  455. {
  456.     BOOLEAN *p;
  457.  
  458.     p = (BOOLEAN *) calloc(size, sizeof(BOOLEAN));
  459.     if (p == (BOOLEAN *) 0)
  460.         nospace(file, line);
  461.  
  462.     return(&p[0]);
  463. }
  464.  
  465.  
  466. /*****************************************************************************/
  467. /*                              FILL_IN:                                     */
  468. /*****************************************************************************/
  469. /* FILL_IN is a subroutine that pads a buffer, STRING,  with CHARACTER a     */
  470. /* certain AMOUNT of times.                                                  */
  471. /*****************************************************************************/
  472. void fill_in(char string[], int amount, char character)
  473. {
  474.     int i;
  475.  
  476.     for (i = 0; i <= amount; i++)
  477.         string[i] = character;
  478.     string[i] = '\0';
  479.  
  480.     return;
  481. }
  482.  
  483.  
  484. /*****************************************************************************/
  485. /*                                  QCKSRT:                                  */
  486. /*****************************************************************************/
  487. /* QCKSRT is a quicksort algorithm that takes as arguments an array of       */
  488. /* integers, two numbers L and H that indicate the lower and upper bound     */
  489. /* positions in ARRAY to be sorted.                                          */
  490. /*****************************************************************************/
  491. static void qcksrt(short array[], int l, int h)
  492. {
  493.     int lower,
  494.         upper,
  495.         top,
  496.         i,
  497.         j,
  498.         pivot,
  499.         lostack[14],  /* A stack of size 14 can sort an array of up to */
  500.         histack[14];  /* 2 ** 15 - 1 elements                          */
  501.  
  502.     top = 1;
  503.     lostack[top] = l;
  504.     histack[top] = h;
  505.     while (top != 0)
  506.     {
  507.         lower = lostack[top];
  508.         upper = histack[top--];
  509.  
  510.         while (upper > lower)
  511.         {
  512.             i = lower;
  513.             pivot = array[lower];
  514.             for (j = lower + 1; j <= upper; j++)
  515.             {
  516.                 if (array[j] < pivot)
  517.                 {
  518.                     array[i] = array[j];
  519.                     i++;
  520.                     array[j] = array[i];
  521.                 }
  522.             }
  523.             array[i] = pivot;
  524.  
  525.             top++;
  526.             if (i - lower < upper - i)
  527.             {
  528.                 lostack[top] = i + 1;
  529.                 histack[top] = upper;
  530.                 upper = i - 1;
  531.             }
  532.             else
  533.             {
  534.                 histack[top] = i - 1;
  535.                 lostack[top] = lower;
  536.                 lower = i + 1;
  537.             }
  538.         }
  539.     }
  540.  
  541.     return;
  542. }
  543.  
  544.  
  545. /*****************************************************************************/
  546. /*                               NUMBER_LEN:                                 */
  547. /*****************************************************************************/
  548. /* NUMBER_LEN takes a state number and returns the number of digits in that  */
  549. /* number.                                                                   */
  550. /*****************************************************************************/
  551. int number_len(int state_no)
  552. {
  553.     int num = 0;
  554.  
  555.     do
  556.     {
  557.         state_no /= 10;
  558.         num++;
  559.     }   while (state_no != 0);
  560.  
  561.     return num;
  562. }
  563.  
  564.  
  565. /*************************************************************************/
  566. /*                            RESTORE_SYMBOL:                            */
  567. /*************************************************************************/
  568. /* This procedure takes two character strings as arguments: IN and OUT.  */
  569. /* IN identifies a grammar symbol or name that is checked as to whether  */
  570. /* or not it needs to be quoted. If so, the necessary quotes are added   */
  571. /* as IN is copied into the space identified by OUT.                     */
  572. /* NOTE that it is assumed that IN and OUT do not overlap each other.    */
  573. /*************************************************************************/
  574. void restore_symbol(char *out, char *in)
  575. {
  576.     int  len;
  577.  
  578.     len = strlen(in);
  579.     if (len > 0)
  580.     {
  581.         if ((len == 1 && in[0] == ormark) ||
  582.             (in[0] == escape)             ||
  583.             (in[0] == '\'')               ||
  584.             (in[len - 1] == '\'')         ||
  585.             (strchr(in, ' ') != NULL &&
  586.             (in[0] != '<' || in[len - 1] != '>')))
  587.         {
  588.             *(out++) = '\'';
  589.             while(*in != '\0')
  590.             {
  591.                 if (*in == '\'')
  592.                     *(out++) = *in;
  593.                 *(out++) = *(in++);
  594.             }
  595.             *(out++) = '\'';
  596.             *out = '\0';
  597.  
  598.             return;
  599.         }
  600.     }
  601.  
  602.     strcpy(out, in);
  603.  
  604.     if (out[0] == '\n')   /* one of the special grammar symbols? */
  605.         out[0] = escape;
  606.  
  607.     return;
  608. }
  609.  
  610.  
  611. /*****************************************************************************/
  612. /*                          PRINT_LARGE_TOKEN:                               */
  613. /*****************************************************************************/
  614. /* PRINT_LARGE_TOKEN generates code to print a token that may exceed the     */
  615. /* limit of its field.  The argument are LINE which is the symbol a varying  */
  616. /* length character string, TOKEN which is the symbol to be printed, INDENT  */
  617. /* which is a character string to be used as an initial prefix to indent the */
  618. /* output line, and LEN which indicates the maximum number of characters that*/
  619. /* can be printed on a given line.  At the end of this process, LINE will    */
  620. /* have the value of the remaining substring that can fit on the output line.*/
  621. /* If a TOKEN is too large to be indented in a line, but not too large for   */
  622. /* the whole line, we forget the indentation, and printed it. Otherwise, it  */
  623. /* is "chapped up" and printed in pieces that are each indented.             */
  624. /*****************************************************************************/
  625. void print_large_token(char *line, char *token, char *indent, int len)
  626. {
  627.     int toklen;
  628.  
  629.     char temp[SYMBOL_SIZE + 1];
  630.  
  631.     toklen = strlen(token);
  632.  
  633.     if (toklen > len && toklen <= PRINT_LINE_SIZE-1)
  634.     {
  635.         fprintf(syslis, "\n%s", token);
  636.         ENDPAGE_CHECK;
  637.         token = "";
  638.         strcpy(line,indent);
  639.     }
  640.     else
  641.     {
  642.         for (; toklen > len; toklen = strlen(temp))
  643.         {
  644.             memcpy(temp, token, len);
  645.             temp[len] = '\0';
  646.             fprintf(syslis, "\n%s",temp);
  647.             ENDPAGE_CHECK;
  648.             strcpy(temp, token+len + 1);
  649.             token = temp;
  650.         }
  651.         strcpy(line,indent);
  652.         strcat(line,token);
  653.     }
  654.  
  655.     return;
  656. }
  657.  
  658.  
  659. /*****************************************************************************/
  660. /*                                PRINT_ITEM:                                */
  661. /*****************************************************************************/
  662. /* PRINT_ITEM takes as parameter an ITEM_NO which it prints.                 */
  663. /*****************************************************************************/
  664. void print_item(int item_no)
  665. {
  666.     int rule_no,
  667.         symbol,
  668.         len,
  669.         offset,
  670.         i,
  671.         k;
  672.  
  673.     char tempstr[PRINT_LINE_SIZE + 1],
  674.          line[PRINT_LINE_SIZE + 1],
  675.          tok[SYMBOL_SIZE + 1];
  676.  
  677.     /*********************************************************************/
  678.     /* We first print the left hand side of the rule, leaving at least   */
  679.     /* 5 spaces in the output line to accomodate the equivalence symbol  */
  680.     /* "::=" surrounded by blanks on both sides.  Then, we print all the */
  681.     /* terminal symbols in the right hand side up to but not including   */
  682.     /* the dot symbol.                                                   */
  683.     /*********************************************************************/
  684.  
  685.     rule_no = item_table[item_no].rule_number;
  686.     symbol = rules[rule_no].lhs;
  687.  
  688.     restore_symbol(tok, RETRIEVE_STRING(symbol));
  689.     len = PRINT_LINE_SIZE - 5;
  690.     print_large_token(line, tok, "", len);
  691.     strcat(line, " ::= ");
  692.     i = (PRINT_LINE_SIZE / 2) - 1;
  693.     offset = MIN(strlen(line)-1, i);
  694.     len = PRINT_LINE_SIZE - (offset + 4);
  695.     i = rules[rule_no].rhs;  /* symbols before dot */
  696.  
  697.     k = ((rules[rule_no].rhs + item_table[item_no].dot) - 1);
  698.     for (; i <= k; i++)
  699.     {
  700.         symbol = rhs_sym[i];
  701.         restore_symbol(tok, RETRIEVE_STRING(symbol));
  702.         if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE - 4)
  703.         {
  704.             fprintf(syslis,"\n%s", line);
  705.             ENDPAGE_CHECK;
  706.             fill_in(tempstr, offset, SPACE);
  707.             print_large_token(line, tok, tempstr, len);
  708.         }
  709.         else
  710.             strcat(line, tok);
  711.         strcat(line, BLANK);
  712.     }
  713.  
  714.     /*********************************************************************/
  715.     /* We now add a DOT "." to the output line and print the remaining   */
  716.     /* symbols in the right hand side.  If ITEM_NO is a complete item,   */
  717.     /* we also print the rule number.                                    */
  718.     /*********************************************************************/
  719.     if (item_table[item_no].dot == 0 || item_table[item_no].symbol == empty)
  720.         strcpy(tok, ".");
  721.     else
  722.         strcpy(tok, " .");
  723.     strcat(line, tok);
  724.     len = PRINT_LINE_SIZE - (offset + 1);
  725.     for (i = rules[rule_no].rhs +
  726.               item_table[item_no].dot;/* symbols after dot*/
  727.           i <= rules[rule_no + 1].rhs - 1; i++)
  728.     {
  729.         symbol = rhs_sym[i];
  730.         restore_symbol(tok, RETRIEVE_STRING(symbol));
  731.         if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE -1)
  732.         {
  733.             fprintf(syslis, "\n%s", line);
  734.             ENDPAGE_CHECK;
  735.             fill_in(tempstr, offset, SPACE);
  736.             print_large_token(line, tok, tempstr, len);
  737.         }
  738.         else
  739.             strcat(line, tok);
  740.         strcat(line, BLANK);
  741.     }
  742.     if (item_table[item_no].symbol == empty)   /* complete item */
  743.     {
  744.         sprintf(tok, " (%d)", rule_no);
  745.         if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE - 1)
  746.         {
  747.             fprintf(syslis, "\n%s", line);
  748.             ENDPAGE_CHECK;
  749.             fill_in(line,offset, SPACE);
  750.         }
  751.         strcat(line,tok);
  752.     }
  753.     fprintf(syslis, "\n%s", line);
  754.     ENDPAGE_CHECK;
  755.  
  756.     return;
  757. }
  758.  
  759.  
  760. /*****************************************************************************/
  761. /*                               PRINT_STATE:                                */
  762. /*****************************************************************************/
  763. /* PRINT_STATE prints all the items in a state.  NOTE that when single       */
  764. /* productions are eliminated, certain items that were added in a state by   */
  765. /* CLOSURE, will no longer show up in the output.  Example: If we have the   */
  766. /* item [A ::= .B]  in a state, and the GOTO_REDUCE generated on B has been  */
  767. /* replaced by say the GOTO or GOTO_REDUCE of A, the item above can no longer*/
  768. /* be retrieved, since transitions in a given state are reconstructed from   */
  769. /* the KERNEL and ADEQUATE items of the actions in the GOTO and SHIFT maps.  */
  770. /*****************************************************************************/
  771. void print_state(int state_no)
  772. {
  773.     struct shift_header_type sh;
  774.  
  775.     struct goto_header_type  go_to;
  776.  
  777.     short *item_list;
  778.  
  779.     int kernel_size,
  780.         i,
  781.         n,
  782.         item_no,
  783.         next_state;
  784.  
  785.     BOOLEAN end_node,
  786.             *state_seen,
  787.             *item_seen;
  788.  
  789.     struct node *q;
  790.  
  791.     char buffer[PRINT_LINE_SIZE + 1],
  792.          line[PRINT_LINE_SIZE + 1];
  793.  
  794.     /*********************************************************************/
  795.     /* ITEM_SEEN is used to construct sets of items, to help avoid       */
  796.     /* adding duplicates in a list.  Duplicates can occur because an     */
  797.     /* item from the kernel set will either be shifted on if it is not a */
  798.     /* complete item, or it will be a member of the Complete_items set.  */
  799.     /* Duplicates can also occur because of the elimination of single    */
  800.     /* productions.                                                      */
  801.     /*********************************************************************/
  802.  
  803.     state_seen = Allocate_boolean_array(max_la_state + 1);
  804.     item_seen  = Allocate_boolean_array(num_items + 1);
  805.     item_list  = Allocate_short_array(num_items + 1);
  806.  
  807. /* INITIALIZATION -----------------------------------------------------------*/
  808.  
  809.     for ALL_STATES(i)
  810.         state_seen[i] = FALSE;
  811.  
  812.     for ALL_ITEMS(i)
  813.         item_seen[i] = FALSE;
  814.  
  815.     kernel_size = 0;
  816.  
  817. /* END OF INITIALIZATION ----------------------------------------------------*/
  818.  
  819.     i = number_len(state_no) + 8; /* 8 = length("STATE") + 2 spaces + newline*/
  820.     fill_in(buffer, (PRINT_LINE_SIZE - i) ,'-');
  821.  
  822.     fprintf(syslis, "\n\n\nSTATE %d %s",state_no, buffer);
  823.     output_line_no +=3;
  824.  
  825.     /*********************************************************************/
  826.     /* Print the set of states that have transitions to STATE_NO.        */
  827.     /*********************************************************************/
  828.     n = 0;
  829.     strcpy(line, "( ");
  830.  
  831.     for (end_node = ((q = in_stat[state_no]) == NULL);
  832.          ! end_node;
  833.          end_node = (q == in_stat[state_no]))
  834.     {/* copy list of IN_STAT into array */
  835.         q = q -> next;
  836.         if (! state_seen[q -> value])
  837.         {
  838.             state_seen[q -> value] = TRUE;
  839.             if (strlen(line) + number_len(q -> value) > PRINT_LINE_SIZE-2)
  840.             {
  841.                 fprintf(syslis,"\n%s",line);
  842.                 ENDPAGE_CHECK;
  843.                 strcpy(line, "  ");
  844.             }
  845.             if (q -> value != 0)
  846.             {
  847.                 sprintf(buffer, "%d ", q -> value);
  848.                 strcat(line, buffer);
  849.             }
  850.         }
  851.     }
  852.     strcat(line, ")");
  853.     fprintf(syslis,"\n%s\n", line);
  854.     output_line_no++;
  855.     ENDPAGE_CHECK;
  856.  
  857.     /*********************************************************************/
  858.     /* Add the set of kernel items to the array ITEM_LIST, and mark all  */
  859.     /* items seen to avoid duplicates.                                   */
  860.     /*********************************************************************/
  861.  
  862.     for (q = statset[state_no].kernel_items; q != NULL; q = q -> next)
  863.     {
  864.         kernel_size++;
  865.         item_no = q -> value;
  866.         item_list[kernel_size] = item_no;    /* add to array */
  867.         item_seen[item_no] = TRUE;         /* Mark as "seen" */
  868.     }
  869.  
  870.     /*********************************************************************/
  871.     /* Add the Complete Items to the array ITEM_LIST, and mark used.     */
  872.     /*********************************************************************/
  873.     n = kernel_size;
  874.     for (q = statset[state_no].complete_items; q != NULL; q = q -> next)
  875.     {
  876.         item_no = q -> value;
  877.         if (! item_seen[item_no])
  878.         {
  879.             item_seen[item_no] = TRUE; /* Mark as "seen" */
  880.             item_list[++n] = item_no;
  881.         }
  882.     }
  883.  
  884.     /*********************************************************************/
  885.     /* Iterate over the shift map.  Shift-Reduce actions are identified  */
  886.     /* by a negative integer that indicates the rule in question , and   */
  887.     /* the associated item can be retrieved by indexing the array        */
  888.     /* ADEQUATE_ITEMS at the location of the rule.  For shift-actions, we*/
  889.     /* simply take the predecessor-items of all the items in the kernel  */
  890.     /* of the following state.                                           */
  891.     /* If the shift-action is a look-ahead shift, we check to see if the */
  892.     /* look-ahead state contains shift actions, and retrieve the next    */
  893.     /* state from one of those shift actions.                            */
  894.     /*********************************************************************/
  895.     sh = shift[statset[state_no].shift_number];
  896.     for (i = 1; i <= sh.size; i++)
  897.     {
  898.         next_state = SHIFT_ACTION(sh, i);
  899.         while (next_state > (int) num_states)
  900.         {
  901.             struct shift_header_type next_sh;
  902.  
  903.             next_sh = shift[lastats[next_state].shift_number];
  904.             if (next_sh.size > 0)
  905.                 next_state = SHIFT_ACTION(next_sh, 1);
  906.             else
  907.                 next_state = 0;
  908.         }
  909.  
  910.         if (next_state == 0)
  911.             q = NULL;
  912.         else if (next_state < 0)
  913.             q = adequate_item[-next_state];
  914.         else
  915.         {
  916.             q = statset[next_state].kernel_items;
  917.             if (q == NULL) /* single production state? */
  918.                 q = statset[next_state].complete_items;
  919.         }
  920.         for (; q != NULL; q = q -> next)
  921.         {
  922.             item_no = q -> value - 1;
  923.             if (! item_seen[item_no])
  924.             {
  925.                 item_seen[item_no] = TRUE;
  926.                 item_list[++n] = item_no;
  927.             }
  928.         }
  929.     }
  930.  
  931.     /*********************************************************************/
  932.     /* GOTOS and GOTO-REDUCES are analogous to SHIFTS and SHIFT-REDUCES. */
  933.     /*********************************************************************/
  934.     go_to = statset[state_no].go_to;
  935.     for (i = 1; i <= go_to.size; i++)
  936.     {
  937.         if (GOTO_ACTION(go_to, i) > 0)
  938.         {
  939.             q = statset[GOTO_ACTION(go_to, i)].kernel_items;
  940.             if (q == NULL)          /* single production state? */
  941.                 q = statset[GOTO_ACTION(go_to, i)].complete_items;
  942.         }
  943.         else
  944.             q = adequate_item[- GOTO_ACTION(go_to, i)];
  945.  
  946.         for (; q != NULL; q = q -> next)
  947.         {
  948.             item_no = q -> value - 1;
  949.             if (! item_seen[item_no])
  950.             {
  951.                 item_seen[item_no] = TRUE;
  952.                 item_list[++n] = item_no;
  953.             }
  954.         }
  955.     }
  956.  
  957.     /*********************************************************************/
  958.     /* Print the Kernel items.  If there are any closure items, skip a   */
  959.     /* line, sort then, then print them.  The kernel items are in sorted */
  960.     /* order.                                                            */
  961.     /*********************************************************************/
  962.     for (item_no = 1; item_no <= kernel_size; item_no++)
  963.          print_item(item_list[item_no]);
  964.     if (kernel_size < n)
  965.     {
  966.         fprintf(syslis, "\n");
  967.         ENDPAGE_CHECK;
  968.         qcksrt(item_list, kernel_size + 1, n);
  969.         for (item_no = kernel_size + 1; item_no <= n; item_no++)
  970.             print_item(item_list[item_no]);
  971.     }
  972.  
  973.     ffree(item_list);
  974.     ffree(item_seen);
  975.     ffree(state_seen);
  976.  
  977.     return;
  978. }
  979.  
  980.  
  981. /*****************************************************************************/
  982. /*                                 NOSPACE:                                  */
  983. /*****************************************************************************/
  984. /* This procedure is invoked when a call to MALLOC, CALLOC or REALLOC fails. */
  985. /*****************************************************************************/
  986. void nospace(char *file_name, long line_number)
  987. {
  988.     fprintf(stderr,
  989.             "*** Cannot allocate space ... LPG terminated in "
  990.             "file %s at line %d\n", file_name, line_number);
  991.     exit(12);
  992. }
  993.  
  994.  
  995. /************************************************************************/
  996. /*                               STRUPR:                                */
  997. /************************************************************************/
  998. /* StrUpr and StrLwr.                                                   */
  999. /* These routines set all characters in a string to upper case and lower*/
  1000. /*  case (respectively.)  These are library routines in DOS, but        */
  1001. /*  are defined here for the 370 compiler.                              */
  1002. /************************************************************************/
  1003. char *strupr(char *string)
  1004. {
  1005.     char *s;
  1006.  
  1007.     /*********************************************************************/
  1008.     /* While not at end of string, change all lower case to upper case.  */
  1009.     /*********************************************************************/
  1010.     for (s = string; *s != '\0'; s++)
  1011.         *s = (islower((int) *s) ? toupper((int) *s) : *s);
  1012.  
  1013.     return string;
  1014. }
  1015.  
  1016. /************************************************************************/
  1017. /*                               STRLWR:                                */
  1018. /************************************************************************/
  1019. char *strlwr(char *string)
  1020. {
  1021.     char *s;
  1022.  
  1023.     /*********************************************************************/
  1024.     /* While not at end of string, change all upper case to lower case.  */
  1025.     /*********************************************************************/
  1026.     for (s = string; *s != '\0'; s++)
  1027.         *s = (isupper((int) *s) ? tolower((int) *s) : *s);
  1028.  
  1029.     return string;
  1030. }
  1031.