Em Assembler, a entrada e saída de dados não são instruções de máquina — são macros que geram chamadas para serviços do z/OS. O modelo clássico de I/O usa a DCB (Data Control Block) para descrever um dataset, e as macros OPEN, GET, PUT e CLOSE para operar sobre ele. Entender macros é também entender como o COBOL funciona por baixo.
1. O que são macros em Assembler
Uma macro é um nome que o assembler substitui por um bloco de instruções durante a montagem. Macros permitem usar serviços complexos do sistema operacional com uma única linha de código.
🦕 Analogia — macros como atalhos de teclado
Imagine que para abrir um arquivo você precisaria fazer 20 passos. Uma macro como OPEN encapsula esses 20 passos em uma chamada. O assembler "expande" a macro durante a montagem, gerando o código real. Você escreve OPEN (ENTRADA,(INPUT)) e o assembler gera as dezenas de instruções necessárias para montar o SVC call ao z/OS.
As macros padrão do z/OS estão nas bibliotecas SYS1.MACLIB e SYS1.MODGEN — por isso essas bibliotecas aparecem no JCL de compilação como SYSLIB.
2. A DCB — Data Control Block
A DCB é uma estrutura de dados que descreve um dataset: seu formato, tamanho de registro, organização e a DD do JCL que o representa. É declarada como um bloco de dados no programa:
Sintaxe geral da DCB:
nome DCB DSORG=PS, Organização: PS=sequential, PO=partitioned
MACRF=(GM), Macro form: G=GET/P=PUT, M=Move/L=Locate
DDNAME=ddname, Nome da DD no JCL
RECFM=FB, Formato: F=fixed, B=blocked, V=variable
LRECL=80, Logical record length
BLKSIZE=800, Block size
EODAD=nomefim Rotina chamada no fim do arquivo (para GET)
Exemplo — DCB de entrada (leitura):
ENTRADA DCB DSORG=PS,MACRF=(GM),DDNAME=SYSIN,
RECFM=FB,LRECL=80,BLKSIZE=800,
EODAD=FIMFILE
Exemplo — DCB de saída (escrita):
SAIDA DCB DSORG=PS,MACRF=(PM),DDNAME=SYSPRINT,
RECFM=FBA,LRECL=133,BLKSIZE=1330
O MACRF define como a macro acessa o dataset. GM = GET Move (copia o registro para um buffer), PM = PUT Move (copia do buffer para o dataset). Existe também GL/PL (Locate) que retorna o endereço do registro em vez de copiar — mais eficiente para registros grandes.
3. OPEN e CLOSE
Antes de usar um dataset, é preciso abri-lo com OPEN. Ao final, fechar com CLOSE:
Abrir para leitura e escrita:
OPEN (ENTRADA,(INPUT),SAIDA,(OUTPUT))
Verificar se o OPEN foi bem-sucedido:
TM ENTRADA+48,X'10' Testa bit DCBOPEN da DCB
BZ ERROPEN Se zero, OPEN falhou
Fechar os datasets:
CLOSE (ENTRADA,,SAIDA)
O campo ENTRADA+48 é o offset do byte de status na DCB (DCBOPEN). Se o bit 0x10 estiver setado, o arquivo foi aberto com sucesso. Esse teste é importante em código de produção — um OPEN falhado e ignorado causará ABEND na primeira leitura.
4. GET e PUT
O GET lê um registro do dataset para um buffer; o PUT escreve do buffer para o dataset:
GET — ler próximo registro para buffer:
GET ENTRADA,INREC Lê um registro de ENTRADA para INREC
(se fim do arquivo, desvia para EODAD=FIMFILE)
PUT — escrever registro do buffer para dataset:
PUT SAIDA,OUTREC Escreve OUTREC no dataset SAIDA
Buffers declarados com DS, tamanho = LRECL:
INREC DS CL80 Buffer de entrada (LRECL=80)
OUTREC DS CL133 Buffer de saída (LRECL=133)
5. Programa completo de I/O
Um programa que lê registros de SYSIN e copia para SYSPRINT com um prefixo:
COPYREC CSECT
STM R14,R12,12(R13)
BALR R12,0
USING *,R12
ST R13,SAVAREA+4
LA R13,SAVAREA
* Abrir arquivos
OPEN (ENTRADA,(INPUT),SAIDA,(OUTPUT))
* Loop de leitura
LOOP GET ENTRADA,INREC Lê próximo registro
* Montar linha de saída
MVI OUTREC,C' ' ASA: espaço = avançar 1 linha
MVC OUTREC+1(6),=CL6'DADO: ' Prefixo
MVC OUTREC+7(80),INREC Copia registro de entrada
PUT SAIDA,OUTREC Escreve na saída
B LOOP Próximo registro
* Fim do arquivo (EODAD)
FIMFILE CLOSE (ENTRADA,,SAIDA)
* Retorno
L R13,SAVAREA+4
LM R14,R12,12(R13)
SR R15,R15
BR R14
* DCBs
ENTRADA DCB DSORG=PS,MACRF=(GM),DDNAME=SYSIN,
RECFM=FB,LRECL=80,BLKSIZE=800,
EODAD=FIMFILE
SAIDA DCB DSORG=PS,MACRF=(PM),DDNAME=SYSPRINT,
RECFM=FBA,LRECL=133,BLKSIZE=1330
* Dados
SAVAREA DS 18F
INREC DS CL80
OUTREC DS CL133
END COPYREC
6. Outras macros úteis
WTO — Write To Operator (console):
WTO 'PROGRAMA INICIADO' Mensagem literal
WTO TEXT=MENSAGEM,MF=E Mensagem em área de trabalho
MENSAGEM WTO 'PROCESSAMENTO CONCLUIDO',MF=L Lista form (pré-montada)
ABEND — finalizar com código de abend:
ABEND 100,DUMP Abend U0100 com dump de memória
ABEND 200 Abend U0200 sem dump
GETMAIN / FREEMAIN — alocar e liberar memória dinâmica:
GETMAIN R,LV=4096 Aloca 4096 bytes; R1 ← endereço
FREEMAIN R,LV=4096,A=(R1) Libera a memória
TIME — obter data e hora do sistema:
TIME DEC,TIMEWORK,LINKAGE=SYSTEM
R0 ← hora em packed decimal (HHMMSSth)
R1 ← data em packed decimal (0CYYDDDF)
TIMEWORK DS 2F