Site Map: Back to Utilities
Ten things about /free.
You have probably seen many happy articles touting /free and the advantages of /free. Well, welcome to the nitty gritty of converting existing code over to /free. We are going to discuss things those articles never mention, specifically the tasks involved in getting your current code converted over to /free.
This page will describe things I learned in the process of converting my utilities over to /free. It will also present a path, that will let you begin using and understanding /free based code and techniques. There will also be a tips section with some ideas and suggestions that can help you write better code. It also suggests several utilities from my page that you can use to facilitate converting your code into /free.
First things, the bad stuff, then I will move on to more constructive areas. Converting existing code to /free is not easy, in fact it can be extremely time consuming and difficult. There is no IBM supplied CVTRPGSRC-type command to convert your code. As we will note later, there are many things that CAN NOT be converted and must be rewritten. Consider this reply from IBM when I asked about conversion tools. "Craig, we didn't have any intention of making it easy to convert to /free. Our intention was that /free should mainly be used for new code, using the best coding methods possible. By making it easy to do a conversion, most people would have yet another version of their old RPG II and RPG III programs."
They got one part right, it isn’t easy. But it is also not impossible. It really depends on how the program is written that you wish to convert. That brings up another good point. Even if you don’t have v5r1 yet, you can still start using only the opcodes and techniques available in /free. It will make future conversions MUCH simpler.
Ok, don’t panic here. No opcodes are valid in /free. Just kidding. /Free did, however, drop a lot of opcodes. Some of the dropped opcodes are no big deal. Others, like the MOVE opcodes, are a MAJOR stumbling block to converting existing code (and to writing new code!)
The following opcodes are not allowed between the /Free tags: ADD, ANDxx, CABxx, CALL, CASxx, CAT, COMP, DEFINE, DIV, DOUxx, DOWxx, GOTO, IFxx, MOVE, MOVE(P), MOVEA, MOVEL, MOVEL(P), MULT, MVR, ORxx, PARM, PLIST, SCAN, SETOFF, SETON, SUB, SUBST, SUBST(P), TAG, TESTB, TESTN, TIME, WHENxx, Z-ADD, or Z-SUB. CALL opcodes must be converted to CALLP (call prototyped) and all PARMS must be converted to prototype structures.
Here is the path.
FIRST: Get the JCR5FPRT utility from the utilities page. Get either the v5r1 or v4 (if v4, it is called jcr5free on the v4 page) version, depending on your OS. The utility prints a side-by-side listing that shows your original columnar rpg4 code on the left and what that code would look like converted to /free on the right. You will notice many lines of code on the /free side that have ????????. This is code that will not convert to /free. (you will probably see way too many of these).
SECOND: Get the book, RPGIV JumpStart, Fourth Edition, by Bryan Meyers. You can find this book on his website at http://www.bmeyers.net . Read this book. Let me repeat that, read this book cover to cover. I have a copy at work and at home. It will be a big help.
THIRD: Fix everything in your original source that will not convert to things that will convert. Very simple. (not). If your code is still in RPGIII style format, like FACTOR1 IFEQ FACTOR2, then I suggest you get the JCR4MAX utility from my page. It will convert a TON of things over to a format that will convert easier into /free. Rerun the JCR5FPRT utility. Please note we are going to address 'how to do' many of the things that will not convert later.
FOURTH: Convert all *ENTRY and CALL parms to to main procedure interface and CALLP prototypes. Get the JCR4PROTO utility from main page to accomplish this task for you! (note: sorry v4 guys, this is a v5r1 utility only.) Also notice the beta status of this utility on the main page.
FIFTH: After there are no more ??????? in the JCR5FPRT utility’s output, run the JCR5FREE utility to generate /free code from your source. The JCR5FREE utility is available here. The JCR5FREE utility reads your existing source and generates a new RPGLE source member. It does not alter your existing code in any way
After you have generated the /free source, there are still things that may have to changed in your /free code before it will compile.
Does your original program have any LOOKUP, CHECK, SCAN, CHECKR opcodes. If so, this can get ugly! All these were replaced by bifs. The bif returns a numeric value to tell if the lookup was successful or not. Remember the original opcodes set on an indicator or %found. Well there is no indicator and %found is not set by the bif. Anything in your code conditioned by the indicator or %found (related to these opcodes) will HAVE to have that logic rewritten.
Another thing about the %scan bif. It replaces the SCAN opcode if you were not using an array in the result field. The %scan bif will NOT load an array with each occurrence of the scan value, as did the SCAN opcode. Once again, if knowing every occurrence of the scan value is required, you will have to code your own looping logic and load your own array of positions.
Klist/Kflds. I recommend you move them up to the top of your program. Right under the D specs. That is probably were they are going at some future release anyway. Move the /free statement down below the last kfld opcode.
There is one ‘feature’ in the converter that you will have to manually correct after conversion.
If A=B or
A=C; will convert correctly.
If A=B;
Or
A=C; will have an extra ; at the end of
the first if statement. You will need
to manually remove the first ; .
SIXTH: Get the
IFNUMB utility. It is a requirement for
formatting and structure numbering your new /free source.
THINGS TO CHANGE IN YOUR COLUMNAR CODE.
The remainder of this page is suggestions of ways to
fix ??????? problems.
MOVE, MOVEL
Ok heads up and brace yourself.. The MOVE and MOVEL
opcodes are not in /free. Gone is all
the wonderfully intentional disregard for data types, attributes, and field
lengths these opcodes allowed.
There are BIFs provided to address many of the functions
provided be these opcodes, but the following situations will now require you to
code a data structure solution.
Author’s note: The %DEC bif v5r2 now addresses many of the
issues discussed below!
DS situation 1.
Building a numeric value.
A(1,0)=8
B(1,0)=2 C(2,0)
You may not movel
B into C and MOVE A into C and get C=28.
You will have to build a data structure
DS
c 2s 0
b 1s
0 overlay(c:1)
a 1s
0 overlay(c:2)
DS situation2:
Moving alpha in numeric..
There is no functionality provided in v5r1 to do this common programming
requirement without using a DS or pointers! (Authors note:
This particular v5r1 failing really sucks.) The %DEC biff addresses this very
nicely in v5r2 and is even better than the MOVE opcode.
MOVE alpha
numeric would be coded
as
DS
Alpha 1
1
Numeric 1
1s 0
This also requires some additional logic in your program.
If you are making decisions based on there being blanks in the alpha
value, you have to check for *blanks or
‘0’. You also have to verify the alpha
value is a valid numeric value ‘0’ through ‘9’ before referencing the numeric
field or you will get a decimal data error.
DS situation3:
Trying to build an alpha field with none zero suppressed
numeric.
AlphaBld(8)
, Alpha1(1)=’A’, Numeric(7,0)=1
If the end result in AlphaBld8 is to be ‘A0000001’, then
you must define a DS
Ds
Alphabld 1 8
Alpha1 1
1
Numeric 2
8s 0
There are some cross attribute manipulations you can do
without a DS.
You can load a zero-suppressed numeric into an alpha
field.. Just be aware it is zero
suppressed.
A(5) N(3,0)=1
Eval
A=%char(n) A will equal
‘1 ‘
Evalr
A=%char(n) A will equal ‘ 1’
There is also a %editc (edit code) and %editw (editword)
bif avail.
Eval
a=%editc(N:‘4’) applies a 4 edit
code to N and loads it into A.
A=’1 ‘
Be careful that your alpha receiver is large enough to
hold the edited value!!
A(5) N(5,0)
Eval
a=%editc(N:‘J’) could blow as
the J edit code adds a minus sign and commas to the value going into A
Also be aware the EVAL opcode blanks the result field
first, you will either have to update substrings of a field or define a
DS to update only part of a field
MATH (JCR4MAX will fix many as many attribute compatible of these as possible)
All math opcode functionality will be replaced with bifs or data structures.
Figure 1.
Columnar /free
A ADD B
C C = A + B; // addition
A MULT B
C C= A * B;
// multiplication
A SUB B
C C = A - B; // subtraction
Z-ADD B
C C=B; // z-add
Z-SUB B
C C= -(B); // z-sub
A DIV B
C C = A / B; or %div
// division
MVR D %rem
Note: DIV and MVR
remainder have some special circumstances and new BIFs. They will be discussed later.
Super
Important: Expression math will not
truncate significant digits. You will
get error message RNQ0103 ‘The target for a numeric operation is too small to
hold the result.’
This is a crucial difference for RPG programmers. We have always taken for granted that RPG
will automatically truncate numbers (maybe even gotten in trouble with it a few
times!). Please remain thoughtful
when using expressions, you have to
make sure the resulting field is large enough.
The non-truncating feature of expression math has caused some negative preconceptions about
using it, even to the point where many will not use it. I am going to suggest that expressions are
just as robust as any other opcode, when used correctly. I would rather my program blow than generate
incorrect output due to me defining a result field too small.
**
In instances were we legitimately want to truncate a
numeric field, you have to code a Data Structure. An example of this might be a 20-digit barcode, but needing only
the last 10 digits for a case number.
To get the last 10 digits, instead using a z-add opcode or move opcode,
you would code the following data structure.
DS
big s
20p 0
small s
10p 0 overlay(big:11)
DIV and MVR (divide and move remainder operations and
BIFs)
Tech note: It is recommended that you code the H spec
keyword EXPROPTS (*RESDECPOS) if your program is going to have divide
expressions with intermediate fields.
The applies the "Result
Decimal Position" precision rules and forces intermediate results in
expressions to have no fewer decimal positions than the result. A=(C * (D/E)). The expression (D/E) is considered an intermediate
result.
Now we come to the %REMark comment line opcode, No
wait! That is not a comment line, it is the new move remainder BIF!! (IBM should consider renaming this bif
(quickly) to %MVR or anything beside %rem.
It is way too confusing with VB or other languages.)
The move remainder function is no longer dependent on a
preceding DIV opcode.
Before, if you were interested in the value of R, you
would code the following statement.
A DIV B
C
MVR R
Now you code for the remainder value directly with
R=%rem(A:B) //
move remainder
Just to mention it, you may also code divide statements
this way C=%div(a:b). The %div bif
will return only the integer portion (no decimals) of the quotient that results
from dividing A by B. Both A and B
must be defined as numeric with zero decimal positions. There is no %add, %mult, or %sub bifs so
the %div bif is a somewhat of an anomaly.
DATE arithmetic
(JCR5FREE will convert all of these OK)
LOGIC Structures.
The old version 3 style logic structures, meaning the
opcodes IFxx, ANDxx, DOUxx, DOWxx, Orxx , WHENxx, etc, that relied on comparing
the values of Factor1 with the values of
Factor2, are not allowed in /free.
These use of these Factor1 OPCODE Factor2 statements has been steadily
declining since V4 as the extended factor2 variation of these opcodes is much
more intuitive to use and easier to read and allows expressions. There is still quite a bit of the old style
usage in our legacy code, though I am personally glad to see these type opcodes
be left behind.
Figure 5.
F1 IFGT F2
if f1 > f2
F1 ANDGT F2 and
f1 > f2
F1 WHENEQ F2 when
f1 = f2
Etc…
DO – FOR – JCR5FREE will generate dummy counters where required. You will have to define the counters in the D specs.
The DO opcode is not valid in /free. For the most part, the functionality of the
DO opcode has been replaced by the FOR opcode. I digress for a moment:
I like the FOR (v4.4 beginning) opcode!
Brings back all those early memories of Fortran and Basic. The FOR opcode is extremely versatile, allowing expressions as compare values, has a MUCH better ‘step’ method than
provided by the DO opcode, and the increment value is much be better placed.
Figure 6.
A Do B
c For C = A
downto B By -2
Enddo -2.
The FOR is also much better at counting backwards!
Now back to the DO.
As you can see in Figure 7, the
first two uses of the DO have a direct replacement using the FOR opcode.
The functionality of DO factor2 with no result counter is not available
directly in /free.
Figure 7.
A DO B
C replaced by For c = a to b
DO B
C replaced by For c
= 1 to b
DO B
has no direct replacement.
To duplicate this logic, you will have to code some type
of artificial count value. Here is an
example: For DummyCount = 1 to B
CALL (call a
program)
The old CALL/PARM structures will have to be replaced with
CALLP and the parms being prototyped.
Don’t let this step frighten you!
After you do couple of them, you
will come to like this requirement of /free.
See any of my utilities for an example of this.)
Miscellaneous Opcodes dropped from /free but having easy
/free equivalent method. Please note
that not using the following opcodes has been recommended long before
/free. It is just that /free forces
their non-use.
CASxx (compare
and execute subroutine) is gone and there is no replacement structure.
A caseq
B subr1
Endcs
Would have to recoded using a SELECT or IF structure
Select
When a=b
Exsr subr1
Endsl
CABxx (compare and
branch). These type structures are
generally avoided anyway, but it is in a lot of our older code. If you thinking about converting some of
your legacy code to /free, this logic will have to be rewritten. The GOTO and TAG opcodes are gone also so
there will need to be some serious thought about program flow
restructuring
CAT
(concatenate). The eval
statement in conjunction with the %trimr bif has effectively replaced this
opcode.
A CAT B:0
C C = %trimr(A) + B
COMP
(compare). This has been
replaced by the Eval.
A COMP B
10 ((10 in eq position)
Eval *in10=
(A=B). If the expression is true, the
indicator is turned on, if expression is false, indicator is turned off.
DEFINE (like
define)
This has been replaced on the D specs using the like()
keyword.
The calculation line
*LIKE
DEFINEA B, which defines field B to be have the
same attributes as field A,
is replaced by a definition spec
B like(A).
SETON, SETOFF.
Replaced by the eval opcode with requirement of having to code one line
per each indicator. Offsetting the
additional code is the advantage of being able to, perhaps, document each
indicator a bit better.
SETOFF 010203
is replaced by
eval *in01 = *off // clear subfile
eval *in02 =
*off // error
eval *in03 =
*off // exit
SCAN
The %scan bif
directly replaces the SCAN opcode if you where not using an array in the
result field. The %scan bif will NOT
load an array with each occurrence of the scan value as did the SCAN
opcode. Once again, if knowing every occurrence of the scan
value is required, you will have to code your own looping logic and load your
own array of positions.
MOVEA (move
array).
This is another opcode that is probably used throughout
your legacy code. (I have 9000
occurrences of it in my legacy code.)
It suffered the same fate as the MOVE and MOVEL opcodes and is not
available in /free. You will have to
code your own looping logic and handle the eval on an element-by-element basis
or do some fairly complex pointer manipulations to emulate this lost
functionality.
TESTB (test
bit)
Many of the popular system APIs require this
functionality. There is no alternative
mechanism in /free to accomplish this.
As a solution, I have designed a user-defined function that isolates the
TESTB opcode out of your main lines of code.
See the EXPDBR utility for an example. The user defined function will
not be in /free format, but the rest of your code can be all /free.
TESTN (test numeric)
You can code a %check bif to replace this opcode, but remember, testn set on an indicator, %check returns a numeric value.
All my V5R4 /free-based utilities are available in the download text DOWNLOAD along with all other programs on this site.
Copyright © Craig Rutledge
2008