By Don V Nielsen, May 19, 2000
Disclaimer:
Bixoft converted "Redesigning Assembler Language Development" into a
web-document with permission of the original author for
re-publication.
We also applied several minor changes. Nevertheless, the copyrights
of
Mr. Nielsen still apply to the document below.
All samples in this document are no more than examples, and are in no
way
guaranteed to be free of errors or omissions. You may use (parts of)
these
code-samples, but it remains in all aspects your own responsibility
to
test your programs.
Contact:
Mr. Nielsen will gladly accept your comments, remarks etc.
e-mail Don Nielsen.
This document contains the following chapters:
The purpose of this paper is to bring to light coding methods and techniques using Assembler Language and the HLASM Assembler. The HLASM Assembler has evolved with much more power than many people realize. Knowledge of this power and understanding how to utilize it may save you many hours of coding and development, as well as reduce your maintenance efforts.
Programming concepts such as abstraction, reuse, derivation, and qualification can be implemented in assembler language just as they are in higher level languages, like C, COBOL, and Basic. Expanded use of copybooks is encouraged. New methods of implementing copybooks with the USING statement will be introduced. In addition, how and why DSECTs should be defined at the top of the source code will be explained.
Two simple applications are used to demonstrate how to work with the new concepts. The first application is a simple census program that reads records from a dataset, and then stores state abbreviations and their quantity in a table. The application demonstrates all the new coding techniques for building tables. It also demonstrates how these techniques can reduce or eliminate coding changes when the elements of the table change.
The second application is also a census program. This application does not use a table. Instead, it uses a dataset sorted by state abbreviation. It tallies state quantities as records are read by comparing the state abbreviation of the current record to the state abbreviation with the previous record. This application demonstrates how one DSECT can be used to simultaneously map two different records.
At first, learning these techniques might seem like a lot of work. Implementing them might appear to be a lot of typing. However, as time passes and the techniques are employed more frequently, their use will become second nature, and you will find the improvement in readability a great bonus. Your maintenance efforts will be dramatically reduced. In some instances, maintenance may even be eliminated.
The sample programs in Appendix A and Appendix B use HLASM Toolkit macros. These macros add programming structures found in other languages, such as IF/ELSE/ENDIF, DO loops, and others. The macros simplify coding and increase readability of the code.
Bixoft Remark:
In stead of the toolkit, the macros employed in Bixoft's eXtended
Assembly
language may be used for structure and even better readability.
Webster defines abstraction as: "the act or process of separating or removing." Applying the term abstraction to computer programming means to separate the programmer from the underlying details of the process. Calling a function is one example of abstraction. A function is called to complete a task and return a result. We do not need to know how the function performs its task. We simply trust that it is going to perform that task correctly and return the correct result.
This trust is the most difficult concept that we assembler programmers need to exercise. Most of us assembler programmers want to know all the details. However, implementing abstraction will simplify our coding. This requires trusting that some things are simply because they are, and that it is not necessary for us to know why they are. This concept takes effort to accept. You should realize that the concept has been applied and accepted for a long time with regard to system routines.
Reuse is the concept of implementing the past effort of others in order to save development time and effort. A called module is one form of reuse. A macro is another example. When a standard set of logic can be coded as a called module or a macro, then others in the future can implement that logic without having to develop it (redeveloping the wheel, so to say). Yet another form of reuse is the copybook. The copybook is the definition of some structure. Others will not have to expend time and effort coding a structure if that structure is already available as a copybook - or a macro.
Derivation is receiving or obtaining something from a source. In the definition of a field, we may derive an attribute of the field from a previously defined field. For example, a program needs to save a copy of the ZIP code from an input record. The program utilizes a macro or a copybook that has already defined the attributes of the ZIP code. The existing attributes from the existing definition in the macro or copybook can be derived and used in the definition of the new field.
A field is the simplest of structures. It represents one piece of data. To the assembler, a field represents a number of bytes in storage and not much else. Some may consider the type of data to be important. However, to the assembler, the definition of a field as packed, hexadecimal, or character is for the convenience of the programmer. The most meaningful attribute of a field is the amount of storage it occupies.
All records and table entries can be described with a lay-out. A lay-out is a structure that maps data. It defines the locations and lengths of fields, and enforces structure. The length of a lay-out is the cumulative value of the field lengths plus any padding caused by field alignment. Records and table entries are functionally the same.
Always code lay-outs for table entries and records. This is the first, most important step when beginning to code. Coding lay-outs simplify the development and maintenance of programs. If a lay-out is to be shared across multiple programs, then save the lay-out as a macro or a copybook. This will reduce coding time and effort on future projects.
A table is an area of storage dedicated to holding a series of related data. A table consists of one or more entries, where the lay-out of each entry is identical. Visually, a two-dimensional table may be thought of as a piece of lined paper; the paper represents the table, and each of the lines represents an entry.
Tables, like fields, have attributes. A table has a starting address, which is the first byte of the first entry. It has an ending address, which is the last byte of the last entry. The space that the table occupies can be divided evenly by the entry length, yielding the maximum number of entries that the table can hold.
A simple census table application is used to demonstrate the concepts presented. The table will consist of two fields: state abbreviation and census count. Later, counts by gender will be added to the table entry lay-out. This will demonstrate how a table and program can be constructed such that a change in a lay-out's definition will not incur any coding changes. Maintenance to the program's code will have been eliminated.
The first step in developing the program is mapping the input dataset. The program reads input data through a DD name INFILE. It uses a DCB by the same name to read the input data. The data is read directly into a record structure defined by a copybook named CMS0001A. The copybook contains all the field definitions, and is implemented as a DSECT. The base structures (record lay-out and DCB) are coded as follows:
... INPUT_LAYOUT DSECT COPY CMS0001A * Standard record lay-out L_INPUT_LAYOUT EQU *-INPUT_LAYOUT * Calculate length of lay-out ... INREC DS CL(L_INPUT_LAYOUT) * Define storage for input ... INFILE DCB DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL ...
When using a macro in stead of a copybook (or a macro using a copybook), the sample above could be recoded as:
... INPUT_LAYOUT CMS0001A DSECT=YES * Lay-out and length of input ... INREC DS CL(L_INPUT_LAYOUT) * Define storage for input ... INFILE DCB DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL ...
The concepts of reuse, abstraction, and derivation have all been applied in the above example. The use of the macro or copybook CMS0001A is an example of reuse and abstraction. First, an existing lay-out is being reused rather than redeveloping it. Always try to use an existing macro or copybook when available. The benefits of using a macro or copybook are:
Use of the macro or copybook implements abstraction, too. The macro or copybook hides the details of the record lay-out. Yes, it is important to know the record lay-out that one is working with. However, detailed knowledge of the lay-out's structure is seldom required. Abstraction is also applied with the definition of L_INPUT_LAYOUT. This statement uses the assembler to calculate the length of the defined lay-out. It is abstract because you do not need to know the length; you trust that the length has been calculated for your use.
Derivation is used in the definition of the INREC field. The assembler sets the length of INREC using the calculated record length, L_INPUT_LAYOUT. This is also an example of how to implicitly define a field's length. With HLASM, the length attribute of a field can be assigned from a previously defined field. Deriving the length attribute allows HLASM to allocate storage based on the existing length value.
HLASM allows you to define a field's length explicitly or implicitly. An explicit definition of a field's length has the actual length coded. For example, the above INREC definition could have been coded explicitly using "INREC DS CL200" This is a simpler method of defining INREC. However, there are two reasons for discouraging the use of explicit lengths:
In order to allocate storage explicitly, one must have prior knowledge of the space required. One would have to research the macro or copybook, determine its length, and code that length in the explicit definition. In addition, much effort is required to update programs when the length of the lay-out changes. All programs that implement the lay-out will require research in order to update its explicit storage allocations.
An implicit definition means that a symbol is used to define the field's length. L_INPUT_LAYOUT is an example of an implicit length because the symbol is a representation of the required length. L_INPUT_LAYOUT is the length of CMS0001A as calculated by the assembler. Broad implementation of this concept can reduce maintenance efforts from hours to minutes. Should the actual length of CMS0001A change, the assembler will calculate the new length, assign the length value to L_INPUT_LAYOUT, which is then used to set the length of INREC. Thus, updating the macro or copybook also updates all programs - automatically.
... INPUT_LAYOUT CMS0001A DSECT=YES * Lay-out and length of input ... TABLE_ENTRY DSECT STATE DS CL(L'CMSTATE) * State abbreviation TOTAL DS F * Total quantity L_TABLE_ENTRY EQU *-TABLE_ENTRY * Calculate length of entry ... MAX_ENTRIES EQU 100 * Maximum nr of entries in table ... INREC DS CL(L_INPUT_LAYOUT) * Define storage for input ... INFILE DCB DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL ... * Define table storage STATE_CENSUS_TABLE DC (MAX_ENTRIES)XL(L_TABLE_ENTRY)'00' E_STATE_CENSUS_TABLE EQU * * End of table ...
Two structures and a constant have been added to our code example. The TABLE_ENTRY structure provides a map of the fields used in the table entry. The first field, STATE, is for the state abbreviation and it is the key field for searching the table. Notice that STATE is the second example of derivation. STATE derives its length from CMSTATE. You are not required to know how long CMSTATE is. You trust that STATE will be defined for an equal number of bytes.
The second field, TOTAL is the counter field. It is defined as F, a signed binary fullword, or 32 bits. As each input record is processed, the state abbreviation is located in the table. If the abbreviation is not found, then it is added. The TOTAL field is then incremented.
The assembler must be used to calculate L_TABLE_ENTRY. This is required because the length of STATE is derived. There is no way to know, without research, the actual length of CMSTATE. So, we trust that the assembler derives the length of CMSTATE and assigns it to STATE. The result is the length of STATE being equal to the length of CMSTATE. L_TABLE_ENTRY is equal to L'STATE+L'TOTAL plus any padding bytes required for alignment. Once again, the actual length value is not important. It is important to realize that the length exists and that it has been computed correctly by the assembler.
MAX_ENTRIES is a constant that represents the maximum number of entries that can be stored in the table. It is used in the definition of STATE_CENSUS_TABLE. The table's size is controlled by this constant. A table, as defined earlier, is the space used by all the table entries. Thus, the size of the table is equal to the table's entry length times the maximum number of entries. The actual definition of STATE_CENSUS_TABLE is an example of this calculation. Using MAX_ENTRIES and L_TABLE_ENTRY to implicitly define the attributes of the table, the assembler calculates the space required and allocates that space to the symbol STATE_CENSUS_TABLE
The real power of this implicit definition is realized when the table requires maintenance. All it takes to expand the number of entries that STATE_CENSUS_TABLE may contain is to change the MAX_ENTRIES value. In addition, if the table's entry definition changes, the assembler uses the resulting entry length in establishing the size of STATE_CENSUS_TABLE. This will be demonstrated later when the gender counters are added to TABLE_ENTRY.
... USING INPUT_LAYOUT,INREC * Assign DSECT to INREC USING TABLE_ENTRY,R3 * Assign DSECT to REGISTER ... FILELOOP GET INFILE,INREC * Read record into storage LA R3,STATE_CENSUS_TABLE * Load ptr to table entry TBLLOOP C R3,=A(E_STATE_CENSUS_TABLE) * If end of table BNL ERRTABLE * branch to error routine CLI STATE,X'00' * If state is null (empty entry) BE ADDSTATE * then add state to table CLC CMSTATE,STATE * Input matches table record? BE STFOUND * Yes: entry located LA R3,L_TABLE_ENTRY(R3) * Point next entry in table B TBLLOOP * and go check this entry ADDSTATE MVC STATE,CMSTATE * Init new state in table STFOUND LA R1,1 * Load increment value A R1,TOTAL * Add quantity for state ST R1,TOTAL * Save incremented value B FILELOOP * And go get next record ...
After an input record has been read, it is necessary to locate the state abbreviation in the table. Before we can access any data, both the input record and the table entry must be mapped. This is accomplished with the USING statement. USING is not an instruction that is processed like a compare instruction or a branch instruction. It is a directive used by the assembler to determine how and where storage is being mapped. DSECTS are used to describe the storage. A DSECT can map storage as referenced by a symbol, or it can map storage as referenced by the contents of a register. Both implementations are used in the example.
USING INPUT_LAYOUT,INREC applies the CMS0001A lay-out to the storage defined as INREC. Whenever a field from the CMS0001A copybook is referenced by an instruction, the data from that field is pulled from the INREC storage space. CMSTATE is located at position 147 of the CMS0001A lay-out. Whenever CMSTATE is referenced in the program, position 147 of INREC (or INREC+146) is the source of the data.
USING TABLE_ENTRY,R3 applies the TABLE_ENTRY lay-out to the storage being pointed to by register 3. Whenever a field from the TABLE_ENTRY lay-out is referenced by an instruction, the data from that field is located within storage pointed at with R3. STATE is located at position 1 of the table entry lay-out. Whenever STATE is referenced in the program, then the first byte pointed to by R3 [or 0(R3)] is the location of the state abbreviation in the table entry.
The flow of the programming loop is as follows:
Let's go over some key concepts at this point. The first point is the relationship between INPUT_LAYOUT and INREC. INREC was defined using the calculated length of the input record lay-out, or L_INPUT_LAYOUT. While INREC has the proper amount of storage defined, it does not have fields assigned to it. References to fields within INREC are assigned by the USING INPUT_LAYOUT,INREC statement. Thus, whenever a field from INPUT_LAYOUT is referenced, it is the storage from INREC that is accessed.
The symbol L_TABLE_ENTRY is used to increment the table pointer, R3. The assembler uses the calculated value. A change in the table entry length will not affect this code.
... INPUT_LAYOUT CMS0001A DSECT=YES * Lay-out and length of input ... TABLE_ENTRY DSECT STATE DS CL(L'CMSTATE) * State abbreviation TOTAL DS F * Total quantity FEMALE DS F * Female quantity MALE DS F * Male quantity UNKNOWN DS F * Unknown gender L_TABLE_ENTRY EQU *-TABLE_ENTRY * Calculate length of entry ... MAX_ENTRIES EQU 100 * Max.nr of entries in table ... INREC DS CL(L_INPUT_LAYOUT) * Define storage for input ... INFILE DCB DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL ... * Define table storage STATE_CENSUS_TABLE DC (MAX_ENTRIES)XL(L_TABLE_ENTRY)'00' E_STATE_CENSUS_TABLE EQU * * End of table ...
Now that we have the basic program developed, new counters are going to be added to the table. In adding these counters, you are going to realize the effort and time saving qualities provided by these programming techniques.
The only change required for the entire program is to add the fields FEMALE, MALE, and UNKNOWN. That's it. The program can be reassembled with no other changes.
Let's go through what has happened and how the assembler resolves the changes. Three fields were added to TABLE_ENTRY. These fields have increased the table entry length by twelve bytes. The calculated value L_TABLE_ENTRY is used throughout the program. The assembler calculates the required table storage using the implicit values of L_TABLE_ENTRY and MAX_ENTRIES and assigns that amount of storage to STATE_CENSUS_TABLE.
No changes are necessary in the processing code. The statements affected by the changes are as follows:
Note:
if the size of CMSTATE is altered in the CMS0001A macro or copybook,
this application can be reassembled, error free, with no
modifications,
whatsoever.
Many programs need to compare the contents of one record to the contents of another record. In this case, we have two instances of the same structure. In the past, this meant coding two separate lay-outs with field names that are mildly different. An example might be ZIP1 and ZIP2.
HLASM provides a feature called the Labelled Using statement to resolve this problem. A Labelled Using statement allows us to assign one DSECT to multiple locations at the same time. The locations may be referenced by a register, or may be assigned to a symbol defined in core.
To demonstrate this power, a new census program will be developed. We will assume the input dataset is sorted into state abbreviation sequence. The program will read records and increment a counter. When the state abbreviation changes, the counter will contain the number of records for the previous state abbreviation.
To accomplish this, the program is going to read a record, compare the state abbreviation on the record just read to the previous record's state abbreviation. If there is a change, then a count will be produced. The record just read will be moved to the storage assigned for the previous record.
... COUNTER DC PL4'1' * State counter PREVREC DS CL(L_INPUT_LAYOUT) * Storage for input record ... INFILE DCB DDNAME=INFILE,DSORG=PS,MACRF=GL,EODAD=EOFINFIL ...
The above code establishes a save area for the previous record processed. Once an input record has been processed, it will be moved to PREVREC. In addition, the MACRF on the DCB has been changed from GM to GL. This informs the program that the input record is not moved to a defined storage area with each get. The record read by the system is considered the current record, and it remains in its buffer where it can be referenced with R1.
Note:
if the program is using any system service other than the get macro,
or calls
any subprogram during the processing of any record, R1 will be
considered
a volatile register, and cannot be used to keep any data or pointer
during or after execution of that service or call. In a real program
R1 should be used only as a temporary or working register.
A table is not defined in this application as nothing is being tabled. The program uses the change in state abbreviation to indicate a state count.
... PRV USING INPUT_LAYOUT,INREC * Assign DSECT to INREC CUR USING INPUT_LAYOUT,R1 * Assign DSECT to register ... FILELOOP GET INFILE * Read record into storage CLC CUR.CMSTATE,PRV.CMSTATE * State changed? BNE CHGSTATE * Yes: go process changed state * Save current record MVC INREC,CUR.INPUT_LAYOUT * or code "INREC,0(R1)" AP COUNTER,P'1' * Increment counter B FILELOOP * and go read next record ...
The USING statements are assigned the labels PRV and CUR. The USING labelled PRV uses INPUT_LAYOUT to map storage at PREVREC. The USING labelled CUR uses INPUT_LAYOUT to map storage at 0(R1), which is the location of the record within its buffer. The USING labels are used to qualify a field name so that the assembler understands which instance of the field name you are referring to. PRV.CMSTATE refers to the location of CMSTATE within PREVREC, or PREVREC+146. CUR.CMSTATE refers to the location of CMSTATE, as pointed to by R1, or 146(R1).
The assembler operates using two passes of the source code. In the first pass of the source code, it identifies all symbols and attempts to identify all the attributes of those symbols. However, some attributes may not be resolved because they cannot be established in a sequential manner. In these cases, the attributes will not be resolved until the second pass of the source code.
Identification of symbols involves reading copybooks and expanding macros. Macros are those single statements that generate code for you. For example, DCB, OPEN, and GET are examples of macros. Structured programming macros from the HLASM Toolkit or Bixoft's eXtended Assembly language like IF/ELSE/ENDIF and DO/END are other examples. Some macros require all symbol attributes to be resolved during the first pass. Without resolution, the assembler may generate errors because it cannot identify field lengths.
The assembler processes the source in sequence. So, placing DSECTs that invoke copybooks at the top of the source code establishes the symbols early on so that a macro's code can be expanded without error.
Personally, I like to have all DSECTs at the top of the program. This is in line with other languages like PASCAL, C, COBOL, and BASIC. It provides one location for all the structures, and provides the programmer with information as to what the program will be working with.
Bixoft Remark:
Our advice is to insert all DSECTs at the top of the program. This
has the
following advantages:
The beginning of an assembler program will normally begin with some type of housekeeping entry macro. However, if you place DSECTS above the entry macro, it may cause an assembly error. To prevent the error from occurring, a change in the housekeeping code at the top of the program is required. A program should follow this structure.
ProgName CSECT * * DSECTS and mapping macros go here * ProgName "Housekeeping Macro or entry point CSECT logic" ...
The CSECT statement at the top prevents the assembly errors from occurring.
Bixoft remark:
When using Bixoft's eXtended Assembly language, the PGM macro is
used
for generating the entry logic, including all mappings required.
E.g.:
ProgName PGM VERSION=V00R00M00, * Version number * HDRTXT='Sample program', * SAVES=2, * Internal save-areas * MAPS=(CMS0001A, * Private lay-outs * DCB,DCBE,DECB,IOB) * Standard IBM lay-outs
As this paper demonstrates, programming concepts like abstraction, reuse, and derivation can be utilized in assembler as they are in higher level languages like PASCAL, C, or BASIC. Abstraction can be used to hide the details of structure that would otherwise clutter the source code. Reuse allows us to leverage the accomplishments of others so that our effort is reduced. Derivation allows us to use pre-existing attributes in the definition of like fields. All the concepts give us the ability to make the HLASM assembler work harder for us so we do not have to.
The sample programs show how abstraction and reuse are applied to macro and/or copybook usage. Macros and copybooks standardize our programs. It speeds up the process of understanding the code because field names will be consistent from one module to the next. Copybooks also provide the basis from which we can derive like storage spaces and like field definitions. For example, we can use the definition of CMSTATE in the definition of a table entry so those like fields have like attributes.
The sample programs also demonstrate that broad use of these techniques can dramatically reduce our future maintenance efforts. In some cases, maintenance may be reduced to zero when a record or field definition changes.
It is my hope that you will take an interest in the techniques explained in this paper. The use of these techniques will save you much time and effort in the future. These techniques reduce the impact that change has on the entire module.
SAMPLE01 CSECT INPUT_LAYOUT DSECT COPY CMS0001A * Standard record lay-out L_INPUT_LAYOUT EQU *-INPUT_LAYOUT * Calculate length of lay-out TABLE_ENTRY DSECT STATE DS CL(L'CMSTATE) * State abbreviation TOTAL DS FL4 * Total quantity FEMALE DS FL4 * Female quantity MALE DS FL4 * Male quantity UNKNOWN DS FL4 * Unknown gender L_TABLE_ENTRY EQU *-TABLE_ENTRY * Calculate length of entry MAX_ENTRIES EQU 100 * 100 Total entries SAMPLE01 ENTERMPG BASE=R12,VER=A,MAIN=N,TEST=Y,DESC='TABLE EXAMPLE' USING INPUT_LAYOUT,INREC * Assign DSECT to symbol USING TABLE_ENTRY,R3 * Assign DSECT to register IF (CLI,FirstTime,EQ,FTyes) * Only during first pass MVI FirstTime,FTno * Set first-pass indicator OPEN (INFILE,INPUT) * Open input dataset ENDIF , * DO INF * Do until end of file READREC GET INFILE,INREC * Read input record LA R3,STATE_CENSUS_TABLE * Point to start of table DO UNTIL=(C,R3,NL,=A(E_STATE_CENSUS_TABLE)) IF (CLI,STATE,EQ,X'00') * Empty state located? MVC STATE,CMSTATE * Yes: add new state to table ENDIF IF (CLC,CMSTATE,EQ,STATE) * State entry located? INCR TOTAL * Increment total count SELECT CLI,CMGENDER,EQ * Which gender: WHEN CMGENDER_MALE * Male? INCR MALE * Yes: increment male counter WHEN CMGENDER_FEMALE * Female? INCR FEMALE * Yes: increment female counter ELSE , * Unknown gender, so INCR UNKNOWN * increment unknown count ENDSEL B READREC * Exit from inner do loop ENDIF LA R3,L_TABLE_ENTRY(R3) * Point next table entry ENDDO , * and go check this entry WTO 'No more room in table' * Out of table space... ABEND 666 * No more room ENDDO , * End of outer loop EOF CLOSE INFILE * Close input dataset LEAVEMPG RC=0 * End of job LTORG FirstTime DC XL1'00' * First-pass indicator FTYES EQU X'00' * Yes: first pass FTno EQU X'FF' * No: initialization done INREC DS CL(L_INPUT_LAYOUT) * define storage for input INFILE DCB DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOF * Define the table STATE_CENSUS_TABLE DC (MAX_ENTRIES)XL(L_TABLE_ENTRY)'00' E_STATE_CENSUS_TABLE EQU * * Define end-of-table address END SAMPLE01
SAMPLE02 CSECT INPUT_LAYOUT DSECT COPY CMS0001A * Standard record lay-out L_INPUT_LAYOUT EQU *-INPUT_LAYOUT * Calculate length of lay-out SAMPLE02 ENTERMPG BASE=R12,VER=A,MAIN=N,TEST=Y,DESC='ABBR SAMPLE' PRV USING INPUT_LAYOUT,INREC * Assign DSECT to symbol CUR USING INPUT_LAYOUT,R3 * Assign DSECT to register IF (CLI,FirstTime,EQ,FTyes) * Only during first pass MVI FirstTime,FTno * Set first-pass indicator OPEN (INFILE,INPUT) * Open input dataset GET INFILE * Read first record LR R3,R1 * Set pointer to record read * Copy first record to prevent recognition of a state change * for the very first record read. MVC PRV.INPUT_LAYOUT,CUR.INPUT_LAYOUT ENDIF , * DO INF * Do until end of file GET INFILE * Read a record LR R3,R1 * Set ptr to current record IF (CLC,CUR.CMSTATE,NE,PRV.CMSTATE) * Change in state? OI COUNTER+L'COUNTER-1,X'0F' * Make counter unsigned UNPK WTO01+24(7),COUNTER * Insert counter into message MVC WTO01+15(L'CMSTATE),PRV.CMSTATE * Add previous state WTO01 WTO 'STATE: .. QTY=XXXXXXX ' * Display state and count ZAP COUNTER,=P'0' * Reset counter ENDIF AP COUNTER,=P'1' * Increment counter * Make current record the previous one MVC PRV.INPUT_LAYOUT,CUR.INPUT_LAYOUT * MVC INREC,0(R3) * Alternative code for move ENDDO EOF CLOSE INFILE * Close input dataset LEAVEMPG RC=0 * End of job LTORG FirstTime DC XL1'00' * First-pass indicator FTYES EQU X'00' * Yes: first pass FTno EQU X'FF' * No: initialization done COUNTER DC PL4'1' * Initialize counter to one INREC DS CL(L_INPUT_LAYOUT) * Define storage for input INFILE DCB DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOF END
This site is a member of WebRing. You are invited to browse the list of mainframe-loving sites. |
Dinos are not dead. They are alive and well and living in data centers all around you. They speak in tongues and work strange magics with computers. Beware the dino! And just in case you're waiting for the final demise of these dino's: remember that dinos ruled the world for 155-million years! | |
[ Join Now | Ring Hub | Random | | ] |
To Introduction.
To Background Terminology.
To Building Blocks.
To Step 1, Map the Data.
To Step 2, Build the Program.
To Using the Same Lay-out Twice.
To Placing DSECTs at the Top of the Program.
To In Conclusion.
To Sample Program Using Table.
To Sample Program Using Change in State
Abbreviation.
Below you find the logo of our sponsor and logos of the web-standards that this page adheres to.