The CL for OS/400 is often called "command language" but its official name, perhaps showing its age, is "control language." It is, however, unlike any job control language of those legacy operating systems. CL was developed long after JCL and OCL and is a compiled language with program variables, error messages, and limited structured programming constructs, such as IF/THEN/ELSE and DO. Soon, IBM will introduce an incredible number of long overdue enhancements to CL.
CL has been around so long that most AS/400 and iSeries programmers know it like the back of their hand. So when IBM quietly introduced ILE CL six or seven years ago, most developers easily overlooked it. ILE CL--or more properly, CL for ILE--is simply a version of the CL compiler that targets the Integrated Language Environment.
Few enhancements were incorporated into the language in conjunction with the new compiler. IBM did the minimum necessary to get the compiler to be compatible. Even then, however, a few minor enhancements were required. It is these enhancements that allow CL for ILE to work effectively with your RPG IV and COBOL programs for ILE.
ILE Program Model
The CL compiler supports the ILE program model. This means that the CL compiler is a two-phase compiler (just like RPG IV). Phase I compiles the CL code, producing a *MODULE object. Phase II binds the CL module (possibly with other modules) and generates a *PGM object. Like RPG, COBOL, and CL, there is also a one-step compiler command (CRTBNDCL) that compiles the source into a *MODULE, storing it in QTEMP, then binds the module, producing a *PGM program--all by using option 14 on the PDM menu.
As with other ILE languages, a CL *MODULE object may be bound together with other non-CL ILE modules to create a program. For example, if an RPG IV program needs to run a few CL commands, just create an ILE CL source member that runs those CL commands, compile the CL source into a *MODULE, then bind that module with the RPG IV *MODULE object, creating a single program object.
Converting to ILE CL
As with most ILE languages, a new SEU attribute or source type has been introduced with CL for ILE. It is "CLLE." In fact, changing the old CLP source type to CLLE is all you need to do to convert an existing CL source member into an ILE CL source member.
The CL Compilers
And, as with the other ILE languages, PDM options 14 and 15 recognize this source type and evoke the necessary compilers. If PDM option 14 is selected on a source member whose source type is CLLE, the CRTBNDCL command is evoked, whereas a source type of CLP evokes the CRTCLPGM command. If PDM option 15 is selected for a source type of CLLE, the CRTCLMOD command is evoked. Option 15 is not allowed for source members with a source type of CLP.
The CRTCLMOD command compiles the CLLE source code and generates a *MODULE object. *MODULE objects, as you may know, cannot be called, but are used as input by the second phase of the compiler to produce program or service program objects.
The CRTPGM command uses one or more *MODULE objects and generates a *PGM program. The *MODULE objects may be from any ILE programming language: CLLE, RPGLE, C, etc.
The CRTSRVPGM command also uses one or more *MODULE objects as input but generates a *SRVPGM object. Although there is nothing wrong with doing so, it is rare that you use CL in a service program.
The CRTBNDCL command simplifies the CL program creation process by allowing a CLLE source member to be compiled to a *MODULE object then bound into a *PGM object. This one-step compiler command is tied into PDM option 14. This command, along with CRTBNDRPG, CRTBNDC, and CRTBNDCBL were created to provide a level of compatibility with the original CRTxxxPGM compiler (one source member to one program) commands.
So the steps in compiling a CL "program" can be as easy as PDM option 14 or as complex as the following:
CRTCLMOD MODULE(MYCLMOD2) SRCFILE(QCLSRC) DBGVIEW(*SOURCE)
CRTRPGMOD MODULE(MYRPGMOD3) SRCFILE(QRPGLESRC) DBGVIEW(*SOURCE)
CRTPGM PGM(MYPGM) MODULE(MYCLMOD1 MYCLMOD2 MYRPGMOD3) ACTGRP(QILE)
CL "programs" may be made up of modules from any ILE-based language; therefore, a program is really an ILE program, not a CL program. In the example above, I'm creating a *PGM object from two CL *MODULE objects and one RPG *MODULE object.
Language Syntax
The CL for ILE language syntax included few enhancements from the original CL compiler language. The most notable is the addition of the CALLPRC (call procedure) statement. CALLPRC allows you to call a procedure written in any ILE language. This means that any procedure written in RPG IV (or C for that matter) may be called using the CALLPRC statement.
The CALLPRC command is used just like the original CALL command; however, only bound-in procedures may be called with CALLPRC. In addition, CALLPRC includes the RTNVAL parameter. This parameter receives the return value from a procedure.
Unfortunately, CL for ILE does not include any additional data types. So character, decimal, and logical are the only data types that may be used. This can present a problem when calling procedures. If a procedure expects a parameter value in integer format ('I' data type in RPG IV), it must be passed as a character value and wrapped in the %BIN built-in function. For example:
0002 DCL VAR(&COUNTB) TYPE(*CHAR) LEN(4)
0003 CHARVAR VAR(%BIN(COUNTB)) VALUE(&COUNT)
0004 CALLPRC PRC(MYPROC) PARM(%BIN(&COUNTB))
On lines 1 and 2, two CL variables are declared. The first one is &COUNT, which is a 10-digit numeric value. The second one is &COUNTB, which is a 4-position character field. In order to copy the numeric value from &COUNT into &COUNTB as an integer value, the %BIN built-in function is used (line 3) with the CHGVAR command. If %BIN were not used, then the value of &COUNT would be copied into &COUNTB as a character value. So without %BIN, the value X'F0F0F0F6' would be copied to &COUNTB--instead of X'00000006', which is what is needed to represent the integer value.
Line 4 is the procedure call. Here, the &COUNTB variable is passed to the MYPROC procedure. Note that even though %BIN is used on line 3, it is again required on line 4 to represent the value in &COUNTB as a binary value.
The data types, *CHAR and *DEC, may be passed normally. Remember that *DEC is packed decimal format, not zoned numeric.
A Simple Example
I want to illustrate how to mix RPG IV and CL together to enhance CL with RPG-like functions. The example I chose answers a question I get a lot: "How do I get the day of the week from a CL date?" Answer: Use RPG IV.
Listed below, in Figure 1, is the CLLE source code for a CL module named MDTEST1.
|
Figure 1: CLLE Source Calling a Procedure (MDTEST1)
The CL source member listed in Figure 1 has one goal in life: to retrieve the job date and then calculate the day of the week. To do this, it retrieves the current job date, using RTVJOBA (line 7). Then, the job date is converted from *CYMD format to *ISO format (lines 8 and 9). This *ISO date is used to format a status message that is sent to the end user on lines 14 to 16.
To calculate the day of the week, rather than build a CL routine or call a command that I may not know about, I chose (for example purposes) to call a procedure written in RPG IV. The GetDayOfWeek procedure is called on lines 10 and 11. It accepts a character input value in *CYMD format. *CYMD, in case you haven't used it before, is the CL date format used in CL commands when sending date values to CL and RPG programs.
On line 11 the RTNVAL keyword is used to accept the integer return value. This value will represent the day of the week as a number. Since the return value is a "short" integer value, it is 2 bytes in length. Using %BIN(&COUNTB) ensures that the return value will be stored as a properly formatted "binary" value in the &COUNTB field.
On line 12, the returned value is converted into a decimal value by copying it with the CHGVAR command, again using %BIN in the VALUE parameter. In this case, the target variable is the decimal variable named &DAYOFWEEK.
Since we want to send a completion message to the end user, we need to use the day of the week in a concatenated string. Therefore, we cannot use it in numeric form. So on line 13, we convert the decimal value to character. Then finally, on lines 14 to 16, we build and send a completion messages to the end user.
The source for the GETDAYOFWEEK procedure is listed Figure 2.
|
Figure 2: RPG IV Procedure Source Called from CL
Note that there is only one procedure in the RPG IV source member and that its procedure is exported.
To compile the CL source in Figure 1 and the RPG IV source from Figure 2, use the following commands:
CRTRPGMOD MODULE(MDTEST2) SRCFILE(QRPGLESRC) DBGVIEW(*SOURCE)
CRTPGM PGM(MDTEST) MODULE(MDTEST1 MDTEST2) ACTGRP(QILE)
Note that since we didn't use the ENTMOD (entry module) keyword on the CRTPGM command, it defaulted to MDTEST1--that is, ENTMOD(*FIRST). That way, the CL module is what is loaded when the program is called.
I hope this helps clear up migration to ILE CL from traditional CL programs. Moving to ILE CL is important for file overrides and scoping. To use the advanced features in RPG IV (such as procedures), you need to compile RPG source members such that they do not run in the default activation group. Consequently, you also need to move any supporting CL programs to CL for ILE. Otherwise, all kinds of override issues and scoping problems could arise.
LATEST COMMENTS
MC Press Online