New in V7R5 – Part 2. FOR-EACH, ENUM, %SPLIT, %SUBARR

Hello everyone and welcome to part 2 of V7R5 News. In this article I am going to show four new opcodes and built-in functions that I think you may find useful.

I’ll show you how to use the FOR-EACH opcode, which is very useful when you have to process a list of elements, and of course I’ll also show you how to use an ENUMeration and the built-in %SPLIT and %SUBARRAY functions that can be used with FOR-EACH.

This time I’m going to explain the built-in functions and the sentence DCL-ENUM before explain FOR-EACH and then I’ll show you a complete program with examples of all of this.

ENUM

dcl-enum {qualified};
   {dcl-c} name1 value1;
   {dcl-c} name2 value2;
   .
   {dcl-c} nameN valueN;
end-enum;

An enumeration is a list of  named constants that can be used anywhere in the code where a constant can be used and can be used as an array too. It can be qualified if needed.

It is defined between dcl-enum and end-enum. Inside you must type the list of named constants. If the name of the constant is equal to the name of a reserved word you must type dcl-c before the name to define it correctly.

ENUM example:

				
					dcl-enum permission qualified;
    dcl-c read 'r';
    dcl-c write 'w';
    execute 'x';
end-enum;
				
			

Explanation:

Line 1: Begin the declaration of the enumeration.

Line 2: The named constant read can be an opcode in RPG so dcl-c must be specified.

Line 3: The named constant write can be an opcode in RPG so dcl-c must be specified.

Line 4: The named constant excecute does not match with any reserved word so dcl-c can be omitted.

Line 5: End the declaration of the enumeration.

%SPLIT

%SPLIT(string {: separators { : *ALLSEP {: *NATURAL | *STDCHARSIZE}}})

%SPLIT splits a string into an array of substrings, which is what it returns. It can be used in any expression where an array can be used except SORTA, %ELEM, %LOOKUP and %SUBARRAY.

The first parameter is the string to split which can be alphanumeric, graphic or UCS2.

The second parameter is the list of characters that indicates the end of each substring.

The third parameter can be *ALLSEP, and would indicate that each separator is considered to split two substrings. If you do not specify separators that follow other separators, leading separators and trailing separators are ignored.

%SPLIT Example with comments in code:

				
					**free

dcl-s string varchar(100);
dcl-s array  varchar(20) dim(*auto:10);
dcl-s i      uns(3);

string = 'Hello..I''m testing SPLIT';

array = %split(string:'. ');
// *ALLSEP is not used

snd-msg 'There are ' + %char(%elem(array)) + ' elements in the array' %target(*self:2);
// There are 4 elements in the array

for i = 1 to %elem(array);
    snd-msg 'array(' + %char(i) + ') = ' + array(i) %target(*self:2);
endfor;
// array(1) = Hello
// array(2) = I'm
// array(3) = Testing
// array(4) = SPLIT

array = %split(string:'. ':*allsep);
//*ALLSEP is used as the third parameter, so the string '..' is considered as two separators

snd-msg 'There are ' + %char(%elem(array)) + ' elements in the array' %target(*self:2);
// There are 5 elements in the array

for i = 1 to %elem(array);
    snd-msg 'array(' + %char(i) + ') = ' + array(i) %target(*self:2);
endfor;
// array(1) = Hello
// array(2) = ' '
// array(3) = I'm
// array(4) = Testing
// array(5) = SPLIT

*inlr = *on;
				
			

%SUBARR

%SUBARR(array:start-index{:number-of-elements})

%SUBARR returns a section of the array starting at start-index. Optionally you can specify the number of elements to return. If you don’t specify a number the built-in function will return the remain of the array.

%SUBARR example with comments in code:

				
					**free

dcl-s array1  varchar(20) dim(*auto:10);
dcl-s array2  varchar(20) dim(*auto:20);
dcl-s i      uns(3);

array1(1) = 'First element';
array1(2) = 'Second element';
array1(3) = 'Third element';
array1(4) = 'Fourth element';
array1(5) = 'Fifth element';

array2 = %subarr(array1:3);
// Returns from third element to the end

snd-msg 'There are ' + %char(%elem(array2)) + ' elements in array2' %target(*self:2);
for i = 1 to %elem(array2);
    snd-msg 'array2(' + %char(i) + ') = ' + array2(i) %target(*self:2);
endfor;
// There are 3 elements in array2
// array2(1) = Third element
// array2(2) = Fourth element
// array2(3) = Fifth element

%elem(array2) = 1;
array2 = %subarr(array1:2:2);
// Returns 2 elements from second element

snd-msg 'There are ' + %char(%elem(array2)) + ' elements in array2' %target(*self:2);
for i = 1 to %elem(array2);
    snd-msg 'array2(' + %char(i) + ') = ' + array2(i) %target(*self:2);
endfor;
// There are 2 elements in array2
// array2(1) = Second element
// array2(2) = Third element

*inlr = *on;
				
			

FOR-EACH

FOR-EACH{(H)} item IN array | %LIST | %SPLIT | %SUBARR | enumeration

FOR-EACH processes the elements of the array, %LIST, %SPLIT, %SUBARRAY or the enumeration one at a time.


The first parameter (item) must be a variable, it cannot be an array. It will contain the element to process from the second parameter.


For numeric type elements, it supports the H (half-adjust) operation extender to round decimals.

FOR-EACH example:
(Explanation and screenshots below)

				
					**free

dcl-ds prices;
    base      packed(8:2) inz(95);
    medium    like(base)  inz(984);
    advanced  like(base)  inz(5698);
    premium   like(base)  inz(12345);
    arrPrice  like(base) dim(4) samepos(base);
end-ds;

dcl-s price  like(base);
dcl-s elem   packed(1);

dcl-enum permission qualified;
    dcl-c read 'r';
    dcl-c write 'w';
    execute 'x';
end-enum;

dcl-s perm           char(1);
dcl-s permissionList varchar(100);

dcl-s phone varchar(20);

dcl-s sentences   varchar(10000);
dcl-s sentence    varchar(1000);
dcl-s word        varchar(20);
dcl-s numWords    packed(4);

//FOR-EACH / %SUBARR
snd-msg 'FOR-EACH' %target(*self:2);
for-each price in arrprice;
    select price;
        when-in %range(0:100);
            snd-msg %char(price) + ' is a base price' %target(*self:2);
         when-in %range(101:1000);
            snd-msg %char(price) + ' is a medium price' %target(*self:2);
         when-in %range (1001:10000);
            snd-msg %char(price) + ' is an advanced price' %target(*self:2);
         other;
            snd-msg %char(price) + ' is a premium price' %target(*self:2);
    endsl;
endfor;

snd-msg 'FOR-EACH with %SUBARR' %target(*self:2);
elem = 2;
for-each price in %subarr(arrprice:2:2);
    snd-msg 'The value for element ' + %char(elem) + ' is ' + %char(price) %target(*self:2);
    elem += 1;
endfor;

// FOR-EACH with ENUM
snd-msg 'FOR-EACH with ENUM' %target(*self:2);

permissionList = 'Permission list is';
for-each perm in permission;
    permissionList += (' ' + perm);
endfor;

snd-msg permissionList %target(*self:2);

// FOR-EACH with %LIST
snd-msg 'FOR-EACH with %LIST' %target(*self:2);

for-each phone in %list('iPhone 15':'iPhone 14':'iPhone 13');
   snd-msg 'Update available for ' + phone %target(*self:2);
endfor;

// FOR-EACH with %SPLIT
snd-msg 'FOR-EACH with %SPLIT' %target(*self:2);
snd-msg 'The following sentences:' %target(*self:2);

sentences = 'This is the first sentence. The second one ends with a semicolon; final sentence.';

for-each sentence in %split(sentences:'.;');
    for-each word in %split(sentence);
        numWords += 1;
    endfor;
endfor;

snd-msg '''' + sentences + '''' %target(*self:2);
snd-msg 'have ' + %char(numWords) + ' words.'  %target(*self:2);

*inlr = *on;


				
			

Explanation:

Line 1: Code will be fully free.

Line 3-12: Data structure and variables to be used with for-each and arrays and subarrays

Line 14-21: Enumeration and variables to be used with for-each and enumerations.

Line 23: Variable to be used with for-each and %list.

Line 25-29: Variables to be used with for-each and %split.

Line 32: for-each will loop for every element in arrprice and puts the value in price variable.

Line 47: for-each will loop for every element in the subarray and puts the value in price variable.

Line56: for-each will loop for every named constant in the enumeration and puts the value in perm variable.

Line 65: for-each will loop for every element in the list and puts the value in phone variable.

Line 75-79: for-each will loop for each sentence split from the sentences variable and put the value into the sentence variable. Then a new for-each will loop for each split word from the previous sentence variable and place the value into the word variable. Finally, numWords is incremented to contain the total number of words in all sentences in the sentences variable.

Looking at the job log:

I hope you liked the post. Don’t hesitate to comment what you want and see you in the next post.

3 Responses

    1. Hi Jessie, thank you for your comment.

      snd-msg is an opcode that sends an *INFO or *ESCAPE message to any procedure on the call stack. Once the message is sent, it will appear in the job log. %TARGET is the third parameter of the opcode and allows us to write which procedure the message will be sent to. If you don’t type it the message will be set to the current procedure if the message type is *INFO or it will be sent to the caller procedure if the message type is *ESCAPE. This parameter can specify the offset in the program stack too. So %target(*self:2) means that the message will be sent to the current procedure (*self) but 2 positions up in the program stack so it will be shown in the screen in which you call the program on line 24. You will see a plus symbol (+) if more than one message was sent. Press page up or page down to navigate through them.

Leave a Reply

Your email address will not be published. Required fields are marked *