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: