Rediseñando el Desarrollo con Lenguaje Ensamblador.

Por Don V Nielsen, May 19, 2000

Disclaimer:
Bixoft convirtió "Rediseñando el Desarrollo con Lenguaje Ensamblador" en un documento de web con el permiso del autor original para su republicación. También efectuamos varios cambios menores. Aún asi aplican los Derechos de Autor del Sr. Nielsen en el documento a continuación.
Todas los programas muestras en este documento, no son mas que ejemplos, y no están de manera alguna garantizados de estar libres de errores u omisiones. Ud. puede usar (partes de) el código muestra, pero permanece su propia responsabilidad el probar sus programas en todos los aspectos.

Contact:
El Sr. Nielsen agradecerá sus comentarios, observaciones, etc. Don Nielsen e-mail.

Este documento contiene los siguientes capítulos:

Introducción.

El propósito de este documento es sacar a la luz métodos de codificación y técnicas usando Lenguaje Ensamblador y el Ensamblador HLASM. El Ensamblador HLASM ha evolucionado con mucho más poder que el que muchas personas se han dado cuenta. El conocimiento de este poder y la comprensión de como utilizarlo, le puede ahorrar muchas horas de desarrollo y código, al mismo tiempo que reduce los esfuerzos de mantenimiento.

La programación de conceptos tales como abstracción, reuso, derivación y calificación, puede ser implementada en lenguaje ensamblador, de la misma manera que estos son codificados en lenguajes de alto nivel, como C, COBOL, y Basic. Promovemos el uso extensivo de Copybooks. Se introducirán nuevos métodos de implementación de la instrucción USING. También se explicará como y por qué los DSECTs deben ser definidos al principio del código fuente.

Se usan dos aplicaciones sencillas para demostrar como trabajar con los conceptos nuevos. La primera aplicación es un programa simple de censo que lee registros de un archivo, y luego guarda la abreviatura de estado y su contador en una tabla. La aplicación demuestra todas las nuevas técnicas de codificación para construir tablas. También demuestra como estas técnicas pueden reducir o eliminar cambios en el código cuando cambian los elementos de la tabla.

La segunda aplicación es también un programa de censos. Esta aplicación no usa una tabla. En su lugar, usa un archivo ordenado por la abreviatura de estado. Totaliza las cantidades por estado, al tiempo que los registros son leidos al comparar la abreviatura del estado del registro actual con la abreviatura de estado del registro anterior. Esta aplicación demuestra como una DSECT puede usarse para proyectar simultáneamente dos registros distintos.

Al principio, el aprender estas técnicas puede parecer como mucho trabajo. La implementación puede parecer que es mucho teclear. Sin embargo, al pasar el tiempo y las técnicas se emplean más frecuentemente, su uso llega a ser natural, y Ud. encontrará que las mejorías al leer son una gran ventaja. Sus esfuerzos de mantenimiento se reducirán dramáticamente. En algunas ocasiones, el mantenimiento puede inclusive ser eliminado.

Los programas muestra en los apéndices A y apéndice B usan macros de HLASM. Estas macros agregan estructuras de programación encontradas en otros lenguajes, tales como IF/ELSE/ENDIF, ciclos DO, y otros. Las macros simplifican el código e incrementan la comprensibilidad del código.

Comentario de Bixoft:
En lugar del conjunto de utilerías, las macros empleadas en el Lenguage Ensamblador eXtendido de Bixoft pueden usarse para estructura y lograr un mejor entendimiento de la aplicación.

Terminología usada.

Abstracción.

Webster define abstracción como: "El acto o proceso de separar o remover." La aplicación del término abstracción a la programación, significa separar al programador de los detalles fundamentales del proceso. Llamar una función es un ejemplo de abstracción. Una función se llama para completar una tarea y regresar un resultado. Nosotros no necesitamos conocer como la función ejecuta su tarea. Simplemente confiamos que va a ejecutar su tarea correctamente y regresar el resultado correcto.

Esta confianza o dependencia es el concepto más difícil que nosotros los programadores de ensamblador necesitamos practicar. La mayoría de nosotros queremos conocer todos los detalles. Sin embargo, practicando la abstracción simplificará nuestro código. Esto requiere el confiar que algunas cosas son simplemente porque lo son, y no es necesario que nosotros conozcamos porqué son así. Este concepto lleva mucho esfuerzo de nuestra parte para aceptarlo. Ud. debería darse cuenta que este concepto ha sido aplicado y aceptado por un largo tiempo con respecto a las rutinas del sistema.

Reuso.

Reuso es el concepto de implementar el esfuerzo hecho por otros para ahorrar tiempo y esfuerzo en el desarrollo. El llamar un módulo es una forma de reuso. Una macro es otro ejemplo. Cuando un ente de lógica estándar puede ser codificado como un módulo a llamar, o macro, entonces otras personas en el futuro pueden implementar esa lógica sin tener que desarrollarla (inventar la rueda de nuevo, por así decirlo). Otra forma de reuso es el copybook. El copybook es la definición de alguna estructura. Otros no perderán más tiempo y esfuerzo codificando una estructura que ya está disponible como copybook o como macro.

Derivación.

Derivación es recibir u obtener algo de un código fuente. En la definición de un campo, podemos derivar un atributo del campo, de un campo previamente definido. Por ejemplo, un programa necesita guardar una copia del código postal tomado de un registro leido. El programa usa una macro o copybook que ya ha definido los atributos del código postal. Los atributos existentes de una definición existente en la macro o copybook puede ser derivados y usados en la definición de un nuevo campo.

Partes Fundamentales.

El Campo.

Un campo es la estructura más simple. Representa una pieza de datos. Para el ensamblador, un campo representa nada más que un número de bytes en memoria. Algunos podrían considerar importante el tipo de datos. Sin embargo, para el ensamblador, la definición de un campo como empacado, hexadecimal o caracter es para la conveniencia del programador. El atributo más significativo de un campo es la cantidad de espacio que ocupa.

La Vista de un Registro o Entrada en Tabla.

Todos los registros y entradas en tablas se pueden describir con una vista. Una vista (lay-out) es la estructura que describe los datos. Define la ubicación y longitud de los campos, y hace respetar su estructura. La longitud de una vista es el total de las longitudes acumuladas de todos los campos, más cualquier otros bytes adicionados con propósito de alineamiento. Los registros y entradas en la tabla tienen la misma funcionalidad.

Siempre codifique estas vistas para entradas en las tablas o registros de un archivo. Este primer paso, es el paso más importante cuando comience a codificar. Codificar estas vistas simplifica el desarrollo y mantenimiento de los programas. Si una vista va a compartirse entre varios programs, entonces guarde esta vistas como macro o como un copybook. Esto reducirá el tiempo de codificación y el esfuerzo en futuros projectos.

La Tabla.

Una tabla es un área de memoria dedicada a mantener una serie de datos relacionados. Una tabla consiste de una o mas entradas, donde la vista de cada entrada es idéntica. Visualmente, una tabla de dos dimensiones puede ser representado como una pieza de papel rayado de un cuaderno. El papel representa la tabla y cada una de las lineas representa una entrada.

Las tablas, así como los campos, tienen atributos. Una tabla tiene una dirección de inicio, que es el primer byte de la primer entrada. Tiene una dirección de fin, que es el último byte de la última entrada. El espacio que ocupa la tabla puede ser dividido equitativamente por la longitud de la entrada, dando el máximo número de entradas que la tabla puede mantener.

Una tabla sencilla de aplicación de censo, se usa para demostrar los conceptos presentados. La tabla consistirá de dos campos: Abreviatura del estado y total del censo. Más tarde se agregarán totales por género a la vista de la tabla. Esto demostrará como una tabla y un programa pueden construirse de tal manera que un cambio en la definición de la vista no significará cambios en la codificación. El mantenimiento al código del programa podría haberse eliminado.

Paso 1, Proyección (Mapa) de los Datos.

El primer paso en el desarrollo del programa es la proyección del dataset de entrada. El programa lee los datos a través de una DD llamada INFILE. Usa una DCB con el mismo nombre para leer los datos de entrada. Los datos son leidos directamente en una estructura del registro definido por un copybook llamado CMS0001A. El copybook contiene todas las definiciones de campos, y es implementado como una DSECT. La estructra base (vista del registro y DCB) se codifican como sigue:

         ...
INPUT_LAYOUT DSECT
         COPY  CMS0001A                * Vista estándar del registro
L_INPUT_LAYOUT EQU *-INPUT_LAYOUT      * Calcula la longitud de la vista
         ...
INREC    DS    CL(L_INPUT_LAYOUT)      * Define memoria para la entrada
         ...
INFILE   DCB   DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL
         ...

Cuando se usa una macro en lugar de un copybook (o una macro usando un copybook), la muestra anterior podría recodificarse como:

         ...
INPUT_LAYOUT CMS0001A DSECT=YES        * Vista y longitud de entrada
         ...
INREC    DS    CL(L_INPUT_LAYOUT)      * Define memoria para entrada
         ...
INFILE   DCB   DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL
         ...

Todos los conceptos de reuso, abstracción, y derivación han sido aplicados en el ejemplo de arriba. El uso de la macro o copybook CMS0001A es un ejemplo de reuso y abstracción. Primero, se reusa una vista existente en lugar de redesarrollarla. Siempre trate de usar una macro o copybook existente cuando esté disponible. Los beneficios del uso de una macro o copybook son:

  1. Una macro o copybook impone el uso estandarizado de nombres de campo a través de muchos programas
  2. Solo existe una definición de la vista del registro
  3. Se aplica un cambio en la vista solo al copybook, no a muchos programas
  4. Se elimina el tiempo y el esfuerzo de recodificar la vista para cada programa

El uso de la macro o copybook también implementa abstracción. La macro o copybook esconde los detalles de la vista del registro. Si, es importante conocer la vista del registro con que uno está trabajando. Sin embargo, rara vez se requiere el conocimiento detallado de la estructura de la vista. La abstracción también se aplica con la definición de L_INPUT_LAYOUT. Esta declaración usa el ensamblador para calcular la longitud de la vista definida. Esto es abstracto porque Ud. no necesita conocer la longitud. Ud. confía que la longitud ha sido calculada para su uso.

La derivación se usa en la definición del campo INREC. El ensamblador establece la longitud de INREC usando la longitud calculada del registro L_INPUT_LAYOUT. Esto es también un ejemplo de como definir implícitamente la longitud de un campo. Con HLASM, el atributo de longitud de un campo puede ser asignado con un campo previamente definido. Derivar el atributo de longitud permite al HLASM asignar la memoria basada en el valor de longitud existente.

El HLASM le permite definir una longitud de campo implícita o explícitamente. Una definición explícita de la longitud de un campo tiene la longitud del campo codificado. Por ejemplo, la definición INREC arriba, ha sido codificada explícitamente usando "INREC DS CL200" Este es el método más sencillo de definir INREC. Sin embargo, hay dos razones para desalentar el uso de longitudes explícitas:

  1. El hacerlo así requiere el conocimiento previo de la longitud de la estructura
  2. Puede cambiar la longitud de la estructura

Para asignar explícitamente la memoria, uno debe conocer previamente la memoria requerida. Uno deberá buscar la macro o el copybook, para determinar su longitud, y codificar esa longitud en la definición explícita. Aparte de esto, se requiere mucho esfuerzo para actualizar los programas cuando cambie la longitud de la vista. Se requerirá indagar todos los programas que tienen implementada la vista, para actualizar la asignación explícita de memoria.

Una definición implícita, significa que se usa un símbolo para definir la longitud del campo. L_INPUT_LAYOUT es un ejemplo de una longitud implícita, porque el símbolo es una representación de la longitud requerida. L_INPUT_LAYOUT es la longitud de CMS0001A calculada por el ensamblador. La implementación abierta de este concepto puede reducir los esfuerzos de mantenimiento de horas a minutos. Si llegara a cambiar la longitud de CMS0001A, el ensamblador calculará la nueva longitud, asignando el valor de longitud a L_INPUT_LAYOUT, que es usado entonces para establecer la longitud de INREC. De esta manera, el actualizar la macro o copybook también actualiza todos los programas automáticamente.

Adicionando la Tabla de Censo.

         ...
INPUT_LAYOUT CMS0001A DSECT=YES        * Vista y longitud de entrada
         ...
TABLE_ENTRY DSECT
STATE    DS    CL(L'CMSTATE)           * Abreviatura de Estado
TOTAL    DS    F                       * Cantidad total
L_TABLE_ENTRY EQU *-TABLE_ENTRY        * Cálculo de longitud de entrada
         ...
MAX_ENTRIES EQU 100                    * Máximo # de entradas en la tabla
         ...
INREC    DS    CL(L_INPUT_LAYOUT)      * Define memoria para la entrada
...
INFILE   DCB   DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL
         ...
* Define la memoria de la tabla
STATE_CENSUS_TABLE DC (MAX_ENTRIES)XL(L_TABLE_ENTRY)'00'
E_STATE_CENSUS_TABLE EQU *             * Fin de tabla
         ...

Se han agregado a nuestro código de ejemplo dos estructuras y una constante. La estructura TABLE_ENTRY provee un mapa de los campos usados en la entrada de la tabla. El primer campo, STATE, es la abreviatura del estado y es el campo llave para realizar búsquedas en la tabla. Note que STATE es el segundo ejemplo de derivación. STATE deriva su longitud desde CMSTATE. Ud. no requiere conocer que tan largo es CMSTATE. Ud. confía que STATE será definido por una cantidad igual de bytes.

El segundo campo, TOTAL es el campo contador. Es definido como F, una palabra binaria con signo, o 32 bits. Cuando cada registro de entrada es procesado, la abreviatura de estado es ubicada en la tabla. Si la abreviatura no se encuentra, entonces se agrega. El campo TOTAL es entonces incrementado también.

El ensamblador debe ser usado para calcular L_TABLE_ENTRY. Esto se requiere porque la longitud de STATE es derivada. No hay manera de saber, - sin investigar - la longitud actual de CMSTATE. Así que confiamos que el ensamblador derivará la longitud de CMSTATE y la asignará a STATE. El resultado es que la longitud de STATE es igual que la longitud de CMSTATE. L_TABLE_ENTRY es igual a L'STATE+L'TOTAL más cualquier número de bytes agregados para alineamiento. Una vez más, el valor de longitud actual no es importante. Lo importantes es que uno se percate que la longitud existe y que ha sido correctamente computada por el ensamblador.

MAX_ENTRIES es una constante que representa el número máximo de entradas que se pueden almacenar en la tabla. Para esto se usa la definición STATE_CENSUS_TABLE. El tamaño de la tabla se controla con esta constante. Una tabla, como se definió anteriormente, es el espacio usado por todas las entradas de la tabla. Es decir, el tamaño de la tabla es igual a la longitud de la entrada de la tabla multiplicada por el número máximo de entradas. La definición actual de STATE_CENSUS_TABLE es un ejemplo de este cálculo. El uso de MAX_ENTRIES y L_TABLE_ENTRY implícitamente definen los atributos de la tabla, el ensamblador calcula la memoria requerida y asigna el símbolo STATE_CENSUS_TABLE a este espacio.

El verdadero poder de esta definición implícita viene cuando la tabla requiere mantenimiento. Todo lo que se requiere para expandir el número de entradas que STATE_CENSUS_TABLE puede contener, es cambiar el valor de MAX_ENTRIES. Aparte de esto, si la definición de la entrada de la tabla cambia, el ensamblador usa la longitud de la entrada resultante para establecer el tamaño de STATE_CENSUS_TABLE. Esto será demostrado más adelante cuando se agregue el contador de género a TABLE_ENTRY.

Step 2, Construyendo el Programa.

Accesando los Campos del Registro y de la Tabla.

         ...
         USING INPUT_LAYOUT,INREC      * Asigna DSECT a INREC
         USING TABLE_ENTRY,R3          * Asigna DSECT a REGISTRO
         ...
FILELOOP GET   INFILE,INREC            * Lee registro a memoria
         LA    R3,STATE_CENSUS_TABLE   * Carga apuntador a entrada de tabla
TBLLOOP  C     R3,=A(E_STATE_CENSUS_TABLE) * Si es el fin de la tabla
         BNL   ERRTABLE                * ...bifurca a rutina de error
         CLI   STATE,X'00'             * Si el estado es nulo(entrada vacía)
         BE    ADDSTATE                * ...agrega el estado a la tabla
         CLC   CMSTATE,STATE           * ¿El estado ya está en la tabla?
         BE    STFOUND                 * Si. Entrada localizada
         LA    R3,L_TABLE_ENTRY(R3)    * Apunta a la siguiente entrada en la tabla
         B     TBLLOOP                 * ...y regresa a verificar esta entrada
ADDSTATE MVC   STATE,CMSTATE           * Inicializa el nuevo estado en la tabla
STFOUND  LA    R1,1                    * Incrementa el contador
         A     R1,TOTAL                * ...agrega el total
         ST    R1,TOTAL                * ...guarda el nuevo valor
         B     FILELOOP                * ... y regresa a leer siguiente registro
         ...

Despues de leer un registro de entrada, es necesario localizar la abreviatura del estado en la tabla. Antes de accessar cualquier dato, se tienen que describir ambos, el registro de entrada y la entrada en la tabla. Esto se logra con la declaración USING. USING no es una instrucción que se procesa como una instrucción de comparación o bifurcación. Es una directiva usada por el ensamblador para determinar como y donde la memoria va a ser descrita. Se usan los DSECTS para describir la memoria. Una DSECT puede describir la memoria como referencia de un símbolo, o puede describir la memoria como referencia del contenido de un registro. El ejemplo usa ambas implementaciones.

La declaración USING INPUT_LAYOUT,INREC empalma la vista de CMS0001A a la memoria definida como INREC. Cuando se hace referencia a un campo del copybook CMS0001A con una instrucción, se extraen los datos de este campo, del espacio de la memoria denominada INREC. CMSTATE se ubica en la posición 147 de la vista de CMS0001A.Cuando se hace referencia a CMSTATE en el programa, esta posición 147 de INREC (o INREC+146) es la fuente de los datos.

La declaración USING TABLE_ENTRY,R3 hace coincidir la vista de TABLE_ENTRY al área de memoria cuya dirección está contenida en el registro 3. Cuando una instrucción hace referencia a un campo representado por la vista de TABLE_ENTRY, los datos de ese campo son localizados dentro de la memoria señalada en el registro 3. El campo STATE se ubica en la posición 1 de la tabla descrita en la vista. Cuando el programa hace referencia al campo STATE, el primer byte indicado en el R3 [o 0(R3)] es la ubicación de la abreviatura del estado en la entrada de la tabla.

El flujo del ciclo de programación funciona como sigue:

Revisemos algunos conceptos claves hasta este punto. El primero, es la relación existente entre INPUT_LAYOUT y INREC. INREC fue definido usando la longitud calculada de la vista del registro de entrada, o L_INPUT_LAYOUT. Mientras INREC tiene definida la cantidad de memoria apropiada, no tiene ningún campo asignado a ella. Las referencias a los campos dentro de INREC son asignadas al utilizar la directiva USING INPUT_LAYOUT,INREC. De esta manera, cuando se hace referencia a un campo de INPUT_LAYOUT, es la memoria de INREC la que es accesada.

El símbolo L_TABLE_ENTRY se usa para incrementar la dirección de la tabla indicada en R3. El ensamblador usa el valor calculado. Cualquier cambio en la longitud de la entrada de la tabla, no afectará al código.

Agregando el contador de Género a la Tabla.

         ...
INPUT_LAYOUT CMS0001A DSECT=YES        * Vista y longitud de entrada
         ...
TABLE_ENTRY DSECT
STATE    DS    CL(L'CMSTATE)           * Abreviatura de estado
TOTAL    DS    F                       * Cantidad total
FEMALE   DS    F                       * Cantidad de mujeres
MALE     DS    F                       * Cantidad de hombres
UNKNOWN  DS    F                       * Sexo desconocido
L_TABLE_ENTRY EQU *-TABLE_ENTRY        * Cálculo de longitud de entrada
         ...
MAX_ENTRIES EQU 100                    * # Max. de entradas en la tabla
         ...
INREC    DS    CL(L_INPUT_LAYOUT)      * Define memoria para entrada
         ...
INFILE   DCB   DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOFINFIL
         ...
* Define memoria de la tabla
STATE_CENSUS_TABLE DC (MAX_ENTRIES)XL(L_TABLE_ENTRY)'00'
E_STATE_CENSUS_TABLE EQU *             * Fin de tabla
         ...

Ahora que hemos desarrollado el programa básico, se agregarán nuevos contadores a la tabla. Al agregar estos contadores, Ud. se dará cuenta del tiempo y esfuerzo que se ahorran al aplicar estas técnicas de programación.

El único cambio requerido por el programa entero es agregar los campos FEMALE, MALE, y UNKNOWN. Eso es todo. Se puede reensamblar el programa sin ningún otro cambio.

Veamos lo que pasó y como el ensamblador resuelve los cambios. Se agregaron tres campos a TABLE_ENTRY. Estos campos han incrementado la longitud de la entrada de la tabla en doce bytes. Se usa el valor calculado L_TABLE_ENTRY en todo el programa. El ensamblador calcula la memoria requerida por la tabla usando los valores implícitos de L_TABLE_ENTRY y MAX_ENTRIES y asigna esa cantidad de memoria a STATE_CENSUS_TABLE.

No se necesitan cambios en el código del proceso en sí. Las instrucciones afectadas por los cambios son los que siguen:

Nota:
Si se altera el tamaño de CMSTATE en el copybook o macro CMS0001A, este programa puede ser reensamblado, libre de errores y sin modificación alguna.

Usando la Misma Vista Dos Veces.

Muchos programas necesitan comparar el contenido de un registro, al contenido de otro registro. En este caso, tenemos dos instancias de la misma estructura. En el pasado, esto significaba codificar dos vistas separadas con nombres de campo ligeramente diferentes. Un ejemplo podría ser ZIP1 y ZIP2.

El HLASM provee una característica llamada la declaración Using Etiquetada, para resolver este problema. Una declaración Using Etiquetada, nos permite asignar un DSECT a múltiples ubicaciones simultánemente. Estos lugares se pueden referenciar por un registro, o pueden ser asignados a a un símbolo definido en la memoria central.

Para demostrar este poder, se desarrollará un nuevo programa de censo. Asumiremos que el dataset de entrada ya viene sorteado por la secuencia de la abreviatura del estado. El programa leerá los registros e incrementará el contador. Cuando la abreviatura del estado cambia, el contador contendrá el número de registros para la anterior abreviatura de estado.

Para lograr esto, el programa va a leer un registro, comparar la abreviatura de estado en el registro que acaba de leer, con la abreviatura de estado del registro leido anteriormente. Si hay un cambio, entonces el conteo se inicializará. Se moverá el registro que se acaba de leer a la memoria asignada para el registro previo.

         ...
COUNTER  DC    PL4'1'                  * contador de estado
PREVREC  DS    CL(L_INPUT_LAYOUT)      * memoria p/registro de entrada
         ...
INFILE   DCB   DDNAME=INFILE,DSORG=PS,MACRF=GL,EODAD=EOFINFIL
         ...

El código de arriba establece un área de resguardo para el registro procesado previamente. Una vez que el registro de entrada ha sido procesado, será movido a PREVREC. En adición, se ha cambiado el valor de MACRF de la DCB de GM a GL. Esto informa al programa que el registro de entrada no se moverá del área de memoria definida que cada registro obtiene. El nuevo registro leido por es sistema, es considerado como el registro actual, y permanece en su memoria intermedia donde puede ser referenciado con R1.

Nota:
Si el programa está usando cualquier otro servicio del sistema, diferente a la macro GET, o hace llamados a cualquier subprograma durante el proceso de cualquier registro, R1 se considerará como registro volátil. En un programa real R1 debe ser usado solamente como un registro de trabajo o temporal.

Puesto que nada está siendo puesto en tablas, no se define ninguna de ellas. El programa usa el cambio en la abreviatura del estado para indicar la inicialización del contador.

         ...
PRV      USING INPUT_LAYOUT,INREC      * Asigna DSECT a INREC
CUR      USING INPUT_LAYOUT,R1         * Asigna DSECT a registro
         ...
FILELOOP GET   INFILE                  * Lee registro a memoria
         CLC   CUR.CMSTATE,PRV.CMSTATE * ¿Cambio el estado?
         BNE   CHGSTATE                * Si: Procesa cambio de estado
* Save current record
         MVC   INREC,CUR.INPUT_LAYOUT  * o codifica "INREC,0(R1)"
         AP    COUNTER,P'1'            * Incrementa contador
         B     FILELOOP                * y regresa a leer sig. registro
         ...

Se asignan las declaraciones USING a las etiquetas PRV y CUR. La USING etiquetada como PRV usa INPUT_LAYOUT para proyectar la memoria en PREVREC. La declaración USING etiquetada como CUR usa INPUT_LAYOUT para describir la memoria en 0(R1), que es la ubicación del registro dentro de su memoria intermedia (buffer). Las etiquetas USING se usan para calificar un nombre de campo de manera que el ensamblador entienda a cual de las dos campos se refiere. PRV.CMSTATE se refiere a la ubicación de CMSTATE dentro de PREVREC, o PREVREC+146. CUR.CMSTATE se refiere a la ubicación de CMSTATE, al cual señala el R1, o 146(R1).

Colocando DSECTs al Principio del Programa.

¿Por qué Colocar DSECTs al Principio del Programa?

El ensamblador opera haciendo dos pasadas al código fuente. En la primera pasada del fuente, identifica todos los símbolos e intenta identificar todos los atributos de esos símbolos. Sin embargo, algunos atributos pueden no ser resueltos porque no se establecen de manera secuencial. En estos casos, los atributos no serán resueltos sino hasta la segunda pasada sobre el código fuente.

La identificación de los símbolos involucra la lectura de copybooks y la expansión de macros. Las macros son esas sencillas declaraciones que generan código por Ud.. Por ejemplo, DCB, OPEN, y GET son ejemplos de macros. Los macros de programación estructurada del conjunto de utilerías de HLASM o del lenguaje Ensamblador eXtendido de Bixoft como IF/ELSE/ENDIF y DO/END son otros ejemplos. Algunas macros requieren que todos los atributos de los símbolos sean resueltos durante la primera pasada. Si no hay resolución, el ensamblador puede generar errores porque no puede identificar la longitud de los campos.

El ensamblador procesa el fuente en forma secuencial. Asi, el colocar las DSECTs al principio del código fuente para que invoque los copybooks, establece los símbolos temprano en el proceso, de manera que el código de la macro pueda expandirse sin errores.

Personalmente, me gusta tener todos los DSECTs al principio del programa. Esto se apega a lo hecho en otros lenguajes como PASCAL, C, COBOL, y BASIC. Provee una ubicación para todas las estructuras, y provee al programador con información de con que va a trabajar el programa.

Observación de Bixoft:
Nuestro consejo es insertar todas las DSECTs al principio del programa. Esto tiene las siguientes ventajas:

Rutina de Entrada (Housekeeping) Requerida Adicional.

El programa ensamblador normalmente comenzará con algún tipo de macro de rutinas de entrada. Sin embargo, si Ud. coloca las DSECTS por encima de la macro de entrada, puede causar un error al ensamblar. Para prevenir que el error ocurra, se requiere un cambio en el código de la rutina de entrada al principio del programa. Un programa debería seguir esta estructura.

NombProg CSECT
*
*        Aqui van las DSECTS y la descripción de macros
*
NombProg "Macro de Rutinas de entrada o punto de entrada lógica CSECT"
         ...

La declaración CSECT al principio previene la ocurrencia del error del ensamblador.

Comentario de Bixoft:
Cuando use el lenguaje Ensamblador eXtendido de Bixoft, la macro PGM se usa para genera la entrada lógica, incluyendo todas las descripciones requeridas. E.g.:

NombProg PGM   VERSION=V00R00M00,      * Versión número                *
               HDRTXT='Programa muestra',                              *
               SAVES=2,                * Areas de resguardo internas   *
               MAPS=(CMS0001A,         * Vistas privadas               *
               DCB,DCBE,DECB,IOB)      * Vistas estándar de IBM

En Conclusión.

Asi como este documento lo demuestra, los conceptos de programación, como abstracción, reuso y derivación se pueden utilizar tanto en ensamblador como en otro lenguaje de alto nivel como PASCAL, C, o BASIC. La abstración puede usarse para esconder los detalles de la estructura que de otra manera atestarían el código fuente. El reusar nos permite apoyarnos en los logros de otros, reduciendo de esta manera nuestros esfuerzos. La derivación nos permite usar atributos preexistentes en la definición de campos similares. Todos los conceptos nos dan la habilidad de hacer que el HLASM trabaje más fuerte por nosotros, asi no tenemos que hacerlo nosotros.

Los segmentos de programas, muestran como se aplican la abstracción y el reuso, al uso de macros y copybooks. Las macros y copybooks estandarizan nuestros programas. Aceleran el proceso de entendimiento del código porque los nombres de campo serán consistentes de un módulo a otro. Los copybooks también proporcionan las bases desde las cuales podemos derivar espacios de memoria y definiciones de campo similares. Por ejemplo, podemos usar la definición de CMSTATE en la definición de una entrada de la tabla, de manera que campos similares tengan atributos similares.

Los programas muestra, también demuestan que el uso abierto de estas técnicas pueden reducir drásticamente nuestros esfuerzos de mantenimiento futuro. En algunos casos pueden reducirse a zero cuando cambia la definición de un campo.

My esperanza es que Ud. tome interés en las técnicas explicadas aquí. El uso de estas técnicas le ahorrará mucho tiempo y esfuerzo en el futuro. Estas técnicas reducirán el impacto de los cambios en todo el módulo.

Apéndice A: Programa Muestra Usando Tabla.

SAMPLE01 CSECT
INPUT_LAYOUT DSECT
         COPY  CMS0001A                * Vista estándar del registro
L_INPUT_LAYOUT EQU *-INPUT_LAYOUT      * Calcula la long de la vista

TABLE_ENTRY DSECT
STATE    DS    CL(L'CMSTATE)           * Abreviatura del estado
TOTAL    DS    FL4                     * Cantidad Total
FEMALE   DS    FL4                     * Cantidad de Mujeres
MALE     DS    FL4                     * Cantidad de Hombres
UNKNOWN  DS    FL4                     * Género desconocido
L_TABLE_ENTRY EQU *-TABLE_ENTRY        * Calcula la long de la entrada

MAX_ENTRIES EQU 100                    * 100 entradas en total

SAMPLE01 ENTERMPG BASE=R12,VER=A,MAIN=N,TEST=Y,DESC='Ejemplo de Tabla'
         USING INPUT_LAYOUT,INREC      * Asigna DSECT a símbolo
         USING TABLE_ENTRY,R3          * Asigna DSECT a registro

         IF    (CLI,FirstTime,EQ,FTyes) * Solo durante la 1ra. pasada
          MVI  FirstTime,FTno          * Apaga indicador de 1ra. pasada
          OPEN (INFILE,INPUT)          * Abre dataset de entrada
         ENDIF ,                       *

         DO    INF                     * Ejecuta hasta terminar el archivo
READREC   GET  INFILE,INREC            * Lee registro de entrada

          LA   R3,STATE_CENSUS_TABLE   * Punto de entrada de la tabla
          DO   UNTIL=(C,R3,NL,=A(E_STATE_CENSUS_TABLE))

           IF  (CLI,STATE,EQ,X'00')    * ¿Se encontró espacio en tabla?
            MVC STATE,CMSTATE          * Si: agrega un nuevo estado a tabla
           ENDIF

           IF  (CLC,CMSTATE,EQ,STATE)  * ¿Ya se encuentra el estado?
            INCR TOTAL                 * Incrementa el contador
            SELECT CLI,CMGENDER,EQ     * ¿Cual género?:
            WHEN CMGENDER_MALE         * ¿Masculino?
             INCR MALE                 * Si: incrementa contador de hombres
            WHEN CMGENDER_FEMALE       * ¿Femenino?
             INCR FEMALE               * Si: incrementa contador de mujeres
            ELSE ,                     * género desconocido...
             INCR UNKNOWN              * ...incrementa contador
            ENDSEL
            B  READREC                 * Salida de ciclo interno
           ENDIF

           LA  R3,L_TABLE_ENTRY(R3)    * Punto de entrada de sig. entrada
          ENDDO ,                      * ...y verifícarla

          WTO  'No more room in table' * No hay espacio en tabla...
          ABEND 666                    * no más espacio

         ENDDO ,                       * Fin de ciclo externo

EOF      CLOSE INFILE                  * Cierra dataset de entrada
         LEAVEMPG RC=0                 * Fin de trabajo

         LTORG
FirstTime DC   XL1'00'                 * Indicador de 1ra. pasada
FTYES    EQU   X'00'                   * Si: primera pasada
FTno     EQU   X'FF'                   * No: inicialización hecha
INREC    DS    CL(L_INPUT_LAYOUT)      * define memoria para entrada

INFILE   DCB   DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOF

* Define la tabla
STATE_CENSUS_TABLE DC (MAX_ENTRIES)XL(L_TABLE_ENTRY)'00'
E_STATE_CENSUS_TABLE EQU *             * Define dirección de fin de tabla

         END   SAMPLE01

Apéndice B: Programa Muestra Cambiando la Abreviatura del Estado.

SAMPLE02 CSECT

INPUT_LAYOUT DSECT
         COPY  CMS0001A                * Vista de reg. estándar
L_INPUT_LAYOUT EQU *-INPUT_LAYOUT      * Calcula long de vista

SAMPLE02 ENTERMPG BASE=R12,VER=A,MAIN=N,TEST=Y,DESC='MUESTRA ABREV.'
PRV      USING INPUT_LAYOUT,INREC      * Asigna DSECT a símbolo
CUR      USING INPUT_LAYOUT,R3         * Asigna DSECT a registro

         IF    (CLI,FirstTime,EQ,FTyes) * Solo durante 1ra. pasada
          MVI  FirstTime,FTno          * Apaga ind de primera pasada
          OPEN (INFILE,INPUT)          * Abre dataset de entrada
          GET   INFILE                 * Lee primer registro
          LR    R3,R1                  * Iguala apuntadores de reg leido
* Copia el primer registro para prevenir la ejecución de rutina
* de cambio de estado, la primera vez que se lee un registro.
          MVC   PRV.INPUT_LAYOUT,CUR.INPUT_LAYOUT
         ENDIF ,                       *

         DO    INF                     * Ejecuta hasta terminar el archivo
          GET  INFILE                  * Lee un registro
          LR   R3,R1                   * Copia apuntador a reg actual
          IF   (CLC,CUR.CMSTATE,NE,PRV.CMSTATE) *¿Cambio el estado?
           OI  COUNTER+L'COUNTER-1,X'0F' * Quita el signo a contador
           UNPK WTO01+24(7),COUNTER    * Inserta contador al mensaje
           MVC WTO01+15(L'CMSTATE),PRV.CMSTATE * Agrega el estado previo
WTO01      WTO 'STATE: ..   QTY=XXXXXXX ' * Despliega estado y conteo
           ZAP COUNTER,=P'0'           * Reinicia contador
          ENDIF
          AP   COUNTER,=P'1'           * Incrementa contador
* Mueve registro actual a previo
          MVC  PRV.INPUT_LAYOUT,CUR.INPUT_LAYOUT
*         MVC  INREC,0(R3)             * Código alternativo para mover
         ENDDO

EOF      CLOSE INFILE                  * Cierra dataset de entrada
         LEAVEMPG RC=0                 * Fin de trabajo
         LTORG
FirstTime DC   XL1'00'                 * Indicador de 1ra. pasada
FTYES    EQU   X'00'                   * Si: Primera pasada
FTno     EQU   X'FF'                   * No: Inicialización hecha
COUNTER  DC    PL4'1'                  * Inicializz contador a uno
INREC    DS    CL(L_INPUT_LAYOUT)      * Define memoria para entrada

INFILE   DCB   DDNAME=INFILE,DSORG=PS,MACRF=GM,EODAD=EOF

         END

© Copyright Don V. Nielsen 2000. Todos los derechos reservados.

 

Esta página es un miembro de WebRing.
Te invitamos a ver la lista de sitios que apoyan el mainframe. lista of sitios relacionados con mainframes.
Running Tyrannosaurus Rex Los Dinos no estan muertos. Ellos están vivos y bien y viviendo en centros de cómputo a tu alrededor. Hablan en lenguas y esparcen magias extrañas con computadoras. ¡Ten cuidado con el dino! Y por si acaso estás esperando la extincón final de estos dinos: ¡recuerda que los dinos dominaron el mundo por 155 millones de años!
Los Dinos y otros anacronismos
[ Unete ahora | Ring Hub | Al azar | << Anterior | Siguiente >> ]
 

Ir a Introducción.
Ir a Terminología Usada.
Ir a Partes Fundamentales.
Ir a Step 1, Proyección de los Datos.
Ir a Step 2, Construyendo el Programa.
Ir a Usando Dos Veces la Misma Vista.
Ir a Colocando los DSECTs al Principio del Programa.
Ir a In Conclusión.
Ir a Programa Muestra Usando Tabla.
Ir a Programa Muestra Cambiando la Abreviatura del Estado .



Abajo está los logos de nuestros patrocinadores y logos de los estándares de la web a los que se adhiere este sitio.