martedì 9 ottobre 2018

FUSIONE - Un semplice programma COBOL

L'algoritmo di fusione visto prima si può tradurre in un semplice programma in linguaggio COBOL.
Come già detto le strutture S1 e S2 e OUT in questo caso assumono la forma di tre file.

Il listato COBOL, ridotto ai minimi termini per semplicità ma comunque funzionante, è il seguente:

 IDENTIFICATION DIVISION.                           
*--------------------------------------------------*
 PROGRAM-ID. FUSIONE.                               
*--------------------------------------------------*
 ENVIRONMENT DIVISION.                              
 INPUT-OUTPUT SECTION.                              
 FILE-CONTROL.                                      
* FILE DI INPUT CONTENENTE LA STRUTTURA S1          
     SELECT S1          ASSIGN S1.                  
* FILE DI INPUT CONTENENTE LA STRUTTURA S2          
     SELECT S2          ASSIGN S2.                  
* FILE DI OUTPUT CONTENENTE LA FUSIONE S1+S2        
     SELECT OUT         ASSIGN OUT.                 
*--------------------------------------------------*
 DATA DIVISION.                                     
 FILE SECTION.                                      
 FD S1                                      
     LABEL RECORD IS STANDARD               
     RECORDING MODE IS F                    
     BLOCK 0 RECORDS.                       
 01 S1-REC.                                 
    05 S1-STRING                   PIC X.   
 FD S2                                      
     LABEL RECORD IS STANDARD               
     RECORDING MODE IS F                    
     BLOCK 0 RECORDS.                       
 01 S2-REC.                                 
    05 S2-STRING                   PIC X.   
  FD OUT                                    
      LABEL RECORD IS STANDARD              
      RECORDING MODE IS F                   
      BLOCK 0 RECORDS.                      
  01  OUT-REC                      PIC X.   
*--------------------------------------------------*   
 WORKING-STORAGE SECTION.                              
*--------------------------------------------------*   
*                                                      
 01  KEY1                         PIC X VALUE SPACES.  
 01  KEY2                         PIC X VALUE SPACES.  
*                                                      
*--------------------------------------------------*   
 PROCEDURE DIVISION.                                   
*--------------------------------------------------*   
 P000-MAIN-LINE.                                       
*                                                      
     OPEN INPUT S1.                                    
     OPEN INPUT S2.                                    
     OPEN OUTPUT OUT.                                  
     READ S1 INTO KEY1 AT END MOVE HIGH-VALUE  TO KEY1.
     READ S2 INTO KEY2 AT END MOVE HIGH-VALUE  TO KEY2.
     DISPLAY 'INIZIO PROGRAMMA DI FUSIONE'                     
     PERFORM UNTIL KEY1 = HIGH-VALUE AND KEY2 = HIGH-VALUE     
         IF KEY1 < KEY2                                        
            DISPLAY KEY1 ' < ' KEY2 ' - SCRIVO : ' KEY1        
            WRITE OUT-REC FROM KEY1                            
            READ S1 INTO KEY1 AT END MOVE HIGH-VALUE TO KEY1   
         ELSE                                                  
            IF KEY1 > KEY2                                     
               DISPLAY KEY1 ' > ' KEY2 ' - SCRIVO : ' KEY2     
               WRITE OUT-REC FROM KEY2                         
               READ S2 INTO KEY2 AT END MOVE HIGH-VALUE TO KEY2
            ELSE                                               
               WRITE OUT-REC FROM KEY1                         
               DISPLAY KEY1 ' = ' KEY2 ' - SCRIVO : ' KEY1     
               READ S1 INTO KEY1 AT END MOVE HIGH-VALUE TO KEY1
               READ S2 INTO KEY2 AT END MOVE HIGH-VALUE TO KEY2
            END-IF                                             
         END-IF                                   
     END-PERFORM.                                 
     DISPLAY 'TERMINE PROGRAMMA DI FUSIONE'.      
     CLOSE S1.                                    
     CLOSE S2.                                    
     CLOSE OUT.                                   
     GOBACK.                                      
*                                                 
 P000-EXIT.                                       
     EXIT.                                        
Nella PROCEDURE DIVISION è riportato l'algoritmo visto prima corredato di alcune DISPLAY per esporne in SYSOUT l'operato.

Un Job JCL di lancio può essere il seguente:

//SYSADMX JOB (12345678),SYSADM,MSGCLASS=H,               
//        MSGLEVEL=(1,1),CLASS=A,NOTIFY=&SYSUID           
//STEP1 EXEC PGM=FUSIONE                                  
//STEPLIB DD DSN=SYSADM.LIB.LOAD,DISP=SHR                 
//S1      DD DSN=SYSADM.PE000.S1,DISP=SHR                 
//S2      DD DSN=SYSADM.PE000.S2,DISP=SHR                 
//OUT     DD DSN=SYSADM.PE000.OUT,                        
//           DISP=(,CATLG,DELETE),SPACE=(CYL,(8,8),RLSE), 
//           DCB=(LRECL=1,RECFM=FB)                       

//SYSOUT DD SYSOUT=* 

Come si vede in esso semplicemente dichiariamo i file elaborati dal programma e allochiamo il file prodotto in output.

Popoliamo i due files in input come segue:

S1 = 1,3,5,7,9
S2 = 2,4,6,7

E lanciamo il JCL.
Al termine dell'esecuzione il file OUT conterrà i valori:

OUT = 1,2,3,4,5,6,7,7,9

mentre in SYSOUT potremo vedere le DISPLAY poste nel programma:

********************************
INIZIO PROGRAMMA DI FUSIONE     
1 < 2 - SCRIVO : 1              
3 > 2 - SCRIVO : 2              
3 < 4 - SCRIVO : 3              
5 > 4 - SCRIVO : 4              
5 < 6 - SCRIVO : 5              
7 > 6 - SCRIVO : 6              
7 = 7 - SCRIVO : 7              
9 > 7 - SCRIVO : 7              
9 <   - SCRIVO : 9              
TERMINE PROGRAMMA DI FUSIONE    

********************************

Come già detto, questo è un programma minimale. Manca ad esempio la gestione degli errori in fase di I/O, tipicamente tramite FILE-STATUS ma rende bene l'idea dell'operato dell'algoritmo.






















venerdì 5 ottobre 2018

Fusione, un algoritmo.

Con riferimento al post precedente, un algoritmo che realizzi la fusione fra due strutture dati potrebbe essere il seguente:

Supponiamo che le strutture S1 e S2 siano due file e che si voglia scrivere in output un nuovo file contenente l'unione dei due input.

L'idea di base è di memorizzare la chiave di fusione in una variabile "key1" per S1 e "key2" per S2 e lavorare sulle relazioni logiche che possono crearsi fra queste due variabili.

  1. Se key1 è minore di key2, S1 andrà in output e un nuovo valore di S1 sarà letto;
  2. Se key1 è maggiore di key2, S2 andrà in output e un nuovo valore di S2 sarà letto;
  3. Se key1 è uguale a key2, uno fra S1 e S2 andrà in output e un nuovo valore sia di S1 che di S2 sarà letto;
Questa serie di confronti andrà avanti fino a quando tutte le letture saranno completate.
Per gestire il caso, frequente, di file di grandezza diversa si avrà cura, nel caso uno dei due file termini prima dell'altro, di porre la chiave corrispondente ad un valore "tappo" (Tipicamente in COBOL si usa HIGH-VALUE).
In questo modo una delle due condizioni 1 e 2 sarà sempre verificata provocando lo scarico dell'altro file in output.

L'algoritmo precedente può essere espresso in pseudo-codifica nel modo seguente:

START
    OPEN S1, S2,OUT;
    READ S1 IN KEY1 AT END KEY1=HV;
    READ S2 IN KEY2 AT END KEY2=HV;
    PERFORM UNTIL KEY1=HV AND KEY2=HV
        IF KEY1 < KEY2 THEN
             WRITE OUT FROM S1;
             READ S1 IN KEY1 AT END KEY1=HV;
        ELSE
             IF KEY1 > KEY2 THEN
                 WRITE OUT FROM S2;
                 READ S2 IN KEY2 AT END KEY2=HV;         
             ELSE
                  WRITE OUT FROM S1;
                  READ S1 IN KEY1 AT END KEY1=HV;
                  READ S2 IN KEY2 AT END KEY2=HV;
             END-IF;
       END-IF;
    END-PERFORM;
    CLOSE S1,S2,OUT
END