Arrays [ Getting Started With TRANSACT V ] MPE/iX 5.0 Documentation
Getting Started With TRANSACT V
Arrays
It is possible to set up multi-dimensional arrays in Transact. We will
look at examples of one- and two-dimensional arrays. The bubble sort
example illustrated in Figure 6-20 can be implemented replacing the
dynamic part-number data structure with a static list or one-dimensional
array of part numbers. The resulting program might look like this:
______________________________________________________________
| |
| 1 system ex66,base=orders; |
| 2 define(item) temp-part x(8): |
| 2.1 part-table 20 x(8): |
| 2.2 each-part x(8)=part-table: |
| 3 from-part x(8)=part-table: |
| 4 to-part x(8)=part-table(9); |
| 5 define(item) count i(4),init=0: |
| 6 dun x(4),init="no": |
| 7 yes x(4),init="yes": |
| 8 no x(4),init="no"; |
| 9 define(item) parts-this-pass i(4): |
| 10 no-of-parts i(4); |
| 11 <<deleted>> |
| 12 list temp-part: |
| 12.1 part-number: |
| 12.2 part-table: |
| 13 parts-this-pass: |
| 14 no-of-parts; |
| 15 list count: |
| 16 dun: |
| 17 yes: |
| 18 no; |
| 19 <<deleted>> |
| 20 repeat |
| 21 do |
| 22 <<deleted>> |
| 23 get(serial) parts,list=(part-number),status;|
| 24 if status = 0 then |
| 24.1 do |
| 25 let (count) = (count) + 1; |
| 25.1 move (each-part((count))) = (part-number);|
| 25.2 doend |
| 26 else let (dun) = (yes); |
| 27 doend |
| 28 until (dun) = (yes); |
| 29 let (no-of-parts) = (count); |
| 30 let (parts-this-pass) = (no-of-parts); |
| 31 while (parts-this-pass) > 0 |
| 32 perform 100-bubble-sort; |
| 33 <<deleted 33-39>> |
______________________________________________________________
Figure 8-7. One dimensional array
_______________________________________________________________________
| |
| 40 let (count) = (no-of-parts); |
| 41 while (count) > 0 |
| 42 do |
| 43 display(table) each-part((count)),head="part-number";|
| 44 <<deleted>> |
| 45 let (count) = (count) - 1; |
| 46 doend; |
| 47 end; |
| 48 |
| 49 100-bubble-sort: |
| 50 |
| 51 <<deleted>> |
| 52 let (count)= 1; |
| 53 while (count) < (parts-this-pass) |
| 54 do |
| 55 <<moved to 65.1>> |
| 56 <<deleted 56-57>> |
| 58 if (from-part((count))) < (to-part((count))) |
| 59 then |
| 60 do |
| 61 move (temp-part) = (to-part((count))); |
| 62 move (to-part((count))) = (from-part((count)));|
| 63 move (from-part((count))) = (temp-part); |
| 64 doend; |
| 65 <<deleted>> |
| 65.1 let (count) = (count) + 1; |
| 66 doend; |
| 67 let (parts-this-pass) = (parts-this-pass) - 1; |
| 68 return; |
_______________________________________________________________________
Figure 8-7. One dimensional array (cont.)
This example was purposely left as close as possible to the bubble sort
example. The differences between the two examples are highlighted.
Lines 2.1 through 4 define the part number array and the individual items
within the array that we need to access. Line 2.1 defines the array to
contain 20 occurrences of 8 bytes each. Lines 2.2 through 4 define
individual items within the array that we will use for storing,
retrieving, and comparing.
The verbs used for IMAGE access cannot refer to subscripted items. The
items must be parent items. Thus, line 23 retrieves the next part-number
from the database. If we have not reached the end of the dataset, line
25.1 moves the part-number retrieved into the next array occurrence of
part-table. Notice the double set of parentheses around the item count.
The innermost set denotes that we are subscripting a reference to
each-part. The next set denotes that we are using an item named count to
contain the array occurrence to be accessed.
Using a fixed data structure rather than a dynamic data structure allows
us to delete several lines of code that were needed to manipulate the
dynamic data structure. These lines are identified as <<deleted>>
throughout the example.
The balance of the example is very similar to the dynamic data structure
implementation of the bubble sort problem. However, there is one other
area of the example worth mentioning. Notice that line 4 defines to-part
to start in the ninth byte of the part-table array. This differs from
the definition of from-part which starts in the first byte of the
part-table array (line 3). This allows us to access two different
occurrences of part-number in the array using the same subscript value,
as is illustrated in lines 58-64. For example, if count has the value 1,
then using from-part references the first part-number in the array and
using to-part references the second part-number in the array.
Sometimes one-dimensional arrays contain multiple occurrences of more
than one item. The following example illustrates this.
________________________________________________________________
| |
| 1 system ex67,base=orders; |
| 2 define(item) order-table 10 x(10): |
| 3 ot-line 9(2)=order-table: |
| 4 ot-part x(8)=order-table(3): |
| 5 index i(4): |
| 6 end-of-table i(4); |
| 7 list order-no: |
| 8 line-no: |
| 9 part-number: |
| 10 index: |
| 11 end-of-table: |
| 12 order-table; |
| 13 data order-no; |
| 14 set(key)list (order-no); |
| 15 let (index) = 1; |
| 16 find(chain) orderline,list=(line-no:part-number)|
| 17 ,perform=100-each-line; |
| 18 let (end-of-table) = (index); |
| 19 let (index) = 1; |
| 20 while (index) < (end-of-table) |
| 21 do |
| 22 display(table) ot-line((index)): |
| 23 ot-part((index)); |
| 24 let (index) = (index) + 1; |
| 25 doend; |
| 26 exit; |
| 27 |
| 28 100-each-line: |
| 29 |
| 30 move (ot-part((index))) = (part-number); |
| 31 move (ot-line((index))) = (line-no); |
| 32 let (index) = (index) + 1; |
| 33 return; |
________________________________________________________________
Figure 8-8. One-dimensional record array (multiple items)
Line 2 defines an array consisting of 10 occurrences of 10 bytes each.
Each occurrence is made up of a 2-byte line number and an 8-byte part
number (lines 3 and 4).
Notice again that the IMAGE access verbs cannot reference array items.
Thus lines 16-17 retrieve the next values of line-no and part-number,
then lines 30-31 move these values into the next array occurrence, and
line 32 increments the array occurrence subscript.
Lines 20-25 are a loop that subscripts through the array and prints out
the contents of line-no (ot-line) and part-number (ot-part).
Transact allows subscripting of only one dimension of an array.
Consequently, if an array has more than one dimension, other methods must
be used to qualify the array access of all but the outermost dimension.
This qualification is made possible by the LET OFFSET verb.
The next example is a two-dimensional array and illustrates using a
subscript to qualify the outermost dimension and using LET OFFSET to
qualify the inner dimension.
__________________________________________________________________
| |
| 1 system ex68,base=orders; |
| 2 define(item) order-table 10 x(50): |
| 3 ot-yr-indx x(50) = order-table: |
| 4 ot-year 9(2)=ot-yr-indx: |
| 5 ot-mo-indx 12 9(4)=ot-yr-indx(3): |
| 6 ot-mo 9(4)=ot-mo-indx; |
| 7 define(item) date x(6): |
| 8 date-yy 9(2)=date: |
| 9 date-mm 9(2)=date(3): |
| 10 indx i(4): |
| 11 end-of-table i(4),init=1; |
| 12 define(item) dun i(4): |
| 13 no i(4),init=0: |
| 14 yes i(4),init=1; |
| 15 list dun: |
| 16 no: |
| 17 yes; |
| 18 list order-table,init: |
| 19 end-of-table: |
| 20 indx: |
| 21 date: |
| 22 order-no: |
| 23 order-date: |
| 24 quantity; |
| 25 find(serial) orderhead,list=(order-no,order-date),|
| 26 perform=100-each-order; |
| 27 display order-table; |
| 28 exit; |
__________________________________________________________________
Figure 8-9. Two-dimensional array
_____________________________________________________________________
| |
| 30 100-each-order: |
| 31 |
| 32 move (date) = (order-date); |
| 33 set(key) list (order-no); |
| 34 find(chain) orderline,list=(quantity) |
| 35 ,perform=200-each-line; |
| 36 return; |
| 37 |
| 38 200-each-line: |
| 39 let (indx) = 0; |
| 40 let (dun) = (no); |
| 41 while (dun) = (no) |
| 42 do |
| 43 let (indx) = (indx) + 1; |
| 44 if (ot-year((indx))) = (date-yy) |
| 45 then let (dun) = (yes) |
| 46 else |
| 47 if (indx) = (end-of-table) |
| 48 then |
| 49 do |
| 50 let (end-of-table) = (end-of-table) + 1; |
| 51 let (ot-year((indx))) = (date-yy); |
| 52 let (dun) = (yes); |
| 53 doend; |
| 54 doend; |
| 55 let offset(ot-mo) = [(date-mm) - 1] * 4; |
| 56 let (ot-mo((indx))) = (ot-mo((indx))) + (quantity);|
| 57 return; |
_____________________________________________________________________
Figure 8-9. Two-dimensional array (cont.)
Lines 2 through 6 define the array. The array is intended to hold up to
10 years of data by month. The data that is to be accumulated into the
table is the order quantity for each order and part number.
Line 2 specifies that the first dimension of the array is 10 years of
information. At this time, we must also specify the total byte length of
all information for a year (which is 50). As discussed below, the 50
bytes for each year contain a 2-byte year number and 12 monthly
quantities of 4 bytes each.
Line 3 defines a parent item for one year in the array.
Lines 4 and 5 define the child items that make up a year. A subscript
will be used to access a year and a byte offset via the LET OFFSET verb
will be used to access a month within a year.
Line 5 also defines the parent item for one year of information by month.
Line 6 defines a month within the year.
Line 44 uses the subscript indx to access the year in the array. If the
value of the year in the array is the same as the value of the year in
the input record, we have resolved the year to accumulate to. If it does
not, then the loop is iterated until the matching year is found or the
end of the array is reached. If the end of the array is reached, a new
entry is made into the array, storing the new year number (line 51).
Line 55 specifies the byte offset for a month relative to its parent
item. Since the length of data for each month is 4 bytes, the offset for
the nth month is (n - 1) * 4. Use of LET OFFSET specifies the starting
byte position relative to the base. The base is zero. Thus the first
month has a zero offset, the second month has an offset of 4, which is
the length of the item ot-mo.
The above example illustrates using both subscripts and LET OFFSET to
access a multi-dimensional array.
The following example illustrates using LET OFFSET exclusively to access
the array.
__________________________________________________________________
| |
| 1 system ex68a,base=orders; |
| 2 define(item) order-table 10 x(50): |
| 3 ot-yr-indx x(50) = order-table: |
| 4 ot-year 9(2)=ot-yr-indx: |
| 5 ot-mo-indx 12 9(4)=ot-yr-indx(3): |
| 6 ot-mo 9(4)=ot-mo-indx; |
| 7 define(item) date x(6): |
| 8 date-yy 9(2)=date: |
| 9 date-mm 9(2)=date(3): |
| 10 indx i(4): |
| 11 end-of-table i(4),init=0; |
| 12 define(item) dun i(4): |
| 13 no i(4),init=0: |
| 14 yes i(4),init=1; |
| 15 list dun: |
| 16 no: |
| 17 yes; |
| 18 list order-table,init: |
| 19 end-of-table: |
| 20 indx: |
| 21 date: |
| 22 order-no: |
| 23 order-date: |
| 24 quantity; |
| 25 find(serial) orderhead,list=(order-no,order-date),|
| 26 perform=100-each-order; |
| 27 display order-table; |
| 28 exit; |
__________________________________________________________________
Figure 8-10. Two-dimensional array with LET OFFSET
________________________________________________________________
| |
| 30 100-each-order: |
| 31 |
| 32 move (date) = (order-date); |
| 33 set(key) list (order-no); |
| 34 find(chain) orderline,list=(quantity) |
| 35 ,perform=200-each-line; |
| 36 return; |
| 37 |
| 38 200-each-line: |
| 39 let (indx) = -1; |
| 40 let (dun) = (no); |
| 41 while (dun) = (no) |
| 42 do |
| 43 let (indx) = (indx) + 1; |
| 43.1 let offset(ot-yr-indx) = (indx) * 50; |
| 44 if (ot-year) = (date-yy) |
| 45 then let (dun) = (yes) |
| 46 else |
| 47 if (indx) = (end-of-table) |
| 48 then |
| 49 do |
| 50 let (end-of-table) = (end-of-table) + 1;|
| 51 let (ot-year) = (date-yy); |
| 52 let (dun) = (yes); |
| 53 doend; |
| 54 doend; |
| 55 let offset(ot-mo) = [(date-mm) - 1] * 4; |
| 56 let (ot-mo) = (ot-mo) + (quantity); |
| 57 return; |
________________________________________________________________
Figure 8-10. Two-dimensional array with LET OFFSET (cont.)
The differences between this example and example EX68 are highlighted.
Line 43.1 specifies the byte offset for a year. At this point, we have
resolved addresses for the child items of ot-yr-indx which are ot-year
and ot-mo-indx. Since the length of the data for each year is 50 bytes
(2 byte year and 12 months of 4 bytes each), the offset for the nth year
is (n -1) * 50. However, in the example, indx is used to indicate a year
and has been specified relative to zero. Thus the example does not need
to convert n to be relative to zero.
Line 55 specifies the byte offset for a month relative to its parent
item. Since the length of data for each month is 4 bytes, the offset for
the nth month is (n - 1) * 4.
Notice that once the proper offsets for an item have been established,
the item can be referenced directly without any further qualification
(lines 44, 51, and 56).
The above example is not the only way a two-dimensional array can be
implemented. It is perhaps as close as it is possible to get to the way
COBOL or Pascal might define the same array, recognizing that Transact
always requires you to specify byte offsets rather than an occurrence
number.
The following example illustrates an alternative way to implement the
same array. It is not any better than the first and in fact, the first
is probably easier to follow. However, it is presented with the hope of
improving your understanding of the ways you can manipulate data storage.
__________________________________________________________________
| |
| 1 system ex69,base=orders; |
| 2 define(item) order-table x(500): |
| 3 <<deleted>> |
| 4 ot-year 9(2)=order-table: |
| 5 <<deleted>> |
| 6 ot-mo 9(4)=order-table; |
| 7 define(item) date x(6): |
| 8 date-yy 9(2)=date: |
| 9 date-mm 9(2)=date(3): |
| 10 indx i(4): |
| 11 end-of-table i(4),init=0; |
| 12 define(item) dun i(4): |
| 13 no i(4),init=0: |
| 14 yes i(4),init=1; |
| 15 list dun: |
| 16 no: |
| 17 yes; |
| 18 list order-table,init: |
| 19 end-of-table: |
| 20 indx: |
| 21 date: |
| 22 order-no: |
| 23 order-date: |
| 24 quantity; |
| 25 find(serial) orderhead,list=(order-no,order-date),|
| 26 perform=100-each-order; |
| 27 display order-table; |
| 28 exit; |
__________________________________________________________________
Figure 8-11. Two-dimensional array, special use of LET OFFSET
________________________________________________________________________________
| |
| 30 100-each-order: |
| 31 |
| 32 move (date) = (order-date); |
| 33 set(key) list (order-no); |
| 34 find(chain) orderline,list=(quantity) |
| 35 ,perform=200-each-line; |
| 36 return; |
| 37 |
| 38 200-each-line: |
| 39 let (indx) = -1; |
| 40 let (dun) = (no); |
| 41 while (dun) = (no) |
| 42 do |
| 43 let (indx) = (indx) + 1; |
| 43.1 let offset(ot-year) = (indx) * 50; |
| 44 if (ot-year) = (date-yy) |
| 45 then let (dun) = (yes) |
| 46 else |
| 47 if (indx) = (end-of-table) |
| 48 then |
| 49 do |
| 50 let (end-of-table) = (end-of-table) + 1; |
| 51 let (ot-year) = (date-yy); |
| 52 let (dun) = (yes); |
| 53 doend; |
| 54 doend; |
| 55 let offset(ot-mo) = offset(ot-year) + 2 + [(date-mm) - 1] * 4;|
| 56 let (ot-mo) = (ot-mo) + (quantity); |
| 57 return; |
________________________________________________________________________________
Figure 8-11. Two-dimensional array, special use of LET OFFS
In this example, the definition of the array makes no reference to the
number of years or the number of months in a year. It is just 500 bytes
long, which is the same as the previous example of 10 years by month
where the data for each year is a 2-digit year and 12 months of 4 bytes
each.
The only items that will ever be referred to in this array are ot-year
and ot-mo. These are the only items defined and the definition of them
does not indicate where they are within the array. The definition only
establishes that they are child items of the array, and references to
them will be made relative to the start of the array.
This means that before we address either of these items, we must fully
establish the byte offset of each.
Line 43.1 establishes the byte offset for ot-year. There is no
difference between this and the previous example. The reason is that
both examples define ot-year relative to the start of the array.
Line 55 establishes the byte offset for ot-mo. Here there is a big
difference between this and the previous example. The previous example
defined the start of the months to be relative to the start of a year
plus 2 bytes. The start of a year was defined relative to the start of
the array. In the current example, ot-mo was defined relative to the
start of the array. Therefore its byte offset must account for the year
offset plus the month offset within year plus the fact that the start of
the months for a year are offset from the start of a year by 2 bytes to
allow for storage of a 2-byte year number.
Looking at line 55 and relating it to the above, we already know the year
offset since we set it in line 43.1. Thus we can include it by
specifying OFFSET(ot-year) which is equivalent to the calculation (indx)
* 50. Each month is 4 bytes long, so the offset of the month we want to
reference relative to zero is [(date-mm) - 1] * 4. Finally, the first
month of a year is offset by 2 bytes from the beginning of each year's
data.
MPE/iX 5.0 Documentation