LL1P20: PROC;
/****************************************************************
*              LL(1) GRAMMAR ANALYZER - PHASE 2                 *
*PURPOSE:                                                       *
*    THIS PROGRAM SORTS THE VOCABULARY AND PRINTS THE INTERNAL  *
*    FORM OF THE LANGUAGE IN A BNF FORMAT.                      *
*INPUT:                                                         *
*OUTPUT:                                                        *
*OUTLINE:                                                       *
*REMARKS:                                                       *
****************************************************************/

/****************************************************************
* * * * * * * * * * * COMMON DATA DEFINITIONS * * * * * * * * * *
****************************************************************/

/*      * * *  COMMON REPLACEMENTS  * * *       */
%REPLACE TRUE BY '1'B;
%REPLACE FALSE BY '0'B;

%INCLUDE 'LL1CMN.DCL';  /* GET COMMON AREAS. */

/****************************************************************
* * * * * * * * * * * COMMON PROCUDURES * * * * * * * * * * * * *
****************************************************************/


%INCLUDE 'LL1PRC.DCL';


/****************************************************************
* * * * * * * * * * * GRAMMAR PRINT PROCUDURES * * * * * * * * **
****************************************************************/

PRINT_PRODUCTIONS: PROC;
/*THIS ROUTINE IS RESPONSIBLE FOR PRINTING THE VOCABULARY. */
       DCL I BIN(15);          /* INDEXES */
       DCL J BIN(15);
       DCL NUM_LINES BIN(15);  /* MAXIMUM NUMBER OF LINES */
       DCL LHS_ENT CHAR(10) VARYING;
       DCL RHS_ENT(5) CHAR(10) VARYING;

/* OUTPUT THE HEADING. */
       ON ENDPAGE(LSTFIL)
          BEGIN;
             PUT FILE(LSTFIL) PAGE;
             PUT FILE(LSTFIL) SKIP(3)
                 EDIT('*** PRODUCTION LISTING ***','PAGE',
                       PAGENO(LSTFIL)-1)
                 (X(20),A(26),X(10),A(4),F(4));
             PUT FILE(LSTFIL) SKIP(1);
          END;
       SIGNAL ENDPAGE(LSTFIL);

/* PRINT THE REPORT LINES. */
       PUT FILE(LSTFIL) SKIP(1)
                 EDIT('STARTING SYMBOL: ',VOC(CHRNUM(STRSYM)))
                 (X(14),A(17),A(10));
       DO I=1 TO NUMPRD;
          LHS_ENT=VOC(CHRNUM(LHS(I)));
          DO J=1 TO 5;
             IF J>LENGTH(RHS(I)) THEN
                RHS_ENT(J)='';
             ELSE
                RHS_ENT(J)=VOC(CHRNUM(SUBSTR(RHS(I),J,1)));
          END;
          PUT FILE(LSTFIL) SKIP(1)
              EDIT(I,LHS_ENT,' -> ',(RHS_ENT(J) DO J=1 TO 5),';')
                 (F(4),X(01),A,A(04),5(A,X(01)),A(1));
       END;

       END  PRINT_PRODUCTIONS;


PRINT_VOCABULARY: PROC;
/*THIS ROUTINE IS RESPONSIBLE FOR PRINTING THE VOCABULARY. */
       DCL I BIN(15);          /* INDEXES */
       DCL J BIN(15);
       DCL NUM_LINES BIN(15);  /* MAXIMUM NUMBER OF LINES */
       DCL TRM_ENT CHAR(10) VARYING;
       DCL NTRM_ENT CHAR(10) VARYING;

/* DETERMINE MAX LENGTH FOR LOOP. */
       IF LENGTH(TRM)>LENGTH(NTRM) THEN
          NUM_LINES=LENGTH(TRM);
       ELSE
          NUM_LINES=LENGTH(NTRM);

/* OUTPUT THE HEADING. */
       ON ENDPAGE(LSTFIL)
          BEGIN;
             PUT FILE(LSTFIL) PAGE;
             PUT FILE(LSTFIL) SKIP(3)
                 EDIT('*** VOCABULARY LISTING ***','PAGE',
                       PAGENO(LSTFIL)-1)
                 (X(20),A(26),X(10),A(4),F(4));
             PUT FILE(LSTFIL) SKIP(1)
                 EDIT('TERMINALS','NON-TERMINALS')
                 (X(19),A(10),X(05),A(13));
             PUT FILE(LSTFIL) SKIP(1);
          END;
       SIGNAL ENDPAGE(LSTFIL);

/* PRINT THE REPORT LINES. */
       DO I=1 TO NUM_LINES;
          IF I>LENGTH(TRM) THEN        /* GET TERMINAL ENTRY.*/
             TRM_ENT='';
          ELSE
             TRM_ENT=VOC(CHRNUM(SUBSTR(TRM,I,1)));
          IF I>LENGTH(NTRM) THEN       /* GET NON-TERMINAL ENTRY.*/
             NTRM_ENT='';
          ELSE
             NTRM_ENT=VOC(CHRNUM(SUBSTR(NTRM,I,1)));
             PUT FILE(LSTFIL) SKIP(1)
                 EDIT(I,TRM_ENT,NTRM_ENT)
                 (X(14),F(4),X(01),A(10),X(05),A(10));
       END;

         END  PRINT_VOCABULARY;


SORT_VOCABULARY: PROC;
/*THIS ROUTINE IS RESPONSIBLE FOR SORTING THE VOCABULARY. */
/*IT SORTS:
               1) NON-TERMINAL VS TERMINAL
                  2) SYMBOL
/*THEN IT UPDATES ALL THE TABLES TO REFLECT THE NEW ORDER. */

       DCL I BIN(15);          /* INDEXES */
       DCL J BIN(15);
       DCL SORT_FLAG BIT(1);
       DCL 1 VOC_INDEX(254),   /* SORT INDEX FOR VOCABULARY */
           2 TRM_IND BIT(1),   /* 0=NON-TERMINAL 1=TERMINAL */
           2 SYM_LEN BIN(7),   /* SYMBOL LENGTH */
           2 ORIG CHAR;        /* ORIGINAL ORDER */
       DCL 1 TMP_INDEX,        /* TEMP AREA FOR BUBBLE SORT */
           2 TRM_IND BIT(1),   /* 0=NON-TERMINAL 1=TERMINAL */
           2 SYM_LEN BIN(7),   /* SYMBOL LENGTH */
           2 ORIG CHAR;        /* ORIGINAL ORDER */
       DCL TMP_VOC(254) CHAR(10) VARYING;
       DCL TMP_REORG(254) BIN(15);

/* BUILD SORT INDEX. */
       STRSYM=SUBSTR(NTRM,1,1); /*STARTING SYMBOL*/
       DO I=1 TO NUMVOC;
          VOC_INDEX.TRM_IND(I)=ISTRM(NUMCHR(I));
          VOC_INDEX.SYM_LEN(I)=LENGTH(VOC(I));
          VOC_INDEX.ORIG(I)=NUMCHR(I);
       END;

/* BUBBLE SORT THE INDEX. */
       SORT_FLAG=TRUE;
       DO WHILE(SORT_FLAG=TRUE);
          SORT_FLAG=FALSE;
          DO I=1 TO NUMVOC-1;
             IF VOC_INDEX.TRM_IND(I)=TRUE &
                VOC_INDEX.TRM_IND(I+1)=FALSE THEN
                DO;
                   TMP_INDEX=VOC_INDEX(I);
                   VOC_INDEX(I)=VOC_INDEX(I+1);
                   VOC_INDEX(I+1)=TMP_INDEX;
                   SORT_FLAG=TRUE;
                END;
             ELSE
                IF VOC_INDEX.TRM_IND(I)=VOC_INDEX.TRM_IND(I+1) THEN
                   IF VOC(CHRNUM(VOC_INDEX.ORIG(I))) >
                       VOC(CHRNUM(VOC_INDEX.ORIG(I+1))) THEN
                      DO;
                         TMP_INDEX=VOC_INDEX(I);
                         VOC_INDEX(I)=VOC_INDEX(I+1);
                         VOC_INDEX(I+1)=TMP_INDEX;
                         SORT_FLAG=TRUE;
                      END;
          END;
       END;

/* PUT THE VOCABULARY TABLE IN ORDER SPECIFIED BY THE SORT. */
       DO I=1 TO NUMVOC;
          TMP_VOC(I)=VOC(CHRNUM(VOC_INDEX.ORIG(I)));
       END;
       DO I=1 TO NUMVOC;
          VOC(I)=TMP_VOC(I);
       END;


/* PUT THE NON-TERMINAL TABLE IN ORDER SPECIFIED BY THE SORT. */
       NTRM='';
       DO I=1 TO NUMVOC;
          IF VOC_INDEX.TRM_IND(I)=FALSE THEN
             NTRM=NTRM || NUMCHR(I);
       END;

/* PUT THE TERMINAL TABLE IN ORDER SPECIFIED BY THE SORT. */
       TRM='';
       DO I=1 TO NUMVOC;
          IF VOC_INDEX.TRM_IND(I)=TRUE THEN
             TRM=TRM || NUMCHR(I);
       END;

/* TRANSLATE THE PRODUCTIONS ARRAY TO THE NEW INDEX. */
       DO I=1 TO NUMVOC;
          TMP_REORG(CHRNUM(VOC_INDEX.ORIG(I)))=I;
       END;
       DO I=1 TO NUMPRD;
          LHS(I)=NUMCHR(TMP_REORG(CHRNUM(LHS(I))));
          IF LENGTH(RHS(I))>0 THEN
             DO J=1 TO LENGTH(RHS(I));
                SUBSTR(RHS(I),J,1)=NUMCHR(TMP_REORG(CHRNUM(
                                   SUBSTR(RHS(I),J,1))));
             END;
       END;
       STRSYM=NUMCHR(TMP_REORG(CHRNUM(STRSYM))); /*STARTING SYMBOL*/

/* RETURN TO CALLER. */
         END  SORT_VOCABULARY;


/****************************************************************
* * * * * * * * * * * MAIN LINE PROCEDURE * * * * * * * * * * * *
****************************************************************/

/* DO INITIALIZATION. */
     PUT SKIP LIST('BEGINNING PHASE 2 PROCESSING.');

/* PRINT THE GRAMMAR. */
    CALL SORT_VOCABULARY;
    CALL PRINT_VOCABULARY;    /* PRINT THE VOCABULARY. */
    CALL PRINT_PRODUCTIONS;   /* PRINT THE PRODUCTIONS. */

/* RETURN TO CALLER. */
    PUT SKIP LIST('PHASE 2 PROCESSING COMPLETE - NO ERRORS.');
    END LL1P20;