APIs by Example: A Machine Interface (MI) Compiler

Article ID: 15575

In the last issue, I reported on a few sources for MI documentation. Several readers wrote to ask if I had a MI compiler that I could send them. I do indeed have a MI compiler, and I thought I'd share it with all of you.

Three items make up the compiler. They are:

* Command CrtMIPgm (Create MI Program)
This is the command used to create a MI program.

* CLLE program CrtMIPgmC
This is the command processing program for command CrtMIPgm. This program calls RPG program CrtMIPgmR to complete the process.

* RPG IV program CrtMIPgmR
This program is called by command processing program CrtMIPgmC and is used to set up and make the call to the Create Program (QPRCrtPg) API that creates the MI program.

Rather than spend pages documenting fully API QPRCrtPg, I hit the highlights. For the full documentation, visit

http://publib.boulder.ibm.com/iseries/v5r2/ic2924/info/apis/qprcrtpg.htm.

Let's begin with a look at the API's input parameter requirements.

* Intermediate representation of the program
This is a string (e.g., field, array) containing the MI source statements.

* Length of the intermediate representation of the program
This is the length of all the MI source statements combined.

* Qualified program name
This is the qualifed name to use for the compiled program. Special value *CURLIB is valid for the library portion.

* Program text
This short descriptive text is used as the program object's text attribute.

* Qualified source file name
This field is for informational purposes. The API doesn't use the values in this field to determine where to find the source used in creating the program. Rather, the API places the values in this field in the program object's service attributes that identify the source file used in creating the program (i.e., the source file information you see when you use DspObjD to display the program's object description). You can specify anything you wish for this field, valid or not! You are responsible for ensuring the integrity of this information. (By the way, special values sich as *LIBL for the library are not allowed.)

Special value *NONE for the source file name is supported and when used, the API doesn't place source file information in the service attributes of the object description.

* Source file member
Like the qualified source file name, this field is for informational purposes and you are responsible for its integrity. The API places this value in the program object's service attributes that identify the source member used in creating the program. This value must be blank if you specify *NONE for the qualified source file name.

* Source file last changed date and time
This is another field used for informational purposes. As with the previous two source information fields, you're responsible for the integrity of this field.

This field is of the format CYYMMDDHHMMSS and is placed in the program object's service attributes that identify the source member's last changed date and time. This value must be blank if you specify *NONE for the qualified source file name.

* Qualified printer file name
This is the qualifed name of the printer file used for listings generated by the API. Special values *CURLIB and *LIBL are valid for the library portion. If you specify *NOLIST in the option template parameter (discussed shortly), this parameter is ignored.

* Starting page number
This field determines the page number generated listings are to begin with. The default value is 1. If you specify *NOLIST in the option template parameter, this parameter is ignored.

* Public authority
This field defines the authority to give users that do not have specific private authorities, and where the user's group has no specific authority, to the object.

Valid values include special values *CHANGE, *ALL, *USE, *EXCLUDE or you can Specify an authorization list by name.

* Option template
This is an array of options used in creating the program. These options are optional (see how that works!) and you can specify up to 16 of them. These options control things such as whether to generate an executable program, whether to generate listings, and whether to optimize the program. There is considerable information on this options so I refer you to the previously mentioned online documentation for details.

* Number of option template entries
This is simply a count of the number of options specified in the option template parameter.

The API also has an optional parameter used as input/output - the standard API error structure.

Let's begin our look at the compiler with command CrtMIPgm as follows.

/*  ===============================================================  */
/*  = Command....... CrtMIPgm                                     =  */
/*  = Description... Create Machine Interface Program             =  */
/*  = CPP........... CrtMIPgmC                                    =  */
/*  = Source type... Cmd                                          =  */ 
/*  = Compile....... CrtCmd     Cmd(YourLib/CrtMIPgm)             =  */
/*  =                           Pgm(YourLib/CrtMIPgmC)            =  */
/*  =                           PrdLib(YourLib)                   =  */
/*  ===============================================================  */

             Cmd        Prompt( 'Create MI Program' )

             Parm       Kwd( Pgm )                                    +
                        Type( QPgm )                                  +
                        Min( 1 )                                      +
                        Prompt( 'Program' )

             Parm       Kwd( SrcFile )                                +
                        Type( QSrcFile )                              +
                        Prompt( 'Source file' )

             Parm       Kwd( SrcMbr )                                 +
                        Type( *Name )                                 +
                        Len( 10 )                                     +
                        Dft( *Pgm )                                   +
                        SpcVal(                                       +
                                ( *Pgm )                              +
                              )                                       +
                        Expr( *Yes )                                  +
                        Prompt( 'Source member' )

             Parm       Kwd( Text )                                   +
                        Type( *Char )                                 +
                        Len( 50 )                                     +
                        Dft( *SrcMbrTxt )                             +
                        SpcVal(                                       +
                                ( *SrcMbrTxt )                        +
                              )                                       +
                        Expr( *Yes )                                  +
                        Prompt( 'Text ''description''' )

             Parm       Kwd( UsrPrf )                                 +
                        Type( *Name )                                 +
                        Len( 10 )                                     +
                        Rstd( *Yes )                                  +
                        Dft( *User )                                  +
                        SpcVal(                                       +
                                ( *User )                             +
                                ( *Adopt )                            +
                                ( *Owner )                            +
                              )                                       +
                        Expr( *Yes )                                  +
                        PmtCtl( *PmtRqs )                             +
                        Prompt( 'User profile' )

             Parm       Kwd( Replace )                                +
                        Type( *Char )                                 +
                        Len( 10 )                                     +
                        Rstd( *Yes )                                  +
                        Dft( *Yes )                                   +
                        SpcVal(                                       +
                                ( *Yes *Replace )                     +
                                ( *No *NoReplace )                    +
                              )                                       +
                        Expr( *Yes )                                  +
                        PmtCtl( *PmtRqs )                             +
                        Prompt( 'Replace program' )

             Parm       Kwd( Aut )                                    +
                        Type( *Name )                                 +
                        Len( 10 )                                     +
                        Dft( *LibCrtAut )                             +
                        SpcVal(                                       +
                                ( *LibCrtAut )                        +
                                ( *Change )                           +
                                ( *All )                              +
                                ( *Use )                              +
                                ( *Exclude )                          +
                              )                                       +
                        Expr( *Yes )                                  +
                        PmtCtl( *PmtRqs )                             +
                        Prompt( 'Authority' )

             Parm       Kwd( GenOpt )                                 +
                        Type( *Char )                                 +
                        Len( 11 )                                     +
                        Dft(  )                                       +
                        Rstd( *Yes )                                  +
                        SpcVal(                                       +
                                ( *Gen )                              +
                                ( *NoGen )                            +
                                ( *NoList )                           +
                                ( *List )                             +
                                ( *NoXRef )                           +
                                ( *XRef )                             +
                                ( *NoAtr )                            +
                                ( *Atr )                              +
                                ( *AdpAut )                           +
                                ( *NoAdpAut )                         +
                                ( *SubScr )                           +
                                ( *NoSubScr )                         +
                                ( *UnCon )                            +
                                ( *SubStr )                           +
                                ( *NoSubStr )                         +
                                ( *ClrPSSA )                          +
                                ( *NoClrPSSA )                        +
                                ( *ClrPASA )                          +
                                ( *NoClrPASA )                        +
                                ( *NoIgnDec )                         +
                                ( *IgnDec )                           +
                                ( *NoIgnBin )                         +
                                ( *IgnBin )                           +
                                ( *NoOverlap )                        +
                                ( *Overlap )                          +
                                ( *NoDup )                            +
                                ( *Dup )                              +
                                ( *Opt )                              +
                                ( *NoOpt )                            +
                              )                                       +
                        Max( 14 )                                     +
                        Expr( *Yes )                                  +
                        PmtCtl( *PmtRqs )                             +
                        Prompt( 'Generation options' )

QPgm:        Qual       Type( *Name )                                 +
                        Len( 10 )                                     +
                        Min( 1 )                                      +
                        Expr( *Yes )

             Qual       Type( *Name )                                 +
                        Len( 10 )                                     +
                        Dft( *CurLib )                                +
                        SpcVal(                                       +
                                ( *CurLib )                           +
                              )                                       +
                        Expr( *Yes )                                  +
                        Prompt( 'Library' )

QSrcFile:    Qual       Type( *Name )                                 +
                        Len( 10 )                                     +
                        Dft( QMISrc )                                 +
                        Expr( *Yes )

             Qual       Type( *Name )                                 +
                        Len( 10 )                                     +
                        Dft( *LibL )                                  +
                        SpcVal(                                       +
                                ( *LibL )                             +
                                ( *CurLib )                           +
                              )                                       +

                        Expr( *Yes )                                  +
                        Prompt( 'Library' )

Comparing the command's parameters to API QPRCrtPg's aforementioned input requirements shows that many of the API's parameters come directly from command CrtMIPgm. Command CrtMIPgm does not let you specify the following parameters required by QPRCrtPG:

* Intermediate representation of the program
The MI source statements you present to API QPCrtPg are simply a string that can be derived any way you wish (e.g., field contents, array contents). The CrtMIPgm utility, however, requires that you place the MI statements in a source file.

* Length of the intermediate representation of the program
This is a calculated value.

* Source file last changed date and time
CrtMIPgm retrieves this information from the source file member used to create the program.

* Qualified printer file name
For simplicity's sake, the utility always uses print file QsysPrt.

* Starting page number
For simplicity's sake, the utility always starts generated listings on page 1.

* Number of option template entries
This is a calculated value.

* API error structure
This structure is internal to the programs used by CrtMIPgm.

You may also notice that I mentioned you could specify up to 16 generation options in the option template parameter, but that command CrtMIPgm allows a maximum of 14. The command specifies an individual parameter for two of the these options, UsrPrf (user profile) and Replace (replace program). Program CrtMIPgmR adds the UsrPrf and Replace parameters to the option template before calling API QPRCrtPg.

Command processing program CrtMIPgmC is a CLLE program that runs in a new activation group. CrtMIPgmC follows.

/*  ===============================================================  */
/*  = Program....... CrtMIPgmC                                    =  */
/*  = Description... Create Machine Interface Program             =  */
/*  =                Command processing program for CrtMIPgm      =  */ 
/*  = Source type... CLLE                                         =  */
/*  = Compile ...... CrtBndCL   Pgm(YourLib/CrtMIPgmC)            =  */
/*  =                           DftActGrp(*No)                    =  */
/*  =                           ActGrp(*New)                      =  */
/*  ===============================================================  */

Pgm                                                                   +
(                                                                     +

  &Pgm                                                                +
  &SrcFile                                                            +
  &SrcMbr                                                             +
  &Text                                                               +
  &UsrPrf                                                             +
  &Replace                                                            +
  &Aut                                                                +
  &GenOpt                                                             +
)

/*  ===============================================================  */
/*  = Declarations                                                =  */
/*  ===============================================================  */

  Dcl        &Pgm         *Char     (   20    )
  Dcl        &SrcFile     *Char     (   20    )
  Dcl        &SrcMbr      *Char     (   10    )
  Dcl        &Text        *Char     (   50    )
  Dcl        &UsrPrf      *Char     (   10    )
  Dcl        &Replace     *Char     (   10    )
  Dcl        &Aut         *Char     (   10    )
  Dcl        &GenOpt      *Char     (  156    )
  Dcl        &PgmNm       *Char     (   10    )
  Dcl        &PgmLib      *Char     (   10    )
  Dcl        &SrcFileNm   *Char     (   10    )
  Dcl        &SrcFileLib  *Char     (   10    )
  Dcl        &SrcChgDate  *Char     (   13    )
  Dcl        &CurText     *Char     (   50    )
  Dcl        &NbrCurRcd   *Dec      (   10  0 )
  Dcl        &ErrorFlag   *Lgl
  Dcl        &MsgID       *Char     (    7    )
  Dcl        &MsgDta      *Char     (  256    )
  Dcl        &MsgF        *Char     (   10    )
  Dcl        &MsgFLib     *Char     (   10    )

/*  ===============================================================  */
/*  = Global error monitor                                        =  */
/*  ===============================================================  */

  MonMsg     ( CPF0000 MCH0000 ) Exec(                                +
    GoTo     Error                   )

/*  ===============================================================  */
/*  = Initialization                                              =  */
/*  ===============================================================  */

  ChgVar     ( &PgmNm )   ( %Sst( &Pgm  1 10 ) )
  ChgVar     ( &PgmLib )  ( %Sst( &Pgm 11 10 ) )

  ChgVar     ( &SrcFileNm )   ( %Sst( &SrcFile  1 10 ) )
  ChgVar     ( &SrcFileLib )  ( %Sst( &SrcFile 11 10 ) )

  If         ( &SrcMbr *Eq '*PGM' )                                   +
    ChgVar     ( &SrcMbr )  ( &PgmNm )

  RtvMbrD    File( &SrcFileLib/&SrcFileNm )                           +
             Mbr( &SrcMbr )                                           +
             SrcChgDate( &SrcChgDate )                                +
             Text( &CurText )                                         +
             NbrCurRcd( &NbrCurRcd )

  If         ( &Text *Eq '*SRCMBRTXT' )                               +
    ChgVar     ( &Text )  ( &CurText )

  If         ( &Aut *Eq '*LIBCRTAUT' )                                +
    Do
      RtvLibD    Lib( &PgmLib )                                       +
                 CrtAut( &Aut )
      If         ( &Aut *Eq '*SYSVAL' )                               +
        RtvSysVal  SysVal( QCrtAut )                                  +
                   RtnVar( &Aut )
    EndDo

/*  ===============================================================  */
/*  = Call program to create MI program                           =  */
/*  ===============================================================  */

  OvrPrtF    File( QSysPrt )                                          +
             SplFName( &PgmNm )                                       +
             OvrScope( *Job )

  Call       CrtMIPgmR                                                +
             (                                                        +
               &Pgm                                                   +
               &SrcFile                                               +
               &SrcMbr                                                +
               &Text                                                  +
               &UsrPrf                                                +
               &Replace                                               +
               &Aut                                                   +
               &GenOpt                                                +
               &SrcChgDate                                            +
               &NbrCurRcd                                             +
               &MsgID                                                 +
               &MsgDta                                                +
             )

  If         ( &MsgID *NE ' ' )                                       +
    SndPgmMsg  MsgID( &MsgID )                                        +
               MsgF( QCPFMsg )                                        +
               MsgDta( &MsgDta )                                      +
               ToPgmQ( *Same )                                        +
               MsgType( *Escape )

/*  ===============================================================  */
/*  = Exit program                                                =  */
/*  ===============================================================  */

  DltOvr     File( QSysPrt )                                          +
             Lvl( *Job )

  Return

/*  ===============================================================  */
/*  = Error routine                                               =  */
/*  ===============================================================  */

Error:

  If         ( &ErrorFlag )                                           +
    Return

  ChgVar     ( &ErrorFlag )  ( '1' )

  DltOvr     File( QSysPrt )                                          +
             Lvl( *Job )

  RcvMsg     MsgType( *Excp )                                         +
             MsgDta( &MsgDta )                                        +
             MsgID( &MsgID )                                          +
             MsgF( &MsgF )                                            +
             MsgFLib( &MsgFLib )
  MonMsg     ( CPF0000 MCH0000 )

SndMsg:

  SndPgmMsg  MsgID( &MsgID )                                          +
             MsgF( &MsgFLib/&MsgF )                                   +

             MsgDta( &MsgDta )                                        +
             MsgType( *Escape )
  MonMsg     ( CPF0000 MCH0000 )

EndPgm

Program CrtMIPgmC begins by initializing a few pieces of information including:

* Source member name
* Source change date and time
* Text
* Public authority

Next, the program overrides print file QsysPrt so that the spooled file name of any generated spooled file placed in an output queue will be the same as the program being created. This simplifies the act of locating any generated lists and is consistent with other program creation commands.

The program then calls RPG program CrtMIPgmR, whose job it is to construct the parameters required by API QPRCrtPg and then invoke the API. Notice that the final two parameters on the call to CrtMIPgmR are MsgID (message identifier) and MsgDta (message data). If the call to API QPRCrtPG fails, program CrtMIPgmR extracts the message identifier and the message data reported in the standard API structure and returns that information so that CrtMIPgmC can use it to report the error to the user.

The final program used in compiling an MI program, CrtMIPgmR, follows.

       //  =================================================================
       //  = Program....... CrtMIPgmR                                      =
       //  = Description... Create Machine Interface Program               =
       //  = Source type... RPGLE                                          =
       //  = Compile....... CrtBndRPG  Pgm(YourLib/CrtMIPgmR)              =
       //  =                           DftActGrp(*No)                      =
       //  =                           ActGrp(*Caller)                     =
       //  =================================================================

     FMISrc     IF   F   92        Disk    UsrOpn
     F                                     ExtFile( SrcF )
     F                                     ExtMbr( SrcMbr )

       //  =================================================================
       //  = Entry parameters                                              =
       //  =================================================================

     D EntryParms      Pr                  ExtPgm( 'CRTMIPGMR' )
     D  ParameterIn                  20
     D  ParameterIn                  20
     D  ParameterIn                  10
     D  ParameterIn                  50
     D  ParameterIn                  10
     D  ParameterIn                  10
     D  ParameterIn                  10
     D  ParameterIn                        LikeDS( GenOptInModel )
     D  ParameterIn                  13
     D  ParameterIn                  10P 0
     D  ParameterOut                  7
     D  ParameterOut                256

     D EntryParms      PI
     D  Pgm                          20
     D  SrcFile                      20
     D  SrcMbr                       10
     D  Text                         50
     D  UsrPrf                       10
     D  Replace                      10
     D  Aut                          10
     D  GenOptIn                           LikeDS( GenOptInModel )
     D  SrcChgDate                   13
     D  NbrCurRcd                    10P 0
     D  MsgID                         7
     D  MsgDta                      256

       //  =================================================================
       //  = Procedure prototypes                                          =
       //  =================================================================

     D CreateProgram   Pr                  ExtPgm( 'QPRCRTPG' )
     D  ParameterIn                  80    Dim( 32767 )
     D  ParameterIn                  10I 0
     D  ParameterIn                  20
     D  ParameterIn                  50
     D  ParameterIn                  20
     D  ParameterIn                  10
     D  ParameterIn                  13
     D  ParameterIn                  20
     D  ParameterIn                  10I 0
     D  ParameterIn                  10
     D  ParameterIn                 176
     D  ParameterIn                  10I 0
     D  ParameterIO                        LikeDS( StdErrorModel )

       //  =================================================================
       //  = Data definitions                                              =
       //  =================================================================

     D StdErrorModel   DS                  Qualified
     D                               10I 0 Inz( %Size( StdErrorModel ))
     D  BytesAvail                   10I 0 Inz( *Zero )
     D  MsgID                         7    Inz( *Blank )
     D                                1    Inz( X'00' )
     D  MsgDta                      256    Inz( *Blank )

     D GenOptInModel   DS                  Based( GenOptInModelPtr )
     D                                     Qualified
     D  NbrOpts                       5I 0
     D  Opt                         154

     D StdError        DS                  LikeDS( StdErrorModel )
     D                                     Inz( *LikeDS )

     D GenOpt          S            176
     D NbrGenOpts      S             10I 0

     D Src             S             80    Dim( 32767 )

     D SrcF            S             21
     D SrcLen          S             10I 0
     D PrtF            S             20    Inz( 'QSYSPRT   *LIBL' )
     D StrPage         S             10I 0 Inz( 1 )
     D Pos             S              3I 0
     D Index           S              5I 0

     IMISrc     NS
     I                                 13   92  SrcInfo

      /Free

       //  =================================================================
       //  = Open source file                                              =
       //  =================================================================

           SrcF = %Trim( %Subst( SrcFile : 11 : 10 ) ) +
                  '/'                                  +
                  %Trim( %Subst( SrcFile : 1 : 10 ) ) ;

           Open MISrc ;

       //  =================================================================
       //  = Set parameters for API to create program                      =
       //  =================================================================

           SrcLen = NbrCurRcd * 80 ;

           Pos = ( GenOptIn.NbrOpts * 11 ) ;
           If GenOptIn.NbrOpts > *Zero ;
             GenOpt = %Subst( GenOptIn.Opt : 1 : Pos ) ;
           EndIf ;
           Pos = Pos + 1 ;
           %Subst( GenOpt : Pos : 11 ) = Replace ;
           Pos = Pos + 11 ;
           %Subst( GenOpt : Pos : 11 ) = UsrPrf ;

           NbrGenOpts = GenOptIn.NbrOpts + 2 ;

       //  =================================================================
       //  = Load source to instruction stream parameter                   =
       //  =================================================================

           Read MISrc ;
             DoW Not( %EOF( MISrc ) ) ;
               Index = Index + 1 ;
               Src( Index ) = SrcInfo ;
               Read MISrc ;
             EndDo ;

       //  =================================================================
       //  = Close source file                                             =
       //  =================================================================

           Close MISrc ;

       //  =================================================================
       //  = Call API to create the MI program                             =
       //  =================================================================

           CreateProgram
           (
             Src        :
             SrcLen     :
             Pgm        :
             Text       :
             SrcFile    :
             SrcMbr     :
             SrcChgDate :
             PrtF       :
             StrPage    :
             Aut        :
             GenOpt     :
             NbrGenOpts :
             StdError
           ) ;

           If StdError.BytesAvail <> *Zero ;
             MsgID = StdError.MsgID ;
             MsgDta = StdError.MsgDta ;
           EndIf ;

           *InLR = *On ;

      /End-Free

The program begins with a file specification naming MISrc as an input file. This is a program described file used in reading your MI source member. The program actually opens the source file and member specified by the values in fields SrcF and SrcMbr that appear for the ExtFile (external file) and ExtMbr (external member) keywords, respectively. For simplicity's sake, I didn't allow for full flexibility in the size of the source record - it just didn't seem necessary. The source file record should be 92 bytes in size (the default). This gives you 80 bytes of source data per record.

After defining the entry parameters, the program defines the procedure prototype type for API QPRCrtPG. Notice that the first parameter is defined as 80 bytes in length (remember, that's the source data length) and is defined as an array with a dimension of 32767. The elements in this array will contain the source statements with each element being a record in the source file. If you need more than 32767 records for a single MI program, chances are you've missed the point in your design!

Next, appear the data definitions. They're straightforward and need no discussion.

Finally, we come to the processing. The basic steps are as follows:

  1. Open the source file.
  2. Initialize the source length, generation option template, and number of generation options parameters needed by API QPRCrtPg.
  3. Read source file and store source records in the array passed to API QPRCrtPg.
  4. Close the source file.
  5. Call API QPRCrtPg to create the program and if the API returns an error condition, report that condition to the caller by setting the MsgID and MsgDta parameter values.

ProVIP Sponsors

ProVIP Sponsors