Com os fundamentos e a integração TSO/ISPF dominados, este artigo fecha a trilha com os recursos avançados do REXX que separam scripts simples de ferramentas robustas. Stems são os arrays do REXX — estruturas de dados associativas que guardam listas de qualquer tamanho. PARSE é a instrução mais poderosa da linguagem para decompor strings. SIGNAL ON é o mecanismo de tratamento de erros que torna seus execs resilientes.
1. Stems — arrays no REXX
Um stem é uma variável com um ponto no nome — LISTA. — que funciona como array associativo. Por convenção, LISTA.0 guarda o número de elementos e LISTA.1, LISTA.2... guardam os valores:
/* Criar um stem manualmente */
FRUTAS.0 = 3
FRUTAS.1 = 'Maçã'
FRUTAS.2 = 'Banana'
FRUTAS.3 = 'Laranja'
/* Percorrer o stem */
DO I = 1 TO FRUTAS.0
SAY I'.' FRUTAS.I
END
/* Construir stem dinamicamente (ex: capturando linhas) */
CONTADOR = 0
DO WHILE CONDITION
CONTADOR = CONTADOR + 1
DADOS.CONTADOR = VALOR_ATUAL
END
DADOS.0 = CONTADOR
Stems também aceitam índices não numéricos — como chaves em um dicionário:
/* Stem com chave textual — como hashmap */
SALARIO.'MARIA' = 4500
SALARIO.'JOAO' = 3200
SALARIO.'ANA' = 5100
NOME = 'MARIA'
SAY NOME'ganha' SALARIO.NOME
/* Saída: MARIA ganha 4500 */
🦕 Analogia — Stems como tabelas do COBOL
No COBOL você usa OCCURS para criar arrays e acessa elementos com TABELA(I). No REXX, o stem TABELA.I faz o mesmo papel — mas sem declaração prévia, sem tamanho fixo, e aceitando índices de qualquer tipo. É mais próximo de um dicionário Python do que de um array Java.
2. PARSE — decompondo strings com templates
O PARSE é a instrução mais poderosa do REXX para extrair partes de uma string. Ele usa um template para descrever como dividir o texto:
/* PARSE VAR — decompor uma variável */
LINHA = 'CALCJOB JOB01234 OUTPUT 0000'
/* Por espaços (cada palavra vai para uma variável) */
PARSE VAR LINHA JOBNOME JOBID STATUS RC_STEP
SAY JOBNOME /* CALCJOB */
SAY JOBID /* JOB01234 */
SAY RC_STEP /* 0000 */
/* Por posição — extrai colunas fixas */
REGISTRO = 'MARIA SANTOS SP004500'
PARSE VAR REGISTRO 1 NOME 11 SOBRENOME 21 UF 23 SALARIO
SAY NOME /* MARIA */
SAY UF /* SP */
SAY SALARIO /* 004500 */
/* PARSE VALUE — decompor uma expressão */
PARSE VALUE DATE('S') WITH AAAA +4 MM +2 DD
SAY 'Ano:' AAAA 'Mês:' MM 'Dia:' DD
/* DATE('S') retorna '20260617' → AAAA=2026, MM=06, DD=17 */
/* PARSE com delimitador customizado */
CSV = 'MARIA,SANTOS,SP,4500'
PARSE VAR CSV NOME ',' SOBRENOME ',' UF ',' SALARIO
3. Subrotinas — CALL, RETURN e PROCEDURE EXPOSE
Subrotinas organizam o código e evitam repetição. No REXX, subrotinas internas ficam após o corpo principal e são separadas por um label com dois pontos:
/* REXX - exemplo com subrotinas */
CALL ImprimirCabecalho 'RELATÓRIO MENSAL'
CALL ProcessarDados
EXIT 0
/* ── Subrotina sem isolamento de variáveis ── */
ImprimirCabecalho:
PARSE ARG TITULO
SAY CENTER(TITULO, 60, '=')
RETURN
/* ── Subrotina com PROCEDURE EXPOSE ── */
ProcessarDados: PROCEDURE EXPOSE DADOS. TOTAL
/* Somente DADOS. e TOTAL são visíveis aqui.
Outras variáveis do chamador não existem neste escopo. */
DO I = 1 TO DADOS.0
TOTAL = TOTAL + DADOS.I
END
RETURN
💡 PROCEDURE EXPOSE — escopo explícito
Sem PROCEDURE, a subrotina compartilha todas as variáveis com o chamador (como parágrafos do COBOL). Com PROCEDURE, as variáveis ficam isoladas — a subrotina não enxerga nada do chamador. Com PROCEDURE EXPOSE você declara explicitamente quais variáveis quer compartilhar. Use PROCEDURE EXPOSE para evitar efeitos colaterais acidentais em execs grandes.
Funções que retornam valor
/* Subrotina que retorna valor — chamada como função */
RESULTADO = Dobrar(21)
SAY RESULTADO /* 42 */
EXIT 0
Dobrar: PROCEDURE
PARSE ARG N
RETURN N * 2
4. SIGNAL ON — tratamento de erros
O SIGNAL ON configura handlers para diferentes tipos de condição de erro. Quando a condição ocorre, o REXX desvia para o label correspondente:
/* Configurar handlers antes de começar */
SIGNAL ON ERROR NAME TratarErro
SIGNAL ON SYNTAX NAME TratarSintaxe
SIGNAL ON HALT NAME TratarHalt
/* Código principal */
ADDRESS TSO 'LISTDS DATASET.INEXISTENTE'
IF RC \= 0 THEN SIGNAL TratarErro
SAY 'Processamento concluído'
EXIT 0
/* ── Handlers ── */
TratarErro:
SAY 'ERRO detectado na linha' SIGL
SAY 'RC do último comando:' RC
SAY 'Condição:' CONDITION('C')
EXIT 12
TratarSintaxe:
SAY 'ERRO DE SINTAXE na linha' SIGL
SAY ERRORTEXT(RC)
EXIT 16
TratarHalt:
SAY 'Exec interrompido pelo usuário'
EXIT 4
Variáveis especiais disponíveis nos handlers:
| Variável | Conteúdo |
SIGL | Número da linha que causou o erro |
RC | Return code do comando ou condição |
CONDITION('C') | Nome da condição (ERROR, SYNTAX...) |
CONDITION('D') | Descrição da condição |
ERRORTEXT(n) | Texto do erro REXX número n |
5. TRACE — depurando execs
O TRACE é o depurador built-in do REXX. Ele exibe cada instrução antes de executar e mostra os valores intermediários — invaluable quando um exec não está se comportando como esperado:
/* Ativar trace de resultados */
TRACE R /* R = Results: mostra instrução + valor resultante */
A = 10
B = A * 3
SAY B
/* Saída do trace:
3 *-* A = 10
>>> 10
4 *-* B = A * 3
>>> 30
5 *-* SAY B
30 */
/* Desativar trace */
TRACE O /* O = Off */
| Opção | O que mostra |
TRACE R | Instrução + valor resultante de cada expressão |
TRACE I | Tudo — cada token intermediário (muito verboso) |
TRACE C | Só comandos enviados para o ambiente (ADDRESS TSO...) |
TRACE E | Só erros — útil em produção para log mínimo |
TRACE O | Off — desativa trace |
6. Exemplo completo — script de inventário
Um exec que captura a lista de datasets de um usuário, filtra os maiores que um threshold e gera um relatório:
/* REXX - Inventário de datasets por usuário */
ARG PREFIXO THRESHOLD
IF PREFIXO = '' THEN PREFIXO = 'USUARIO'
IF THRESHOLD = '' THEN THRESHOLD = 80
SIGNAL ON ERROR NAME FimComErro
/* Capturar lista de datasets */
CALL OUTTRAP 'SAIDA.'
ADDRESS TSO 'LISTCAT LEVEL('PREFIXO') ALL'
CALL OUTTRAP 'OFF'
/* Imprimir cabeçalho */
SAY CENTER('DATASETS ACIMA DE 'THRESHOLD'% DE USO', 60, '=')
SAY LEFT('DATASET', 44) RIGHT('%USO', 6)
SAY COPIES('-', 50)
ENCONTRADOS = 0
DO I = 1 TO SAIDA.0
IF POS('NONVSAM', SAIDA.I) > 0 THEN DO
PARSE VAR SAIDA.I . '-' DSN .
DSN = STRIP(DSN)
R = LISTDSI("'"DSN"'")
IF SYSUSED >= THRESHOLD THEN DO
SAY LEFT(DSN, 44) RIGHT(SYSUSED'%', 6)
ENCONTRADOS = ENCONTRADOS + 1
END
END
END
SAY COPIES('-', 50)
SAY ENCONTRADOS 'dataset(s) precisam de atenção.'
EXIT 0
FimComErro:
SAY 'Erro na linha' SIGL'. RC='RC
EXIT 12