The NetRexx Tutorial
- Control Structures
NetRexx Tutorial - Control Structures


Control Structures

Introduction.

No algorithmic language would be complete without instructions that allow the execution of statements depending on certain conditions for performing iterations and selections. NetRexx has many such instructions for allowing program flow control. Probably the most important is the do...end construct.

Statement Block.

A statement block is a sequence of statements enclosed by a do (...) end. A statement block looks like this:

 
do
   statement_1
   statement_2
   (...)
   statement_N
end
 

NetRexx executes these statements in sequence Ñ from the first to the last. Syntactically, a block of statements is accepted in place of any single statement.

if/then/else.

The if/then/else construct is used to conditionally execute an instruction or a group of instructions. The if/then/else construct can also be used to select between two alternatives.

 
if expression
  then instruction
  else instruction
 

The expression is evaluated, and MUST result in '0' or '1'. Thus, as you can imagine:

 
if expression
  then instruction   if expression results to 1
  else instruction   if expression results to 0
 

NOP

It is usually difficult to do 'nothing'. However, the nop instruction was created for just such a purpose: it is a dummy instruction.

 
NOP
 

It is useful as target for a then or else clause:

 
--------------------------------------------------------
   if a = 3
     then NOP
     else say 'a is NOT 3.'
--------------------------------------------------------
                                          example of NOP
 

loop for (with a repetitor)

The loop instruction is used (as we have already seen), to group a set of instructions, and to execute (optionally) more than once. In its easier case, the loop for looks suspiciously like the C-language for statement. Let us consider a first case:

 
loop for expression
  statement_1
  statement_2
  (...)
  statement_N
end
 

In this case, expression - an expression that evaluates a number - tells NetRexx 'how many times to execute the loop'. Here is an example:

 
--------------------------------------------------------
/* this statement will be executed 3 times */
loop for 3
  say 'Hello'
end
--------------------------------------------------------
                                            do N example
 

Will print on your screen:

 
   Hello
   Hello
   Hello
 
 
--------------------------------------------------------
list = 'MARTIN JOE PAULA'
/* this statement will be executed 3 times */
loop for list.words()
  parse list name list
  say 'Hi!' name
end
--------------------------------------------------------
                                     second do N example
 

Will print on your screen:

 
   Hi MARTIN
   Hi JOE
   Hi PAULA
 

Of course, you can use a variable (which we will regard as an index) to run the iteration. This is a 'controlled repetitive loop'. A more complex case is the following:

 
loop name = expr1 to expr2
  statement_1
  statement_2
  (...)
  statement_N
end
 

Examples:

 
--------------------------------------------------------
loop i = 1 to 5
  say i
end
--------------------------------------------------------
                                            loop example
 

Will print on your screen:

 
   1
   2
   3
   4
   5
 
 
--------------------------------------------------------
cols   = 2
rows   = 3
loop i = 1 to cols
  loop j = 1 to rows
    say j
  end
end
--------------------------------------------------------
                                     loop with 2 indices
 

Will print on your screen:

 
   1
   2
   3
   1
   2
   3
 

In the above examples, we always incremented by a positive quantity (+1). What about when your increment is NOT +1? The solution is again a do, but now with a by statement. Our do loop will then look like:

 
loop varname = expr1 to expr2 by expr3
  statement_1
  statement_2
  (...)
  statement_N
end
 

And here are some examples:

 
--------------------------------------------------------
loop i = 2 to -1 by -1
  say i
end
--------------------------------------------------------
                                              by example
 

Will print on your screen:

 
   2
   1
   0
  -1
 
 
--------------------------------------------------------
x1 = 2.1
x2 = 2.5
increment = .1
loop x = x1 to x2 by increment
  say x
end
--------------------------------------------------------
                                              by example
 

Will print on your screen:

 
   2.1
   2.2
   2.3
   2.4
   2.5
 

You can even add a repetition counter, which sets a limit to the number of iterations if the loop is not terminated by other conditions. Our loop loop will then look like the following:

 
loop varname = expr1 to expr2 by expr3 for expr4
  statement_1
  statement_2
  (...)
  statement_N
end
 

Example:

 
--------------------------------------------------------
y_start = .9
y_end = 2.7
loop y = y_start to y_end by .9 for 2
  say y
end
--------------------------------------------------------
                                             for example
 

Will print on your screen:

 
   .9
   1.8
 

loop/while/until.

The while and until constructs commonly found in other programming languages are also available in NetRexx, as a condition to the ubiquitous loop statement. Here is how to build a simple while loop:

 
loop while expression
  statement_1
  statement_2
  (...)
  statement_N
end
 

And here is how to build a simple until loop:

 
loop until expression
  statement_1
  statement_2
  (...)
  statement_N
end
 

Consider the example:

 
--------------------------------------------------------
i = 1
loop while i < 7
  say i '\-'
  i = i+1
end
--------------------------------------------------------
                                           while example
 

---> The previous code will print: 1 2 3 4 5 6

 
--------------------------------------------------------
i = 1
loop until i > 6
  say i '\-'
  i = i+1
end
--------------------------------------------------------
                                                   until
 

---> Will print: 1 2 3 4 5 6

do resume.

A nice NetRexx feature is that you can combine the loop in its repetitive form with the loop in its conditional form (i.e. the while/until construct we just considered). This can lead to constructs that look like:

 
--------------------------------------------------------
loop i = 1 to 10 while i < 6
  say i '\-'
end
--------------------------------------------------------
                                        combined example
 

---> This code will print: 1 2 3 4 5. There is a nice 'side effect' to this feature, and that is the possibility of building a while/until loop without incrementing (or decrementing) the control variable yourself. Consider the case we just looked at:

 
--------------------------------------------------------
i = 1.0
loop while i < 3
  say i '\-'
  i = i+.5
end
--------------------------------------------------------
                                        do while example
 

---> This code will produce: 1.0 1.5 2.0 2.5 We need to define the start value i = 1.0, and define the step increment i = i+.5. All this can be avoided with the following construct:

 
--------------------------------------------------------
loop i = 1.0 by .5 while i < 3
  say i '\-'
end
--------------------------------------------------------
                                     do by while example
 

---> Will print: 1.0 1.5 2.0 2.5 This code is much more compact. A resume' of what we have seen so far on the do instruction:

 
----------------------------------------------------------------------
 
loop repetitor conditional
     --------- -----------
          |         |
          |         +----------< _ WHILE expr_w
          |                      _ UNTIL expr_u
          |
          +------------< _ var = expr_i TO expr_t BY expt_b FOR expr_f
                         _ expr_r
                         _ FOREVER
 
   instruction_1
   instruction_2
   (...)
   instruction_N
end
 
----------------------------------------------------------------------
 

select.

The select instruction is used to execute one of several alternative instructions. The format is:

 
select
  when expression_1 then instruction_1
  when expression_2 then instruction_2
  when expression_3 then instruction_3
  (...)
  otherwise instruction_N
end
 

What NetRexx does is evaluate the expressions after the when. If the result is '1', then what follows the corresponding then is executed (this can be anything Ñ a single instruction, a set of instructions inside a do ... end clause, etc.). Upon return, the control will pass directly to the end instruction. If none of the when expressions result in a '1', then the otherwise instruction is executed. NOTE: the otherwise clause is NOT mandatory, but if none of the when expressions results in a '1', and the otherwise is not present, you will get a 'SYNTAX error'. It is thus wise to ALWAYS add an otherwise clause at the end of a select, usually with a NOP instruction.

 
--------------------------------------------------------
(...)
/* this will print a flag corresponding to the */
/* inactivity time of a terminal:              */
 
/* the table is the following                  */
/* hour    0...1...2...3...4...5...6...7...8   */
/* flag    ****;;;;::::::::.................   */
 
/* where 'hour' is since how many hours the    */
/* terminal is inactive, and flag is the       */
/* flag we want to display                     */
 
/*   inactive: time (in hours)   a terminal */
/*             has been inactive            */
select
  when inactive < 1 then flag = '*'
  when inactive < 2 then flag = ';'
  when inactive < 4 then flag = ':'
  otherwise flag = '.'
end
(...)
--------------------------------------------------------
                                          select example
 

iterate.

Use the iterate instruction to alter the flow of control within a repetitive do loop (i.e. any do construct which is NOT a plain do). The syntax is:

 
do (expression)
  statement_1
  (...)
  statement_N
  (condition) iterate [name]
  statement_N+1
  (...)
  statement_M
end
 

If program flow reaches the iterate instruction, the control is passed back to the do instruction, so that the statements statement_N+1,...statement_M are NOT executed. Here is an example:

 
--------------------------------------------------------
loop i = 1 to 5
  say '* \-'
  if i = 3 then iterate
  say i '\-'
end
--------------------------------------------------------
                                         iterate example
 

---> This will print: * 1 * 2 * * 4 * 5 The iterate instruction also supports a 'name' following it, and name (if present) must be the variable name of a current active loop. Consider this following code atom:

 
--------------------------------------------------------
num = 7
loop i = 1 to num
  line = "
  loop j = 1 to num
    if i = j then
      do
        say line
        iterate i
      end
    line = line j
  end
end
--------------------------------------------------------
                                      iterate example II
 

This code will print:

 

 
 1
 1 2
 1 2 3
 1 2 3 4
 1 2 3 4 5
 1 2 3 4 5 6

 

leave.

Use the leave instruction to exit immediately from a do loop. The syntax is:

 
loop (expression)
  statement_1
  (...)
  statement_N
  (condition) leave [name]
  statement_N+1
  (...)
  statement_M
end
 

The flow of control is passed to the instruction that FOLLOWS the corresponding end in the loop loop. Here is an example:

 
--------------------------------------------------------
loop i = 1 to 5
  say '* \-'
  if i = 3 then leave
  say i '\-'
end
--------------------------------------------------------
 

---> The above code will produce the output: * 1 * 2 * You should note that leave is similar, in a certain sense, to the iterate instruction: like it, leave 'breaks' the normal flow of control in the do loop. Pictorially:

 
loop           <------+
  (...)               |
  (...)           (back to beginning)
  (...)               |
      iterate  -------+
      leave    -------+
  (...)               |
  (...)           (jump past the end)
  (...)               |
end                   |
               <------+
 

Real Examples.

As usual, we now present some 'real-life' examples.

Simulating the 'foreach' instruction.

As you may have noticed, the foreach instruction does not exist in NetRexx. And if you are a shell programmer, you may well also be without it. However, here is a trick for simulating it with a minimum of effort:

 
--------------------------------------------------------
loop while list ^= "       | -> foreach item (list)
  parse list item list      |
  (...)                     |
end                         |    end
--------------------------------------------------------
                                         foreach example
 

The only thing you need to remember is that the list variable, at the end of the do loop, will be NULL; remember to save it if you plan to use it later.

Reading a 'stanza' file.

Configuration files are usually divided in the UNIX terminology into 'stanzas'. A 'stanza' is a uniquely identified portion of the file that contains the parameters for a specified entity. VM programmers may identify a 'stanza' as a single entry in a NAMES file: an identifier marks the start of a stanza, and a set of parameters follows, until a new stanza (or an End_of_File) is reached. Let us look at a 'stanza' example:

 
+------------------------------------------------------------------+
| # comment line                                                   |
| node: rsl3pm1              #  first stanza                       |
|   machine: rs6000          #  defines node                       |
|   vendor: IBM              #    rsl3pm1                          |
|   location: b32r035        #                                     |
|                                                                  |
| node: sgl3pm1              #  second one                         |
|   machine: Indigo2         #  defines node                       |
|   vendor: SGI              #     sgl3pm1                         |
|   location: b11r023        #                                     |
|                                                                  |
| node: hpl3sn05                                                   |
|   machine: 730/50                                                |
|   vendor: H/P                                                    |
|   location: b71r233                                              |
+------------------------------------------------------------------+
                                            Source file: test.stanza

You should note that:

The following program is composed of a small call to a routine that does the job of:

As you can see, the function is a good example of utilisation of the do, leave, iterate instructions.

 
+----------------------------------------------------------------------+
| -- readst.nrx                                                        |01
| --                                                                   |02
| parse arg nodeid .                                                   |03
|                                                                      |04
| --                                                                   |05
| --                                                                   |06
|                                                                      |07
| -- read the file                                                     |08
| --                                                                   |09
| infid = xFile('test.stanza')                                         |10
| rc = infid.rd_file()                                                 |11
| if rc <> 0 then                                                      |12
|   do                                                                 |13
|     say 'problem reading "'infid.name'".'                            |14
|     exit 1                                                           |15
|   end                                                                |16
|                                                                      |17
| output = ''                                                          |18
| found  = 0                                                           |19
| loop i = 1 to infid.line[0]                                          |20
|   if infid.line[i] = '' then iterate                                 |21
|   parse infid.line[i] key rest '#' .                                 |22
|   if key = '#' then iterate                                          |23
|   if key = 'node:' then                                              |24
|     do                                                               |25
|       if found then leave                                            |26
|       if rest = nodeid then                                          |27
|         do                                                           |28
|           found = 1                                                  |29
|           iterate                                                    |30
|         end                                                          |31
|     end                                                              |32
|   if found = 0 then iterate                                          |33
|   parse infid.line[i] line '#' .                                     |34
|   output = output line                                               |35
| end                                                                  |36
| out = output.space()                                                 |37
| if out = ''                                                          |38
|   then say 'Not found.'                                              |39
|   else say output.space()                                            |40
|                                                                      |41
| exit 0                                                               |42
+----------------------------------------------------------------------+
                                                              readst.nrx
Download the source for the readst.nrx example

NOTEs:

Run this program and here is the result you will get:

 
....................................................................
rsl3pm1 (182) java readst sgl3pm1
machine: Indigo2 vendor: SGI location: b11r023
rsl3pm1 (183) java readst rsl3pm1
machine: rs6000 vendor: IBM location: b32r035
rsl3pm1 (184)
....................................................................
                                                       readst.output

Expanding a list.

The following problem might appear totally 'academic'. It did to me until I encountered the following problem. A directory contained a set of files (more than 20 000), each identified by a number (as filename). To make the problem clearer, my directory contained these files:

 
  10000      10001      10002       10003
  10004      10005      10006       10007
  (...)
  33002      33003      33004       33005
 

The user needed to perform operations on a subset of the files Ñ for example:

 
    10000 10981 10982 10983 21900 21901
or: 30291 30292
or: 67234 67235 67236 67237 77889 88974 88975
 

The user had to start from N and continue until item M, or from item J for K files. There was no easy solution with UNIX standard wild-cards. And the only solution was to write the items one by one. The small program (and routine) that follows is a possible solution to the problem Ñ it expands a pattern according to a very simple syntax:

 
  first-last
  first.how_many
 

The expansion is then of the type:

 
 
  10020-10022  -> 10020 10021 10022
  30452.4      -> 30452 30453 30454 30455
 
 

The program will accept any combination of items containing '.' or '-', or simple single items. The program is really very simple:

 
+------------------------------------------------------------------+
| parse arg teststr                                                |01
| say expandlist(teststr)                                          |02
| exit 0                                                           |03
+------------------------------------------------------------------+
                                                         explist.nrx
Download the source for the explist.nrx example

And of course requires this small function: (I present it separately so that you can quickly put it inside a bigger program if you like it).

 
+----------------------------------------------------------------------+
| -- method......: listexpand                                          |72
| -- purpose.....:                                                     |73
| --                                                                   |74
|   method listexpand(il=Rexx) public static                           |75
|     ol = ''                                                          |76
|     loop while il <> ''                                              |77
|       parse il it il                                                 |78
|       if it.pos('.') <> 0 then                                       |79
|         do                                                           |80
|           parse it f'.'n                                             |81
|           loop i = f to f+n-1                                        |82
|             if ol.pos(i) <> 0 then iterate i                         |83
|             ol = ol i                                                |84
|           end                                                        |85
|           iterate                                                    |86
|         end                                                          |87
|       if it.pos('-') <> 0 then                                       |88
|         do                                                           |89
|           parse it f'-'l                                             |90
|           loop i = f to l                                            |91
|             if ol.pos(i) <> 0 then iterate i                         |92
|             ol = ol i                                                |93
|           end                                                        |94
|           iterate                                                    |95
|         end                                                          |96
|        if ol.pos(it) <> 0 then iterate                               |97
|        ol = ol it                                                    |98
|     end                                                              |99
|     Return ol                                                        |00
|                                                                      |01
+----------------------------------------------------------------------+
                                          xstring.nrx(Method:listexpand)
Download the complete source for the xstring.nrx library

Here is what you can use it for:

 
....................................................................
rsl3pm1 (9) explist 2000 3045.3 7002-7003
2000 3045 3046 3047 7002 7003
 
rsl3pm1 (11) echo `explist 20000 30890-30900`
20000 30890 30891 30892 30893 30894
30895 30896 30897 30898 30899 30900
 
rsl3pm1 (12)  ls -la `explist 20000 30890-30900`
(...)
 
rsl3pm1 (13) cat `explist 20000.7 30890-30900` > toto
(...)
....................................................................
                                                         explist.out

Operation on arrays.

It is sometimes usefull to convert information from an array, to a string, and viceversa.

 
+----------------------------------------------------------------------+
| -- method......: a2s                                                 |31
| -- purpose.....: converts a Rexx array to a string                   |32
| --                                                                   |33
|   method a2s(a=Rexx) public static                                   |34
|     a = a                                                            |35
|     out = ''                                                         |36
|     loop i = 1 to a[0]                                               |37
|       out = out a[i]                                                 |38
|     end                                                              |39
|     return out                                                       |40
|                                                                      |41
+----------------------------------------------------------------------+
                                                 xstring.nrx(Method:a2s)
Download the complete source for the xstring.nrx library

 
+----------------------------------------------------------------------+
| -- method......: s2a                                                 |18
| -- purpose.....: converts a string to an array                       |19
| --                                                                   |20
|   method s2a(str=Rexx,a=Rexx) public static                          |21
|     a = a                                                            |22
|     i = 0                                                            |23
|     loop while str <> ''                                             |24
|       parse str nn str                                               |25
|       i = i+1                                                        |26
|       a[i] = nn                                                      |27
|     end                                                              |28
|     a[0] = i                                                         |29
|                                                                      |30
+----------------------------------------------------------------------+
                                                 xstring.nrx(Method:s2a)
Download the complete source for the xstring.nrx library

The following example will show the utilization of such functions.

 
+----------------------------------------------------------------------+
| -- simple test of a2s and s2a                                        |01
| --                                                                   |02
|                                                                      |03
| -- convert a string to an array                                      |04
| --                                                                   |05
| b = rexx(")                                                         |06
| xstring.s2a('52 45 66 3 4',b)                                        |07
| loop i = 1 to b[0]                                                   |08
|   say i ':' b[i]                                                     |09
| end                                                                  |10
|                                                                      |11
| -- convert an array to a string                                      |12
| --                                                                   |13
| c = rexx(")                                                         |14
| c[0] = 3                                                             |15
| c[1] = 'This is a test'                                              |16
| c[2] = 'another el.'                                                 |17
| c[3] = 'LAST ONE.'                                                   |18
|                                                                      |19
| s = xstring.a2s(c)                                                   |20
| say s                                                                |21
|                                                                      |22
| exit 0                                                               |23
+----------------------------------------------------------------------+
                                                              tarray.nrx
Download the source for the tarray.nrx example

Chapter FAQ

 
 *** This section is: 
  
 *** and will be available in next releases

Chapter Summary

A resume' of some of the concepts we've encountered in this chapter:

 
_ block of instructions           | do (...) end
                                  | - ex.: do
                                  |          instructions
                                  |          instructions
                                  |        end
                                  |
_ 'for' loop                      |  loop for n=n1 to n2 (...) end
                                  | - ex.: loop i = 1 to 6
                                  |          instructions
                                  |          instructions
                                  |        end
                                  |
_ 'while' loop                    |  loop while expr (...) end
                                  | - ex.: loop while i < 6
                                  |          instructions
                                  |          instructions
                                  |        end
                                  |
 
 
 *** This section is: 
  
 *** and will be available in next releases


File: nr_9.html.

The contents of this WEB page are Copyright © 1997 by Pierantonio Marchesini / ETH Zurich.

Last update was done on 18 May 1998 21:47:43(GMT +2).