• No se han encontrado resultados

Diseño de programas mediante el uso de procedimientos

In document Lenguaje Ensamblador Irvine 5a Edición (página 176-181)

direccionamiento y aritmética

8. Copia de una cadena al revés

5.6 Diseño de programas mediante el uso de procedimientos

Cualquier aplicación de programación poco común tiende a involucrar una variedad de tareas distintas. Po- dríamos codifi car todas las tareas en un solo procedimiento, pero el programa sería difícil de leer y mantener. Es mejor dedicar un solo procedimiento para cada tarea.

Al crear un programa, se debe crear un conjunto de especifi caciones en las que se mencione con exacti- tud lo que se supone debe hacer el programa. Las especifi caciones deben ser el resultado de un cuidadoso análisis del problema que tratamos de resolver. Después se diseña el programa de acuerdo con las especifi - caciones. Un método de diseño estándar es dividir un problema general en tareas discretas; a este proceso se le conoce como descomposición funcional, o diseño de arriba-abajo. Este método depende de ciertos principios básicos:

• Un problema extenso puede dividirse con más facilidad en pequeñas tareas.

• Un programa es más fácil de mantener si cada procedimiento se prueba por separado. • Un diseño de arriba-abajo nos permite ver cuántos procedimientos están relacionados entre sí.

• Cuando se está seguro del diseño en general, es más fácil concentrarse en los detalles, escribiendo el código que implemente cada procedimiento.

En la siguiente sección demostraremos el método de diseño de arriba-abajo para un programa que recibe enteros como entrada y calcula su suma. Aunque el programa es simple, el mismo método puede aplicarse a programas de casi cualquier tamaño.

5.6.1 Programa para sumar enteros (diseño)

A continuación se muestran las especifi caciones para un programa simple, al que llamaremos Suma de

enteros:

Escriba un programa que pida al usuario tres enteros de 32 bits, los almacene en un arreglo, calcule la suma del arreglo y muestre la suma en la pantalla.

El siguiente seudocódigo muestra cómo podríamos dividir las especifi caciones en tareas: Programa de suma de enteros

Pedir al usuario tres enteros Calcular la suma del arreglo Mostrar la suma

En nuestra preparación para escribir un programa, vamos a asignar un nombre de procedimiento a cada tarea:

Main

PedirEnteros SumaArreglo MostrarSuma

En el lenguaje ensamblador, las tareas de entrada-salida requieren, por lo general, la implementación de código detallado. Para reducir parte de este detalle, podemos llamar a procedimientos que borren la pantalla, muestren una cadena, reciban un entero como entrada, y muestren un entero en pantalla:

Main

Clrscr ; Borra la pantalla

PedirEnteros

WriteSting ; muestra una cadena

ReadInt ; recibe un entero como entrada

SumaArreglo ; suma los enteros

MostrarSuma

WriteString ; muestra una cadena

WriteInt ; muestra un entero

5.6 Diseño de programas mediante el uso de procedimientos 143

Diagrama de estructura El diagrama de la fi gura 5-10, conocido como diagrama de estructura, describe la estructura del programa. Los procedimientos de la biblioteca de enlace están sombreados.

Figura 5−10 Diagrama de estructura para el programa de suma.

Programa maestro Vamos a crear una versión mínima del programa, a la que llamaremos programa

maestro. Este programa sólo contiene procedimientos vacíos (o casi vacíos). El programa se ensambla y se

ejecuta, pero en realidad no hace nada útil:

TITLE Programa de suma de enteros (Suma1.asm) ; Este programa pide al usuario tres enteros, ; los guarda en un arreglo, calcula la suma del ; arreglo y muestra la suma.

INCLUDE Irvine32.inc .data

.code main PROC

; Procedimiento principal de control del programa. ; Llama a: Clrscr, PedirEnteros, ; SumaArreglo, MostrarSuma exit main ENDP ;--- PedirEnteros PROC ;

; Pide tres enteros al usuario, y los inserta ; en un arreglo.

; Recibe: ESI apunta a un arreglo de

; enteros tipo doble palabra, ECX = tamaño del arreglo. ; Devuelve: el arreglo contiene los valores

; que introdujo el usuario ; Llama a: ReadInt, WriteString

;--- ret PedirEnteros ENDP ;--- SumaArreglo PROC ;

; Calcula la suma de un arreglo de enteros de 32 bits.

; Recibe: ESI apunta al arreglo, ECX = tamaño del arreglo ; Devuelve: EAX = suma de los elementos del arreglo ;--- ret SumaArreglo ENDP ;--- MostrarSuma PROC ;

; Muestra la suma en la pantalla ; Recibe: EAX = la suma

; Llama a: WriteString, WriteInt

;--- ret

MostrarSuma ENDP END main

Un programa maestro nos proporciona la oportunidad de asignar todas las llamadas a los procedimien- tos, estudiar las dependencias entre ellos, y posiblemente mejorar el diseño estructural antes de codifi car los detalles. Use comentarios en cada procedimiento para explicar su propósito y los requerimientos de los pará- metros.

5.6.2 Implementación de la suma de enteros

Vamos a completar el programa de sumas. Declararemos un arreglo de tres enteros y utilizaremos una cons- tante defi nida para el tamaño del arreglo, en caso de que necesitemos cambiarlo posteriormente:

CUENTA_ENTEROS = 3

arreglo DWORD CUENTA_ENTEROS DUP (?) Se utiliza un par de cadenas como indicadores en la pantalla:

cad1 BYTE "Escriba un entero con signo: ",0 cad2 BYTE "La suma de los enteros es: ",0

El procedimiento main borra la pantalla, pasa un apuntador de arreglo al procedimiento PedirEnteros, llama a SumaArreglo y a MostrarSuma:

call Clrscr

mov esi,OFFSET arreglo mov ecx,CUENTA_ENTEROS call PedirEnteros call SumaArreglo call MostrarSuma

• PedirEnteros llama a WriteString para pedir un entero al usuario. Después llama a ReadInt para recibir el entero del usuario y almacena el entero en el arreglo al que apunta ESI. Un ciclo ejecuta estos pasos varias veces.

• SumaArreglo calcula y devuelve la suma de un arreglo de enteros.

• MostrarSuma muestra un mensaje en la pantalla (“La suma de los enteros es:”) y llama a WriteInt para mostrar el entero en EAX.

Listado del programa terminado La siguiente lista muestra el programa de Sumas completo: TITLE Programa de suma de enteros (Suma2.asm)

; Este programa pide tres enteros al usuario, ; los almacena en un arreglo, calcula la suma del ; arreglo y muestra la suma.

; Última actualización: 06/01/2006

5.6 Diseño de programas mediante el uso de procedimientos 145

INCLUDE Irvine32.inc CUENTA_ENTEROS = 3 .data

cad1 BYTE "Escriba un entero con signo: ",0 cad2 BYTE "La suma de los enteros es: ",0 arreglo DWORD CUENTA_ENTEROS DUP(?)

.code main PROC

call Clrscr

mov esi,OFFSET arreglo mov ecx,CUENTA_ENTEROS call PedirEnteros call SumaArreglo call MostrarSuma exit main ENDP ;--- PedirEnteros PROC USES ecx edx esi

;

; Pide al usuario un número arbitrario de enteros ; y los inserta en un arreglo.

; Recibe: ESI apunta al arreglo, ECX = tamaño del arreglo ; Devuelve: nada

;---

mov edx,OFFSET cad1 ; "Escriba un entero con signo"

L1: call WriteString ; muestra la cadena

call ReadInt ; lee entero y lo coloca en EAX

call Crlf ; avanza a la siguiente línea de salida

mov [esi],eax ; almacena en el arreglo

add esi,TYPE DWORD ; siguiente entero

loop L1 ret

PedirEnteros ENDP

;--- SumaArreglo PROC USES esi ecx

;

; Calcula la suma de un arreglo de enteros de 32 bits. ; Recibe: ESI apunta al arreglo, ECX = número

; de elementos del arreglo

; Devuelve: EAX = suma de los elementos del arreglo ;---

mov eax,0 ; establece la suma a cero

L1: add eax,[esi] ; agrega cada entero a la suma

add esi,TYPE DWORD ; apunta al siguiente entero

loop L1 ; repite para el tamaño del arreglo

ret ; la suma está en EAX

SumaArreglo ENDP

;--- MostrarSuma PROC USES edx

;

; Muestra la suma en la pantalla ; Recibe: EAX = la suma

; Devuelve: nada

;--- mov edx,OFFSET cad2 ; "La suma de..." call WriteString

call WriteInt ; muestra EAX

call Crlf ret

MostrarSuma ENDP END main

5.6.3 Repaso de sección

1. ¿Cómo se llama el proceso de dividir las tareas extensas en tareas más pequeñas?

2. ¿Qué procedimientos en el diseño del programa de Sumas (sección 5.6.1) se encuentran en la biblioteca Irvine32?

3. ¿Qué es un programa maestro?

4. (Verdadero/Falso): el procedimiento SumaArreglo del programa de Sumas (sección 5.6.1) hace referencia directa al nombre de una variable tipo arreglo.

5. ¿Qué líneas en el procedimiento PedirEnteros del programa de Sumas (sección 5.6.1) tendría que modifi car- se para poder manejar un arreglo de palabras de 16 bits? Cree una versión y pruébela.

6. Dibuje un diagrama de fl ujo para el procedimiento PedirEnteros del programa de Sumas (en la sección 5.5.4 presentamos los diagramas de fl ujo).

5.7

Resumen del capítulo

Este capítulo presenta la biblioteca de enlace del libro, para facilitarle a usted el procesamiento de las opera- ciones de entrada-salida en las aplicaciones de lenguaje ensamblador.

La tabla 5-1 presenta la mayoría de los procedimientos de la biblioteca de enlace Irvine32. El listado más actualizado de todos los procedimientos está disponible en el sitio Web del libro.

El programa de prueba de la biblioteca en la sección 5.3.3 demuestra una variedad de funciones de en-

trada-salida de la biblioteca Irvine32. Genera y muestra una lista de números aleatorios, un vaciado de los registros, y un vaciado de memoria. Muestra enteros en varios formatos y demuestra la entrada/salida con cadenas.

La pila en tiempo de ejecución es un arreglo especial que se utiliza como área temporal de almacenamien-

to para direcciones y datos. El registro ESP almacena un desplazamiento (OFFSET) en alguna ubicación en la pila. A la pila se le conoce como estructura UEPS (último en entrar, primero en salir), ya que el último valor que se coloca en la pila es el primero que se saca. Una operación push (meter) copia un valor en la pila. Una operación pop (sacar) elimina un valor de la pila y lo copia en un registro o variable. A menudo, las pilas almacenan direcciones de retorno de procedimientos, parámetros de procedimientos, variables locales y registros que los procedimientos utilizan en forma interna.

La instrucción PUSH primero decrementa el apuntador de la pila y después copia un operando de origen en la pila. La instrucción POP primero copia el contenido de la pila al que apunta ESP en un operando de destino de 16 o 32 bits, y después incrementa a ESP.

La instrucción PUSHAD mete los registros de propósito general de 32 bits en la pila, y la instrucción PUSHA hace lo mismo para los registros de propósito general de 16 bits. La instrucción POPAD saca valores de la pila y los coloca en los registros de propósito general de 32 bits, y la instrucción POPA hace lo mismo para los registros de propósito general de 16 bits.

La instrucción PUSHFD mete el registro EFLAGS de 32 bits en la pila, y POPFD saca un valor de la pila y lo coloca en EFLAGS. PUSHF y POPF hacen lo mismo para el registro FLAGS de 16 bits.

5.7 Resumen del capítulo 147

El programa InvCad (sección 5.4.2) utiliza la pila para invertir una cadena de caracteres.

Un procedimiento es un bloque de código con nombre, que se declara mediante las directivas PROC y

ENDP. La ejecución de un procedimiento termina con la instrucción RET. El procedimiento SumaDe, que se muestra en la sección 5.5.1, calcula la suma de tres enteros. La instrucción CALL ejecuta un procedimiento, insertando la dirección del mismo en el registro apuntador de instrucciones. Cuando el procedimiento termi- na, la instrucción RET (retorno de procedimiento) regresa al procesador al punto en el programa desde donde se hizo la llamada al procedimiento. Una llamada a procedimiento anidada ocurre cuando un procedimiento que se llamó hace una llamada a otro procedimiento antes de regresar.

Una etiqueta de código seguida de un signo de dos puntos es local para su procedimiento circundante. Una etiqueta de código seguida de :: es global, lo que la hace accesible desde cualquier instrucción en el mismo archivo de código fuente.

El procedimiento SumaArreglo, que se muestra en la sección 5.5.3, calcula y devuelve la suma de los

elementos en un arreglo.

El operador USES, junto con la directiva PROC, nos permite mostrar todos los registros que modifi ca un procedimiento. El ensamblador genera código que mete los registros al principio del procedimiento y los saca antes de regresar.

Un programa de cualquier tamaño debe diseñarse cuidadosamente, siguiendo un conjunto de especifi - caciones claras. Un método estándar es utilizar la descomposición funcional (diseño de arriba-abajo) para dividir el programa en procedimientos (funciones). Primero se determina el orden y las conexiones entre los procedimientos, y después se llenan los detalles de cada procedimiento.

5.8

Ejercicios de programación

Cuando escriba programas para resolver los ejercicios de programación, use varios procedimientos siempre que sea posible. Siga el estilo y las convenciones de nomenclatura que se utilizan en este libro, a menos que su instructor le indique lo contrario. Use comentarios explicativos en sus programas al principio de cada procedimiento, y enseguida de las instrucciones que sean complicadas. Como algo extra, es posible que su instructor le pida que proporcione diagramas de fl ujo o seudocódigo para los programas de las soluciones.

In document Lenguaje Ensamblador Irvine 5a Edición (página 176-181)