Converting z/OS assembler code to COBOL

Learn the advantages of converting your low-level z/OS® assembler code to the more flexible, user-friendly COBOL language. Understand some of the differences between the languages and some basics about converting your programs. Code samples in each language illustrate the differences. [In the article update, a space was removed between R1 and R2 in the section "Understanding the basics of an assembler instruction," and Listing 3 was divided into two code samples. -Ed.]

Sandhya Prabhakaran (saprabha@in.ibm.com), Systems Software Engineer, IBM

Photo of Sandhya PrabhakaranSandhya Prabhakaran works on product development with the Advanced Program to Program Communication (APPC) team of the IBM® System z™ software group in Bangalore, India. This is Sandhya's first contribution to developerWorks.



12 January 2007 (First published 17 November 2006)

Introduction: Why convert to COBOL?

In today's programming, with programs written in high-level and scripting languages, it is easy to forget that a significant portion of enterprise IT function lives on big iron mainframes in the form of z/OS assembler code. You may find that your own investment in assembler applications is reaching its end and that you need to move to a higher level language, but you are not ready to jump all the way to Java™ and other newer languages. Remember that COBOL language, though not today's hottest technology under the sun (by a long shot), still offers dramatically greater flexibility and ease-of-coding than assembler language. Though there seems to be a rush to Java and other Web-enabled languages, COBOL remains the only proven 4GL language that handles large volumes of data to be processed on the mainframe.

Coding in assembler language is not like coding in any other language, because assembler lacks the flexibility and user-friendliness of a high-level language. A low-level language directly addresses memory-resident areas called registers; in any high-level language, the variables handle this function.

There are several reasons to convert a low-level assembler program to the higher level COBOL language. The main reasons are:

  • There might be licensing issues with assembler code, and the code might expire. Licensing is often expensive, and you risk losing rights to use the code.
  • Assembler code can be difficult to maintain because of a shortage of experienced professionals.
  • Programming in assembler language is not as flexible or user-friendly as COBOL language.

This article introduces you to some of the intricacies of the assembler language and provides general guidance for how to convert assembler code to COBOL. Code samples show the same program in assembler and COBOL to illustrate the differences.


Understanding the basics of an assembler instruction

An assembler instruction is generally divided into the following four parts:

  • Label
  • Mnemonic (the operation to be performed)
  • Operands and parameters
  • Comment

The label and comment are not required.

For example, consider the following instruction:

ADD-ROUTINE AR R1,R2

This means that the contents in R1 and R2 are added, and the result is stored in R1. The various parts are as follows:

  • ADD-ROUTINE is the label.
  • AR is the mnemonic for ADD REGISTERS.
  • R1 and R2 are the operands. The contents of these registers are added, and the sum is placed in R1).

In assembler, registers are memory locations.


Exploring the framework of an assembler program

Assembler programs generally follow a framework that consists of the following parts:

SAVEAREA HANDLING
This is an initial housekeeping routine that saves the current register contents so that the registers can be used for programming purposes in the assembler routine and restored to their original contents after the routine is completed.
CSECT (code section)
In this part of the program, the variables used in the assembler routine are defined as DC, DS, and EQU, and the logic is coded.
USING statement
The assembler language uses this statement to set the location of the current base register.
DSECT (dummy section) declarations
When other programs call the assembler routines, these declaractions within the assembler program receive the parameters of the calling programs.

Listing 1 shows a simple assembler code fragment that contains the parts of this framework. A doubleslash (//) precedes comments about instructions.

Listing 1. Assembler code fragment
HELLO CSECT 
    USING *,15 	        //Make R15 and HELLO point to the current address where 
          	            //this instruction is present 

    SAVE 14,12,12(13)   //Save contents in R14,R12 into address location        
                        //pointed to by (12+R13) R14, and R12 holds the return address 
                        //(the address of the next instruction to be run in the 
                        //calling program)

    LR 12,15		    //Load register R12 with contents of R15				
    USING HELLO,12  
    WTO 'Hello world.'	//Display ‘Hello world’ on console
    XR 15,15		    //Ex-or to clear R15
    RETURN (14,12) 	    //Restore the contents of R14 and R12
    END

Converting assembler to COBOL: A few tips

COBOL uses a different framework. Here are some tips to follow when converting assembler code to COBOL:

  • Declare variables in the DIVISION under WORKING-STORAGE SECTION.
  • Code logic in the PROCEDURE DIVISION.
  • Ignore a USING statement.
  • Map DSECT (dummy section) declarations as linkage section variables.
  • Replace register names, such as R1 and R2, with meaningful names in COBOL.
  • When copying or moving blocks of data from one memory location to another using COBOL, use the pointer concept. The pointer concept replaces the LOAD and STORE instructions of assembler. Declare a pointer as 01 PTR1 USAGE IS POINTER.
  • Change MODE statements in assembler to if-else conditions in COBOL.
  • Do not explicitly code DS-Declare Storage for variables in COBOL; it is automatically handled during variable declaration.

The code from Listing 1 is converted to COBOL in Listing 2.

Listing 2. Assembler code fragment rewritten in COBOL
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       PROCEDURE DIVISION.
       MAIN-PARA.
                        DISPLAY 'Hello world'.
                        STOP RUN.

Code samples: Converting assembler to COBOL

Listing 3 shows part of a sample assembler routine called ASSEM123, and Listing 4 shows its equivalent in COBOL code. The routine creates a copy of a certain memory range (<1K) and copies a 1K chunk of data into another program-defined area. This process repeats until the entire block of data >1K is copied to the program-defined area. This is a called routine with parameters passed to it.

Note that comments to the code are surrounded by asterisks (**) or preceded by double slashes (//).

Listing 3. Assembler routine code sample ASSEM123
ASSEM123 CSECT                                                          
        STM    R14,R12,12(R13)         SAVE REGS                        
        BALR   R12,0                   ESTABLISH BASE REGISTER          
        USING  *,R12                                                    
        ST     R13,WKAREA+4                                             
        LA     R13,WKAREA                                               
        SPACE  3                                                        
        L      R6,0(R1)                ESTABLISH ADDR TO BEG OF W-S     
        USING  WSSTRT,R6                                                
        L      R5,4(R1)                ESTABLISH ADDR TO END OF W-S     
        USING  WSEND,R5                                                 
        L      R8,8(R1)                ESTABLISH ADDR TO W-S SAVE AREA  
        USING  WSSAVE,R8                                                
        L      R4,12(R1)               ESTABLISH ADDR TO W-S PARM LIST  
        USING  WSPARM,R4                                                
        MVI    DONEFLG,NOTDONE         SET FLAG TO NOT DONE             
        LR     R7,R5                       PREPARE FOR SUBTRACTION          
        SR     R7,R6                       DETERMINE LENGTH OF W-S          
 
        AH     R7,ONE                 FOR CORRECT LENGTH, SET UP 1     
        CH     R7,FULLREC        BIGGER THAN THE 1K SAVE REC      
        BH     MRECS                  NEED TO STORE MULTIPLE SAVE RECS 
        LR     R9,R7                      SET UP FOR 1 MOVE AND SAVE       
        STH    R7,0(R8)                SET LENGTH IN SAVE REC           
        LA     R8,2(R8)                 BUMP TGT PTR PAST LENGTH 1/2WORD 
        MVCL   R8,R6                  MOVE WS TO WS SAVE REC           
        MVI    DONEFLG,DONE            SET FLAG TO DONE                 
        B      FINISH                    EXIT                             
MRECS   DS     0H                                                       
        CLC    SAVER6,=F'00'           FIRST TIME THROUGH?              
        BE     FIRST                           R6 OK AS IS, MUST MOVE MAX LRECL 
        L      R6,SAVER6                   LOAD PTR TO NEXT WS AREA TO MOVE 
        LR     R7,R5                           R5 POINTS TO WS END, CALC        
        SR     R7,R6                           DETERMINE LENGTH OF WS TO MOVE   
        AH     R7,ONE                      SET UP 1 FOR PROPER LENGTH       
        CH     R7,FULLREC             REMAINING WS <= SAVE REC SIZE?   
        BNH    CONT1                     YES...MOVE ACTUAL WS LENGTH      
FIRST   LH     R7,FULLREC        NO...LOAD MAX REC SIZE           
CONT1   LR     R9,R7                   LOAD ODD RECS WIH MOVE LENGTH    
        STH    R7,0(R8)                    SET LENGTH IN SAVE REC           
        LA     R8,2(R8)                     BUMP TGT PTR PAST LENGTH         
        MVCL   R8,R6                   MOVE WS TO WS SAVE REC           
        AR     R6,R7                   BUMP SOURCE PTR BY MOVE LENGTH   
        ST     R6,SAVER6               SAVE FOR NEXT CALL               
        CR     R6,R5                   MOVED ALL WS?                    
        BL     FINISH                  NOT YET...EXIT                   
        MVI    DONEFLG,DONE            SET FLAGE TO DONE                
        B      FINISH                  AND EXIT                         
        EJECT                                                           

FINISH  DS     0H                                                       
        XR     R15,R15                 ZERO TO RETURN CODE REG          
        L      R13,WKAREA+4            RESTORE BACK PTR                 
        LM     R14,R12,12(R13)         RESTORE REGS                     
        BR     R14                     RETURN TO CALLER                 
        SPACE  3                                                        

//Defining all the variables used in the assembler routine

WKAREA  DS     18F                     REG SAVE AREA                    
FULLREC DC     H'0998'                 MAX REX SIZE FOR WS SAVE REC     
ONE     DC     H'0001'                 MAX REX SIZE FOR WS SAVE REC     
        SPACE  1                                                        
NEWSLEN DC     F'00000000'             NEW WS LENGTH SAVE AREA          
WSACUM  DC     F'00000000'             OLD WS ACCUMULATOR ON RESTORE    
WTOMSG  WTO     'U0001-** RSAM ABEND - CHANGE IN WORKING STORAGE SIZE',X
               ROUTCDE=11,MF=L                                          
        SPACE  1                
         
//Here 4 DSECTS are given that correspond to 4 parameters 
//sent to the corresponding COBOL code 
//(these are captured in the LINKAGE SECTION of the COBOL code)  
                            
WSSTRT  DSECT                          WORKING-STORAGE START ADDR       
        DS     F                                                        
WSEND   DSECT                          WORKING-STORAGE END ADDR         
        DS     F                                                        
WSSAVE  DSECT                          WORKING-STORAGE SAVE RECORD      
        DS     F                                                        
WSPARM  DSECT                          WORKING-STORAGE SAVE MODE        
        MODE    DS     CL1                                                      
        SAVER6  DS     F              R6 SAVE AREA                     
        DONEFLG DS     CL1            TELLS IF ALL OF WS WAS MOVED     


DONE    EQU    C'D'                    DONE MOVE                        
NOTDONE EQU    C'N'                    NOT DONE MOVE                    
ERROR   EQU    C'E'                    WS LENGTH HAS CHANGED ON RESTART 
        SPACE  1                                                        
R1      EQU    1                       PARAMETER LIST ADDRESS           
R3      EQU    3                       WORK REGISTER                    
R4      EQU    4                       PARAMETER LIST ADDRESS           
R5      EQU    5                       PARAMETER LIST ADDRESS           
R6      EQU    6                       W-S PARM ADDR                    
R7      EQU    7                       W-S START ADDR                   
R8      EQU    8                       W-S END ADDR                     
R9      EQU    9                       W-S SAVE RECORD ADDR             
R10     EQU    10                      SAVE REG FOR W-S START ADDR      
R11     EQU    11                                                       
R12     EQU    12                      MODULE BASE REG                  
R13     EQU    13                                                       
R14     EQU    14                      LINK REGISTER                    
R15     EQU    15                      BRANCH REGISTER                  
        SPACE  3                                                        
        END

Because the assembler routine is a called routine, a driver program is simulated to test the COBOL equivalent. This driver passes the four parameters to the COBOL code equivalent to the ones used in the assembler routine. Listing 4 shows that the driver passes a 1K chunk of data named WS-DISPAREA to the equivalent COBOL code.

Listing 4. Assembler driver program code fragment
       IDENTIFICATION DIVISION.
       PROGRAM-ID. DRIVER1.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
        01 WS-PTR1 USAGE POINTER.
        01 WS-PTR2 USAGE POINTER.
        01 WS-INDEX PIC 9(2) VALUE ZEROS.
        01 WSSAVE-PARM-AREA.
              05 WSSAVE-PARM  PIC X VALUE 'S'.
              05 WSSAVE-INDEX PIC S9(8) COMP SYNC VALUE +0.
              05 WSSAVE-RETURN-CODE PIC X VALUE 'N'.
        01 WSSAVE-R POINTER.
       LINKAGE SECTION.
        01 WS-DISPAREA PIC X(1000)
       PROCEDURE DIVISION USING WS-DISPAREA.
       MAIN-PARA.

//SETS THE POINTERS TO THE START AND END OF WS-DISPAREA .HERE 
//ADDRESSABILITY IS GIVEN TO THESE POINTER VARIABLES BY POINTING 
//IT TO  WS-DISPAREA.WS-DISPAREA SHOULD ALWAYS  BE DEFINED IN THE 
//LINKAGE SECTION ELSE AN ADDRESSABILITY ERROR WILL BE SHOWN  
      
               SET WS-PTR1 TO ADDRESS OF WS-DISPAREA.
               SET WS-PTR2 TO ADDRESS OF WS-DISPAREA(999:1)
               CALL PGM1 USING WS-PTR1
                                                   WS-PTR2
                                                   WSSAVE-PARM-AREA
                                                   WSSAVE-R.
               END-CALL.
               STOP RUN.

Listing 5 shows the assembler code from Listing 4 converted to COBOL. Note that the driver program with the four parameters calls PGM1, the COBOL code equivalent to that used in the assembler routine. The length of the data passed is calculated and then copied into a program-defined area.

Listing 5. Assembler routine code sample ASSEM123 rewritten in COBOL
IDENTIFICATION DIVISION.
  PROGRAM-ID. PGM1.
  ENVIRONMENT DIVISION.
  DATA DIVISION.

  WORKING-STORAGE SECTION.
  01 WORK-RECORD PIC X(100) VALUE SPACES.

  01 SUBSCR PIC 9(5) VALUE ZERO.
  01 LOOP-COUNTER PIC 9(5) VALUE ZERO.
  01 WS-REMAINDER PIC 9(5) VALUE ZERO.
  01 LOOP-EXIT PIC 9(1) VALUE ZERO.
  01 WS-LENGTH PIC 9(5) VALUE ZERO.
  01 WS-IDX PIC 9(5) VALUE 1.
  01 WS-IDX2 PIC 9(5) VALUE 1.
  01 WS-POINTER POINTER.

  LINKAGE SECTION.

  01 START-ADDRESS-POINTER POINTER.
  01 END-ADDRESS-POINTER POINTER.

  01 WS-END PIC X(1).
  01 WS-PARM.
     05 WS-PARM1  PIC X.
     05 WS-INDEX1 PIC S9(8) COMP SYNC.
     05 WS-RETURN-CODE PIC X.

  01 WS-AREA.
     05 MY-ARRAY PIC X(1) OCCURS 1000 TIMES.

  01 WSSAVE-R1.
     05 WSSAVE-R12 PIC X(1) OCCURS 100 TIMES.

  PROCEDURE DIVISION USING START-ADDRESS-POINTER
                           END-ADDRESS-POINTER
                           WS-PARM
                           WSSAVE-R1.

  MAIN-PARA.
 IF WS-PARM1 EQUAL 'S' AND WS-RETURN-CODE EQUAL 'N'

      DISPLAY 'START-ADDRESS-POINTER=' START-ADDRESS-POINTER

      DISPLAY 'END-ADDRESS-POINTER=' END-ADDRESS-POINTER

      SET ADDRESS OF WS-AREA TO START-ADDRESS-POINTER
      DISPLAY 'WS-AREA=' WS-AREA
      SET ADDRESS OF WS-END TO END-ADDRESS-POINTER
*******************************************************************
//BLOCK TO CALCULATE THE LENGTH OF THE WORKING-STORAGE 
//SECTION PASSED 
*******************************************************************
     PERFORM UNTIL LOOP-EXIT = 1
         IF MY-ARRAY ( WS-IDX ) NOT = WS-END
            COMPUTE
                 WS-LENGTH = WS-LENGTH + 1
            END-COMPUTE
         ELSE
            SET WS-POINTER TO ADDRESS OF MY-ARRAY(WS-IDX)
            IF WS-POINTER = END-ADDRESS-POINTER
               MOVE 1 TO LOOP-EXIT
            END-IF
            COMPUTE
               WS-LENGTH = WS-LENGTH + 1
            END-COMPUTE
         END-IF
         ADD 1 TO WS-IDX
     END-PERFORM

      DISPLAY 'LENGTH OF AREA PASSED=' WS-LENGTH
********************************************************************
//COPIES THE  WORKING-STORAGE SECTION PASSED VIA WS-DISPAREA 
//OF THE DRIVER INTO WS-AREA. FROM WS-AREA, DATA IS COPIED TO 
//WORK RECORD AND FROM WORK-RECORD TO THE WSSAVE-R12 
//ARRAY, WHICH IS 100 BYTES LONG. WORK RECORD ALSO HOLDS 
//ONLY 100 BYTES OF DATA THUS TRANSFERRING THE DATA TO 
//WSSAVE-R12
********************************************************************


      DIVIDE WS-LENGTH BY 100 GIVING LOOP-COUNTER
                               REMAINDER WS-REMAINDER
      END-DIVIDE
      MOVE 1 TO SUBSCR
      PERFORM LOOP-COUNTER TIMES
         MOVE WS-AREA(SUBSCR:100) TO WORK-RECORD
         DISPLAY 'WORK-RECORD=' WORK-RECORD
         MOVE WORK-RECORD TO WSSAVE-R12(WS-IDX2)
          COMPUTE
              SUBSCR = SUBSCR + 10
         END-COMPUTE
         COMPUTE
              WS-IDX2 = WS-IDX2 + 10
         END-COMPUTE
      END-PERFORM
      IF WS-REMAINDER NOT = ZERO
         MOVE WS-AREA(SUBSCR:WS-REMAINDER) TO
              WORK-RECORD
         MOVE WORK-RECORD TO WSSAVE-R12(WS-IDX2)
      END-IF

END-IF.

MOVE 'D' TO WS-RETURN-CODE.
DISPLAY WS-RETURN-CODE.

EXIT PROGRAM.

Resources

Learn

  • developerWorks System z: Learn more about System z mainframe systems.
  • Introduction to the New Mainframe: z/OS Basics: Refer to this IBM Redbook™ that provides the background knowledge and skills necessary to begin using the basic facilities of a mainframe computer. This redbook is the first in a series of textbooks designed to introduce mainframe concepts and to prepare students for a career in large-systems computing.
  • IBM z/OS portal: Browse the latest information about z/OS and find links to downloadable z/OS technology and migration information.
  • IBM Systems™: Want more? The developerWorks IBM Systems zone hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials.
  • developerWorks technical events and webcasts: Stay current with developerWorks technical events and webcasts.

Get products and technologies

  • IBM trial software: Build your next development project with software for download directly from developerWorks.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=175303
ArticleTitle=Converting z/OS assembler code to COBOL
publish-date=01122007