Como encontrar um objeto do tipo Subroutine cujo nome lógico é diferente do nome físico desse objeto?
Considere que a subrotina ISNUMGT0 (criada no post nº 1) tenha sido salva com o nome físico S12345AB. Assim, num programa qualquer que use essa subrotina, teríamos algo do tipo:
...
PERFORM ISNUMGT0 #NUM #EH-NUM
...
Porém, ao editarmos ISNUMGT0 (comando "E ISNUMGT0"), não achamos objeto algum. Como proceder então? É simples. Ao editar, basta acrescentar a opção F, assim: E F ISNUMGT0
Até a próxima.
ObjectNatural
Catálogo de dicas, soluções e padrões aplicáveis ao desenvolvimento de sistemas em Natural.
sexta-feira, 15 de fevereiro de 2013
terça-feira, 15 de maio de 2012
2. Dica de debug
Como percorrer os objetos que compõem um programa à medida que são executados?
Isso facilita a identificação de objetos de interesse (por exemplo, o nome de um mapa que se deseja alterar o layout) e a localização de erros.
Segue o passo-a-passo:
1) Digite TEST ON na linha de comando para ativar o modo de teste;
2) Na linha de comando, digite: TEST SET BP ALL BEG (o que equivale a colocar um breakpoint no início de cada objeto da biblioteca atual);
3) Por fim, ainda na linha de comando, digite MYPROG para iniciar a execução do seu programa;
4) A partir de então, à medida que cada breakpoint é atingido, abre-se uma janela onde se pode optar por listar o código-fonte bem na linha do breakpoint (opção L), ou avançar para o próximo breakpoint (ou seja, para o próximo objeto da sequência de chamadas) via opção G.
OBS: Quando um breakpoint é atingido e listamos o código-fonte correspondente, podemos executar o programa passo a passo a partir desse breakpoint usando a tecla F2, ou podemos avançar para o próximo breakpoint digitando o comando GO.
OBS: Para apagar todos os breakpoints, digite, na linha de comando: TEST DE BP **
OBS: Para dasativar o modo de teste, digite, na linha de comando: TEST OFF
Até a próxima.
Isso facilita a identificação de objetos de interesse (por exemplo, o nome de um mapa que se deseja alterar o layout) e a localização de erros.
Segue o passo-a-passo:
1) Digite TEST ON na linha de comando para ativar o modo de teste;
2) Na linha de comando, digite: TEST SET BP ALL BEG (o que equivale a colocar um breakpoint no início de cada objeto da biblioteca atual);
3) Por fim, ainda na linha de comando, digite MYPROG para iniciar a execução do seu programa;
4) A partir de então, à medida que cada breakpoint é atingido, abre-se uma janela onde se pode optar por listar o código-fonte bem na linha do breakpoint (opção L), ou avançar para o próximo breakpoint (ou seja, para o próximo objeto da sequência de chamadas) via opção G.
OBS: Quando um breakpoint é atingido e listamos o código-fonte correspondente, podemos executar o programa passo a passo a partir desse breakpoint usando a tecla F2, ou podemos avançar para o próximo breakpoint digitando o comando GO.
OBS: Para apagar todos os breakpoints, digite, na linha de comando: TEST DE BP **
OBS: Para dasativar o modo de teste, digite, na linha de comando: TEST OFF
Até a próxima.
segunda-feira, 12 de março de 2012
1. Validando campos numéricos de mapas
Como verificar se o valor de um campo alfa do mapa (tela) é numérico e maior que zero?
Tenho visto comumente a seguinte abordagem em vários programas analisados, e o que é pior, para cada campo a ser validado, essa lógica se repete...
O problema óbvio dessa abordagem é que uma entrada do tipo "1_0" ou "1 0" será interpretada erroneamente como "100", além da já mencionada duplicação de código.
A solução é desenvolver uma rotina genérica que valide isso, independente do tamanho do campo do mapa.
A primeira rotina valida apenas se o campo é numérico...
Note que se faz necessário substituir espaços e underlines à esquerda por zeros para que valores do tipo "_100__" sejam considerados numéricos, mas não valores do tipo "_10_0_".
A segunda rotina valida se o campo é numérico e maior que zero...
A seguir, temos um exemplo de utilização da rotina ISNUMGT0 a partir de outro objeto Natural.
...
LOCAL
1 #VALOR-A (A17)
1 #EH-NUM-MAIOR-QUE-0 (L)
...
Até a próxima.
Tenho visto comumente a seguinte abordagem em vários programas analisados, e o que é pior, para cada campo a ser validado, essa lógica se repete...
1 #VALOR-A (A10)
1 #AUX (A10)
1 REDEFINE #AUX
2 #AUX-N (N10)
...
IF #VALOR-A = ' '
REINPUT ...
END-IF
*
MOVE RIGHT #VALOR-A TO #AUX
EXAMINE #AUX FOR ' ' REPLACE '0'
EXAMINE #AUX FOR '_' REPLACE '0'
*
IF #AUX <> MASK(NNNNNNNNNN) OR #AUX-N <= 0
REINPUT ...
END-IF
O problema óbvio dessa abordagem é que uma entrada do tipo "1_0" ou "1 0" será interpretada erroneamente como "100", além da já mencionada duplicação de código.
A solução é desenvolver uma rotina genérica que valide isso, independente do tamanho do campo do mapa.
A primeira rotina valida apenas se o campo é numérico...
DEFINE DATA
PARAMETER
/* 29 EH O TAMANHO MAXIMO PARA UM CAMPO NUMERICO
/* ATUALMENTE. 'BY VALUE' EH FUNDAMENTAL AQUI
/* PARA QUE A ROTINA SEJA GENERICA.
/* PARA QUE A ROTINA SEJA GENERICA.
1 #VALOR-A (A29) BY VALUE
1 #IS-NUMERIC (L)
*
LOCAL
1 #I (N2)
1 #CHAR (A1)
1 #MAX-LEN (N2) CONST<29>
1 #MAX-LEN (N2) CONST<29>
END-DEFINE
*
DEFINE SUBROUTINE ISNUM
#IS-NUMERIC := FALSE
*
IF #VALOR-A = ' '
ESCAPE ROUTINE
END-IF
*
MOVE RIGHT #VALOR-A TO #VALOR-A
*
MOVE RIGHT #VALOR-A TO #VALOR-A
*
/* SUBSTITUI ESPACOS E UNDERLINES A ESQUERDA
/* POR ZEROS.
/* POR ZEROS.
FOR #I 1 TO #MAX-LEN
MOVE SUBSTRING(#VALOR-A, #I, 1) TO #CHAR
*
*
IF #CHAR <> '_' AND #CHAR <> ' '
IF #CHAR = '-' AND #I <> #MAX-LEN /* POE O SINAL NA 1A POSICAO.
MOVE '0' TO SUBSTRING(#VALOR-A, #I, 1)
MOVE '-' TO SUBSTRING(#VALOR-A, 1, 1)
END-IF
*
IF #CHAR = '-' AND #I <> #MAX-LEN /* POE O SINAL NA 1A POSICAO.
MOVE '0' TO SUBSTRING(#VALOR-A, #I, 1)
MOVE '-' TO SUBSTRING(#VALOR-A, 1, 1)
END-IF
*
ESCAPE BOTTOM
ELSE
MOVE '0' TO SUBSTRING(#VALOR-A, #I, 1)
*
IF #I = #MAX-LEN /* SO HA ESPACOS E UNDERLINES.
ESCAPE ROUTINE
END-IF
*
IF #I = #MAX-LEN /* SO HA ESPACOS E UNDERLINES.
ESCAPE ROUTINE
END-IF
END-IF
END-FOR
*
IF #VALOR-A IS (N29)
#IS-NUMERIC := TRUE
END-IF
END-SUBROUTINE
END
Note que se faz necessário substituir espaços e underlines à esquerda por zeros para que valores do tipo "_100__" sejam considerados numéricos, mas não valores do tipo "_10_0_".
A segunda rotina valida se o campo é numérico e maior que zero...
DEFINE DATA
PARAMETER
1 #VALOR-A (A29) BY VALUE
1 REDEFINE #VALOR-A
2 #VALOR (N29)
1 #IS-NUMERIC-GT-0 (L)
*
LOCAL
1 #IS-NUMERIC (L)
END-DEFINE
*
DEFINE SUBROUTINE ISNUMGT0
#IS-NUMERIC-GT-0 := FALSE
*
*
/* PRIMEIRO, VERIFICA SE O CAMPO EH NUMERICO.
PERFORM ISNUM #VALOR-A #IS-NUMERIC
*
IF #IS-NUMERIC
MOVE RIGHT #VALOR-A TO #VALOR-A
EXAMINE #VALOR-A FOR ' ' REPLACE '0'
EXAMINE #VALOR-A FOR '_' REPLACE '0'
*
/* VERIFICA SE O CAMPO EH MAIOR QUE ZERO.
/* 'IS (N29)' REJEITA VALORES DO TIPO
/* '0-111111111111111111111111111'.
/* 'IS (N29)' REJEITA VALORES DO TIPO
/* '0-111111111111111111111111111'.
IF #VALOR-A IS (N29) AND #VALOR > 0
#IS-NUMERIC-GT-0 := TRUE
END-IF
END-IF
END-SUBROUTINE
END
A seguir, temos um exemplo de utilização da rotina ISNUMGT0 a partir de outro objeto Natural.
...
LOCAL
1 #VALOR-A (A17)
1 #EH-NUM-MAIOR-QUE-0 (L)
...
PERFORM ISNUMGT0 #VALOR-A #EH-NUM-MAIOR-QUE-0
IF NOT #EH-NUM-MAIOR-QUE-0
REINPUT 'CAMPO DEVE SER NUMERICO E MAIOR QUE ZERO' MARK *#VALOR-A
END-IF
Até a próxima.
Assinar:
Postagens (Atom)