Vistas de página en total

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.

No hay comentarios:

Publicar un comentario

Si tienes algún comentario, duda o sugerencia, o si quieres aportar algún código creado a partir de las librerías expuestas aquí, por favor, indícamelo.