Vistas de página en total

Mostrando entradas con la etiqueta string. Mostrar todas las entradas
Mostrando entradas con la etiqueta string. Mostrar todas las entradas

viernes, 7 de marzo de 2014

ITOA

   Como un lector me planteó este problema, que ya tenía resuelto y me pasó su versión de la rutina para 32bits. He decidido volver a hacer una entrada con el proceso.
   Esta vez lo colocaré para TASM2.0, usando las directivas uses y argum. Aunque lo seguiré colocando en 16bits, ya que para 32 es idéntico. cambiando SI por ESI, DI por EDI etc y realizando la división en un solo paso (cambiando AX por EAX) , a no ser que se quiera hacer con números de 64 bits en cuyo caso la rutina quedaría igual que la actual, cambiando todos los registros a los extendidos.

En la versión puesta usámos procesador de 16 bits y interpretamos números de 32 bits:
        mov ax,[si+2]    ;toma la parte alta del número
       xor dx,dx             ;borra el resto
        div cx                ;divide por la base
        mov [si+2],ax         ; almacena el resultado
        mov ax,[si]        ;toma la parte baja
        div cx               ; divide por la base
        mov [si],ax          ;almacena el resultado
        mov bl,dl           ;toma el resto en bl, para indexar el caraceter


Si usásemos procesador de  32 bits y interpretamos números de 32 bits:
       mov ax,[esi]    ;toma la parte alta del número
       xor edx,edx             ;borra el resto
        div cx                ;divide por la base
        mov [esi],eax         ; almacena el resultado
         mov bl,dl           ;toma el resto en bl, para indexar el caraceter


Si usásemos procesador de  32 bits y interpretamos números de 64 bits:

        mov eax,[esi+4]    ;toma la parte alta del número
        xor dx,dx             ;borra el resto
        div cx                ;divide por la base
        mov [si+4]e,ax         ; almacena el resultado
        mov eax,[esi]        ;toma la parte baja
        div cx               ; divide por la base
        mov [esi],eax          ;almacena el resultado
        mov bl,dl           ;toma el resto en bl, para indexar el caraceter


El resto del paso a 32bits queda para el lector, ya que es muy sencillo.




ITOA.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

        public _itoa


.model compact,pascal

.data

caracteres db "0123456789ABCDEF"
numero dd 0
puntero dw 0
.code

proc _itoa uses bx cx dx si di,dest,dato,base
        mov cx,base       ;recogida del parámetro base a la que se convertirá
        mov bx,dato           ;recogida del parámetro numero de 16 bits a convertir
        mov si,offset numero   ;puntero a la variable auxiliar para procesamiento del número
        mov di,dest             ;recogida del parámetro destino, donde se quiere dejar el string de salida
        mov ax,[bx]              ;tomamos el numero a procesar y lo guardamos en la variable número
        mov [si],ax              ; primer word
        mov dx,[bx+2]              ;segundo word
        mov [si+2],dx
        cmp word ptr base,10       ;Verifica si la base es 10
        jne posit
        test word ptr [si+2],8000h   ; si la base es 10, verifica el signo en el bit alto
        jz posit
        xor word ptr [si],0ffffh     ; el signo es negativo y por lo tanto hace el complemento a 2
        xor word ptr [si+2],0ffffh
        add word ptr [si],1
        adc word ptr [si+2],0
        mov byte ptr [di],'-'          ; añade el signo a la cadena de salida
        inc di
        mov puntero,di               ; almacena el puntero para el inicio la posterior formación del número

  posit:
        xor bh,bh     ;inicia bh
        xor di,di    ;inica cuenta de caracteres , uso ahora di como contador
  conv:
        mov ax,[si+2]    ;toma la parte alta del número
        xor dx,dx             ;borra el resto
        div cx                ;divide por la base
        mov [si+2],ax         ; almacena el resultado
        mov ax,[si]        ;toma la parte baja
        div cx               ; divide por la base
        mov [si],ax          ;almacena el resultado
        mov bl,dl           ;toma el resto en bl, para indexar el caraceter
        mov dl,[bx+caracteres]   ; coge el caracter correspondiente al valor del resto
        push dx                 ;almacena en pila el caracter interpretado, para recogerlo luego en ax
        inc di                   ;incrementa di, usado como contador de caracteres
        cmp byte ptr [si],0        ;Ha terminado la conversión si el número ya es 0
        jne conv
        cmp byte ptr [si+2],0
        jne conv
        mov cx,di                ;almacena el contador en cx para la copia
        mov di,puntero           ; recupero el valor de DI como puntero al destino
   final:
        pop ax                     ; recupera el caracter interpretado
        mov [di],al                 ;almacena el caracter en la cadena
        inc di                       ;incrementa el puntero
        loop final                   ; continua la copia
        mov byte ptr [di],0           ; coloca el 0 de final de cadena
        ret
_itoa endp

end



domingo, 8 de diciembre de 2013

Concatenar un número indeterminado de cadenas

Como respuesta a una pregunta de un lector del blog, voy a añadir esta entrada.

   Si no me equivoco al interpretar su pregunta, el problema que se quiere es poder concatenar dos o más cadenas en una destino.
   Para hacerlo de forma elegante, voy a crear una macro.
    Esta macro va a concatenar las cadenas mediante llamadas consecutivas a la función strcat.
    La ventaja de la macro es que podemos añadir la llamada adicional solo si se pasa como parámetro el puntero a una nueva cadena, de forma que podemos dejar definida la función para un número indeterminado de cadenas. En este caso lo haré de 2 hasta 7.

   Para ello vamos a usar la función strcat para unir las dos primeras cadenas a la tercera. Luego, cuando exista el siguiente parámetro, tomaremos la dirección del destino, calcularemos su longitud y la sumaremos a su dirección de puntero. Así crearemos un puntero al final de la cadena destino. Esto lo haré en SI, para poder direccionarlo como [si] y pasarlo como parámetro a la macro strcpy. Así con esa nueva dirección puedo llamar de nuevo a strcpy y acoplar la cadena a la que ya existía.
    También lo podía haber hecho mediante sucesivas llamadas a strcat destino,destino,fuente?, pero de esta segunda forma perdería tiempo en copiar muchas veces la misma cadena.

    Si llamo a la macro
            Add_str destino,fuente1,fuente2  ;copia dos cadenas en destino
            Add_str destino,fuente1,fuente2,fuente3   ;copia tres cadenas en destino
        etc

    Add_Str macro destino,fuente1,fuente2,fuente3,fuente4,fuente5,fuente6,fuente7
               strcat destino,fuente1,fuente2      ;primera llamada con el mínimo permitido
            push si
           ifnb <fuente3>
               strlen destino
               lea si,destino
               add si,ax
               strcpy [si],fuente3      ;primera llamada
           else
                 ifnb <fuente4>
                     strlen destino
                      lea si,destino
                      add si,ax
                      strcpy [si],fuente4      ;segunda llamada
                  else
                      ifnb <fuente5>
                           strlen destino
                             lea si,destino
                             add si,ax
                            strcpy [si],fuente5      ;tercera llamada
                      else
                            ifnb <fuente6>
                                strlen destino
                                 lea si,destino
                                add si,ax
                                strcpy [si],fuente6      ;cuarta llamada
                             else
                                 ifnb <fuente7>
                                     strlen destino
                                     lea si,destino
                                    add si,ax
                                    strcpy [si],fuente7      ;quinta llamada
                                 endif
                            endif
                     enidf
              endif
         endif
         pop si
endm

  Realmente lo he creado como una nueva función, pero podría haber ampliado simplemente las que ya tenía publicadas en la cabecera string.mac.
   Por ejemplo, podríamos haberla llamado strcat directamente, pues en su modo más corto llama directamente a esa función. 

    Hay que tener en cuenta que el enlace está enviado a una versión inicial de las macros. En ella no usábamos el comando USE del TASM 2.0.
   Para pasar al modo de programación actual, en el que si usamos ya el comando USE del TASM2.0 habrá que aplicar la conversión indicada en la entrada del blog "pasamos a integrar TASM2.0"
   Con esta salvedad, colocaré ahora una versión actualizada de strcat y otra de strcpy, que podrán hacer la misma función que la anterior.

    Si en vez de crear una función nueva ampliamos strcat para que tenga polimorfismo, quedará:

strcat macro destino,fuente1,fuente2,fuente3,fuente4,fuente5,fuente6,fuente7
 ifndef _strcat
      extrn _strcat:near
 endif
        lea ax,destino
        push ax
       lea ax,fuente1
        push ax
        lea ax,fuente2
        push ax
        call _strcat                ;primera llamada. Sumamos fuente1, y fuente2 en destino
  
; a partir de ahí todo es igual    
        push si
           ifnb <fuente3>
               strlen destino
               lea si,destino
               add si,ax
               strcpy [si],fuente3      ;primera llamada
           else
                 ifnb <fuente4>
                     strlen destino
                      lea si,destino
                      add si,ax
                      strcpy [si],fuente4      ;segunda llamada
                  else
                      ifnb <fuente5>
                           strlen destino
                             lea si,destino
                             add si,ax
                            strcpy [si],fuente5      ;tercera llamada
                      else
                            ifnb <fuente6>
                                strlen destino
                                 lea si,destino
                                add si,ax
                                strcpy [si],fuente6      ;cuarta llamada
                             else
                                 ifnb <fuente7>
                                     strlen destino
                                     lea si,destino
                                    add si,ax
                                    strcpy [si],fuente7      ;quinta llamada
                                 endif
                            endif
                     enidf
              endif
         endif
         pop si 

  endm

    El ahorro es simplemente tener una sola función que vale para todo, ya que no tiene sentido strcat si Add_Str hace lo mismo.
 
     Pero claro, igualmente podríamos pensar con strcpy. Dado que strcat no es mas que dos llamadas a strcpy, podríamos construir strcat mediante strcpy, y si hacemos polimorfismo, nos bastará con strcpy, para realizar todas las posibilidades.

      ¿Que Sacrificamos?
      Sacrificamos código. Si usamos macro, cada llamada consumirá más código, que si usamos la llamada a la función strcat. Es por eso que cree strcat. Sin embargo, Add_Str si interesa hacerlo en macro, ya que concatenar  más de una cadena a la vez es más raro, y tener una función que no se usa, también puede aumentar el código, al incorporar librerías innecesarias.

    De todas formas vamos a ver como crear un strcpy,que sirva para todo.

strcpy macro destino,fuente1,fuente2,fuente3,fuente4,fuente5,fuente6,fuente7
ifndef _strcpy
    extrn _strcpy:near
endif
        lea ax,destino
        push ax
        lea ax,fuente1    ;copia inicial
        push ax
        call _strcpy
; a partir de ahí todo es igual , pero con una llamada más
        push si
           ifnb <fuente2>
               strlen destino
               lea si,destino
               add si,ax
               strcpy [si],fuente2      ;primera llamada
           else
                 ifnb <fuente3>
                     strlen destino
                      lea si,destino
                      add si,ax
                      strcpy [si],fuente3     ;segunda llamada
                  else
                      ifnb <fuente4>
                           strlen destino
                             lea si,destino
                             add si,ax
                            strcpy [si],fuente4      ;tercera llamada
                      else
                            ifnb <fuente5>
                                strlen destino
                                 lea si,destino
                                add si,ax
                                strcpy [si],fuente5      ;cuarta llamada
                             else
                                 ifnb <fuente6>
                                     strlen destino
                                     lea si,destino
                                    add si,ax
                                    strcpy [si],fuente6       ;quinta llamada
                                 else
                                    ifnb <fuente7>
                                         strlen destino
                                         lea si,destino
                                         add si,ax
                                         strcpy [si],fuente7       ;quinta llamada

                                    endif
                                 endif
                            endif
                     enidf
              endif
         endif
         pop si 
 endm

    Como se ve, hará lo mismo, y podrá usarse tanto para copiar una cadena, como para acoplar de 2 a 7 cadenas.
    Pero claro, para sumar dos cadenas perderemos más espacio si lo usamos varias veces, frente a usar strcat.

miércoles, 24 de julio de 2013

AHORCADO (5/5)

    Ya tenemos las herramientas necesarias para hacer el juego. Las rutinas expuestas antes, no necesitamos guardarlas en librerías, pues son parte de este programa. Por lo tanto son parte del código principal.
    Este, por lo tanto, es el fichero .asm completo que habrá que compilar.
    En el usamos funciones de time, de stdio, de string, y de main.
    El ejecutable resulta de 5232 Bytes

   Es importante pedir la letra con getch, la almacenamos en letra, y luego la convertimos en mayúsculas con upr.

   El programa está preparado para ser un .exe. Para que sea .com debemos colocar la directiva "_modelo com" y linkarlo con una librería preparada para .com.
    Esta librería se formará compilando todas las rutinas expuestas anteriormente pero con esta directiva. y creando luego una libreria completa para .com
   En el caso de que se compile como .com habrá que pasar los datos al final del programa. Esto no lo podemos hacer ahora, pues se producen problemas de compilación.

AHORCADO.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
include stdio.mac
include string.mac
include time.mac

_modelo exe
_stack 250

_data
;palabras
p1 db 9,"BARCELONA",0
P2 DB 4,"CASA",0
P3 DB 4,"CAMA",0
P4 DB 5,"ARBOL",0
P5 DB 7,"ARMARIO",0
P6 DB 5,"COJIN",0
P7 DB 5,"SUELO",0
P8 DB 4,"FLOR",0
P9 DB 3,"PAN",0
P10 DB 11,"ENCRUCIJADA",0
P11 DB 4,"HOJA",0
P12 DB 8,"CUADERNO",0
P13 DB 11,"ENSAMBLADOR",0
P14 DB 8,"PROGRAMA",0
P15 DB 7,"COLEGIO",0
P16 DB 6,"CAMARA",0

TABLA DW OFFSET P1
      DW OFFSET P2
      DW OFFSET P3
      DW OFFSET P4
      DW OFFSET P5
      DW OFFSET P6
      DW OFFSET P7
      DW OFFSET P8
      DW OFFSET P9
      DW OFFSET P10
      DW OFFSET P11
      DW OFFSET P12
      DW OFFSET P13
      DW OFFSET P14
      DW OFFSET P16

PAL_SEL DW 0
mascara DB "__________________________",0

a_buscar dw 0
letra db 0
fallos db 0
titulo db "AHORCADO",0
pregunta db "INDICA UNA LETRA",0
acierto db "!Enhorabuena! Acertaste",0
perdio db "!Lo siento! Has periddo",0
NW_intento db "Quieres intentarlo de nuevo? S/N",0
limpia db "    ",0
HORCA DB 218,196,196,196,0   ;"┌───┐"


_code
ahorcado proc far
        main   ; inicia
nw:
        call nw_pal    ;gernera una nueva palabra
        mov fallos,0   ;coloca el contador fallos a 0
        ;Preparamos la pantalla
        clrscr
        gotoxy 10,2     ;dibujamos horca
        puts titulo
        gotoxy 8,4
        puts horca
        gotoxy 8,5
        putchar 179
        gotoxy 8,6
        putchar 179
        gotoxy 8,7
        putchar 179
        gotoxy 8,8
        putchar 179
        gotoxy 8,9
        putchar 193
 
        gotoxy 10,10   ; muestra la mascara incial
        puts mascara
        gotoxy 10,13     ; hacemos la pregunta
        puts pregunta
_otro:
        gotoxy 29,13      ;limpia la ultima respuesta
        puts limpia
        gotoxy 29,13
        getch letra    ;pedimos la letra
        upr letra    ;convierte en mayuscula
        call buscar    ;busca la letra
        cmp bh,1       ; 1 si encuentra la letra
        je bien
        inc fallos     ; cuenta un fallo
        cmp fallos,8
        jne bien
        ;perido el juego
        gotoxy 11,4
        putchar 191  ;"┐"   ;dibuja la horca
        gotoxy 10,20         ;Perdiste
        puts perdio
        jmp  nw_int          

bien:
        gotoxy 10,10
        puts mascara
        call muneco
        cmp bl,1      ;1 si faltan letras
        jne _fin     ; estrucutra de saltos debido a que el salto relativo no llega hasta _otro
        jmp _otro
_fin:
        gotoxy 10,20         ;ha acertado
        puts acierto
nw_int:
        gotoxy 10,21
        puts nw_intento
        getch al             ;espera pulsación antes de salir
        upr                   ;convierte al en mayusculas
        cmp al,'S'
        jne  _salir
        jmp nw
_salir: exit 0

endp

nw_pal proc near
        push di
        push si
        random
        and ax,0fh    ; tomo numeros >16
        shl ax,1      ;multiplico por dos
        add ax,offset tabla   ;indexo a la tabla de punteros a palabras
        mov si,ax      ;paso la dirección a 'SI' para indexar
        mov ax,[si]    ; recupero la dirección de la palabra de la tabla de punteros
        mov pal_sel,ax  ; almaceno la dirección de la palabra
        mov si,ax        ; paso esta dirección a si para indexar
        mov di,offset mascara  ; usa 'DI' como indexador de mascara
        mov al,[si]   ; leo el numero de letras de la palabra
ini:
        mov byte ptr [di],'_'   ;borra la mascara
        inc di             ; incrementamos puntero busqueda
        dec al           ; decremento el número de letras
        jnz ini
        mov byte ptr [di],0 ; pongo final de cadena
        pop si
        pop di
ret
nw_pal endp

; busca la letra
; devuelve bl=1 si la encuentra la letra
;          bh=1 si faltan letras
buscar proc near
        push di
        push si
        push cx
        mov bx,0  ;borra banderas
        mov si,pal_sel
        mov di,offset mascara
        mov cl,[si] ;numero de letras a contador de busqueda
        inc si ;salta la longitud de la palabra
prueba:
        mov al,letra
        cmp byte ptr [si],al ;comprueba la letra pasada en al
        jne otra
        mov [di],al ; almacena la letra en mascara
        mov bh,1  ; marca bandera letra encontrada
otra:
        cmp byte ptr [di],"_"
        jne sigue
        mov bl,1  ; bandera palabra incompleta
sigue:
        inc si
        inc di
        dec cl
        jnz prueba
        pop cx
        pop si
        pop di
ret
buscar endp

;representación del muneco
; el contador está en la variable 'fallos'
muneco proc near
        push bx
        mov bl,fallos
        cmp bl,7
        jb s1
        gotoxy 12,8
        putchar '\'
s1:
        cmp bl,6
        jb s2
        gotoxy 10,8
        putchar '/'
s2:
        cmp bl,5
        jb s3
        gotoxy 11,7
        putchar 179   ;"│"
s3:
        cmp bl,4
        jb s4
        gotoxy 11,6
        putchar 179   ;"│"
s4:
        cmp bl,3
        jb s5
        gotoxy 12,6
        putchar '\'
s5:
        cmp bl,2
        jb s6
        gotoxy 10,6
        putchar '/'
s6:
        cmp bl,1
        jb fin
        gotoxy 11,5
        putchar 'O'
fin:
        pop bx
        ret
muneco endp
_end ahorcado








lunes, 8 de julio de 2013

COMPARA CADENAS DE TEXTO




STRCMP.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac

 extrn _strlen:near
_modelo exe
_code
rutina _strcmp destino,fuente
        PUSH SI
        PUSH DI
        PUSH ES
        PUSH DS
        POP ES
        MOV SI,[BP].destino
        MOV DI,[BP].fuente
        CLD
   MAS: CMPSB
        jne final
        CMP BYTE PTR [SI-1],0
        JNZ MAS
final:
        POP ES
        POP DI
        POP SI
 
rutina_end
_data
_end

sábado, 6 de julio de 2013

CORTA CADENA





STRCUT.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.


include main.mac
_modelo exe
_code
rutina _strcut destino,inicio,final,fuente

        PUSH SI
        PUSH DI
        PUSH ES
        PUSH DS
        POP ES

        MOV SI,[BP].fuente
        MOV DI,[BP].destino
        ADD SI,[BP].inicio
        MOV CX,[BP].FINAL
        SUB CX,[BP].INICIO
        CLD
   MAS: MOVSB
        CMP BYTE PTR [SI-1],0
        JZ FIN
        LOOP MAS
FIN:
        MOV BYTE PTR [DI],0
        POP ES
        POP DI
        POP SI
rutina_end
_data
_end

jueves, 4 de julio de 2013

CONCATENAR CADENAS


    Esta función completa las funciones de manejo de cadenas. En este caso concatena dos cadenas.
    En este caso vamos a sumar dos cadenas y las vamos a trasladar a una nueva.
    Los parámetros se pasan por pila. En este programa usaré la versión para ASM. En TASM 2.0 podremos substituir [bp].fuente1 por fuente1 usando el comando user . 

    Ver el paso a TASM en http://myassembler.blogspot.com/2013/08/pasamos-integrar-tasm-20.html

STRCAT.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
extrn _strcpy:near
extrn _strlen:near
_modelo exe

_code
rutina _strcat  dest,fuent1,fuent2
        push bx                                           ;Salva registro usado en el programa
        mov ax,[bp].fuent1                       ;toma los parámetros pasados por pila
        push ax                                           ;lo guarda como fuente para la 1ª  llamada a strcpy
        mov ax,[bp].dest                            ;toma los parámetros pasados por pila
        push ax                                           ;lo guarda como destino para la 1ª  llamada a strcpy
        call _strcpy                                     ; llama a copia de string
        pop ax                                             ;recupera la dirección destino de pila
        pop bx                                             ;elimina el otro dato de pila
        mov bx,ax                                       ;guarda la dirección del destino para luego en bx
        push ax                                           ; lo almacena en piula para strlen
        call _strlen                                        ;calcula la longitud
        add sp,2                                             ;elimina los datos de pila
        add bx,ax                                         ;suma al offset de destino, la longitud de destino
        mov ax,[bp].fuent2                         ;Toma la dirección del segundo string 
        push ax                                              ;lo almacena en pila para llamada a strcpy
        push bx                                            ; almacena el offset de destino, que ahora es nuevo
        call _strcpy                                         ;llama a copia de string
        add sp,4                                            ;recupera la pila
        pop bx                                               ;recupera el registro bx
rutina_end    
_data
_end

martes, 2 de julio de 2013

COPIA DE CADENAS DE TEXTO


         Esta función copia una cadena, en otra.

STRCPY.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
_modelo exe

_code
rutina _strcpy dest,fuente
        PUSH SI
        PUSH DI
        PUSH ES
        PUSH DS
        POP ES

        MOV SI,[BP].fuente
        MOV DI,[BP].destino
        CLD
   MAS: MOVSB
        CMP BYTE PTR [SI-1],0
        JNZ MAS
        POP ES
        POP DI
        POP SI
rutina_end
_data
_end

domingo, 30 de junio de 2013

LONGITUD DE UNA CADENA DE TEXTO


      Para completar la librería STRING de manejo de cadenas vamos a publicar las funciones más necesarias. La primera y básica es strlen. 
     Esta función que calcula la longitud de una cadena.
     En este caso

STRLEN.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
_modelo exe
_code
rutina _strlen  testo
        push bx
        mov bx,[bp].texto
    MAS:
        cmp byte ptr [bx],0
        jz FIN
        inc bx
        jmp MAS
    FIN:
        sub bx,[bp].texto
        mov ax,bx
        pop bx
rutina_end
_data
_end

domingo, 16 de junio de 2013

ENTERO A CADENA

    Esta es la función contraria a la anterior. A esta función le daremos un valor numérico (32bits) y nos devolverá una cadena alfanumérica que representa el número en la base indicada. El formato de la función, como en el resto de mis funciones queda reflejado en la llamada a la función rutina
   
ITOA.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
;_modelo com ; quitar el ; para  compilar para com

_code

rutina _itoa dest,dato,base
        push bx
        push cx
        push dx
        push si
        push di
        mov cx,[bp].base    ;recogida del parámetro base a la que se convertirá
        mov bx,[bp].dato   ;recogida del parámetro numero de 16 bits a convertir
        mov si,offset numero  ;puntero a la variable auxiliar para procesamiento del número
        mov di,[bp].dest     ;recogida del parámetro destino, donde se quiere dejar el string de salida
        mov ax,[bx]        ;tomamos el numero a procesar y lo guardamos en la variable número
        mov [si],ax        ; primer word
        mov dx,[bx+2]    ;segundo word
        mov [si+2],dx   
        cmp word ptr [bp].base,10   ;Verifica si la base es 10
        jne posit
        test word ptr [si+2],8000h  ; si la base es 10, verifica el signo en el bit alto
        jz posit
        xor word ptr [si],0ffffh      ; el signo es negativo y por lo tanto hace el complemento a 2
        xor word ptr [si+2],0ffffh
        add word ptr [si],1
        adc word ptr [si+2],0
        mov byte ptr [di],'-'        ; añade el signo a la cadena de salida
        inc di                              ; incrementa el puntero de salida
        mov puntero,di               ; almacena el puntero para el inicio la posterior formación del número   posit:

        xor di,di                       ;inica cuenta de caracteres , uso ahora di como contador  

         xor bh,bh                    ;inicia bh
  conv:
        mov ax,[si+2]           ;toma la parte alta del número
        xor dx,dx                ;borra el resto
        div cx                       ;divide por la base
        mov [si+2],ax        ; almacena el resultado
        mov ax,[si]        ;toma la parte baja
        div cx                ; divide por la base
        mov [si],ax    ;almacena el resultado
        mov bl,dl               ;toma el resto en bl, para indexar el caraceter
        mov dl,[bx+caracteres]       ; coge el caracter correspondiente al valor del resto
        push dx                         ;almacena en pila el caracter interpretado, para recogerlo luego en ax
        inc di                         ;incrementa di, usado como contador de caracteres
        cmp byte ptr [si],0    ;Ha terminado la conversión si el número ya es 0
        jne conv
        cmp byte ptr [si+2],0
        jne conv
        mov cx,di               ;almacena el contador en cx para la copia
        mov di,puntero; recupero el valor de DI como puntero al destino
   final:
        pop ax                  ; recupera el caracter interpretado
        mov [di],al         ;almacena el caracter en la cadena
        inc di                  ;incrementa el puntero
        loop final           ; continua la copia
        mov byte ptr [di],0    ; coloca el 0 de final de cadena
        pop di
        pop si
        pop dx
        pop cx
        pop bx
        pop bp
        ret
_itoa endp
_data
caracteres db "0123456789ABCDEF"
numero dd 0
puntero dw 0
_end






viernes, 14 de junio de 2013

CADENA A ENTERO

  Esta función, que es parte de la cabecera STRING. Nos permitirá convertir cualquier cadena de caracteres, que represente un número en cualquier base, a su valor numérico en un valor entero.

    En este caso como puede verse, nos hemos apoyado en la función anterior _may, la cual no se llamada a través de la macro strupr definida en STRING.MAC, sino  copiando el código de la macro.
    Esto es debido que la macro usa lea para tomar la dirección de la variable, y en este caso la dirección la tomamos del dato que ya se ha pasado por pila.

    Como ya habíamos definido la cabecera STRING.MAC, ahora podemos usarla en esta función, para directamente usar la función que necesitamos y que ya hemos implementado. Es decir strupr. por ello al comienzo de la función incluimos las cabeceras main ( para usar rutina) y string ( para usar strpur).

ATOI.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
include string.mac
_modelo exe
_code

      extrn _may:near
rutina _atoi dest,text,base
        push bx
        push cx
        push dx
        push si
        push di
        mov di,offset numero
   nuevo:

       ;strupr [bp].text
         ifndef _may
              extrn _may:near
         endif
        mov ax,[bp].text
        push ax
        call _may
        pop ax

        mov bx,ax
        cmp word ptr [bp].base,10
        jne otro
        cmp byte ptr [bx],'-'            ;;compruevo si es negativo
        jne otro
        inc bx
 otro:
        mov cx,[bp].base                 ;busqueda de caracter entre los definidos
        mov si,offset caracteres         ;en la base de numeracion
        mov al,[bx]
    busca:
        cmp al,[si]
        jz encont
        inc si
        loop busca
    encont:
        or cx,cx
        jz analisis
        mov ax,si
        sub ax,offset caracteres
        mov [di],al
        inc di
        inc bx
        cmp byte ptr  [bx],0
        jnz otro
   analisis:
        dec di
        mov bx,di
        mov di,[bp].dest        ;direccion de la variable dword
        mov word ptr [di],0
        mov word ptr [di+2],0
        mov multl,1               ;peso del bit 1,2,4,8
        mov multh,0
        mov cx,[bp].base         ;base de numeracion

  acum:
        mov al,[bx]
        cbw
        mov si,ax
        mov ax,multl
        mul si
        add [di],ax
        adc [di+2],dx
        mov ax,multh
        mul si
        add [di+2],ax
        mov ax,multh
        mul cx
        mov multh,ax
        mov ax,multl
        mul cx
        mov multl,ax
        add multh,dx

        dec bx                   ;sigiente numero
        cmp bx,offset numero-1
        je fin
        cmp byte ptr [bx],'-'
        jne acum
        xor word ptr [di],0ffffh
        xor word ptr [di+2],0ffffh
        add word ptr [di],1
        adc word ptr [di+2],0
  fin:  pop di
        pop si
        pop dx
        pop cx
        pop bx
        pop bp
        ret
_atoi endp

_data
caracteres db "0123456789ABCDEF"
numero db 33 dup (0)
multl dw 0
multh dw 0
_end




miércoles, 12 de junio de 2013

PASO A MAYUSCULAS

    Para crear lo básico de STRING, comenzaremos por la función de paso a mayusculas de una cadena. La función la llamo MAY aunque la macro se llama STRUPR.
   Esta función es necesaria para posteriormente convertir las cadenas en números en ATOI.



MAY.ASM

; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
_modelo exe
_code 
rutina _may text
        push bx
        mov bx,[bp].text
mayusc:
        cmp byte ptr [bx],0
        je fin
        cmp byte ptr [bx],'a'
        jb otro
        cmp byte ptr [bx],'z'
        ja otro
        sub byte ptr [bx],'a'-'A'
        jmp otro1
otro:
        cmp byte ptr [bx],'¤'
        jne otro1
        mov byte ptr [bx],'¥'
otro1:
        inc bx
        jmp mayusc
fin:
        pop bx
        pop bp
        ret
endp
_data
_end

lunes, 10 de junio de 2013

DECLARACIÓN FUNCIONES DE CADENA

        Vamos a ver y crear parte de la librería STRING, la cual servirá para el manejo de cadenas. Es importante hacer parte de esta librería enseguida pues en ella tenemos la función itoa y atoi, que vamos a necesitar en las funciones Scanf y Prinf de la librería básica STDIO.
     Por ello comenzaré con la  cabecera STRING.MAC y posteriormente las funciones atoi y itoa, para poder realizar una parte muy importante de la librería que necesitaremos posteriormente para la librerías STDIO.
    Con esta parte de String y la posterior STDIO, estaremos ya en condiciones de hacer nuestros primeros programas de entrada y salida de texto y valores por pantalla.
 
     Como veis, no hace falta decir mucho de las funciones, pues son estructuras iguales a las anteriores, para las llamadas a las funciones auxiliares. Los nombres son parecidos a los usados en C.
      Con estas funciones podremos manejar los textos que entremos por teclado y presentarlos de forma adecuada. Igualmente, cuando más tarde creemos la librería FILE y IO, podremos crear bases de datos con sus ALTAS-BAJAS-MODIFICACIONES.
       Como podemos crear la macro, pero no usarla, podremos hacer el fichero .MAC con todas las funciones, pero solo implementar en la librería itoa y atoi. Lo haremos así, dejando el resto para después de los primeros ejemplos.


STRING.MAC
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

;pasa el caracter al a mayusculas
; se le puede pasar o no parámetro.
; Si no se le pasa parámetro asume que se pasa a mayusculas al
upr macro letra 
local salir
ifnb <letra>
        mov al,letra

endif
        cmp  al,'a'
        jb salir
        cmp al,'z'
        ja salir
        sub al,'a'-'A'
salir:
ifnb <letra>
        mov letra,al

endif
        endm

;pasa la cadena a mayusculas
strupr macro direccion
ifndef _may
    extrn _may:near
endif
        lea ax,direccion
        push ax
        call _may
        pop ax
endm

;devuelve la longitud de la cadena
STRLEN MACRO CADENA
ifndef _strlen
    extrn _strlen:near
endif
       lea AX,CADENA
       PUSH AX
       CALL _STRLEN
       ADD SP,2
ENDM

;compara dos cadenas devuelve las banderas como en una comparacion normal
strcmp macro destino,fuente
ifndef _strcmp
    extrn _strcmp:near
endif
        lea ax,fuente
        push ax
        lea ax,destino
        push ax
        call _strcmp
        pop ax
        pop ax
 endm

strcpy macro destino,fuente
ifndef _strcpy
    extrn _strcpy:near
endif
        lea ax,fuente
        push ax
        lea ax,destino
        push ax
        call _strcpy
        pop ax
        pop ax
 endm

strcut macro destino,inic,fin,fuente
ifndef _strcut
     extrn _strcut:near
endif
        lea ax,fuente
        push ax
        mov ax,fin
        push ax
        mov ax,inic
        push ax
        lea ax,destino
        push ax
        call _strcut
        add sp,8
 endm

strcat macro destino,fuente1,fuente2
 ifndef _strcat
      extrn _strcat:near
 endif
        lea ax,fuente2
        push ax
        lea ax,fuente1
        push ax
        lea ax,destino
        push ax
        call _strcat
        add sp,6
  endm


atoi macro destino,texto,base
  ifndef _atoi
        extrn _atoi:near
  endif
  ifb <base>
        mov ax,10
  else
        mov ax,base
  endif
        push ax
        lea ax,texto
        push ax
        lea ax,destino
        push ax
        call _atoi
        add sp,6
   endm


itoa macro destino,numero,base
ifndef _itoa
        extrn _itoa:near
endif
ifb <base>
        mov ax,10
else
        mov ax,base
endif
        push ax
        lea ax,numero
        push ax
        lea ax,destino
        push ax
        call _itoa
        add sp,6
 endm



domingo, 5 de mayo de 2013

MAIN

 MAIN.MAC - CABECERA PRINCIPAL


   Primero y ante todo decir que el código que voy a implementar no usa muchas directivas ya creadas en MASM y TASM.  Debido a que yo daba clases de Ensamblador y a que comencé con ASM, preferí inicialmente crear directivas propias a usar las que tenía el compilado TASM 2.0. (rutina en vez de proc, modelo en vez de model, _data en vez de .data... etc). De esta forma podía demostrar que realmente las directivas eran definibles. 
    Por eso, aunque muchos digan que lo que estoy haciendo  ya está construido en el compilador, quiero que vean que muchas de las directivas del TASM 2.0 son prescindibles, y que un buen programador puede usar un pequeño compilador y realizar cualquier tarea.
    Esto es importante para los que hemos tenido que compilar con otros compiladores mucho más simples, por ejemplo para otros microprocesadores, y en los que hemos querido aplicar las mismas reglas de programación que con el 8086.
    
     Por eso ruego paciencia. Primero aplicaré mis directivas, y veremos como resulta un código casi idéntico al del ensamblador TASM 2.0.  Así veremos, sin necesidad de desensamblar, lo que realmente hacen esas directivas, que simplifican el código, pero que ocultan cosas, al programador, que se deben conocer y entender.
    Sin embargo, si pensamos usar standares y acoplarnos a códigos de alto nivel, nos conviene usar las directivas incorporadas en el compilador TASM, para compatibilizar de forma sencilla el código con otros lenguajes de alto nivel.
   Por eso a partir de la entrada 50 del blog haré una comparativa de las dos formas y comenzaré a aplicar directamente el código TASM 2.0.

FUNCIONES ACOPLADAS EN MAIN.MAC
    

  Todo lo que iré poniendo ahora será para generar ficheros .exe. Más adelante, Cuando hayamos implementado programas ya con las directivas del TAM completas, lo generaremos en .com.

 Como siempre habrá una cabecera ".mac", bueno ".inc" si se desea, con las macros y definiciones de las funciones. Cuando simplifique los programas a versión completa las llamaré ".inc" para distinguirlas.

  En esta cabecera, como cabecera de inicialización de programa incluyo algunas sentencias de precompilación, que servirán para asignar memoria, segmentos, pila y por supuesto la estructura de lista de argumentos.
       
     Rutina (equivale a proc+ arg en TASM)
     Permite crear estructura para el paso de parámetros través de pila, de esta manera será muy sencillo declarar una función y pasarla hasta 10 variables . Declara  al tiempo la función como publica, al modo que lo hace "C", pero sin apenas darnos cuenta. Se verá mejor cuando coloque la función Graphics.

  _modelo (equivale a model en TASM)
     Sirve para definir el tipo de programa .com o .exe. si no se usa es .exe. Esto se usará paa definr los segmetos
      EN esta macro creamos una constante que podemos identificar en la macro _data, para asignar la zona de datos a DS o CS, según el programa sea . com o .exe. Esto no evitará tener que utilizar dos librerías (una para como y otra para exe) , si no queremos tener que compilar todas las librerías cada vez que hagamos un programa.
   Pero sí nos permitirá tener un programa único para cada librería y una de muy  forma simple compilarlo para uno y otro modo.

  _code (equivale a .code en TASM) 
      Nos define el comienzo de la zona de código.

  _data (equivale a .data en TASM) 
    Nos define el comienzo de la zona de datos. Puede estar antes o después del code, aunque en las funciones es recomendable que esté detrás.

   _end  (equivalente a end en TASM)
        Cierra el programa en caso un programa se debe indicar el nombre de la rutina principal
  _stack (equivale a .stack en TASM)
         Nos inicializa la pila al tamaño indicado en NUMERO

   Todas estas macros crean un entorno de trabajo equivalente al estandar de TASM y MASM, pero sin usar su directivas. Como solo usa if y macro con ellas puede crearse el entrono equivalente a TASM pero en el compilador inicial ASM. Todas estas macros pueden ser eliminadas y substituidas por las directivas equivalentes del TASM 2.0. Cosa que haremos más adelante.

   Con estas  macros podemos ver como se pueden crear no solo llamadas a funciones sino nuevas directivas de compilación. A partir de la entrada 50 del blog veremos como crear con las macros directivas de PROGRAMACIÓN ESTRUCTURADA tales como FOR o WHILE.

 Otras macros más interesantes aún pues no las tiene el TASM son:

   dim - Permite crear una variable compleja tomando una estructura como plantilla.
   asigdata - Nos permitirá reasignar una zona de memoria al segmento de datos.

   of_reg- devuelve la dirección del registro indicado de una tabla que se encuentre en memoria, creada bajo una estructura.

    exit- Fin de programa con salida al sistema.

   encriptar y desencriptar- Funciones especiales que permitirán encriptar parte de los datos del programa, de manera que no sean legibles mediante un Dump del código, pero si sean legibles una vez inicializado el programa.

   string, char, integer Definición de los tres tipos de variables más importantes. Serán usadas en la inicialización de los datos, por lo que están incluidas en el main como definición de variables.

   main - comienzo del programa. Es la encargada de llamar a la linea de comandos si se definieron parámetros y la encargada de asignar la zona de datos si se definió con la macro _data. Así mismo prepara el PSP para que la salvar la dirección de vuelta al sistema.

     Dentro del main existe una directiva por la cual si no se ha añadido la cabecera argum.mac, y por lo tanto no se ha definido la variable externa _line_comand, no se llamará a la función de la librería correspondiente. De esta forma, si no necesitamos argumentos no consumiremos código innecesario.
  Main parece una forma de iniciar el programa pero es mucho más, en realidad  inicializa el programa., reserva la memoria, recoge los argumentos de la línea de comando, y prepara la ejecución. Por ello tomé este nombre para crear una rutina especial, a la que llamaré siempre al inicio del programa ejecutable. Se encargará de inicializar la memoria, la pila del sistema y recoger los argumentos de la linea de comandos, para que posteriormente mediante argv argc  tratarlos.
   En el caso del main  no incluimos la función directamente en la cabecera, pues en este caso el tamaño de la función supera al código de llamada.

  Esta rutina no tendrá argumentos, y será llamada simplemente main
 
   Con esta cabecera estamos creando un entorno de trabajo equivalente al TASM completo, pero sin usar sus directivas más complejas.


MAIN.MAC
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   ;Declaracion de una rutina (función) con paso de variables
    Esta macro crea una estructura de compilación para ser usada  posteriormente en la recogida de los datos pasados a la función.

;define modelo .com o .exe para definir forma de colocar assume en _data
_modelo macro tipo
   tipo equ 1
endm


rutina macro nombre,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10
   nombre&p struc
         dd ?
   irp arg,<arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10>
          ifnb <arg>
             arg  dw ?
          endif
        endm
    nombre&p  ends
        public nombre
nombre proc near

        push bp
        mov bp,sp
        endm


_end macro nombre
 ends  
   end nombre
endm

;genera la cabecera de datos
_data macro
ifndef com
    ends  ;asegura el cierre del segmento anterior
    data segment byte public 'data'
endif
endm

_code macro
    code segment byte public 'code'
    assume cs:code
ifdef com
  assume ds:code
else
    assume ds:data ; esto nos obliga a definir siempre un data aunque sea vacío
 endif
endm

;genera una pila con el tama¤o indicado
_stack macro NUMERO
     pila segment byte stack 'stack'
          db NUMERO dup (0)
     pila ends
     assume ss:pila
 endm


;coloca en pila de direccion del PSP para salir al dos y llama
;a la gesti¢n de la linea de comandos si se ha usado parametros
main macro
    push ds
    xor ax, ax
    push ax
ifdef _lin_comand
    call _lin_comand
endif
ifdef data
    asigdata data
endif
endm

;asigna un nuevo segmento de datos de trabajo
asigdata macro etiq
    assume ds:etiq
    mov ax, etiq
    mov ds, ax
endm

;dimensiona una tabla de numero de elementos con una estructura regis
dim macro tablas,regis,numero
        tablas regis numero dup (<>)
endm


; devuelve la direccion de un registro en una tabla en memoria
of_reg macro dest,lista,numero
      mov dest,offset lista[numero*type(lista)]
endm

;Sale al sistema devolviendo un codigo
exit macro codigo
     mov ah,4ch
ifdif <codigo>,<al>
     mov al,codigo
endif
     int 21h
endm

;encripta una zona de datos con un codigo dado
encriptar macro inicio,bytes,codigo
ifndef _encriptar
     extrn _encriptar:near
endif
         xor ax,ax
         push ax
         mov ax,codigo
         push ax
         mov ax,bytes
         push ax
         lea ax,inicio
         push ax
         call _encriptar
         add sp,8
 endm

;desencripta una zona de datos con un codigo dado
desencriptar macro inicio,bytes,codigo
ifndef _encriptar
        extrn _encriptar:near
endif
         mov ax,28h
         push ax
         mov ax,codigo
         push ax
         mov ax,bytes
         push ax
         lea ax,inicio
         push ax
         call _encriptar
         add sp,8
 endm

;define una cadena de entrada de texto para el scanf
string macro nombre,long
     nombre db long+1,0,long+2 dup (0)
endm

char macro var,ini
  ifb <ini>
      var db ?
  else
      var db ini
  endif
endm

integer macro var,ini
  ifb <ini>
      var dd ?
  else
      var dd ini
  endif
endm