z/OS ISPF Software Configuration and Library Manager Guide and Reference
Previous topic | Next topic | Contents | Contact z/OS | Library | PDF


Telling SCLM how to invoke your parser

z/OS ISPF Software Configuration and Library Manager Guide and Reference
SC19-3625-00

You need to add a few SCLM macros to your project definition for SCLM to invoke your parser. The macros used to define the SKELS parser are shown in Figure 1 For your parser, you need:
  • An FLMLANGL to define your language (if it is not already there)
  • An FLMTRNSL to define your parser
  • An FLMALLOC for each ddname required by your parser
  • An FLMCPYLB for each data set name you want to specify.
In Figure 1 you can examine the keywords on the macros to see how they are used.

On the FLMLANGL macro, the LANG parameter indicates the string (in this case it is SKELS) that needs to be given to SCLM when you want SCLM to treat a module like a skeleton. The BUFSIZE parameter is the number of elements in the LIST_INFO array that SCLM passes to the parser.

On the FLMTRNSL macro, the COMPILE and DSNAME parameter tell SCLM that the parser can be found in SCLM.PROJECT.LOAD(FLM@SKLS). The OPTIONS parameter contains three SCLM variables: @@FLMSTP, @@FLMLIS, and @@FLMSIZ. When the parser converts the character string values of @@FLMLIS and @@FLMSTP to fullword binary integers, the result is the addresses of the LIST_INFO array and the STATS_INFO structure, respectively. The value of @@FLMSIZ is the number of bytes allocated for the LIST_INFO array.

The first FLMALLOC macro allocates the module to be parsed to ddname SSOURCE. The SKELS parser looks at this ddname for the skeleton source. The second FLMALLOC macro allocates an error listings file. If an error occurs during the parse, the SKELS parser writes an explanatory message and provides a recommended solution. If the SKELS parser passes back a return code greater than that specified on the GOODRC parameter of the FLMTRNSL macro, the contents of this listings file are written to the edit listings file for the parse. This is how you can pass messages and information about the parse to your users.

Figure 1. SKELS Parser Definition
/*********************************************************************/
/* ISPF SKELETON LANGUAGE DEFINITION                                 */
/*********************************************************************/
         FLMLANGL    LANG=SKEL,VERSION=V2.3,BUFSIZE=50

  PARSER TRANSLATOR

          FLMTRNSL   CALLNAM='SKEL PARSER',                            C
               COMPILE=FLM@SKLS,                                       C
               DSNAME=SCLM.PROJECT.LOAD,                               C
               FUNCTN=PARSE,                                           C
               PORDER=1,                                               C
               GOODRC=0,                                               C
               VERSION=V1R0M0,                                         C
               OPTIONS='/@@FLMSTP,@@FLMLIS,@@FLMSIZ,'
           (* SOURCE      *)
           FLMALLOC IOTYPE=A,DDNAME=SSOURCE
           FLMCPYLB @@FLMDSN(@@FLMMBR)
           (* LISTING     *)
           FLMALLOC IOTYPE=W,RECFM=VBA,LRECL=133,                      C
               RECNUM=6000,DDNAME=ERROR,PRINT=Y
 
Figure 2. Parser for ISPF skeletons (Part 1 of 8)
 PROCESS;
 /********************************************************************/
 /***                                                              ***/
 /***  Program:   PSKELS                                           ***/
 /***                                                              ***/
 /***  Purpose:   Performs an SCLM parse of ISPF skeletons after   ***/
 /***             SCLM edit and during migration of source to SCLM.***/
 /***                                                              ***/
 /***  Inputs:    A parameter list containing addresses of a       ***/
 /***             structure and a variable-length array into which ***/
 /***             parse information is placed.  The length of the  ***/
 /***             array, in bytes, is also passed.                 ***/
 /***                                                              ***/
 /***             In addition, source from the member to be parsed ***/
 /***             is read from ddname SSOURCE.                     ***/
 /***                                                              ***/
 /***  Outputs:   The structure and array are filled with parse    ***/
 /***             information by this program.  Any error messages ***/
 /***             are written to ddname ERROR.                     ***/
 /***                                                              ***/
 /***  Retcode:   A fullword integer value, indicating the overall ***/
 /***             success of the parse, is returned in register 15.***/
 /***                                                              ***/
 /***             0 = Successful parse; parse information is       ***/
 /***                 returned in the structure and array.         ***/
 /***                                                              ***/
 /***             4 = Variable-length array was too small to hold  ***/
 /***                 all of the parsed information.  Not all      ***/
 /***                 information was passed back to SCLM.  The    ***/
 /***                 number of elements needed is shown in the    ***/
 /***                 listings data set.                           ***/
 /***                                                              ***/
 /***                 To correct this problem, either:             ***/
 /***                                                              ***/
 /***                   * Increase the value of BUFSIZE in the     ***/
 /***                     FLMLANGL macro for this parser, or       ***/
 /***                                                              ***/
 /***                   * Break the skeleton being parsed into     ***/
 /***                     smaller skeletons and use )IM to join    ***/
 /***                     them back together.                      ***/
 /***                                                              ***/
 /***  Logic:     1) Obtain addresses of structure and array from  ***/
 /***                parameter list.                               ***/
 /***             2) Initialize counters in structure.             ***/
 /***             3) For each line of skeleton source:             ***/
 /***                a) Increment appropriate counters.            ***/
 /***                b) If record starts with )IM, find and save   ***/
 /***                   imbedded skeleton name.                    ***/
 /***                c) Scan the record for variable names and     ***/
 /***                   save in a program array any new names.     ***/
 /***                d) If record starts with )DEFAULT, get new    ***/
 /***                   '&' and ')' characters.                    ***/
 /***             4) Calculate summary statistics.                 ***/
 /***             5) Write an 'END ' element to end of parse array.***/
 /***             6) Return.                                       ***/
 /***                                                              ***/
 /********************************************************************/
 
Figure 3. Parser for ISPF skeletons (Part 2 of 8)
 PSKELS: PROC(PARMLIST) OPTIONS(MAIN);
    DCL PARMLIST     CHAR(255) VAR; /* Parameter list                */
    DCL PARMLISTx    CHAR(255) VAR; /* Copy of the parameter list    */
    DCL PAREN        CHAR(1),       /* Contains ')' special char     */
        NAME         CHAR(8),       /* Contains a referenced name    */
        NAMECHRS     CHAR(39),      /* Valid name characters         */
        RECORD       CHAR(80),      /* Output buffer for error list  */
        STAT_PTR     POINTER,       /* Points to stats structure     */
        LIST_PTR     POINTER,       /* Points to parse array         */
        NON_COM_READ BIT(1),        /* Prolog flag                   */
        EOF          BIT(1),        /* End-of-file flag              */
        (I,J,K)      FIXED BIN(31), /* Simple counters               */
        USED_ELMTS   FIXED BIN(31), /* Number of parse array         */
                                    /*    elements used so far       */
        LISTLEN      FIXED BIN(31), /* Total number of available     */
                                    /*    parse array elements       */
        RETCODE      FIXED BIN(31); /* Return code                   */
    DCL ADDR         BUILTIN,
        INDEX        BUILTIN,
        LENGTH       BUILTIN,
        MIN          BUILTIN,
        REPEAT       BUILTIN,
        SUBSTR       BUILTIN,
        VERIFY       BUILTIN,
        PLIRETC      BUILTIN;
    DCL SSOURCE      FILE STREAM INPUT;
    DCL ERROR        FILE STREAM PRINT;
    DCL FXB_OV       FIXED BIN(31), /* Fullword integer              */
        PTR_OV       POINTER BASED(ADDR(FXB_OV));
                                    /* Pointer variable overlay on   */
                                    /*    top of a fullword integer  */
                                    /*    variable                   */
    %INCLUDE(STATINFO);
    %INCLUDE(LISTINFO);
    RETCODE = 0;
    CALL GETPTRS;
    CALL INITIAL;
    CALL PARSE;
    CALL WRAPUP;
    CALL PLIRETC(RETCODE);
 
Figure 4. Parser for ISPF skeletons (Part 3 of 8)
 GETPTRS: PROC;
 /********************************************************************/
 /***                                                              ***/
 /***  Routine:   GETPTRS                                          ***/
 /***                                                              ***/
 /***  Purpose:   Converts the information passed to this program  ***/
 /***             into addresses and array length information.     ***/
 /***                                                              ***/
 /***  Inputs:    A varying length string containing parameters in ***/
 /***             the following format:                            ***/
 /***                                                              ***/
 /***               '<stat_ptr>,<list_ptr>,<length>,'              ***/
 /***                                                              ***/
 /***                  where stat_ptr is the EBCDIC representation ***/
 /***                                 of the address of the static ***/
 /***                                 portion of the account       ***/
 /***                                 record for this member,      ***/
 /***                        list_ptr is the EBCDIC representation ***/
 /***                                 of the address of the        ***/
 /***                                 dynamic portion of the       ***/
 /***                                 account record, and          ***/
 /***                        length   is the number of bytes       ***/
 /***                                 allocated to the dynamic     ***/
 /***                                 portion of the account       ***/
 /***                                 record.  This value is equal ***/
 /***                                 to 228 times the number of   ***/
 /***                                 elements in that array.      ***/
 /***                                                              ***/
 /***             Note that this format is consistent with the     ***/
 /***             OPTIONS keyword on the FLMTRNSL macro that       ***/
 /***             specifies how to invoke this parser.             ***/
 /***                                                              ***/
 /***  Outputs:   The three variables, STAT_PTR, LIST_PTR and      ***/
 /***             LISTLEN are set from the values in the           ***/
 /***             parameter list.                                  ***/
 /***                                                              ***/
 /***  Logic:     1) Find the first comma.                         ***/
 /***             2) Convert the contents of the character string  ***/
 /***                before that comma into integer format.  For   ***/
 /***                example, the string '19,' would be converted  ***/
 /***                into an integer (X'00000013')                 ***/
 /***             3) Find the next comma.                          ***/
 /***             4) Convert the contents of the character string  ***/
 /***                before that comma into integer format.        ***/
 /***             5) Find the last comma.                          ***/
 /***             6) Convert the contents of the character string  ***/
 /***                before that comma into integer format.        ***/
 /***                                                              ***/
 /***  Note:      We take advantage of PL/I's ability to convert   ***/
 /***             a number in character string format into a       ***/
 /***             fullword binary value.                           ***/
 /***                                                              ***/
 /********************************************************************/
    PARMLISTX = PARMLIST;
    I = INDEX(PARMLIST,',');
    FXB_OV = SUBSTR(PARMLIST,1,I-1);
    STAT_PTR = PTR_OV;
    PARMLIST = SUBSTR(PARMLIST,I+1,LENGTH(PARMLIST)-I);
 
Figure 5. Parser for ISPF skeletons (Part 4 of 8)
    I = INDEX(PARMLIST,',');
    FXB_OV = SUBSTR(PARMLIST,1,I-1);
    LIST_PTR = PTR_OV;
    PARMLIST = SUBSTR(PARMLIST,I+1,LENGTH(PARMLIST)-I);

    I = INDEX(PARMLIST,',');
    LISTLEN = SUBSTR(PARMLIST,1,I-1);
    LISTLEN = LISTLEN / 228;
 END GETPTRS;
 INITIAL: PROC;
 /********************************************************************/
 /***                                                              ***/
 /***  Routine:   INITIAL                                          ***/
 /***                                                              ***/
 /***  Purpose:   Initializes the counters and variables to be     ***/
 /***             used during the parse.                           ***/
 /***                                                              ***/
 /***  Inputs:    None.                                            ***/
 /***                                                              ***/
 /***  Outputs:   Initialized variables.                           ***/
 /***                                                              ***/
 /********************************************************************/
    STATINFO.LINES.TOTAL      = 0; /* # of lines in the skeleton     */
    STATINFO.LINES.COMMENT    = 0; /* # of lines starting with )CM   */
    STATINFO.LINES.NON_COMMENT= 0; /* # lines not starting w/ )CM    */
    STATINFO.LINES.BLANK      = 0; /* # lines starting with )BLANK   */
    STATINFO.LINES.PROLOG     = 0; /* # lines before 1st noncomment  */
       /**/
    STATINFO.STMTS.TOTAL      = 0; /* = LINES.TOTAL                  */
    STATINFO.STMTS.COMMENT    = 0; /* = LINES.COMMENT                */
    STATINFO.STMTS.CONTROL    = 0; /* # of lines starting with )     */
    STATINFO.STMTS.ASSIGNMENT = 0; /* = 0                            */
    STATINFO.STMTS.NON_COMMENT= 0; /* = LINES.NON_COMMENT            */
       /**/
    USED_ELMTS = 0;
       /**/
    NAMECHRS   = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$';
    PAREN = ')';
 END INITIAL;
 PARSE: PROC;
 /********************************************************************/
 /***                                                              ***/
 /***  Routine:   PARSE                                            ***/
 /***                                                              ***/
 /***  Purpose:   Parses the skeleton and places the result in the ***/
 /***             account record structures whose addresses were   ***/
 /***             passed to the program.                           ***/
 /***                                                              ***/
 /***  Inputs:    Skeleton source from ddname SSOURCE.             ***/
 /***                                                              ***/
 /***  Outputs:   Parse results in structure STAT_INFO and array   ***/
 /***             LIST_INFO.                                       ***/
 /***                                                              ***/
 /***  Logic:     1) Read each record of the skeleton.  For each   ***/
 /***                line read, increment the appropriate          ***/
 /***                counters.                                     ***/
 /***                                                              ***/
 /********************************************************************/
 
Figure 6. Parser for ISPF skeletons (Part 5 of 8)
    OPEN FILE(SSOURCE);
    EOF = '0'B;
    NON_COM_READ = '0'B;
    ON ENDFILE(SSOURCE) EOF = '1'B;
    GET FILE(SSOURCE) EDIT(RECORD) (A(80));
    DO WHILE (¬EOF);
 /********************************************************************/
 /***  Perform this loop for each record in the skeleton.          ***/
 /********************************************************************/
 /***  Increment total line counter.                               ***/
 /********************************************************************/
       STATINFO.LINES.TOTAL = STATINFO.LINES.TOTAL + 1;
 /********************************************************************/
 /***  If the line starts with )IM, save the name of the           ***/
 /***  imbedded member in LIST_INFO in an 'INCL' array element.    ***/
 /********************************************************************/
       IF SUBSTR(RECORD,1,3) = PAREN ││ 'IM' THEN
         DO;
           CALL GETNAME;
           USED_ELMTS = USED_ELMTS + 1;
           IF USED_ELMTS < LISTLEN THEN
             DO;
               LISTINFO(USED_ELMTS).TYPE = 'INCL';
               LISTINFO(USED_ELMTS).DATA = NAME;
             END;
           ELSE;
         END;
       ELSE;
 /********************************************************************/
 /***  If the line starts with )DOT, save the name of the          ***/
 /***  referenced table in LIST_INFO in a 'USER' array element.    ***/
 /********************************************************************/
       IF SUBSTR(RECORD,1,4) = PAREN ││ 'DOT' THEN
         DO;
           CALL GETNAME;
           USED_ELMTS = USED_ELMTS + 1;
           IF USED_ELMTS < LISTLEN THEN
             DO;
               LISTINFO(USED_ELMTS).TYPE = 'USER';
               LISTINFO(USED_ELMTS).DATA = 'TABLE: ' ││ NAME;
             END;
           ELSE;
         END;
       ELSE;
 /********************************************************************/
 /***  If the line starts with )CM, increment the comment          ***/
 /***  counter.  Otherwise, increment the non-comment counter.     ***/
 /********************************************************************/
       IF SUBSTR(RECORD,1,3) = PAREN ││ 'CM' THEN
         STATINFO.LINES.COMMENT = STATINFO.LINES.COMMENT + 1;
       ELSE
         STATINFO.LINES.NON_COMMENT = STATINFO.LINES.NON_COMMENT + 1;
 
Figure 7. Parser for ISPF skeletons (Part 6 of 8)
 /********************************************************************/
 /***  If the line starts with )BLANK, increment the blank line    ***/
 /***  counter.                                                    ***/
 /********************************************************************/
       IF SUBSTR(RECORD,1,6) = PAREN ││ 'BLANK' THEN
         STATINFO.LINES.BLANK = STATINFO.LINES.BLANK + 1;
       ELSE;
 /********************************************************************/
 /***  If the line starts with ), increment the control            ***/
 /***  statement counter.                                          ***/
 /***                                                              ***/
 /***  If the line does not start with ), increment the data       ***/
 /***  line counter.                                               ***/
 /***                                                              ***/
 /***  If this is the first data line, then we have reached the end***/
 /***  of the prolog (defined here as the comment lines before the ***/
 /***  first data line).  Set the prolog count to the number of    ***/
 /***  comments read so far.                                       ***/
 /********************************************************************/
       IF SUBSTR(RECORD,1,1) = PAREN THEN
         STATINFO.STMTS.CONTROL = STATINFO.STMTS.CONTROL + 1;
       ELSE
         DO;
           IF ¬NON_COM_READ THEN
             DO;
               STATINFO.LINES.PROLOG = STATINFO.LINES.COMMENT;
               NON_COM_READ = '1'B;
             END;
           ELSE;
         END;
 /********************************************************************/
 /***  If this line starts with )DEFAULT, then the special         ***/
 /***  character (the left parenthesis) for control cards might    ***/
 /***  have changed.  Get the new character.                       ***/
 /********************************************************************/
       IF SUBSTR(RECORD,1,8) = PAREN ││ 'DEFAULT' THEN
         DO;
           I = VERIFY(SUBSTR(RECORD,9,72),' ') + 8;
           PAREN = SUBSTR(RECORD,I,1);
         END;
       ELSE;
 /********************************************************************/
 /***  End of parse-a-line loop.  If there's another line, read it ***/
 /***  and go back through the loop.                               ***/
 /********************************************************************/
       GET FILE(SSOURCE) EDIT(RECORD) (A(80));
    END;
    CLOSE FILE(SSOURCE);
 /********************************************************************/
 /***  If there were no non-comment lines, then set the number of  ***/
 /***  prolog lines to the number of comment lines.                ***/
 /********************************************************************/
    IF ¬NON_COM_READ THEN
      STATINFO.LINES.PROLOG = STATINFO.LINES.COMMENT;
    ELSE;
 END PARSE;
 
Figure 8. Parser for ISPF skeletons (Part 7 of 8)
 GETNAME: PROC;
 /********************************************************************/
 /***                                                              ***/
 /***  Routine:   GETNAME                                          ***/
 /***                                                              ***/
 /***  Purpose:   Returns the name specified on an )IM or )DOT     ***/
 /***             statement.                                       ***/
 /***                                                              ***/
 /***  Inputs:    An 80-byte record in variable RECORD.            ***/
 /***                                                              ***/
 /***  Outputs:   The 8-byte name in variable NAME.                ***/
 /***                                                              ***/
 /***  Logic:     1) Find the first blank after the )IM or )DOT.   ***/
 /***             2) Find the next nonblank after that blank.     ***/
 /***             3) Move that nonblank and the next 7 bytes into ***/
 /***                variable NAME.                                ***/
 /***                                                              ***/
 /********************************************************************/
    I = INDEX(RECORD,' ');
    I = VERIFY(SUBSTR(RECORD,I,81-I),' ') + I - 1;
    NAME = SUBSTR(RECORD,I,8);
 END GETNAME;

 WRAPUP: PROC;
 /********************************************************************/
 /***                                                              ***/
 /***  Routine:   WRAPUP                                           ***/
 /***                                                              ***/
 /***  Purpose:   Saves the last of the parse information in the   ***/
 /***             SCLM structures and outputs error messages to    ***/
 /***             the listing file if the LIST_INFO array was not  ***/
 /***             large enough to hold all of the information.     ***/
 /***                                                              ***/
 /***  Inputs:    None.                                            ***/
 /***                                                              ***/
 /***  Outputs:   More data in LIST_INFO and STAT_INFO.            ***/
 /***                                                              ***/
 /***  Logic:     1) Calculate summary information.                ***/
 /***             2) Write an 'END ' element to LIST_INFO.         ***/
 /***             3) If there was not enough room in LIST_INFO,    ***/
 /***                write out messages that describe the error    ***/
 /***                and that indicate how to solve the problem.   ***/
 /***                                                              ***/
 /********************************************************************/
    STATINFO.STMTS.TOTAL       = STATINFO.LINES.TOTAL;
    STATINFO.STMTS.COMMENT     = STATINFO.LINES.COMMENT;
    STATINFO.STMTS.NON_COMMENT = STATINFO.LINES.NON_COMMENT;
 
Figure 9. Parser for ISPF skeletons (Part 8 of 8)
    /**/
    /*   WRITE AN END ELEMENT TO LIST ARRAY                          */
    /**/
    USED_ELMTS = USED_ELMTS + 1;
    IF USED_ELMTS < LISTLEN THEN
      DO;
        LISTINFO(USED_ELMTS).TYPE = 'END ';
        LISTINFO(USED_ELMTS).DATA = ' ';
      END;
    ELSE
      DO;
        OPEN FILE(ERROR);
            /**/
        PUT FILE(ERROR) SKIP LIST(
                 'ERROR: INFORMATION RESULTING FROM PARSE DOES NOT ' ││
                 'FIT IN PARSE ARRAYS.');
            /**/
        PUT FILE(ERROR) SKIP LIST(
                 '       PARSE ARRAY ELEMENTS:', LISTLEN);
            /**/
        PUT FILE(ERROR) SKIP LIST(
                 '       ELEMENTS NEEDED:     ', USED_ELMTS);
            /**/
        PUT FILE(ERROR) SKIP(2) LIST(
                 'FIX:   1) INCREASE BUFSIZE VALUE IN FLMLANGL MACRO,');
            /**/
        PUT FILE(ERROR) SKIP LIST(
                 '              - OR - ');
            /**/
        PUT FILE(ERROR) SKIP LIST(
                 '       2) BREAK THIS SKELETON UP INTO SMALLER ' ││
                 'SKELETONS AND IMBED THEM ');
            /**/
        PUT FILE(ERROR) SKIP LIST(
                 '          IN A NEW "TOP LEVEL" SKELETON ');
            /**/
        PUT FILE(ERROR) SKIP(2) LIST(
                 'PARAMETER LIST: ' ││ PARMLISTX);
            /**/
        LISTINFO(LISTLEN).TYPE = 'END ';
        LISTINFO(LISTLEN).DATA = ' ';
            /**/
        CLOSE FILE(ERROR);
            /**/
        RETCODE = 4;
      END;
 END WRAPUP;
 END PSKELS;
 
Figure 10. LISTINFO Module
 /*********************************************************************/
 /***                                                               ***/
 /***  LISTINFO Structure                                           ***/
 /***                                                               ***/
 /***  Maps the static portion of the account record.               ***/
 /***                                                               ***/
 /***  The number of elements declared for this array should not    ***/
 /***  be greater than the value specified on the BUFSIZE keyword   ***/
 /***  on the FLMLANGL macro.                                       ***/
 /***                                                               ***/
 /*********************************************************************/
    DCL 1 LISTINFO(50)      BASED(LIST_PTR),
          2 TYPE            CHAR(4),
          2 DATA            CHAR(224);
 
Figure 11. STATINFO Module
 /*********************************************************************/
 /***                                                               ***/
 /***  STATINFO Structure                                           ***/
 /***                                                               ***/
 /***  Maps the static portion of the account record.               ***/
 /***                                                               ***/
 /*********************************************************************/
    DCL 1 STATINFO          BASED(STAT_PTR),
          2 LINES,
            3 TOTAL         FIXED BIN(31),
            3 COMMENT       FIXED BIN(31),
            3 NON_COMMENT   FIXED BIN(31),
            3 BLANK         FIXED BIN(31),
            3 PROLOG        FIXED BIN(31),
          2 STMTS,
            3 TOTAL         FIXED BIN(31),
            3 COMMENT       FIXED BIN(31),
            3 CONTROL       FIXED BIN(31),
            3 ASSIGNMENT    FIXED BIN(31),
            3 NON_COMMENT   FIXED BIN(31);
 

Go to the previous page Go to the next page




Copyright IBM Corporation 1990, 2014