//  CAFE2011.EXE is licensed under the terms of the CC-LGPL.
//  (CC-LGPL Version 3, 29 junio 2007 y CAFE2011 version 2011)
//  El objetivo es el libre uso comercial y no comercial del software.
//  Una copia de dicho documento se incluye en esta distribucion.
//  CWSDPMI.EXE, STREAMCO.PAS, el procedimiento TextOut
//  se tomaron de la distribucion FreePascal 2.4.2. con patente similar.
//        StreamCo.PAS es una contraccion conveniente a ocho letras del
//        nombre StreamColl.PAS en la distribucion FreePascal
  {$MODE                OBJFPC          }
  {$INCLUDEPATH         ..\INCLUDE      }
  {$INCLUDE             CAFE_INC.INC    }
unit CAFE_Ej1;

interface

uses SysUtils;

const
  CAFE_BytesExcesoCharByte              = 8;
{
  El verdadero tamano de CAFE_ClassCharByte.MemoriaChar^ es
  CAFE_ClassCharByte.TamanoVector+CAFE_BytesExcesoCharByte.
  TamanoVector revela el tamano "almacenable", pero
  hay unos espacios extras, que permiten poner un "0" final, o
  un byte inicial de tamano, etc.
}

type
  CAFE_Real                             = Real;
{
  Tipo real principal para el programa Ejes.  Puede que
  en algunas aplicaciones matematicas, se prefiera cambiarlo
  a Extended por ejemplo.  En la actualidad no haria
  un cambio consistente.  Debido al sistema variante de la hoja
  de calculo predefinido como Double.
}

  CAFE_ConjuntoByte     = SET OF Byte;
{
  Existe un tipo similar en SysUtils.  Se mantiene segun la version
  original.  Pues antes se ignoraba.
  Para pasar conjuntos de caracteres-Byte en algunos procesos.
}

  CAFE_ConjuntoChar     = SET OF Char;
{
  Para pasar conjuntos de caracteres-Byte en algunos procesos.
}

CONST
  CAFE_1ErrorFaltaFinComentario         : LongInt               = 1;
{
  CAFE_1ErrorFaltaFinComentario         :
        No se encontro un fin de comentario buscado
}

  CAFE_1ErrorFaltaFinString             : LongInt               = 1;
{
  CAFE_1ErrorFaltaFinString             :
        No se encontro final del String
}

  CAFE_1ErrorStringGeneral              : LongInt               = 1;
{
  CAFE_1ErrorStringGeneral              :
        Para indicar un error en la sintaxis de String sin aclarar mas
}

TYPE
  CAFE_ReferenciaCharByte               = CLASS OF CAFE_ClassCharByte;
{
  Referencia de clase para CAFE_ClassCharByte
  Segun la regla aqui se utiliza un campo adicional. Class.ModeloInterior
  o similar para conservar una referencia interna.
  Esto es redundante, pero se han tenido dificultades para evitarla.
}

  CAFE_ClassCharByte    = Packed CLASS
{
  Clase inicial del CharByte.
  Es algo asi como una evolucion del tipo STRING y PChar a la vez,
  pero especializado en analisis Sintactico, y quiza almacenamiento
  de informacion en Bytes compresos.  De momento analisis sintactico,
  de funciones y ordenes como STRING.
}

  Protected
    MemoriaChar         : PChar;
{
  MemoriaChar apunta al punteros completo.  Para accesar a un caracter
  se permite MemoriaChar[ 2020 ], MemoriaChar[ 0 ] no deberia utilizarse,
  y generalmente es 0.
}
  Public
    MemoriaVector       : PChar;
{
  La version original utiliza MemoriaVector y no MemoriaChar.
  Se conserva pues para la facil traduccion del Codigo.
  Apunta al primer dato util, y si Self[ Ocupado+1 ] = 0,
  podria quiza utilizarse como un autentico PChar no
  relocalizable de la forma usual. CUIDADO!, no garantizamos
  que Self[ Ocupado+1 ] = 0, aunque haremos el intento.
}
    TamanoVector,
{
  Espacio asignable util en MemoriaVector.  El verdadero tamano RAM
  para FreeMem es TamanoVector+CAFE_BytesExcesoCharByte, y se accesa
  con MemoriaChar.
}

    Ocupado             : LongInt;
{
  Tamano CHAR efectivamente asignado.  El buen codigo deberia
  asegurar que Ocupado <= TamanoVector siempre.
  Ocupado = 0 y TamanoVector <> 0 significa vacio, algo asi como ''.
}

  // Actualizar siempre
CONSTRUCTOR Create
  (     Tamano          : LongInt                               ); virtual;
{
  Inicializa el CharByte para su buen funcionamiento,
  pero completamente vacio.
  Tamano es el nuevo TamanoVector. (no compatible FreeMem)
}

  // Actualizar siempre
CONSTRUCTOR Create
  ( CONST
        Msg             : ShortString;
        Tamano          : LongInt                               ); virtual;
{
  Inicializar el CharByte para su buen funcionamiento,
  con Msg como datos iniciales. No importa, utilizar Tamano "muy grande".
  Msg podria ser ''.
}

  // Actualizar siempre
CONSTRUCTOR Create
  (     Modelo          : CAFE_ClassCharByte                    ); virtual;
{
  Inicializa el CharByte, copiando completamente el dato
  CharByte de modelo, incluyendo su TamanoVector.
}

  { DOBLE CODIGO }
  {$IFDEF CPUI386_CPU32}
FUNCTION    BuscarSiguienteByte
  ( VAR PosicionActual          : LongInt; ByteBusqueda         : Byte;
        Direccion, IdenticoDiferente            : Boolean     ) : Boolean;
                                pascal; assembler;
  {$ELSE}
FUNCTION    BuscarSiguienteByte
  ( VAR PosicionActual          : LongInt; ByteBusqueda         : Byte;
        Direccion, IdenticoDiferente            : Boolean     ) : Boolean;
  {$ENDIF}
  { DOBLE CODIGO }
{
  FUNCTION BuscarSiguienteByte
        Proceso optimizado en ensamblador para busqueda de caracteres
        en el CharByte, con numeracion inicial de 1.
        Utiliza el metodo de "PosicionActual no es elegible".
        ¨Porque?, pues para hacer cosas como esta
                PosicionActual  := 0;
                WHILE BuscarSiguitenByte
                        ( PosicionActual, Byte( ' ' ), TRUE, FALSE ) DO
                        Write( MemoriaChar[ PosicionActual ] );
        Que escribe todos los caracteres que no sean espacios blanco.
  PosicionActual        : INPUT es la posicion inicial de busqueda.
        Acepta valores fuera de rango.  Buscando
        en la direccion asignada.  Simplemente devuelte
        0 -> PosicionActual, si falla la busqueda, y FUNCTION es FALSE.
        El valor devuelto es el correcto numerado a partir de 1,
        valido en MemoriaChar[ PosicionActual ] como Char
        y Self[ PosicionActual ] como Byte.
        NUNCA devuelve el mismo valor inicial.  Con 0, la unica
        excepcion.
  ByteBusqueda          : Se refiere al Byte de interes.
  Direccion             : TRUE indica --> y FALSE indica sentido <--.
  IdenticoDiferente     : TRUE indica Byte identico, y FALSE
        cualquier Byte diferente.
        NOTA: en Ejes.EXE, la combinacion de una Bandera de ANTONIMOS,
        generalmente TRUE es el primer antonimo.
  FUNCTION BuscarSiguienteByte  : TRUE indica exito y FALSE fracaso.
}

FUNCTION    ExtraerString
  (     PosicionInicial         : LongInt;
        LargoString             : Byte                  ) : ShortString;
                                overload;
{
  FUNCTION ExtraerString
        Proceso de extraccion de cadena corriente en el CHARBYTE
        Extra en PosicionInicial una cadena de largo LargoString.
        Recuerde que el CharByte se numera a partir de 1.
  PosicionInicial               : Debe estar en el rango 1..Ocupado,
        de lo contrario se considera Error grave.
        Con la excepcion de dos casos: Ocupado = 0 y LargoString = 0,
        que devuelven pacificamente '', sin importar PosicionInicial.
  LargoString                   : Tamano del String solicitado.
        LargoString 0 devuelve pacificamente ''.
        Sin Importar PosicionInicial.
  FUNCTION ExtraerString        : devuelve la cadena solicitada.
}

FUNCTION    ExtraerString                                 : ShortString;
                                overload;
{
  FUNCTION ExtraerString
        Intenta extraer la cadena completa almacenada en el CharByte
        hasta un maximo de 255 caracteres.  Datos mayores
        se truncan en la salida de FUNCTION.
        Si Ocupado = 0, la salida es ''.
  FUNCTION ExtraerString        : devuelve la cadena almacenada en el
        CharByte, hasta un maximo de 255 caracteres.
}

PROCEDURE   InsertarString
  ( CONST
        CadenaInsercion         : ShortString;
        PosicionInsercion       : LongInt                               );
                                overload;
{
  PROCEDURE InsertarString
        Inserta en PosicionInsercion del CharByte (comienza en uno).
        CadenaInsercion, los bytes utiles sin el tamano (logicamente).
        CUIDADO: de excederse TamanoVector se considera Error Grave.
  CadenaInsercion               : Cadena a insertar.  Valido '', que
        no hace nada.
  PosicionInsercion             : Indica la posicion a insertar.
        Debe estar en el rango util, a partir de uno.  Es valido
        Ocupado+1, que agrega al final.
        CUIDADO: No se permite el cero, que se considera Error Grave.
                En tal caso se recuerda que este PROCEDURE es overload.
                O bien utilice PosicionInsercion = 1.
}

PROCEDURE   InsertarString
  ( CONST
        CadenaInsercion         : ShortString                           );
                                overload;
{
  PROCEDURE InsertarString
        En realidad borra el dato anterior.  Y coloca CadenaInsercion
        como el nuevo dato, que puede ser muy inferior a TamanoVector.
        CUIDADO: Borra no inserta.
        Si quiere insertar realmente utilice la version overload.
        InsertarString( CadenaInsercion, 1 )
  CadenaInsercion               : Dato a sustituir la informacion
        actual en el CharByte.
}

PROCEDURE   InsertarDatosCharByte
  (     PDatos                  : PChar;
        PosicionInsercion, TamanoInsercion              : LongInt       );
{
  PROCEDURE InsertarDatosCharByte
        Transfiere datos en PDatos^, en modo de insersion
        a PosicionInsercion a partir de 1.  Un total de datos
        de TamanoInsercion.  Se desplazan los datos en el CharByte.
        Insertar los datos en PDatos, que se supone un puntero corriente.
        No es necesario que sea compatible con PChar, ni que termine en
        cero.  Inclusive TamanoInsercion puede superar el limite del
        PChar en cero.  Y transfiere sin consulta.
  PDatos                        : se supone un puntero corriente
        que simplemente apunta al primer dato a transferir.
        No se preocupe por la regla del cero.  Que se ignora completamente.
        NOTA: Internamente Self[ Ocupado+1 ] := 0, al final.
  PosicionInsercion             : Indica la posicion en el CharByte
        para insertar, numerado a partir de uno.
  TamanoInsercion               : Indica el total de bytes a transferir.
        Se puede utilizar un cero que no hace nada.
  CUIDADO: Se considera Error Grave exceder TamanoVector
}

PROCEDURE   EliminarDatosCharByte
  (     PosicionDato, TotalDatos                : LongInt               );
{
  PROCEDURE EliminarDatosCharByte
        Elimina datos existentes en el CharByte.
        Produciendo desplazamiento de Bytes y reasignacion de datos
        conforme se necesite.
        CUIDADO: Se considera error grave eliminar datos inexistentes.
        En tal caso reasigne simplemente Ocupado a un valor menor.
        Por ejemplo Ocupado := 0, se interprete como borrar
        completamente el dato, con riesgo futuro de perdida total de
        los datos efectivamente escritos.
  PosicionDato                  : Posicion del dato a borrar en CharByte.
  TotalDatos                    : Total de bytes a borar en el CharByte.
        No intente borrar por exceso.  PROCEDURE unicamente borra
        datos existentes.
}

PROCEDURE   InsertarExtraccionCharByte
  (     PosicionInsercion       : LongInt;
        VectorFuente            : CAFE_ClassCharByte;
        PosicionExtraccion, TamanoTransferencia                 : LongInt );
{
  PROCEDURE InsertarExtraccionCharByte
        Inserta datos existentes en VectorFuente, a partir
        de Self[ PosicionInsercion ], desplazando los bytes
        que sean necesarios.
        CUIDADO: datos fuera de rango o inexistentes se considera
        que generan Error Grave.
        Es valido PosicionInsercion = Ocupado+1. No es valido el cero.
  PosicionInsercion             : Posicion de insercion numerados
        a partir de 1..Ocupado+1, en Self.
  VectorFuente                  : Contiene los datos existentes
        a transferir.
  PosicionExtraccion            : Define la posicion en VectorFuente,
        a partir de 1, para la extraccion.
  TamanoTransferencia           : Total de datos existentes en
        VectorFuente.Ocupado, a transferir.
}

PROCEDURE   ExtraccionCharByte
  (     VectorFuente            : CAFE_ClassCharByte;
        PosicionExtraccion, TamanoTransferencia                 : LongInt );
{
  PROCEDURE ExtraccionCharByte
        Borra el CharByte con Ocupado = 0, y lo sustituye
        por el Dato en VectorFuente[ PosicionExtraccion ],
        un total de TamanoTransferencia bytes.
        CUIDADO: No se aceptan datos fuera de rango
                ( se utiliza InsertarExtraccionCharByte )
  VectorFuente                  : Contiene los datos existentes
        a transferir.
  PosicionExtraccion            : Define la posicion en VectorFuente,
        a partir de 1, para la extraccion.
  TamanoTransferencia           : Total de datos existentes en
        VectorFuente.Ocupado, a transferir.
}

PROCEDURE   TransferenciaCharByte
  (     VectorFuente            : CAFE_ClassCharByte                    );
{
  PROCEDURE TransferenciaCharByte
        Borra el CharByte con Ocupado = 0, y transfiere
        la totalidad de VectorFuente.
  VectorFuente                  : Contiene los datos existentes
        a transferir.  Es admisible VectorFuente.Ocupado = 0.
}

PROCEDURE   UpDownCaseCharByte
  (     UpDown                  : Boolean                               );
{
  PROCEDURE UpDownCaseCharByte
        Recorre el CharByte en su totalidad, pasando a mayuscula.
        Utiliza el proceso de SysUtils.
  UpDown                        : Si TRUE pasa a mayuscula si FALSE
        para a minuscula.
        Nota: la regla en Ejes.EXE del nombre de un parametro booleano
        formado por dos antonimos, es TRUE el primer antonimo y
        FALSE el segundo antonimo.
}

PROCEDURE   ConcatenarCharByte
  (     VectorFuente            : CAFE_ClassCharByte                    );
{
  PROCEDURE ConcantenarCharByte
        Agrega al CharByte en Self[ Ocupado+1 ]
        la totalidad de VectorFuente.  (anexa al final).
        CUIDADO: Se considera Error Grave fuera de rango.
  VectorFuente                  : Contiene los datos existentes
        a transferir.  Es admisible VectorFuente.Ocupado = 0.
}

PROCEDURE   SustitucionConjuntoByte
  ( CONST
        ConjuntoSeleccion       : CAFE_ConjuntoByte;
        NuevoByte               : Byte;
        BanderaSimultaneo       : Boolean       = TRUE                  );
{
  PROCEDURE SustitucionConjuntoByte
        Recorre el CharByte realizando la sustitucion de todos
        los bytes en ConjuntoSeleccion, por NuevoByte.
  ConjuntoSeleccion             : Conjunto de bytes a ser sustituido.
  NuevoByte                     : El nuevo byte a ser sustituido.
  BanderaSimultaneo             : TRUE busca todos los bytes
        simultaneamente y FALSE lo realiza uno a uno.
        Por razones del ensamblador y del tipo ConjuntoSeleccion
        que mide 32 bytes, probablemente sea mas
        eficiente en velocidad aplicar BanderaSimultaneo = FALSE.
        Al menos en casos que ConjuntoSeleccion tenga pocos datos.
}

PROCEDURE   EscribirByteRepetidoCharByte
  (     ByteEscrito             : Byte;
        PosicionEscritura, TamanoTransferencia          : LongInt;
        ModoInsercion           : Boolean                               );
{
  PROCEDURE EscribirByteRepetidoCharByte
        Escribe en Self[ PosicionEscritura ], un total
        de TamanoTransferencia veces el dato ByteEscrito.
        ModoInsercion TRUE provoca el desplazamiento de datos
        para que no se borren.
        NOTA: El algoritmo de insercion no es muy eficiente,
        especialmente con TamanoTransferencia pequeno.
        Trate de utilizarlo unicamente con Ocupado pequeno
        si ModoInsercion es TRUE.
  ByteEscrito                   : Es el Byte a escribir.
  PosicionEscritura             : Se escribira el primer dato
        en Self[ PosicionEscritura ].  Numerado a partir de uno.
  TamanoTransferencia           : Veces que se escribira ByteEscrito.
  ModoInsercion                 : Si TRUE se inserta con
        desplazamiento de datos, si FALSE se sobreescribe.
}

FUNCTION    BuscarSiguienteSecuencia
  ( VAR PosicionActual          : LongInt;
        VectorFuente            : CAFE_ClassCharByte;
        Direccion               : Boolean                       ) : Boolean;
{
  FUNCTION BuscarSiguienteSecuencia
        Buscar el contenido total de VectorFuente en Self.
        VectorFuente.Ocupado = 0 se considera ErrorGrave.
        Self.Ocupado = 0 simplemente es FUNCTION = FALSE.
        La regla para PosicionActual es:
        A. Se permite PosicionActual fuera de rango.
        B. PosicionActual no es elegible.
        C. La primera posicion valida en Self es uno.
        D. No encuentra devuelve PosicionActual = 0 y FUNCION = FALSE.
        E. Exito devuelve Self[ PosicionActual ] = primer Byte
                del grupo VectorFuente y FUNCTION = TRUE
  PosicionActual                : Indica la posicion de inicio de busqueda,
        no es elegible.  Busca el siguiente a PosicionActual.
  VectorFuente                  : Contiene la informacion a buscar.
        Se busca su totalidad.  VectorFuente.Ocupado = 0 es Error Grave.
  Direccion                     : Si TRUE indica busqueda -->,
        y FALSE buqueda inversa <--.
  FUNCTION BuscarSiguienteSecuencia             : si TRUE indica exito
        Self[ PosicionActual ] seria igual al primer byte
        de VectorFuente.  Si FALSE indica fracaso en la busqueda.
}

FUNCTION    ConteoBuscarSiguienteByte
  ( VAR PosicionActual          : LongInt; ByteBusqueda         : Byte;
        Direccion, PrincipioFin : Boolean                       ) : LongInt;
{
  FUNCTION ConteoBuscarSiguienteByte
        Buscar el "siguiente" grupo que contenga el ByteBusqueda
        (podria ser un grupo de uno).
        Se considera grupo cualquier secuencia de bytes identicos,
        inclusive los aislados.
        Si Self[ PosicionActual ] = ByteBusqueda este
        grupo no es elegible del todo, ni ninguno de sus miembros.
        El grupo puede ser identificado por su
        primer o ultimo miembro segun bandera PrincipioFin.
        Algoritmo util en manejo de insercion de cadenas
        de texto en interpretes tipo Pascal.
  PosicionActual                : Es la posicion de inicio de busqueda.
        El grupo en PosicionActual no es elegible.
  ByteBusqueda                  : Se esta buscando un grupo de
        bytes identicos secuenciales todos ellos a ByteBusqueda.
  Direccion                     : Si TRUE el sentido de busqueda es -->,
        si FALSE el sentido es <--.
  PrincipioFin                  : Si TRUE PosicionActual devuelve el
        inicio de grupo <--, si FALSE devuelve el final --> del grupo.
  FUNCTION ConteoBuscarSiguienteByte    : devuelve el total de bytes
        identicos seguidos del grupo.  Si no encuentra FUNCTION es
        cero, y PosicionActual es cero tambien.
}

PROCEDURE   ExtraccionBlancoParentesis
  (     ByteBlanco, ByteParentesisAbrir, ByteParentesisCerrar   : Byte  );
{
  PROCEDURE ExtraccionBlancoParentesis
        Elimina en CharByte blancos y parejas de parentesis excesivas.
        Los parentesis se eliminan uno de Abrir y otro de Cerrar
        simultaneos al inicio y al final respectivamente.  Tantos
        como aparezcan sin ninguna otra cosa, a parte de blancos.
        Se conserva el resto, sea lo que sea luego de este proceso.
        Por ejemplo, es tipico que
        ( ( ( Exp( 8, 9 ) ) ) )#0
        se interprete como
        Exp( 8, 9 )#0
        Nota: En realidad se controla con Ocupado y no con el #0.
        Pero se intenta sin garantia agregarlo al final.
        Ademas se permite el uso del #0 interno.
  ByteBlanco                    : Es el byte a ser considerado como blanco.
  ByteParentesisAbrir           : Es el byte de apertura de parentesis.
  ByteParentesisCerrar          : Es el byte de cierre de parentesis.
}

FUNCTION    ExtraccionFuenteSeparador
  (     VectorFuente            : CAFE_ClassCharByte;
    VAR PosicionFuente          : LongInt;
        ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar  : Byte;
        Direccion, ExtraccionIzquierda          : Boolean       ) : Boolean;
                                overload;
{
  FUNCTION ExtraccionFuenteSeparador
        El objetivo de FUNCTION es extraer desde VectorFuente
        un parametro de una secuencia de parametros.
        Se consideran los parentesis para determinar los parentesis.
        Es decir entre separador y separador deberia haber
        un numero igual de Parentesis de abrir y cerrar.
        Ejemplo
          '23,34,Suma(25+36,(2+5)),,9*8,'
        PosicionFuente := 0;
        WHILE ( VectorFuente, PosicionFuente, Byte(','), Byte('('),
                Byte(')'), TRUE, TRUE ) DO
                WriteLn( 'Parametro : ', ExtraerString );
        OUTPUT-->
        Parametro : 23
        Parametro : 34
        Parametro : Suma(25+36,(2+5))
        Parametro :
        Parametro : 9*8
        Parametro :
        NOTA: la coma final genera un parametro nulo '' adicional.
  VectorFuente                  : CharByte con la orden a analizar.
  PosicionFuente                : Posicion inicial de busqueda no elegible.
        Podria estar fuera de rango.
        En el interior deberia coincidir con un separador para
        evitar dificultades.
        PosicionFuente de salida de la ultima busqueda
        estara fuera de rango. Podria ser 0 o Ocupado+1 segun direccion.
  ByteSeparador                 : Indica el delimitador, probablemente
        algo asi como ',', u otro.
  ByteParentesisAbrir           : Indica la apertura de parentesis,
        probablemente algo asi como '(' u otro.
  ByteParentesisCerrar          : Indica el cierre de parentesis,
        probablemente algo asi como ')' u otro.
  Direccion                     : Si TRUE indica busqueda en sentido -->,
        y FALSE busqueda en sentido <--.
  ExtraccionIzquierda           : Utilice NOT( Direccion  ), para evitar
        dificultades.
        TRUE indica que se pide lo que este a la derecha
        y si FALSE indica que se pide lo que este a la izquierda.
        CUIDADO: Direccion = ExtraccionIzquierda simplemente
        extrae TODO lo que siga...
        Direccion <> ExtraccionIzquierda extra solo entre separadores.
        Esto es util si se quiere extraer TODO lo que siga o solo un
        parametro.
  FUNCTION ExtraccionFuenteSeparador    : TRUE indica que se extrajo
        un parametro, incluyendo el STRING ''.
        FALSE indica que no se extrajo nada.
        VectorFuente.Ocupado = 0  --> FALSE
        La cadena de blancos es admisible como parametro '  ' y es TRUE.
  NOTA: para evitar confusion utilice la version OVERLOAD sin
        ExtracionIzquierda
}

FUNCTION    ExtraccionFuenteSeparador
  (     VectorFuente            : CAFE_ClassCharByte;
    VAR PosicionFuente          : LongInt;
        ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar  : Byte;
        Direccion               : Boolean                       ) : Boolean;
                                overload;
{
  FUNCTION ExtraccionFuenteSeparador
        El objetivo de FUNCTION es extraer desde VectorFuente
        un parametro de una secuencia de parametros.
        Se consideran los parentesis para determinar los parentesis.
        Es decir entre separador y separador deberia haber
        un numero igual de Parentesis de abrir y cerrar.
        Ejemplo
          '23,34,Suma(25+36,(2+5)),,9*8,'
        PosicionFuente := 0;
        WHILE ( VectorFuente, PosicionFuente, Byte(','), Byte('('),
                Byte(')'), TRUE, TRUE ) DO
                WriteLn( 'Parametro : ', ExtraerString );
        OUTPUT-->
        Parametro : 23
        Parametro : 34
        Parametro : Suma(25+36,(2+5))
        Parametro :
        Parametro : 9*8
        Parametro :
        NOTA: la coma final genera un parametro nulo '' adicional.
  VectorFuente                  : CharByte con la orden a analizar.
  PosicionFuente                : Posicion inicial de busqueda no elegible.
        Podria estar fuera de rango.
        En el interior deberia coincidir con un separador para
        evitar dificultades.
        PosicionFuente de salida de la ultima busqueda
        estara fuera de rango. Podria ser 0 o Ocupado+1 segun direccion.
  ByteSeparador                 : Indica el delimitador, probablemente
        algo asi como ',', u otro.
  ByteParentesisAbrir           : Indica la apertura de parentesis,
        probablemente algo asi como '(' u otro.
  ByteParentesisCerrar          : Indica el cierre de parentesis,
        probablemente algo asi como ')' u otro.
  Direccion                     : Si TRUE indica busqueda en sentido -->
        y extrae el parametro a la izquierda del separador nuevo.
        y FALSE busqueda en sentido <-- y extrae el parametro a la derecha
        del separador nuevo.
  FUNCTION ExtraccionFuenteSeparador    : TRUE indica que se extrajo
        un parametro, incluyendo el STRING ''.
        FALSE indica que no se extrajo nada.
        VectorFuente.Ocupado = 0  --> FALSE
        La cadena de blancos es admisible como parametro '  ' y es TRUE.
}

  { DOBLE CODIGO }
  {$IFDEF CPUI386_CPU32}
FUNCTION    BuscarSiguienteCadena
  ( VAR PosicionActual          : LongInt;
    CONST
        Cadena                  : ShortString ;
        Direccion               : Boolean                       ) : Boolean;
                                pascal; assembler;
  {$ELSE}
FUNCTION    BuscarSiguienteCadena
  ( VAR PosicionActual          : LongInt;
    CONST
        Cadena                  : ShortString ;
        Direccion               : Boolean                       ) : Boolean;
  {$ENDIF}
  { DOBLE CODIGO }
{
  FUNCTION BuscarSiguienteCadena
        Busca Cadena en el CharByte, a partir de PosicionActual.
        En el sentido establecido por la bandera Direccion.
        Se elige el primer byte a la izquierda de la cadena.
        PosicionActual no es elegible.
        Este proceso se encuentra optimizado para ensamblador.
  PosicionActual                : Con numeracion a partir de uno.
        Acepta valores fuera de rango.  El valor input no es elegible,
        y establece el punto inicial de busqueda.
        Retorna la posicion solicitada o cero si no encuentra.
  Cadena                        : Contiene la cadena de busqueda.
  Direccion                     : TRUE indica sentido --> de busqueda,
        FALSE es sentido inverso <--.
}

FUNCTION    VerificarFormatoOrdenBasica
  (     ByteBlanco, ByteParentesisAbrir, ByteParentesisCerrar,
        ByteSeparador     : Byte; ExtraccionPrimaria  : Boolean ) : Byte;
{
  FUNCTION VerificarFormatoOrdenBasica
        En teoria deberian cumplirse los siguientes requisitos,
        en realidad la prueba es menos exigente:
        A. Numero identico de ByteParentesisAbrir y ByteParentesisCerrar.
        B. Ultimo Byte es un ByteParentesisCerrar.
        C. Nunca se cuenta mas ByteParentesisCerrar que ByteParentesisAbrir.
        C. No que existe un ByteSeparador despues de un conteo identico
                de ByteParentesisAbrir y ByteParentesisCerrar.
        D. Antes del primer ByteParentesisAbrir existe algun
                caracter diferente de ByteBlanco, ByteParentesisCerrar o
                ByteSeparador
        E. El primer parentesis abrir deberia estar antes
                de la posicion 256 en CharByte.
        FUNCTION desplaza el primer ByteParentesisAbrir, hacia atras
        para tocar un caracter no blanco.
        Deberia combinarse con VerificarIdentificadorBasicoInsertado,
        para tener una identificacion mejor.
        Advertencia: muchas cosas que no son verdaderos operadores
        basicos pasaran la prueba.  Se considera un criterio inicial.
  ByteBlanco                    : Byte utilizado como blanco.
  ByteParentesisAbrir           : Byte utilizado como parentesis abrir.
  ByteParentesisCerrar          : Byte utilizado como parentesis cerrar.
  ByteSeparador                 : Byte utilizado como separador de
        parametros en un operador.
  ExtraccionPrimaria            : Realiza una eliminacion previa
        de espacios en blanco y parejas de parentesis excesivas
        al inicio y al final que rodeen el operador.
        Puede ser necesario si lee ordenes desde teclado,
        o quiere saber si un parametro es un OperadorBasico.
  FUNCTION VerificarFormatoOrdenBasica          : devuelve la posicion
        del primer parentesis abrir encontrado o cero si
        no se paso la prueba.
}

FUNCTION    VerificarIdentificadorBasicoInsertado
  ( OUT CadenaIdentificador     : ShortString;
        PosicionIdentificador   : LongInt;
        TamanoIdentificador     : Byte;
    CONST
        PrimerByteIdentificador, MedioByteIdentificador,
        UltimoByteIdentificador         : CAFE_ConjuntoByte     ) : Boolean;
{
  FUNCTION VerificarIdentificadorBasicoInsertado
        Verifica que en Self[ PosicionIdentificador ], y de tamano
        TamanoIdentificador existe un IdentificadorBasico
        Ojo:  No se verifica las posiciones anteriores ni posteriores.
                Eso se supone es trabajo de otros procesos.
        Caracteristicas del IdentificadorBasico:
        A. Primer Byte pertenece a PrimerByteIdentificador
        B. UltimoByte pertenece a UltimoByteIdentificador
        C. El resto de los Bytes pertenecen a MedioByteIdentificador.
        Si TamanoIdentificador = 1, solo aplica A, y
        si TamanoIdentificador = 2, solo aplican A y B.
        TamanoIdentificador se puede asignar en exceso,
        si se quiere revisar desde Self[ PosicionIdentificador ]
        hasta el Self[ Ocupado ].
        En caso TRUE el identificador se devuelve en CadenaIdentificador.
  CadenaIdentificador           : devuelve el identificador extraido
        en el caso TRUE.  El caso FALSE genera ''.
  PosicionIdentificador         : numerado a partir de cero.  Se supone
        que el primer caracter se encuentra en Self[ PosicionIdentificador ].
  TamanoIdentificador           : deberia ser exacto para un identificador
        interior.  Puede definirse en exceso, si se supone que el
        identificador termina en Self[ Ocupado ].
  PrimerByteIdentificador       : Conjunto Byte de valores admisibles
        para el primer Byte del identificador.
  MedioByteIdentificador        : Conjunto Byte de valores admisibles
        para los bytes que no sean ni el primero ni el ultimo
        cuando existan.  TamanoIdentificador>2.
  UltimoByteIdentificador       : Si el tamano es mayor que uno,
        el ultimo Byte deberia pertenecer a UltimoByteIdentificador.
  FUNCTION VerificarIdentificadorBasicoInsertado        : devuelve
        TRUE si exito en la verificacion, FALSE en caso contrario.
}

FUNCTION    VerificarIdentificadorBasico
  ( OUT CadenaIdentificador     : ShortString;
    CONST
        PrimerByteIdentificador, MedioByteIdentificador,
        UltimoByteIdentificador         : CAFE_ConjuntoByte     ) : Boolean;
{
  FUNCTION VerificarIdentificadorBasicoInsertado
        Verifica que el CharByte total corresponde a un
        IdentificadorBasico.
        Caracteristicas del IdentificadorBasico:
        A. Primer Byte pertenece a PrimerByteIdentificador
        B. UltimoByte en Ocupado pertenece a UltimoByteIdentificador
        C. El resto de los Bytes pertenecen a MedioByteIdentificador.
        Si Ocupado = 1, solo aplica A, y
        si Ocupado = 2, solo aplican A y B.
        Ocupado > 255 es FALSE.
        En caso TRUE el identificador se devuelve en CadenaIdentificador.
  CadenaIdentificador           : devuelve el identificador extraido
        en el caso TRUE.  El caso FALSE genera ''.
  PrimerByteIdentificador       : Conjunto Byte de valores admisibles
        para el primer Byte del identificador.
  MedioByteIdentificador        : Conjunto Byte de valores admisibles
        para los bytes que no sean ni el primero ni el ultimo
        cuando existan.  TamanoIdentificador>2.
  UltimoByteIdentificador       : Si el tamano es mayor que uno,
        el ultimo Byte deberia pertenecer a UltimoByteIdentificador.
  FUNCTION VerificarIdentificadorBasicoInsertado        : devuelve
        TRUE si exito en la verificacion, FALSE en caso contrario.
}

FUNCTION    VerificarNumeroLongIntInsertado
  ( OUT NumeroExtraido          : LongInt;
        PosicionNumero          : LongInt; TamanoChar : Byte    ) : Boolean;
{
  FUNCTION VerificarNumeroLongIntInsertado
        Verificar que el dato en Self[ PosicionNumero ],
        y de tamano TamanoChar corresponda a un LongInt escrito
        corriente.  Se aplica un SYSTEN.VAL corriente.
        Nota: se ignoraran las posiciones previas y posteriores.
  NumeroExtraido                : En caso de verificacion exitoso
        devuelve el numero.  Indefinido si fracaso.
  PosicionNumero                : Se supone que el numero como
        Char inicia en Self[ PosicionNumero ] segun reglas de SYSTEN.VAL.
        Numeracion inicia en uno.
  TamanoChar                    : Tamano del STRING a 'extraer'
        antes de aplicar el System.VAL.
  FUNCTION VerificarNumeroLongIntInsertado      : TRUE si se identifica
        un LongInt en el lugar se¤alado. FALSE en caso contrario.
}

FUNCTION    VerificarNumeroLongInt
  ( OUT NumeroExtraido          : LongInt                       ) : Boolean;
{
  FUNCTION VerificarNumeroLongInt
        Revisa el CharByte asumiento que en su totalidad
        es convertible de cadena de caracteres a LongInt.
  NumeroExtraido                : En caso de verificacion exitoso
        devuelve el numero.  Indefinido si fracaso.
  FUNCTION VerificarNumeroLongIntInsertado      : TRUE si se identifica
        un LongInt. FALSE en caso contrario.
  NOTA: Ocupado > 255 se asume FALSE sin mayor analisis.
}

FUNCTION    VerificarNumeroRealInsertado
  ( OUT NumeroExtraido          : CAFE_Real;
        PosicionNumero          : LongInt; TamanoChar : Byte    ) : Boolean;
{
  FUNCTION VerificarNumeroRealInsertado
        Verificar que el dato en Self[ PosicionNumero ],
        y de tamano TamanoChar corresponda a un Real escrito
        corriente.  Se aplica un SYSTEN.VAL corriente.
        Nota: se ignoraran las posiciones previas y posteriores.
  NumeroExtraido                : En caso de verificacion exitoso
        devuelve el numero.  Indefinido si fracaso.
  PosicionNumero                : Se supone que el numero como
        Char inicia en Self[ PosicionNumero ] segun reglas de SYSTEN.VAL.
        Numeracion inicia en uno.
  TamanoChar                    : Tamano del STRING a 'extraer'
        antes de aplicar el System.VAL.
  FUNCTION VerificarNumeroLongIntInsertado      : TRUE si se identifica
        un Real en el lugar se¤alado. FALSE en caso contrario.
}

FUNCTION    VerificarNumeroReal
  ( OUT NumeroExtraido          : CAFE_Real                    ) : Boolean;
{
  FUNCTION VerificarNumeroReal
        Revisa el CharByte asumiento que en su totalidad
        es convertible como cadena de caracteres a Real.
  NumeroExtraido                : En caso de verificacion exitoso
        devuelve el numero.  Indefinido si fracaso.
  FUNCTION VerificarNumeroLongIntInsertado      : TRUE si se identifica
        un Real. FALSE en caso contrario.
  NOTA: Ocupado > 255 se asume FALSE sin mayor analisis.
}

FUNCTION    VerificarFormatoByteDuplicadoInsertado
  (     ByteDuplicado           : Byte;
        PosicionInsertado       : LongInt                       ) : LongInt;
{
  FUNCTION VerificarFormatoByteDuplicadoInsertado
        Verifica la existencia de un formato Byte duplicado
        a partir de Self[ PosicionInsertado ]
        El formato ByteDuplicado hace referencia al
        formato STRING en Pascal de comillas.
        EJEMPLO: Cadena := '''Hola'', dijo Jorge';
        Recuerde que las comillas internas estan duplicadas de alli
        el nombre de FUNCTION.
        Prueba positiva si (llamare 'comilla' al ByteDuplicado):
        A. Self[ PosicionInsertado ] = comilla
        B. Self[ PosicionInsertado-1 ] <> comilla
        C. O bien Self[ PosicionInsertado ] comienza un grupo par de comillas
                o existe otro grupo impar de comillas posterior a
                PosicionInsertado.
        Si exito FUNCTION devuelve la posicion final del cierre -->,
        que tiene que ser ByteDuplicado.
        Caso contrario FUNCTION es cero, que identifica el fracaso.
  ByteDuplicado                 : es el Byte a estudiar como duplicado
  PosicionInsertado             : se supone el inicio de comillas.
        Ver condiciones arriba.
  FUNCTION VerificarFormatoByteDuplicadoInsertado       : si exito
        en la verificacion devuelve la posicion del cierre de
        ByteDuplicado.  En caso de fracaso FUNCTION es cero.
}

FUNCTION    VerificarFormatoByteDuplicado
  (     ByteDuplicado           : Byte                          ) : Boolean;
{
  FUNCTION VerificarFormatoByteDuplicado
        Verifica la existencia de un formato Byte duplicado
        a partir de Self[ 1 ], y
        que finalice en Self[ Ocupado ]
        El formato ByteDuplicado hace referencia al
        formato STRING en Pascal de comillas.
        EJEMPLO: '''Hola'', dijo Jorge'#0
        Recuerde que las comillas internas estan duplicadas de alli
        el nombre de FUNCTION.
        Prueba positiva si (llamare 'comilla' al ByteDuplicado):
        A. Self[ 1 ] = Self[ Ocupado ] = comilla
        B. O bien la totalidad de FUNCTION es un grupo par de comillas
                o bien hay un grupo inicial y final impar de comillas.
                Y ningun otro grupo impar.
  ByteDuplicado                 : es el Byte a estudiar como duplicado
  FUNCTION VerificarFormatoByteDuplicado                : si exito
        devuelve TRUE y FALSE en caso contrario.
}

PROCEDURE   EliminarComentariosCharByte
  ( CONST
        CadenaIzquierda1, CadenaDerecha1  , CadenaIzquierda2,
        CadenaDerecha2  , CadenaIzquierda3, CadenaDerecha3      : ShortString;
        ByteBlanco      , ByteExtraccionDoble                   : Byte;
        BanderaByteExtraccionDoble                              : Boolean );
{
  PROCEDURE EliminarComentariosCharByte
        Revisa enteramente el CharByte para eliminar comentarios
        delimitados por tres tipos diferentes de delimitadores.
        Ademas protege optativamente las cadenas tipo
        ByteExtraccionDoble (ejemplo String entrecomillado).
        Se utiliza la regla de Turbo Pascal,
        que al iniciar un comentario se ignora todo
        lo que sigue, hasta el cierre.  Es decir, no hay anidamiento
        de comentarios, unicamente apertura y cierre.
        Por supuesto, el String dentro de comentario se borra.
        Pero el String libre si se protege Por ejemplo '(*HOLA*)'
        se conservaria integramente.
  CadenaIzquierda1              : Inicio de un comentario.  Utilice ''
        para ignorar esta busqueda.
  CadenaDerecha1                : Corresponde al cierre de CadenaIzquierda1.
  CadenaIzquierda2              : Inicio de un comentario.  Utilice ''
        para ignorar esta busqueda.
  CadenaDerecha2                : Corresponde al cierre de CadenaIzquierda2.
  CadenaIzquierda3              : Inicio de un comentario. Utilice ''
        para ignorar esta busqueda.
  CadenaDerecha3                : Corresponde al cierre de CadenaIzquierda3.
  ByteBlanco                    : Los comentarios se borran, rellenando con
        ByteBlanco.
  ByteExtraccionDoble           : Util si se desea proteger String o similar.
        Se asume sigue la regla de la comilla del String.
  BanderaByteExtraccionDoble    : Si TRUE se protege el String, si FALSE
        se ignora dicha proteccion. Nota:  el String dentro de comentario
        si se borra.  Lo que no se afectaria es cosas como '(*HOLA*)'.
}

PROCEDURE   ContraccionByteDuplicado
  (     ByteBusqueda            : Byte                                  );
{
  PROCEDURE ContraccionByteDuplicado
        Utilizado para eliminar la duplicacion de comillas (ByteBusqueda),
        que se sustituyen por una sola.  La idea es obtener el
        String 'verdadero' o lo que se requiera.
        Los grupos pares de comillas, se conserva la mitad.
        Grupos impares, se reducen a la mitad por pares.   El impar sobrante
        se conserva.  Comillas sueltas tambien se conservan.
  ByteBusqueda                  : Byte de la comilla o lo que se requiera.
}

PROCEDURE   ExpansionByteDuplicado
  (     ByteBusqueda            : Byte                                  );
{
  PROCEDURE ExpansionByteDuplicado
        Recorre el CharByte, y las comillas ( ByteBusqueda ) se duplican.
        CUIDADO: Error Grave si no existe espacio suficiente.
        Este proceso puede ser util para generar codigo, cuando
        se requiera.
  ByteBusqueda                  : Consiste en el Byte o comilla a
        duplicarle cada aparicion.
}

PROCEDURE   ExtraccionPrimerByteDuplicado
  (     VectorFuente            : CAFE_ClassCharByte;
    VAR PosicionExtraccion      : LongInt; Direccion            : Boolean );
{
  PROCEDURE ExtraccionPrimerByteDuplicado
        Se extra el dato en PosicionInsercion, que debe
        estar en formato ByteDuplicado a partir de PosicionInsercion,
        de lo contrario activa TRUE CAFE_IntentoInfructuosoSintactico.
        Se extra el dato en CharByte
        y aplica Self.ContraccionByteDuplicado al final.
        (VectorFuente no cambia).
        Por ejemplo:
        Esto es 'terrible insisto es ''terrible''', dije yo.#0
        12345678901234567890123456789012345678901234567890123
        PosicionExtraccion      := 9;
        ExtraccionPrimerByteDuplicado( VectorFuente, Posicion, TRUE );
        WriteLn( ExtraerString );
        OUTPUT -->
        terrible insisto es 'terrible'#0
  VectorFuente                  : Contiene el dato original.
  PosicionExtraccion            : Lugar limite de la extraccion segun
        la regla.  Self[ PosicionExtraccion ] deberia ser comilla o
        equivalente.  Se vuelve 0 si fracaso.  Ningun cambio si exito.
  Direccion                     : Si TRUE se extra la cadena en
        sentido -->, si FALSE en sentido inverso <--.
  NOTA: error sintactico como CAFE_IntentoInfructuosoSintactico.
}

PROCEDURE   InsertarTotalByteDuplicado
  (     PosicionInsercion       : LongInt;
        VectorFuente            : CAFE_ClassCharByte;
        ByteBusqueda            : Byte                                  );
{
  PROCEDURE InsertarTotalByteDuplicado
        Se inserta VectorFuente en PosicionInsercion de Self
        Sigue las reglas de ByteDuplicado para ByteBusqueda
        Por ejemplo:
        terrible insisto es 'terrible'#0
        12345678901234567890123456789012345678901234567890123
        En Vector Fuente
        Esto es , dije yo.#0
        12345678901234567890123456789012345678901234567890123
        En Self
        PosicionInsercion       := 9;
        InsercionTotalByteDuplicado( Posicion, VectorFuente, Ord( '''' ) );
        WriteLn( ExtraerString );
        OUTPUT -->
        Esto es 'terrible insisto es ''terrible''', dije yo.#0
        12345678901234567890123456789012345678901234567890123
  PosicionInsercion             : Indica la posicion para insertar
        VectorFuente en Self.
  VectorFuente                  : Es la cadena a insertar en el texto.
  ByteBusqueda                  : Es el byte duplicado a aplicar la regla.
  NOTA: El error probablemente produzca fin de ejecucion,
  aplica RAISE CAFE_Exception

}


DESTRUCTOR  Destroy; override;
{
  DESTRUCTOR Destroy;
        Se produce la destruccion del CharByte.
}

  Strict Private
FUNCTION    ReadTextoChar                        : ShortString;

  Strict Private
PROCEDURE   WriteTextoChar
  ( CONST
        MyTexto             : ShortString                               );

  Strict Private
FUNCTION    ReadItems
  (     Ide                     : LongInt                       ) : SizeInt;

  Strict Private
PROCEDURE   WriteItems
  (     Ide                     : LongInt;
        MyByte                  : SizeInt                               );

  Strict Private
FUNCTION    AuxiliarExtraccionFuenteSeparador
  ( VAR PosicionActual          : LongInt;
        ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar  : Byte;
        Direccion                               : Boolean       ) : Boolean;

  {$WARNINGS    OFF      }
  Protected
    ModeloInterior              : CAFE_ReferenciaCharByte       deprecated;
  {$WARNINGS    ON       }
{
  ModeloInterior                : Variable redundante a ClassType
        por dificultades en el proceso de duplicado.
        Tambien sirve para inducir caracteristicas por herencia especial.
        La idea :
        Nueva           := ModeloInterior.Create
        similar a
        Nueva           := NewInstance;
        o bien...
        Nueva           := ClassType.Create
}

  Public
  Property
    TextoChar                   : ShortString
                                  Read  ReadTextoChar
                                  Write WriteTextoChar;
{
  TextoChar                     : Sirve para lectura y escritura en el
        CharByte completo mediante asignacion simple.
}

  Public
  Property
    Items[ ide : LongInt ]      : SizeInt
                                  Read  ReadItems
                                  Write WriteItems; Default;
{
  Self[ ide ]                   : Permite accesar a los bytes internos
        del CharByte.  Sigue la regla de MemoriaChar[ ide ].
        En ese sentido puede considerarse
          Self[ ide ]  equivalente Byte( MemoriaChar[ ide ] )
        Ademas Self[ 0 ] devuelve Ocupado
}

                          END;  { CLASS CAFE_ClassCharByte }

    // Excepcion basica de la unidad
  CAFE_Exception        = CLASS ( Exception )
{
  Clase inicial de excepciones para el grupo de Ejes.EXE
}
                          END;  { CAFE_Exception }

    // Exception para mensajes al usuario
  CAFE_MensajeException         = CLASS ( CAFE_Exception )
{
  Clase generadora de CAFE_AdvertenciaUsuario
  Ante la gran variedad de posibles aplicaciones,
  simplemente activa una bandera y mensaje.
  Su objetivo, es mandar mensajes al usuario de advertencia
}

  Public
CONSTRUCTOR     Create
  ( CONST Msg           : String                                ); virtual;
{
  CONSTRUCTOR Create
        Genera la excepcion via algo asi
        IF Tal error.. THEN
            RAISE CAFE_MensajeException.Create( 'Intento inutil' );
        Deberia atrapar con un bloque TRY EXCEPT
        si quiere evitar fin de ejecucion.
        Activa CAFE_AdvertenciaUsuario
  Msg                   : Mensaje a pasar a CAFE_MensajeAdvertenciaUsuario
}

CONSTRUCTOR     Create
  ( CONST Msg           : String;
          Posicion      : LongInt                               ); virtual;
{
  CONSTRUCTOR Create
        Genera la excepcion via algo asi
        IF Tal error.. THEN
            RAISE CAFE_MensajeException.Create( 'Intento inutil', PosFinal );
        Deberia atrapar con un bloque TRY EXCEPT
        si quiere evitar fin de ejecucion.
        Activa CAFE_AdvertenciaUsuario
  Msg                   : Mensaje a pasar a CAFE_MensajeAdvertenciaUsuario
  Posicion              : Valor a pasar a CAFE_PosicionAdvertenciaUsuario
}

    CLASS
PROCEDURE     ClearMessage;
{
  PROCEDURE   ClearMessage
        Desactiva la bandera CAFE_AdvertenciaUsuario, el mensaje
        y su posicion
}

                                  END;  { CAFE_MensajeException }

  CAFE_MensajeInfructuoso       = CLASS ( CAFE_Exception )
{
  Clase generadora de CAFE_IntentoInfructuosoSintactico
  Ante la gran variedad de posibles aplicaciones,
  simplemente activa una bandera y mensaje.
  Su objetivo, es mandar mensajes al usuario de advertencia
}

  Public
CONSTRUCTOR     Create
  ( CONST Msg           : String                                ); virtual;
{
  CONSTRUCTOR Create
        Genera la excepcion via algo asi
        IF Tal error.. THEN
            RAISE CAFE_MensajeInfructuoso.Create( 'Intento inutil' );
        Deberia atrapar con un bloque TRY EXCEPT
        si quiere evitar fin de ejecucion.
        Activa CAFE_IntectoInfructuosoSintactico
  Msg                   : Mensaje a pasar a CAFE_MensajeInfructuosoSintactico
}

CONSTRUCTOR     Create
  ( CONST Msg           : String;
          Posicion      : LongInt                               ); virtual;
{
  CONSTRUCTOR Create
        Genera la excepcion via algo asi
        IF Tal error.. THEN
            RAISE CAFE_MensajeInfructuoso.Create( 'Intento inutil', PosFinal );
        Deberia atrapar con un bloque TRY EXCEPT
        si quiere evitar fin de ejecucion.
        Activa CAFE_IntectoInfructuosoSintactico
  Msg                   : Mensaje a pasar a CAFE_MensajeInfructuosoSintactico
  Posicion              : Valor a pasar a CAFE_PosicionInfructuosoSintactico
}

    CLASS
PROCEDURE     ClearMessage;
{
  PROCEDURE   ClearMessage
        Desactiva la bandera CAFE_IntentoInfructuosoSintactico, el mensaje
        y su posicion
}

                                  END;  { CAFE_MensajeInfructuoso }

  CAFE_MensajeVariado           = CLASS ( CAFE_Exception )
{
  Clase generadora de CAFE_IntentoInfructuosoVariado
  Ante la gran variedad de posibles aplicaciones,
  simplemente activa una bandera y mensaje.
  Su objetivo, es mandar mensajes al usuario de advertencia
}

  Public
CONSTRUCTOR     Create
  ( CONST Msg           : String                                ); virtual;
{
  CONSTRUCTOR Create
        Genera la excepcion via algo asi
        IF Tal error.. THEN
            RAISE CAFE_MensajeVarido.Create( 'Intento inutil' );
        Deberia atrapar con un bloque TRY EXCEPT
        si quiere evitar fin de ejecucion.
        Activa CAFE_IntectoInfructuosoVariado
  Msg                   : Mensaje a pasar a CAFE_MensajeInfructuosoVariado
}

CONSTRUCTOR     Create
  ( CONST Msg           : String;
          Posicion      : LongInt                               ); virtual;
{
  CONSTRUCTOR Create
        Genera la excepcion via algo asi
        IF Tal error.. THEN
            RAISE CAFE_MensajeVariado.Create( 'Intento inutil', PosFinal );
        Deberia atrapar con un bloque TRY EXCEPT
        si quiere evitar fin de ejecucion.
        Activa CAFE_IntectoInfructuosoVariado
  Msg                   : Mensaje a pasar a CAFE_MensajeInfructuosoVariado
  Posicion              : Valor a pasar a CAFE_PosicionInfructuosoVariado
}

    CLASS
PROCEDURE     ClearMessage;
{
  PROCEDURE   ClearMessage
        Desactiva la bandera CAFE_IntentoInfructuosoVariado, el mensaje
        y su posicion
}

                                  END;  { CAFE_MensajeVariado }

var
  CAFE_IntentoInfructuosoSintactico             : Boolean       = FALSE;
{
  CAFE_IntentoInfructuosoSintactico
                        : Para reportar errores sintacticos,
                          las unidadas iniciales son interpretes
                          sintacticos
}

  CAFE_MensajeInfructuosoSintactico             : ShortString   = '';
{
  CAFE_MensajeInfructuosoSintactico
                        : Para enviar un mensaje de fallo sintactico
                          como cadena de texto
}

  CAFE_PosicionInfructuosoSintactico            : LongInt       = 0;
{
  CAFE_PosicionInfructuosoSintactico
                        : Para indicar posicion del error, mediante
                          algun metodo i.e: no. renglon.
                          Se supone para fallos sintacticos
}

var
  CAFE_IntentoInfructuosoVariado                : Boolean       = FALSE;
{
  CAFE_IntentoInfructuosoVariado
                        : Para reportar errores variados como TRUE
}

  CAFE_MensajeInfructuosoVariado                : ShortString   = '';
{
  CAFE_MensajeInfructuosoVariado
                        : Para enviar mensajes de fallo variado
}

  CAFE_PosicionInfructuosoVariado               : LongInt       = 0;
{
  CAFE_PosicionInfructuosoVariado
                        : Para facilitar la ubicacion de la fuente
                          del error, interpretacion por contexto
}

var
  CAFE_AdvertenciaUsuario                       : Boolean       = FALSE;
{
  CAFE_AdvertenciaUsuario
                        : Para pasar advertencias al usuario, que
                          bien podria ser consejos
}

  CAFE_MensajeAdvertenciaUsuario                : ShortString   = '';
{
  CAFE_MensajeAdvertenciaUsuario
                        : Para pasar mensajes al usuario de advertencia,
                          consejo o similar.
}

  CAFE_PosicionAdvertenciaUsuario               : LongInt       = 0;
{
  CAFE_PosicionAdvertenciaUsuario
                        : Para ayudar al usuario a identificar
                          la advertencia, diferente significado por contexto.
}

implementation

TYPE
  PointerByte                   = ^Byte;

CONSTRUCTOR     CAFE_MensajeException.Create
  ( CONST Msg           : String                                        );
BEGIN  { CONSTRUCTOR CAFE_MensajeException.Create }
  Inherited;
  CAFE_AdvertenciaUsuario                       := TRUE;
  CAFE_MensajeAdvertenciaUsuario                := Msg;
  CAFE_PosicionAdvertenciaUsuario               := 0;
END;   { CONSTRUCTOR CAFE_MensajeException.Create }

CONSTRUCTOR     CAFE_MensajeException.Create
  ( CONST Msg           : String;
          Posicion      : LongInt                                       );
BEGIN  { CONSTRUCTOR CAFE_MensajeException.Create }
  Inherited Create( Msg );
  CAFE_AdvertenciaUsuario                       := TRUE;
  CAFE_MensajeAdvertenciaUsuario                := Msg;
  CAFE_PosicionAdvertenciaUsuario               := Posicion;
END;   { CONSTRUCTOR CAFE_MensajeException.Create }

  CLASS
PROCEDURE       CAFE_MensajeException.ClearMessage;
{ virtual }
BEGIN  { PROCEDURE CAFE_MensajeException.ClearMessage }
  CAFE_AdvertenciaUsuario                       := FALSE;
  CAFE_MensajeAdvertenciaUsuario                := '';
  CAFE_PosicionAdvertenciaUsuario               := 0;
END;   { PROCEDURE CAFE_MensajeException.ClearMessage }

CONSTRUCTOR     CAFE_MensajeInfructuoso.Create
  ( CONST Msg           : String                                        );
BEGIN  { CONSTRUCTOR CAFE_MensajeInfructuoso.Create }
  Inherited;
  CAFE_IntentoInfructuosoSintactico             := TRUE;
  CAFE_MensajeInfructuosoSintactico             := Msg;
  CAFE_PosicionInfructuosoSintactico            := 0;
END;   { CONSTRUCTOR CAFE_MensajeInfructuoso.Create }

CONSTRUCTOR     CAFE_MensajeInfructuoso.Create
  ( CONST Msg           : String;
          Posicion      : LongInt                                       );
BEGIN  { CONSTRUCTOR CAFE_MensajeInfructuoso.Create }
  Inherited Create( Msg );
  CAFE_IntentoInfructuosoSintactico             := TRUE;
  CAFE_MensajeInfructuosoSintactico             := Msg;
  CAFE_PosicionInfructuosoSintactico            := Posicion;
END;   { CONSTRUCTOR CAFE_MensajeInfructuoso.Create }

  CLASS
PROCEDURE       CAFE_MensajeInfructuoso.ClearMessage;
{ virtual }
BEGIN  { PROCEDURE CAFE_MensajeInfructuoso.ClearMessage }
  CAFE_IntentoInfructuosoSintactico             := FALSE;
  CAFE_MensajeInfructuosoSintactico             := '';
  CAFE_PosicionInfructuosoSintactico            := 0;
END;   { PROCEDURE CAFE_MensajeInfructuoso.ClearMessage }

CONSTRUCTOR     CAFE_MensajeVariado.Create
  ( CONST Msg           : String                                        );
BEGIN  { CONSTRUCTOR CAFE_MensajeVariado.Create }
  Inherited;
  CAFE_IntentoInfructuosoVariado                := TRUE;
  CAFE_MensajeInfructuosoVariado                := Msg;
  CAFE_PosicionInfructuosoVariado               := 0;
END;   { CONSTRUCTOR CAFE_MensajeVariado.Create }

CONSTRUCTOR     CAFE_MensajeVariado.Create
  ( CONST Msg           : String;
          Posicion      : LongInt                                       );
BEGIN  { CONSTRUCTOR CAFE_MensajeVariado.Create }
  Inherited Create( Msg );
  CAFE_IntentoInfructuosoVariado                := TRUE;
  CAFE_MensajeInfructuosoVariado                := Msg;
  CAFE_PosicionInfructuosoVariado               := Posicion;
END;   { CONSTRUCTOR CAFE_MensajeVariado.Create }

  CLASS
PROCEDURE       CAFE_MensajeVariado.ClearMessage;
{ virtual }
BEGIN  { PROCEDURE CAFE_MensajeVariado.ClearMessage }
  CAFE_IntentoInfructuosoVariado                := FALSE;
  CAFE_MensajeInfructuosoVariado                := '';
  CAFE_PosicionInfructuosoVariado               := 0;
END;   { PROCEDURE CAFE_MensajeVariado.ClearMessage }

  { IMPLEMENTATION }
PROCEDURE ImplementationInsercionRelocalizablePuntero
  ( VAR PunteroDestino        : PointerByte;
    VAR TamanoPunteroDestino  : LongInt; VAR OcupadoPunteroDestino : LongInt;
        PunteroFuente         : PointerByte;
        PosicionInsercion, TamanoTransferencia                  : LongInt );
VAR
  OcupadoFinal,
  TamanoTransferenciaActual,
  TamanoTransferenciaObjetivo,
  TamanoTransferenciaAcumulada  : LongInt;
  PunteroMem                    : Pointer;
  PunteroPivote,
  PosicionInicial,
  PosicionFinal                 : PointerByte;

LABEL
  SalidaError;

BEGIN  { PROCEDURE ImplementationInsercionRelocalizablePuntero }
  IF PunteroDestino = NIL THEN GOTO SalidaError;
  IF OcupadoPunteroDestino > TamanoPunteroDestino THEN GOTO SalidaError;
  IF ( TamanoPunteroDestino     < 0 ) OR
     ( OcupadoPunteroDestino    < 0 ) OR
     ( PosicionInsercion        < 0 ) OR
     ( TamanoTransferencia      < 0 ) THEN GOTO SalidaError;
  IF PosicionInsercion >  TamanoPunteroDestino  THEN GOTO SalidaError;
  IF PosicionInsercion <= OcupadoPunteroDestino THEN BEGIN
    OcupadoFinal                := OcupadoPunteroDestino+TamanoTransferencia;
  END ELSE BEGIN  { IF PosicionInsercion <= OcupadoPunteroDestino ELSE }
    OcupadoFinal                := PosicionInsercion+TamanoTransferencia;
  END;            { IF PosicionInsercion <= OcupadoPunteroDestino ELSE }
  IF TamanoTransferencia = 0 THEN Exit;
  IF OcupadoFinal > TamanoPunteroDestino THEN BEGIN
    GetMem( PunteroMem, OcupadoFinal );
    PosicionInicial             := PunteroMem;
    IF PosicionInsercion >= OcupadoPunteroDestino THEN BEGIN
      IF OcupadoPunteroDestino > 0 THEN
           Move( PunteroDestino^, PosicionInicial^, OcupadoPunteroDestino );
    END ELSE BEGIN  { IF PosicionInsercion >= OcupadoPunteroDestino ELSE }
      IF PosicionInsercion <> 0 THEN
           Move( PunteroDestino^, PosicionInicial^, PosicionInsercion );
      IF ( OcupadoPunteroDestino-PosicionInsercion ) > 0 THEN BEGIN
        PosicionFinal           := PosicionInicial;
        PosicionFinal           :=
                @PosicionInicial[ PosicionInsercion+TamanoTransferencia ];
        PunteroPivote           := @PunteroDestino[ PosicionInsercion ];
        Move( PunteroPivote^, PosicionFinal^,
                        OcupadoPunteroDestino-PosicionInsercion );
      END;  { IF ( OcupadoPunteroDestino-PosicionInsercion ) > 0 }
    END;            { IF PosicionInsercion >= OcupadoPunteroDestino ELSE }
    PunteroMem                  := PunteroDestino;
    FreeMem( PunteroMem, TamanoPunteroDestino );
    TamanoPunteroDestino        := OcupadoFinal;
    PunteroDestino              := PosicionInicial;
  END ELSE BEGIN  { IF OcupadoFinal > TamanoPunteroDestino ELSE }
    IF PosicionInsercion < OcupadoPunteroDestino THEN BEGIN
      TamanoTransferenciaObjetivo
                        := OcupadoPunteroDestino-PosicionInsercion;
      TamanoTransferenciaActual
                        := OcupadoFinal-OcupadoPunteroDestino;
      TamanoTransferenciaAcumulada                := 0;
      PosicionInicial           := @PunteroDestino[ OcupadoPunteroDestino ];
      PosicionFinal             := @PunteroDestino[ OcupadoFinal ];
      REPEAT
        IF TamanoTransferenciaActual >
                ( TamanoTransferenciaObjetivo-TamanoTransferenciaAcumulada )
        THEN TamanoTransferenciaActual          :=
                    TamanoTransferenciaObjetivo-TamanoTransferenciaAcumulada;
        PosicionInicial         := PosicionInicial-TamanoTransferenciaActual;
        PosicionFinal           := PosicionFinal-TamanoTransferenciaActual;
        Move( PosicionInicial^, PosicionFinal^, TamanoTransferenciaActual );
        Inc( TamanoTransferenciaAcumulada, TamanoTransferenciaActual );
      UNTIL TamanoTransferenciaAcumulada = TamanoTransferenciaObjetivo;
    END;  { IF PosicionInsercion < OcupadoPunteroDestino }
  END;            { IF OcupadoFinal > TamanoPunteroDestino ELSE }
  PunteroPivote                 := @PunteroDestino[ PosicionInsercion ];
  IF PunteroFuente <> NIL THEN
      Move( PunteroFuente^, PunteroPivote^, TamanoTransferencia )
                          ELSE
      FillChar( PunteroPivote^, TamanoTransferencia, 0 );
  OcupadoPunteroDestino         := OcupadoFinal;
  Exit;
SalidaError :
  RAISE CAFE_Exception.Create( 'Acceso no permitido en PROCEDURE '+
        'ImplementationInsercionRelocalizablePuntero' );
END;   { PROCEDURE ImplementationInsercionRelocalizablePuntero }
  { IMPLEMENTATION }

  { IMPLEMENTATION }
PROCEDURE ImplementationDeshacerInsercionRelocalizablePuntero
  ( VAR PunteroDestino        : PointerByte;
    VAR TamanoPunteroDestino  : LongInt; VAR OcupadoPunteroDestino : LongInt;
        PosicionInsercion, TamanoTransferencia                     : LongInt;
        BanderaAjustarOcupado                                   : Boolean );
VAR
  PosicionInicial,
  NuevoOcupado,
  TamanoTransferenciaObjetivo,
  TamanoTransferenciaActual,
  TamanoTransferenciaAcumulada  : LongInt;
  PunteroMem                    : Pointer;
  PunteroInicial,
  PunteroFinal,
  NuevoPuntero                  : PointerByte;

LABEL
  SalidaError;

BEGIN  { PROCEDURE ImplementationDeshacerInsercionRelocalizablePuntero }
  IF PunteroDestino = NIL THEN GOTO SalidaError;
  IF ( TamanoPunteroDestino  < 0 ) OR
     ( OcupadoPunteroDestino < 0 ) OR
     ( PosicionInsercion     < 0 ) OR
     ( TamanoTransferencia   < 0 ) THEN GOTO SalidaError;
  PosicionInicial               := PosicionInsercion+TamanoTransferencia;
  IF PosicionInicial > OcupadoPunteroDestino THEN GOTO SalidaError;
  IF BanderaAjustarOcupado THEN BEGIN
    NuevoOcupado                := OcupadoPunteroDestino-TamanoTransferencia;
    IF NuevoOcupado = TamanoPunteroDestino THEN Exit;
    IF NuevoOcupado <> 0 THEN BEGIN
      GetMem( PunteroMem, NuevoOcupado );
      NuevoPuntero              := PunteroMem;
      IF PosicionInsercion <> 0 THEN BEGIN
        Move( PunteroDestino^, NuevoPuntero^, PosicionInsercion );
      END;  { IF PosicionInsercion <> 0 }
      IF PosicionInicial < OcupadoPunteroDestino THEN BEGIN
        PunteroInicial          := @PunteroDestino[ PosicionInicial ];
        PunteroFinal            := @NuevoPuntero[ PosicionInsercion ];
        Move( PunteroInicial^, PunteroFinal^,
                        OcupadoPunteroDestino-PosicionInicial );
      END;  { IF PosicionInicial < OcupadoPunteroDestino }
    END ELSE BEGIN  { IF NuevoOcupado <> 0 ELSE }
      NuevoPuntero              := NIL;
    END;            { IF NuevoOcupado <> 0 ELSE }
    OcupadoPunteroDestino       := NuevoOcupado;
    PunteroMem                  := PunteroDestino;
    FreeMem( PunteroMem, TamanoPunteroDestino );
    PunteroDestino              := NuevoPuntero;
    TamanoPunteroDestino        := OcupadoPunteroDestino;
  END ELSE BEGIN  { IF BanderaAjustarOcupado ELSE }
    IF PosicionInicial = OcupadoPunteroDestino THEN BEGIN
      OcupadoPunteroDestino     := PosicionInsercion;
    END ELSE BEGIN  { IF PosicionInicial = OcupadoPunteroDestino ELSE }
      TamanoTransferenciaObjetivo               :=
                        OcupadoPunteroDestino-PosicionInicial;
      IF TamanoTransferencia = 0 THEN Exit;
      TamanoTransferenciaActual                 := TamanoTransferencia;
      TamanoTransferenciaAcumulada              := 0;
      PunteroInicial            := @PunteroDestino[ PosicionInicial ];
      PunteroFinal              := @PunteroDestino[ PosicionInsercion ];
      REPEAT
        IF TamanoTransferenciaActual >
                ( TamanoTransferenciaObjetivo-TamanoTransferenciaAcumulada )
        THEN TamanoTransferenciaActual  :=
                  TamanoTransferenciaObjetivo-TamanoTransferenciaAcumulada;
        Move( PunteroInicial^, PunteroFinal^, TamanoTransferenciaActual );
        PunteroInicial          := PunteroInicial+TamanoTransferenciaActual;
        PunteroFinal            := PunteroFinal+TamanoTransferenciaActual;
        Inc( TamanoTransferenciaAcumulada, TamanoTransferenciaActual );
      UNTIL TamanoTransferenciaAcumulada = TamanoTransferenciaObjetivo;
      Dec( OcupadoPunteroDestino, TamanoTransferencia );
    END;            { IF PosicionInicial = OcupadoPunteroDestino ELSE }
  END;            { IF BanderaAjustarOcupado ELSE }
  Exit;
SalidaError :
  RAISE CAFE_Exception.Create( 'Acceso no permitido en PROCEDURE '+
        'ImplementationDeshacerInsercionRelocalizablePuntero' );
END;  { PROCEDURE ImplementationDeshacerInsercionRelocalizablePuntero }
  { IMPLEMENTATION }

  {$WARNINGS    OFF             }
CONSTRUCTOR CAFE_ClassCharByte.Create
  (     Tamano          : LongInt                               );
VAR
  PunteroPivote         : Pointer;

BEGIN  { CONSTRUCTOR CAFE_ClassCharByte.Create }
  TamanoVector          := Tamano;
  GetMem( PunteroPivote, Tamano+CAFE_BytesExcesoCharByte );
  MemoriaChar           := PunteroPivote;
  Ocupado               := 0;
  MemoriaVector         := @MemoriaChar[ 1 ];
  FillChar( PunteroPivote^, Tamano+CAFE_BytesExcesoCharByte, 0 );
  ModeloInterior        := CAFE_ClassCharByte;
END;   { CONSTRUCTOR CAFE_ClassCharByte.Create }
  {$WARNINGS    ON              }

  {$WARNINGS    OFF             }
CONSTRUCTOR CAFE_ClassCharByte.Create
  ( CONST
        Msg             : ShortString;
        Tamano          : LongInt                               );
VAR
  PunteroPivote         : Pointer;

BEGIN  { CONSTRUCTOR CAFE_ClassCharByte.Create }
  TamanoVector          := Tamano;
  GetMem( PunteroPivote, Tamano+CAFE_BytesExcesoCharByte );
  MemoriaChar           := PunteroPivote;
  Ocupado               := 0;
  MemoriaVector         := @MemoriaChar[ 1 ];
  FillChar( PunteroPivote^, Tamano+CAFE_BytesExcesoCharByte, 0 );
  InsertarString( Msg, 1 );
  ModeloInterior        := CAFE_ClassCharByte;
END;   { CONSTRUCTOR CAFE_ClassCharByte.Create }
  {$WARNINGS    ON              }

  {$WARNINGS    OFF             }
CONSTRUCTOR CAFE_ClassCharByte.Create
  (     Modelo          : CAFE_ClassCharByte                    );
VAR
  PunteroPivote         : Pointer;

BEGIN  { CONSTRUCTOR CAFE_ClassCharByte.Create }
  TamanoVector          := Modelo.TamanoVector;
  GetMem( PunteroPivote, TamanoVector+CAFE_BytesExcesoCharByte );
  MemoriaChar           := PunteroPivote;
  Ocupado               := 0;
  MemoriaVector         := @MemoriaChar[ 1 ];
  FillChar( PunteroPivote^, TamanoVector+CAFE_BytesExcesoCharByte, 0 );
  TransferenciaCharByte( Modelo );
  ModeloInterior        := CAFE_ClassCharByte;
END;   { CONSTRUCTOR CAFE_ClassCharByte.Create }
  {$WARNINGS    ON              }

  { DOBLE CODIGO }
  {$IFDEF CPUI386_CPU32}
FUNCTION    CAFE_ClassCharByte.BuscarSiguienteByte
  ( VAR PosicionActual          : LongInt; ByteBusqueda         : Byte;
        Direccion, IdenticoDiferente            : Boolean     ) : Boolean;
                                pascal; assembler;
CONST
  Parametros                    = 4*CPUBase;

LABEL
  SalidaFalsa,
        { Asigna FALSE a FUNCTION sin modificar PosicionActual          }
  ActualPositivo,
        { Elude Fuerza PosicionActual := 0 inicial si negativo          }
  ActualRango,
        { Elude Fuerza PosicionActual := Ocupado+1 si muy grande        }
  SentidoInverso,
        { Para establecer sentido de busqueda y fijar %ecx              }
  BusquedaComun,
        { Para establecer busqueda comun independiente de direccion     }
  ColocarECX,
        { Utiliza ECX para determinar output de PosicionActual          }
  RepiteDiferente,
        { Rutina de busqueda para REPNE SCASB es decir diferente        }
  InversaECX,
        { Calculo de PosicionActual( ECX ) en busqueda inversa          }
  UnicaSalida,
        { Para tener una salida comun a TRUE y FALSE por orden          }
  SalidaFinal;
        { Asigna output a FUNCTION y PosicionActual                     }

ASM   { FUNCTION CAFE_ClassCharByte.BuscarSiguienteByte }
                                        { Funcion Principal             }
                                        { %edx  = PosicionActual        }
                                        { %esi  = Ocupado               }
                                        { %edi  = puntero de SCASB      }
  movl  PosicionActual, %edx            { Inicializa                    }
  movl  (%edx), %edx                    {   %edx = PosicionActual       }
  movl  __Self, %esi                    { Inicializa                    }
  addl  Ocupado, %esi                   {   %esi = Ocupado              }
  movl  (%esi), %esi                    {          (__Self+Ocupado)     }
  cmpl  $0, %esi                        { Atrapa casos especiales       }
  je    SalidaFalsa                     {   Ocupado = 0 -> SalidaFalsa  }
  cmpl  $0, %edx                        { El codigo admite              }
  jns   ActualPositivo                  {   PosicionActual < 0          }
  movl  $0, %edx                        {   y lo interpreta como 0      }
ActualPositivo:
  cmpl  %edx, %esi                      { El codigo admite              }
  jns   ActualRango                     {   PosicionActual >> Ocupado   }
  movl  %esi, %edx                      {   asigna simplemente          }
  inc   %edx                            {   PosicionActual := Ocupado+1 }
ActualRango:
  movl  __Self, %ebx                    { Algo extra¤o                  }
  addl  MemoriaVector, %ebx             {   %edi := MemoriaVector+      }
  movl  (%ebx), %edi                    {              PosicionActual   }
  addl  %edx, %edi                      {   Esto es es Byte siguiente   }
                                        {   pues mi numeracion inicia 1 }
  movb  Direccion, %al                  { Establece el sentido          }
  cmp   False, %al                      {   de busqueda                 }
  je    SentidoInverso                  {   para fijar %ecx             }
  cld                                   { Flag Busqueda -->             }
  movl  %esi, %ecx                      { ECX   := Ocupado              }
  subl  %edx, %ecx                      {            -PosicionActual    }
  js    SalidaFalsa                     { Si PosicionActual > Ocupado   }
  jmp   BusquedaComun                   { Codigo Independiente de Flag  }
SentidoInverso:
  subl  $2, %edi                        { Edi -= 2 pues se pide atras   }
  std                                   { Flag Busqueda <--             }
  movl  %edx, %ecx                      { ECX   := PosicionActual-1     }
  dec   %ecx                            {   note la posicion anterior   }
BusquedaComun:
  cmp   $0, %ecx                        { Evita el caso ECX 0           }
  je    SalidaFalsa                     {   en REPE y REPNE             }
  movb  ByteBusqueda, %al               { REPE necesita byte en %al     }
  movb  IdenticoDiferente, %bl          { Bandera para tipo busqueda    }
  cmpb  True, %bl                       {   TRUE busca byte identico    }
  jne   RepiteDiferente                 {   FALSE busca byte diferente  }
  REPNE SCASB                           { Busqueda directa              }
  jne   SalidaFalsa                     {   salto si no encontro        }
  jmp   ColocarECX                      {   y salta a calculo           }
RepiteDiferente:
  REPE  SCASB                           { Busqueda inversa              }
  je    SalidaFalsa                     {   salto si fallo              }
ColocarECX:
  movb  Direccion, %bl                  { Determina sentido segun       }
  cmpb  True, %bl                       {   parametro Direccion         }
  jne   InversaECX                      {   para calculo PosicionActual }
  movl  %esi, %edx                      { Caso TRUE                     }
  subl  %ecx, %edx                      {   PosicionActual :=           }
                                        {       Ocupado-ECX             }
                                        {   REPE decrementa ecx primero }
  jmp   SalidaFinal                     { Salto a calculo final         }
InversaECX:
  movl  %ecx, %edx                      { Caso sentido FALSE            }
  inc   %edx                            {   REPE decrementa ecx primero }
  jmp   SalidaFinal                     {   PosicionActual := ECX+1     }
SalidaFalsa:
  movl  PosicionActual, %ebx            { Asigna output PosicionActual  }
  movl  $0, (%ebx)                      { PosicionActual := 0           }
  movb  False, __Result                 { Evitar interferencias         }
  movl  False, %eax                     { por error al ejecutar         }
                                        { fpc 2.4.2. 2 Marzo 2011       }
  jmp   UnicaSalida                     { Para tener unica salida       }
SalidaFinal:
  movl  PosicionActual, %ebx            { Asigna output PosicionActual  }
  movl  %edx, (%ebx)                    {   PosicionActual := EDX       }
  movb  True, __Result                  { Para salida Final TRUE        }
  movl  True, %eax                      { para evitar errores           }
UnicaSalida:
  leave                                 { Salida comun de Proc          }
  ret   $Parametros                     { Salida comun de Proc          }
END;  { FUNCTION CAFE_ClassCharByte.BuscarSiguienteByte }
  {$ELSE}
FUNCTION    CAFE_ClassCharByte.BuscarSiguienteByte
  ( VAR PosicionActual          : LongInt; ByteBusqueda         : Byte;
        Direccion, IdenticoDiferente            : Boolean     ) : Boolean;
VAR
  DiferenteIdentico             : Boolean;

LABEL
  SalidaFalsa;

BEGIN  { FUNCTION CAFE_ClassCharByte.BuscarSiguienteByte }
  IF Ocupado        =        0 THEN GOTO SalidaFalsa;
  IF PosicionActual <        0 THEN PosicionActual      := 0;
  IF PosicionActual >  Ocupado THEN PosicionActual      := Ocupado+1;
  DiferenteIdentico             := NOT( IdenticoDiferente );
  REPEAT
    IF Direccion THEN BEGIN
      Inc( PosicionActual );
      IF PosicionActual >  Ocupado THEN GOTO SalidaFalsa;
    END ELSE BEGIN  { IF Direccion ELSE }
      Dec( PosicionActual );
      If PosicionActual <        1 THEN GOTO SalidaFalsa;
    END;            { IF Direccion ELSE }
  UNTIL DiferenteIdentico XOR
      ( MemoriaChar[ PosicionActual ] = Chr( ByteBusqueda ) );
  BuscarSiguienteByte           := TRUE;
  Exit;
SalidaFalsa :
  PosicionActual                := 0;
  BuscarSiguienteByte           := FALSE;
END;   { FUNCTION CAFE_ClassCharByte.BuscarSiguienteByte }
  {$ENDIF}
  { DOBLE CODIGO }

PROCEDURE   CAFE_ClassCharByte.InsertarDatosCharByte
  (     PDatos                  : PChar;
        PosicionInsercion, TamanoInsercion              : LongInt       );
VAR
  TamanoPunteroDestino,
  OcupadoPunteroDestino,
  PosicionInsercionNueva,
  TamanoTransferencia           : LongInt;

LABEL
  SalidaError;

BEGIN  { PROCEDURE CAFE_ClassCharByte.InsertarDatosCharByte }
  IF ( PosicionInsercion < 1 ) OR ( PosicionInsercion > ( Ocupado+1 ) )
                                                THEN GOTO SalidaError;
  IF TamanoInsercion = 0 THEN Exit;
  IF ( TamanoInsercion < 0 ) OR
     ( TamanoVector < ( Ocupado+TamanoInsercion ) ) THEN GOTO SalidaError;
  TamanoPunteroDestino          := TamanoVector;
  OcupadoPunteroDestino         := Ocupado;
  PosicionInsercionNueva        := ( PosicionInsercion-1 );
  TamanoTransferencia           := TamanoInsercion;
  ImplementationInsercionRelocalizablePuntero
        ( Pointer( MemoriaVector ),
          TamanoPunteroDestino, OcupadoPunteroDestino,
          Pointer( PDatos ), PosicionInsercionNueva, TamanoTransferencia );
  Ocupado                       := OcupadoPunteroDestino;
  Self[ Ocupado+1 ]             := 0;
  Exit;
SalidaError :
  RAISE CAFE_Exception.Create( 'Inserci¢n de datos CharByte fall¢.' );
END;   { PROCEDURE CAFE_ClassCharByte.InsertarDatosCharByte }

PROCEDURE   CAFE_ClassCharByte.EliminarDatosCharByte
  (     PosicionDato, TotalDatos                : LongInt               );
VAR
  TamanoPunteroDestino,
  OcupadoPunteroDestino,
  PosicionInsercion,
  TamanoTransferencia           : LongInt;

BEGIN  { PROCEDURE CAFE_ClassCharByte.EliminarDatosCharByte }
  TamanoPunteroDestino          := TamanoVector;
  OcupadoPunteroDestino         := Ocupado;
  PosicionInsercion             := ( PosicionDato-1 );
  TamanoTransferencia           := TotalDatos;
  ImplementationDeshacerInsercionRelocalizablePuntero
        ( Pointer( MemoriaVector ), TamanoPunteroDestino,
      OcupadoPunteroDestino, PosicionInsercion, TamanoTransferencia, FALSE );
  Ocupado                       := OcupadoPunteroDestino;
  Self[ Ocupado+1 ]             := 0;
END;   { PROCEDURE CAFE_ClassCharByte.EliminarDatosCharByte }

FUNCTION    CAFE_ClassCharByte.ExtraerString
  (     PosicionInicial         : LongInt;
        LargoString             : Byte                  ) : ShortString;
VAR
  CadenaPivote                  : ShortString;

LABEL
  SalidaRapida;

BEGIN  { FUNCTION CAFE_ClassCharByte.ExtraerString }
  CadenaPivote                  := '';
  IF Ocupado       =   0 THEN GOTO SalidaRapida;
  IF LargoString   =   0 THEN GOTO SalidaRapida;
  IF ( PosicionInicial < 1 ) OR ( PosicionInicial > Ocupado )
  THEN RAISE CAFE_Exception.Create( 'PosicionInicial'+
        ' fuera de rango en CAFE_ClassCharByte.ExtraerString...' );
  IF LargoString > ( Ocupado-PosicionInicial+1 ) THEN
        LargoString     := Ocupado-PosicionInicial+1;
  CadenaPivote[ 0 ]     := Chr( LargoString );
  Move( MemoriaChar[ PosicionInicial ], CadenaPivote[ 1 ], LargoString );
SalidaRapida :
  ExtraerString         := CadenaPivote;
END;   { FUNCTION CAFE_ClassCharByte.ExtraerString }

FUNCTION    CAFE_ClassCharByte.ExtraerString              : ShortString;
BEGIN  { FUNCTION CAFE_ClassCharByte.ExtraerString }
  ExtraerString         := ExtraerString( 1, Ocupado );
END;   { FUNCTION CAFE_ClassCharByte.ExtraerString }

PROCEDURE   CAFE_ClassCharByte.InsertarString
  ( CONST
        CadenaInsercion         : ShortString;
        PosicionInsercion       : LongInt                               );
BEGIN  { PROCEDURE CAFE_ClassCharByte.InsertarString }
  InsertarDatosCharByte
    ( @CadenaInsercion[ 1 ], PosicionInsercion, Ord( CadenaInsercion[ 0 ] ) );
  Self[ Ocupado+1 ]             := 0;
END;   { PROCEDURE CAFE_ClassCharByte.InsertarString }

PROCEDURE   CAFE_ClassCharByte.InsertarString
  ( CONST
        CadenaInsercion         : ShortString                           );
BEGIN  { PROCEDURE CAFE_ClassCharByte.InsertarString }
  Ocupado                       := 0;
  InsertarString( CadenaInsercion, 1 );
  Self[ Ocupado+1 ]             := 0;
END;   { PROCEDURE CAFE_ClassCharByte.InsertarString }

PROCEDURE   CAFE_ClassCharByte.InsertarExtraccionCharByte
  (     PosicionInsercion       : LongInt;
        VectorFuente            : CAFE_ClassCharByte;
        PosicionExtraccion, TamanoTransferencia                 : LongInt );
VAR
  PunteroFuente                 : Pointer;

BEGIN  { CAFE_ClassCharByte.InsertarExtraccionCharByte }
  IF TamanoTransferencia = 0 THEN BEGIN
    Self[ Ocupado+1 ]           := 0;
    Exit;
  END;  { IF TamanoTransferencia = 0 }
  IF ( PosicionExtraccion <  1 ) OR
     ( PosicionExtraccion >  ( VectorFuente.Ocupado+1-TamanoTransferencia ) )
  THEN RAISE CAFE_Exception.Create
        ( 'Acceso fuera de rango en metodo InsertarExtraccionCharByte' );
  PunteroFuente                 :=
                @VectorFuente.MemoriaChar[ PosicionExtraccion ];
  InsertarDatosCharByte
                ( PunteroFuente, PosicionInsercion, TamanoTransferencia );
  Self[ Ocupado+1 ]             := 0;
END;   { CAFE_ClassCharByte.InsertarExtraccionCharByte }

PROCEDURE   CAFE_ClassCharByte.ExtraccionCharByte
  (     VectorFuente            : CAFE_ClassCharByte;
        PosicionExtraccion, TamanoTransferencia                 : LongInt );
BEGIN  { PROCEDURE CAFE_ClassCharByte.ExtraccionCharByte }
  Ocupado               := 0;
  InsertarExtraccionCharByte
                ( 1, VectorFuente, PosicionExtraccion, TamanoTransferencia );
END;   { PROCEDURE CAFE_ClassCharByte.ExtraccionCharByte }

PROCEDURE   CAFE_ClassCharByte.TransferenciaCharByte
  (     VectorFuente            : CAFE_ClassCharByte                    );
BEGIN  { PROCEDURE CAFE_ClassCharByte.TransferenciaCharByte }
  Ocupado               := 0;
  InsertarExtraccionCharByte( 1, VectorFuente, 1, VectorFuente.Ocupado );
END;   { PROCEDURE CAFE_ClassCharByte.TransferenciaCharByte }

PROCEDURE   CAFE_ClassCharByte.UpDownCaseCharByte
  (     UpDown                  : Boolean                               );
VAR
  PosicionActual                : LongInt;

BEGIN  { PROCEDURE CAFE_ClassCharByte.UpDownCaseCharByte }
  Self[ Ocupado+1 ]             := 0;
  IF UpDown THEN StrUpper( MemoriaVector )
            ELSE StrLower( MemoriaVector );
  PosicionActual                := 0;
  WHILE BuscarSiguienteByte( PosicionActual, 0, TRUE, TRUE ) DO BEGIN
    IF UpDown THEN StrUpper( @MemoriaChar[ PosicionActual ] )
              ELSE StrLower( @MemoriaChar[ PosicionActual ] );
  END;  { WHILE BuscarSiguietenByte( ... ) }
END;   { PROCEDURE CAFE_ClassCharByte.UpDownCaseCharByte }

PROCEDURE   CAFE_ClassCharByte.ConcatenarCharByte
  (     VectorFuente            : CAFE_ClassCharByte                    );
BEGIN  { PROCEDURE CAFE_ClassCharByte.ConcatenarCharByte }
  InsertarExtraccionCharByte
                ( Ocupado+1, VectorFuente, 1, VectorFuente.Ocupado );
END;   { PROCEDURE CAFE_ClassCharByte.ConcatenarCharByte }

PROCEDURE   CAFE_ClassCharByte.SustitucionConjuntoByte
  ( CONST
        ConjuntoSeleccion       : CAFE_ConjuntoByte;
        NuevoByte               : Byte;
        BanderaSimultaneo       : Boolean       = TRUE                  );
VAR
  PosicionActual,
  RecorreFuente                 : LongInt;
  RecorreByte                   : Byte;

BEGIN  { PROCEDURE CAFE_ClassCharByte.SustitucionConjuntoByte }
  IF BanderaSimultaneo THEN BEGIN
    FOR RecorreFuente := 1 TO Ocupado DO BEGIN
      IF Byte( MemoriaChar[ RecorreFuente ] ) IN ConjuntoSeleccion
      THEN MemoriaChar[ RecorreFuente ]           := Chr( NuevoByte );
    END;  { FOR RecorreFuente }
  END ELSE BEGIN  { IF BanderaSimultaneo ELSE }
    FOR RecorreByte := Low( Byte ) TO High( Byte ) DO BEGIN
      IF RecorreByte IN ConjuntoSeleccion THEN BEGIN
        PosicionActual          := 0;
        WHILE BuscarSiguienteByte( PosicionActual, RecorreByte, TRUE, TRUE )
        DO BEGIN
          Self[ PosicionActual ]        := NuevoByte;
        END;  { WHILE BuscarSiguienteByte... }
      END;  { IF RecorreByte IN ConjuntoSeleccion }
    END;  { FOR RecorreByte }
  END;            { IF BanderaSimultaneo ELSE }
END;   { PROCEDURE CAFE_ClassCharByte.SustitucionConjuntoByte }

PROCEDURE   CAFE_ClassCharByte.EscribirByteRepetidoCharByte
  (     ByteEscrito             : Byte;
        PosicionEscritura, TamanoTransferencia          : LongInt;
        ModoInsercion           : Boolean                               );
VAR
  PunteroPivote                 : Pointer;

LABEL
  SalidaError;

BEGIN  { PROCEDURE CAFE_ClassCharByte.EscribirByteRepetidoCharByte }
  IF TamanoTransferencia = 0 THEN Exit;
  IF TamanoTransferencia < 0 THEN GOTO SalidaError;
  IF ( PosicionEscritura < 1 ) OR
     ( ( PosicionEscritura+TamanoTransferencia-1 ) > TamanoVector )
  THEN GOTO SalidaError;
  IF ModoInsercion THEN BEGIN
    GetMem( PunteroPivote, TamanoTransferencia );
    FillChar( PunteroPivote^, TamanoTransferencia, ByteEscrito );
    InsertarDatosCharByte
                ( PunteroPivote, PosicionEscritura, TamanoTransferencia );
    FreeMem( PunteroPivote, TamanoTransferencia );
  END ELSE BEGIN  { IF ModoInsercion }
    PunteroPivote               := @MemoriaChar[ PosicionEscritura ];
    FillChar( PunteroPivote^, TamanoTransferencia, ByteEscrito );
    IF Ocupado < ( PosicionEscritura+TamanoTransferencia-1 ) THEN
        Ocupado                 := PosicionEscritura+TamanoTransferencia-1;
  END;            { IF ModoInsercion }
  Self[ Ocupado+1 ]             := 0;
  Exit;
SalidaError :
  RAISE CAFE_Exception.Create( 'Acceso inv lido en '+
                'EscribirByteRepetidoCharByte' );
END;   { PROCEDURE CAFE_ClassCharByte.EscribirByteRepetidoCharByte }

FUNCTION    CAFE_ClassCharByte.BuscarSiguienteSecuencia
  ( VAR PosicionActual          : LongInt;
        VectorFuente            : CAFE_ClassCharByte;
        Direccion               : Boolean                       ) : Boolean;
VAR
  PunteroWord                   : ^Word;
  BanderaDuplo,
  BanderaRepite                 : Boolean;
  PivoteWord                    : Word;
  LimiteSuperior                : LongInt;

LABEL
  SalidaError,
  SalidaFalsa;

BEGIN  { FUNCTION CAFE_ClassCharByte.BuscarSiguienteSecuencia }
  LimiteSuperior                := Ocupado-VectorFuente.Ocupado+1;
  IF LimiteSuperior <= 0 THEN GOTO SalidaFalsa;
  IF Ocupado        =  0 THEN GOTO SalidaFalsa;
  IF PosicionActual < 0 THEN PosicionActual     := 0;
  IF PosicionActual > LimiteSuperior THEN PosicionActual := LimiteSuperior+1;
  IF VectorFuente.Ocupado = 0 THEN GOTO SalidaError;
  IF VectorFuente.Ocupado = 1 THEN BEGIN
    BuscarSiguienteSecuencia    := BuscarSiguienteByte
    ( PosicionActual, Byte( VectorFuente.MemoriaVector^ ), Direccion, TRUE );
    Exit;
  END;  { IF VectorFuente.Ocupado = 1 }
  {$IFDEF CPUI386_CPU32}
  { CUIDADO!!! el cambio descuidado de los directivos de compilador     }
  { podria generar una llamada ciclica                                  }
  IF VectorFuente.Ocupado <= 255 THEN BEGIN
    BuscarSiguienteSecuencia    :=
        BuscarSiguienteCadena
        ( PosicionActual, VectorFuente.ExtraerString, Direccion );
    Exit;
  END;  { IF VectorFuente.Ocupado <= 255 }
  {$ENDIF}
  IF VectorFuente.Ocupado = 2 THEN BanderaDuplo         := TRUE
                              ELSE BanderaDuplo         := FALSE;
  BanderaRepite                 := FALSE;
  PunteroWord                   := Pointer( VectorFuente.MemoriaVector );
  PivoteWord                    := PunteroWord^;
  REPEAT
    IF Direccion THEN BEGIN
      Inc( PosicionActual );
      IF PosicionActual >  LimiteSuperior THEN GOTO SalidaFalsa;
    END ELSE BEGIN  { IF Direccion ELSE }
      Dec( PosicionActual );
      IF PosicionActual <               1 THEN GOTO SalidaFalsa;
    END;            { IF Direccion ELSE }
    PunteroWord                 := Pointer( @MemoriaChar[ PosicionActual ] );
    IF PunteroWord^ = PivoteWord THEN BEGIN
      IF BanderaDuplo THEN BanderaRepite        := TRUE
                      ELSE BanderaRepite        :=
                                ( CompareByte( PunteroWord^,
                                        VectorFuente.MemoriaVector^,
                                        VectorFuente.Ocupado ) = 0 );
    END;  { IF PunteroWord^ = PivoteWord }
  UNTIL BanderaRepite;
  BuscarSiguienteSecuencia      := TRUE;
  Exit;
SalidaError :
  RAISE CAFE_Exception.Create( 'Parametros inadecuados en '+
                'BuscarSiguienteSecuencia' );
SalidaFalsa :
  PosicionActual                := 0;
  BuscarSiguienteSecuencia      := FALSE;
END;   { FUNCTION CAFE_ClassCharByte.BuscarSiguienteSecuencia }

FUNCTION    CAFE_ClassCharByte.ConteoBuscarSiguienteByte
  ( VAR PosicionActual          : LongInt; ByteBusqueda         : Byte;
        Direccion, PrincipioFin : Boolean                       ) : LongInt;
VAR
  PivoteLargo,
  PosicionPivote                : LongInt;

LABEL
  SalidaNula;

BEGIN  { FUNCTION CAFE_ClassCharByte.ConteoBuscarSiguienteByte }
  IF ( PosicionActual >=       1 ) AND
     ( PosicionActual <= Ocupado ) THEN
        IF MemoriaChar[ PosicionActual ] = Chr( ByteBusqueda ) THEN
                IF NOT( BuscarSiguienteByte
                        ( PosicionActual, ByteBusqueda, Direccion, FALSE ) )
                                THEN GOTO SalidaNula;
  IF NOT( BuscarSiguienteByte
                ( PosicionActual, ByteBusqueda, Direccion, TRUE ) )
                                THEN GOTO SalidaNula;
  PosicionPivote                := PosicionActual;
  IF NOT( BuscarSiguienteByte
                ( PosicionPivote, ByteBusqueda, Direccion, FALSE ) )
  THEN BEGIN
    IF Direccion THEN PosicionPivote    := Ocupado+1;
  END;  { IF NOT( BuscarSiguienteByte( ... ) }
  PivoteLargo                   := ABS( PosicionPivote-PosicionActual );
  IF Direccion XOR PrincipioFin THEN BEGIN
    IF PrincipioFin THEN PosicionActual         := PosicionPivote+1
                    ELSE PosicionActual         := PosicionPivote-1;
  END;  { IF Direccion XOR PrincipioFin }
  ConteoBuscarSiguienteByte     := PivoteLargo;
  Exit;
SalidaNula :
  PosicionActual                := 0;
  ConteoBuscarSiguienteByte     := 0;
END;   { FUNCTION CAFE_ClassCharByte.ConteoBuscarSiguienteByte }

PROCEDURE   CAFE_ClassCharByte.ExtraccionBlancoParentesis
  (     ByteBlanco, ByteParentesisAbrir, ByteParentesisCerrar   : Byte  );
VAR
  FinCiclo              : Boolean;
  PosicionIzquierda,
  PosicionDerecha       : LongInt;

LABEL
  AnularOcupado;

BEGIN  { PROCEDURE CAFE_ClassCharByte.ExtraccionBlancoParentesis }
  FinCiclo              := FALSE;
  PosicionIzquierda     := 0;
  PosicionDerecha       := Ocupado+1;
  IF Ocupado = 0 THEN Exit;
  REPEAT
    IF NOT( BuscarSiguienteByte
                ( PosicionIzquierda, ByteBlanco, TRUE , FALSE ) )
    THEN GOTO AnularOcupado;
    IF NOT( BuscarSiguienteByte
                ( PosicionDerecha  , ByteBlanco, FALSE, FALSE ) )
    THEN GOTO AnularOcupado;
    IF ( MemoriaChar[ PosicionIzquierda ] = Chr( ByteParentesisAbrir ) ) AND
       ( MemoriaChar[ PosicionDerecha   ] = Chr( ByteParentesisCerrar ) )
    THEN BEGIN
      IF PosicionIzquierda > PosicionDerecha THEN GOTO AnularOcupado;
    END ELSE BEGIN  { IF MostrarFlechaByte( PosicionIzquierda ) ... ELSE }
      FinCiclo          := TRUE;
    END;            { IF MostrarFlechaByte( PosicionIzquierda ) ... ELSE }
  UNTIL FinCiclo;
  IF PosicionIzquierda > PosicionDerecha THEN BEGIN
    GOTO AnularOcupado;
  END ELSE BEGIN  { IF PosicionIzquierda > PosicionDerecha ELSE }
    Ocupado             := PosicionDerecha;
    IF PosicionIzquierda > 1 THEN
        EliminarDatosCharByte( 1, PosicionIzquierda-1 );
  END;            { IF PosicionIzquierda > PosicionDerecha ELSE }
  Exit;
AnularOcupado :
  Ocupado               := 0;
END;   { PROCEDURE CAFE_ClassCharByte.ExtraccionBlancoParentesis }

FUNCTION    CAFE_ClassCharByte.ExtraccionFuenteSeparador
  (     VectorFuente            : CAFE_ClassCharByte;
    VAR PosicionFuente          : LongInt;
        ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar  : Byte;
        Direccion, ExtraccionIzquierda          : Boolean       ) : Boolean;
                                overload;
VAR
  PosicionLimite                : LongInt;

LABEL
  SalidaFalsa;

BEGIN  { FUNCTION CAFE_ClassCharByte.ExtraccionFuenteSeparador }
  IF PosicionFuente <                     0 THEN PosicionFuente         := 0;
  IF PosicionFuente >  VectorFuente.Ocupado THEN
                        PosicionFuente          := VectorFuente.Ocupado+1;
  PosicionLimite                := PosicionFuente;
  IF VectorFuente.Ocupado =  0 THEN GOTO SalidaFalsa;
  IF VectorFuente.AuxiliarExtraccionFuenteSeparador
        ( PosicionLimite, ByteSeparador, ByteParentesisAbrir,
                                ByteParentesisCerrar, Direccion )
  THEN BEGIN
    IF Direccion THEN BEGIN
      IF ExtraccionIzquierda THEN ExtraccionCharByte
                                ( VectorFuente, PosicionFuente+1,
                                  PosicionLimite-PosicionFuente-1 )
                             ELSE ExtraccionCharByte
                                ( VectorFuente, PosicionLimite+1,
                                  VectorFuente.Ocupado-PosicionLimite );
    END ELSE BEGIN  { IF Direccion ELSE }
      IF ExtraccionIzquierda THEN ExtraccionCharByte
                                ( VectorFuente, 1, PosicionLimite-1 )
                             ELSE ExtraccionCharByte
                                ( VectorFuente, PosicionLimite+1,
                                  PosicionFuente-PosicionLimite-1 );
    END;            { IF Direccion ELSE }
  END ElSE BEGIN  { IF VectorFuente.AuxiliarExtraccionFuente... ELSE }
    IF Direccion XOR ExtraccionIzquierda THEN GOTO SalidaFalsa
    ELSE BEGIN
      IF Direccion THEN BEGIN
        IF PosicionFuente > VectorFuente.Ocupado THEN GOTO SalidaFalsa
        ELSE ExtraccionCharByte
                ( VectorFuente, PosicionFuente+1,
                        VectorFuente.Ocupado-PosicionFuente );
        PosicionLimite          := VectorFuente.Ocupado+1;
      END ELSE BEGIN  { IF Direccion ELSE }
        IF PosicionFuente = 0 THEN GOTO SalidaFalsa
        ELSE ExtraccionCharByte( VectorFuente, 1, PosicionFuente-1 );
      END;            { IF Direccion ELSE }
    END;  { IF Direccion XOR ExtraccionIzquierda }
  END;            { IF VectorFuente.AuxiliarExtraccionFuente... ElSE }
  PosicionFuente                := PosicionLimite;
  ExtraccionFuenteSeparador     := TRUE;
  Exit;
SalidaFalsa :
  PosicionFuente                := 0;
  Ocupado                       := 0;
  ExtraccionFuenteSeparador     := FALSE;
END;   { FUNCTION CAFE_ClassCharByte.ExtraccionFuenteSeparador }

  { Alabado sea Dios en sus Angeles y en sus Santos }
FUNCTION    CAFE_ClassCharByte.ExtraccionFuenteSeparador
  (     VectorFuente            : CAFE_ClassCharByte;
    VAR PosicionFuente          : LongInt;
        ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar  : Byte;
        Direccion               : Boolean                       ) : Boolean;
                                overload;
BEGIN  { FUNCTION CAFE_ClassCharByte.ExtraccionFuenteSeparador }
  ExtraccionFuenteSeparador     :=
        ExtraccionFuenteSeparador( VectorFuente, PosicionFuente,
                ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar,
                Direccion, NOT( Direccion ) );
END;   { FUNCTION CAFE_ClassCharByte.ExtraccionFuenteSeparador }

  { DOBLE CODIGO }
  {$IFDEF CPUI386_CPU32}
FUNCTION    CAFE_ClassCharByte.BuscarSiguienteCadena
  ( VAR PosicionActual          : LongInt;
    CONST
        Cadena                  : ShortString;
        Direccion               : Boolean                       ) : Boolean;
                                pascal; assembler;
CONST
  Parametros                    = 3*CPUBase;

LABEL
  SalidaFalsa,
        { Asigna FALSE a FUNCTION sin modificar PosicionActual          }
  ActualPositivo,
        { Elude Fuerza PosicionActual := 0 inicial si negativo          }
  ActualRango,
        { Elude Fuerza PosicionActual := Ocupado+1 si muy grande        }
  SentidoInverso,
        { Para establecer sentido de busqueda y fijar %ecx              }
  BusquedaComun,
        { Para establecer busqueda comun independiente de direccion     }
  RepiteSCASB,
        { Para repetir la busqueda de caracter si cadena con concuerda  }
  AjusteRepite,
        { Ajustes cada vez que repite la busqueda                       }
  ColocarECX,
        { Utiliza ECX para determinar output de PosicionActual          }
  InversaECX,
        { Calculo de PosicionActual( ECX ) en busqueda inversa          }
  AjusteInversoRepite,
        { Ajuste antes de Repetir busqueda en sentido inverso           }
  SalidaError,
        { Para algunos errores activa bandera de acarreo                }
  SalidaPrecaucion,
        { Evita que por accidente una cadena se encuentre por exceso    }
        { de ocupado.  Poco probable, piense en una secuencia de ceros. }
  IgnorarEdiCMPS,
        { Salta correccion innecesaria a EDI en comparacion directa     }
  SalidaFinal,
        { Asigna output a FUNCTION y PosicionActual                     }
  UnicaSalida;
        { Para tener una salida comun a TRUE y FALSE por orden          }

ASM   { FUNCTION CAFE_ClassCharByte.BuscarSiguienteCadena }
                                        { Funcion Principal             }
                                        { %edx  = PosicionActual        }
                                        { %esi  = Ocupado               }
                                        { %edi  = puntero de SCASB      }
  movl  PosicionActual, %edx            { Inicializa                    }
  movl  (%edx), %edx                    {   %edx = PosicionActual       }
  movl  __Self, %esi                    { Inicializa                    }
  addl  Ocupado, %esi                   {   %esi = Ocupado              }
  movl  (%esi), %esi                    {          (__Self+Ocupado)     }
  cmpl  $0, %esi                        { Atrapa casos especiales       }
  je    SalidaFalsa                     {   Ocupado = 0 -> SalidaFalsa  }
  cmpl  $0, %edx                        { El codigo admite              }
  jns   ActualPositivo                  {   PosicionActual < 0          }
  movl  $0, %edx                        {   y lo interpreta como 0      }
ActualPositivo:
  xorl  %eax, %eax                      { PosicionActual maxima         }
  movl  Cadena, %ebx                    {   Ocupado-TamanoCadena+2      }
  movb  (%ebx), %al                     { al := Cadena[0]               }
  cmpl  $0, %eax                        { Si tamano 0 se salta a error  }
  je    SalidaError                     {   simplemente aplica stc      }
  dec   %eax                            { al := Tamano-1 conveniencia   }
  movl  %eax, %ebx                      { Ahora se compara              }
  addl  %edx, %ebx                      { PosicionActual+al <= Ocupado  }
  cmpl  %ebx, %esi                      {   esta es la comparacion      }
  jns   ActualRango                     {   si todo bien sigue          }
  movb  Direccion, %bl                  { Si problema pregunta          }
  cmpb  True, %bl                       {   si Direccion -->            }
  je    SalidaFalsa                     {   salta a FALSE               }
  movl  %esi, %edx                      {   si Direccion <--            }
  cmpl  %eax, %edx                      { Podria ocurrir que cadena es  }
  js    SalidaFalsa                     {   muy grande y salta a False  }
  subl  %eax, %edx                      {   PosicionActual := Ocupado   }
  inc   %edx                            {       -Cadena[0]+2            }
ActualRango:
  movl  __Self, %ebx                    { Algo extra¤o                  }
  addl  MemoriaVector, %ebx             {   %edi := MemoriaVector+      }
  movl  (%ebx), %edi                    {              PosicionActual   }
  addl  %edx, %edi                      {   Esto es es Byte siguiente   }
                                        {   pues mi numeracion inicia 1 }
  movb  Direccion, %al                  { Establece el sentido          }
  cmp   False, %al                      {   de busqueda                 }
  je    SentidoInverso                  {   para fijar %ecx             }
  cld                                   { Flag Busqueda -->             }
  movl  %esi, %ecx                      { ECX   := Ocupado              }
  subl  %edx, %ecx                      {            -PosicionActual    }
  js    SalidaFalsa                     { Si PosicionActual > Ocupado   }
  jmp   BusquedaComun                   { Codigo Independiente de Flag  }
SentidoInverso:
  subl  $2, %edi                        { Edi -= 2 pues se pide atras   }
  std                                   { Flag Busqueda <--             }
  movl  %edx, %ecx                      { ECX   := PosicionActual-1     }
  dec   %ecx                            {   note la posicion anterior   }
BusquedaComun:
  jecxz SalidaFalsa                     { Evita el caso ECX 0           }
  movl  Cadena, %ebx                    { Primera lectura de Cadena     }
  inc   %ebx                            { Puntero a Cadena[1]           }
  movb  (%ebx), %al                     { al := Cadena[1]               }
                                        { Nota: en una busqueda de      }
                                        {   texto corriente             }
                                        {   probablemente sea mas       }
                                        {   eficiente buscar el ultimo  }
                                        {   caracter en sentido inverso }
RepiteSCASB:
  REPNE SCASB                           { Busqueda directa              }
  jne   SalidaFalsa                     {   salto si no encontro        }
  pushl %eax                            { Cadena Busqueda               }
  pushl %ecx                            { Ahora sigue comparacion de    }
  pushl %edi                            {   cadena, primera una         }
  pushl %esi                            {   precaucion inicial pushl    }
  xorl  %ecx, %ecx                      { Truco 0 inicial rapido        }
  movl  Cadena, %esi                    { cl := Cadena[0]               }
  movb  (%esi), %cl                     {   en %esi la direccion        }
  dec   %ecx                            { Evita comparacion innecesaria }
  jz    ColocarECX                      {   si TamanoCadena es 1        }
  movb  Direccion, %bl                  { Se corrige EDI                }
  cmpb  True, %bl                       {   para busqueda posible       }
  je    IgnorarEdiCMPS                  {   sentido inverso             }
  addl  $2, %edi                        { Note que la busqueda es       }
IgnorarEdiCMPS:
  cld                                   {   directa  asi que suman      }
  add   $2, %esi                        {   %esi apunta a Cadena[2]     }
  REPE  CMPSB                           { Compara identidad de cadena   }
  je    ColocarECX                      { Si igual es Exito             }
  popl  %esi                            { Si False repite               }
  popl  %edi                            {   primera recupera popl       }
  popl  %ecx                            {   que guardamos en precaucion }
  popl  %eax                            { Cadena Inicial Busqueda       }
  movb  Direccion, %bl                  { Segun la direccion debemos    }
  cmp   False, %bl                      {   realizar una coreccion en   }
  je    AjusteInversoRepite             {   %edi que apunta a caracter  }
  cld                                   { Flag Direccion directa        }
  jmp   AjusteRepite                    { Salto al ajuste comun         }
AjusteInversoRepite:
  std                                   { Flag Direccion inversa        }
AjusteRepite:
  jecxz SalidaFalsa                     { Precaucion si ECX 0           }
  jmp   RepiteSCASB                     {   y salta a calculo           }
ColocarECX:
  popl  %esi                            { Restablece registros          }
  popl  %edi                            {   que por precuacion          }
  popl  %ecx                            {   conservamos en el stack     }
  popl  %eax                            { Cadena inicial Busqueda       }
  movb  Direccion, %bl                  { Determina sentido segun       }
  cmpb  True, %bl                       {   parametro Direccion         }
  jne   InversaECX                      {   para calculo PosicionActual }
  movl  %esi, %edx                      { Caso TRUE                     }
  subl  %ecx, %edx                      {   PosicionActual :=           }
                                        {       Ocupado-ECX             }
                                        {   REPE decrementa ECX primero }
  jmp   SalidaPrecaucion                { Salto a calculo final         }
InversaECX:
  movl  %ecx, %edx                      { Caso sentido FALSE            }
  inc   %edx                            {   REPE decrementa ECX primero }
SalidaPrecaucion:
  xorl  %eax, %eax                      { Precaucion poco probable      }
  movl  Cadena, %ebx                    {   PosicionActual+Cadena[0]-1  }
  movb  (%ebx), %al                     {       > Ocupado               }
  dec   %eax                            {   entonces la SalidaFalsa     }
  add   %edx, %eax                      {   podria ocurrir si se buscan }
  cmp   %eax, %esi                      {   secuencias de caracteres    }
  js    SalidaFalsa                     {   nulos o en blanco           }
  jmp   SalidaFinal                     {   PosicionActual := EDX       }
SalidaError:
  stc                                   { Activa bandera de acarreo     }
                                        {   si detecta error            }
SalidaFalsa:
  movl  PosicionActual, %ebx            { Asigna output PosicionActual  }
  movl  $0, (%ebx)                      { PosicionActual := 0           }
  movb  False, __Result                 { Evitar interferencias         }
  movl  False, %eax                     { por error al ejecutar         }
                                        { fpc 2.4.2. 2 Marzo 2011       }
  jmp   UnicaSalida                     { Para tener unica salida       }
SalidaFinal:
  movl  PosicionActual, %ebx            { Asigna output PosicionActual  }
  movl  %edx, (%ebx)                    {   PosicionActual := EDX       }
  movb  True, __Result                  { Para salida Final TRUE        }
  movl  True, %eax                      { para evitar errores           }
UnicaSalida:
  leave                                 { Salida comun de Proc          }
  ret   $Parametros                     { Salida comun de Proc          }
END;  { FUNCTION CAFE_ClassCharByte.BuscarSiguienteCadena }
  {$ELSE}
FUNCTION    CAFE_ClassCharByte.BuscarSiguienteCadena
  ( VAR PosicionActual          : LongInt;
    CONST
        Cadena                  : ShortString ;
        Direccion               : Boolean                       ) : Boolean;
VAR
  PivoteVector                  : CAFE_ClassCharByte;
  TamanoPivote                  : LongInt;

LABEL
  SalidaError;

BEGIN  { FUNCTION CAFE_ClassCharByte.BuscarSiguienteCadena }
  TamanoPivote                  := Ord( Cadena[ 0 ] );
  IF TamanoPivote = 0 THEN GOTO SalidaError;
  PivoteVector                  := CAFE_ClassCharByte.Create( TamanoPivote );
  PivoteVector.InsertarString( Cadena, 1 );
  BuscarSiguienteCadena         := BuscarSiguienteSecuencia
                        ( PosicionActual, PivoteVector, Direccion );
  FreeAndNil( PivoteVector );
  Exit;
SalidaError :
  RAISE CAFE_Exception.Create
        ( 'No se puede buscar NADA '''' en BuscarSiguienteCadena' );
  PosicionActual                := 0;
  BuscarSiguienteCadena         := FALSE;
END;   { FUNCITON CAFE_ClassCharByte.BuscarSiguienteCadena }
  {$ENDIF}
  { DOBLE CODIGO }

FUNCTION    CAFE_ClassCharByte.VerificarFormatoOrdenBasica
  (     ByteBlanco, ByteParentesisAbrir, ByteParentesisCerrar,
        ByteSeparador     : Byte; ExtraccionPrimaria  : Boolean ) : Byte;
VAR
  PosicionParentesis,
  NuevaPosicion,
  PosicionSeparador             : LongInt;

LABEL
  SalidaNula;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarFormatoOrdenBasica }
  IF ExtraccionPrimaria THEN
        ExtraccionBlancoParentesis
                ( ByteBlanco, ByteParentesisAbrir, ByteParentesisCerrar );
  IF Ocupado = 0 THEN GOTO SalidaNula;
  IF Self[ Ocupado ] <> ByteParentesisCerrar
  THEN GOTO SalidaNula;
  PosicionParentesis            := 0;
  IF NOT( BuscarSiguienteByte
                ( PosicionParentesis, ByteParentesisAbrir, TRUE, TRUE ) )
  THEN GOTO SalidaNula;
  IF ( PosicionParentesis > 255 ) OR ( PosicionParentesis = 1 )
  THEN GOTO SalidaNula;
  NuevaPosicion                 := PosicionParentesis;
  IF NOT( BuscarSiguienteByte
                ( NuevaPosicion, ByteBlanco, FALSE, FALSE ) )
  THEN GOTO SalidaNula;
  IF Self[ NuevaPosicion ] = ByteParentesisCerrar THEN GOTO SalidaNula;
  Self[ PosicionParentesis ]    := ByteBlanco;
  PosicionParentesis            := NuevaPosicion+1;
  Self[ PosicionParentesis ]    := ByteParentesisAbrir;
  PosicionSeparador             := 0;
  IF AuxiliarExtraccionFuenteSeparador( PosicionSeparador,
        ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar, TRUE )
  THEN GOTO SalidaNula;
  VerificarFormatoOrdenBasica   := PosicionParentesis;
  Exit;
SalidaNula :
  VerificarFormatoOrdenBasica   := 0;
END;   { FUNCTION CAFE_ClassCharByte.VerificarFormatoOrdenBasica }

FUNCTION    CAFE_ClassCharByte.VerificarNumeroLongIntInsertado
  ( OUT NumeroExtraido          : LongInt;
        PosicionNumero          : LongInt; TamanoChar : Byte    ) : Boolean;
VAR
  CadenaPivote                  : ShortString;
  Code                          : Integer;

LABEL
  SalidaFalsa;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarNumeroLongIntInsertado }
  NumeroExtraido                := 0;
  IF Ocupado      = 0   THEN GOTO SalidaFalsa;
  CadenaPivote                  :=
                ExtraerString( PosicionNumero, TamanoChar );
  IF CadenaPivote = ''  THEN GOTO SalidaFalsa;
  Val( CadenaPivote, NumeroExtraido, Code );
  IF Code <> 0 THEN GOTO SalidaFalsa;
  VerificarNumeroLongIntInsertado               := TRUE;
  Exit;
SalidaFalsa :
  VerificarNumeroLongIntInsertado               := FALSE;
END;   { FUNCTION CAFE_ClassCharByte.VerificarNumeroLongIntInsertado }

FUNCTION    CAFE_ClassCharByte.VerificarNumeroLongInt
  ( OUT NumeroExtraido          : LongInt                       ) : Boolean;
VAR
  Code                          : Integer;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarNumeroLongInt }
  IF Ocupado > 255 THEN BEGIN
    NumeroExtraido              := 0;
    VerificarNumeroLongInt      := FALSE;
  END ELSE BEGIN  { IF Ocupado > 255 ELSE }
    Self[ Ocupado+1 ]           := 0;
    Val( MemoriaVector, NumeroExtraido, Code );
    IF Code <> 0 THEN VerificarNumeroLongInt    := FALSE
                 ELSE VerificarNumeroLongInt    := TRUE;
  END;            { IF Ocupado > 255 ELSE }
END;   { FUNCTION CAFE_ClassCharByte.VerificarNumeroLongInt }

FUNCTION    CAFE_ClassCharByte.VerificarNumeroRealInsertado
  ( OUT NumeroExtraido          : CAFE_Real;
        PosicionNumero          : LongInt; TamanoChar : Byte    ) : Boolean;
VAR
  CadenaPivote                  : ShortString;
  Code                          : Integer;

LABEL
  SalidaFalsa;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarNumeroRealInsertado }
  NumeroExtraido                := 0.0;
  IF Ocupado      =   0 THEN GOTO SalidaFalsa;
  CadenaPivote                  :=
                ExtraerString( PosicionNumero, TamanoChar );
  IF CadenaPivote = ''  THEN GOTO SalidaFalsa;
  Val( CadenaPivote, NumeroExtraido, Code );
  IF Code <> 0 THEN GOTO SalidaFalsa;
  VerificarNumeroRealInsertado                  := TRUE;
  Exit;
SalidaFalsa :
  VerificarNumeroRealInsertado                  := FALSE;
END;   { FUNCTION CAFE_ClassCharByte.VerificarNumeroRealInsertado }

FUNCTION    CAFE_ClassCharByte.VerificarNumeroReal
  ( OUT NumeroExtraido          : CAFE_Real                    ) : Boolean;
VAR
  Code                          : Integer;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarNumeroReal }
  IF Ocupado > 255 THEN BEGIN
    NumeroExtraido              := 0;
    VerificarNumeroReal         := FALSE;
  END ELSE BEGIN  { IF Ocupado > 255 ELSE }
    Self[ Ocupado+1 ]           := 0;
    Val( MemoriaVector, NumeroExtraido, Code );
    IF Code <> 0 THEN VerificarNumeroReal       := FALSE
                 ELSE VerificarNumeroReal       := TRUE;
  END;            { IF Ocupado > 255 ELSE }
END;   { FUNCTION CAFE_ClassCharByte.VerificarNumeroReal }

FUNCTION    CAFE_ClassCharByte.VerificarFormatoByteDuplicadoInsertado
  (     ByteDuplicado           : Byte;
        PosicionInsertado       : LongInt                       ) : LongInt;
VAR
  PivoteRespuesta,
  PivoteLargo                   : LongInt;

LABEL
  SalidaRapida,
  SalidaError;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarFormatoByteDuplicadoInsertado }
  PivoteRespuesta               := 0;
  IF Ocupado = 0 THEN GOTO SalidaRapida;
  IF ( PosicionInsertado <=       0 ) OR
     ( PosicionInsertado >  Ocupado ) THEN GOTO SalidaError;
  IF Self[ PosicionInsertado ] <> ByteDuplicado
                                                THEN GOTO SalidaRapida;
  Dec( PosicionInsertado );
  IF PosicionInsertado <> 0 THEN
        IF Self[ PosicionInsertado ] = ByteDuplicado
                                                THEN GOTO SalidaRapida;
  PivoteRespuesta               := PosicionInsertado;
  PivoteLargo                   := ConteoBuscarSiguienteByte
                ( PivoteRespuesta, ByteDuplicado, TRUE, FALSE );
  IF Odd( PivoteLargo ) THEN REPEAT
    PivoteLargo                 := ConteoBuscarSiguienteByte
                ( PivoteRespuesta, ByteDuplicado, TRUE, FALSE );
  UNTIL Odd( PivoteLargo ) OR ( PivoteLargo = 0 );
SalidaRapida :
  VerificarFormatoByteDuplicadoInsertado                := PivoteRespuesta;
  Exit;
SalidaError  :
  RAISE CAFE_Exception.Create( 'Acceso inv lido en '+
                'VerificarFormatoByteDuplicadoInsertado' );
  VerificarFormatoByteDuplicadoInsertado                := 0;
END;   { FUNCTION CAFE_ClassCharByte.VerificarFormatoByteDuplicadoInsertado }

FUNCTION    CAFE_ClassCharByte.VerificarFormatoByteDuplicado
  (     ByteDuplicado           : Byte                          ) : Boolean;
VAR
  PivoteLargo                   : LongInt;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarFormatoByteDuplicado }
  PivoteLargo                   := VerificarFormatoByteDuplicadoInsertado
                                                        ( ByteDuplicado, 1 );
  IF ( PivoteLargo <> 0 ) AND ( PivoteLargo = Ocupado ) THEN
                VerificarFormatoByteDuplicado                   := TRUE
                                                        ELSE
                VerificarFormatoByteDuplicado                   := FALSE;
END;   { FUNCTION CAFE_ClassCharByte.VerificarFormatoByteDuplicado }

PROCEDURE   CAFE_ClassCharByte.EliminarComentariosCharByte
  ( CONST
        CadenaIzquierda1, CadenaDerecha1  , CadenaIzquierda2,
        CadenaDerecha2  , CadenaIzquierda3, CadenaDerecha3      : ShortString;
        ByteBlanco      , ByteExtraccionDoble                   : Byte;
        BanderaByteExtraccionDoble                              : Boolean );
VAR
  PosicionActual                : LongInt;
  ActivoDelimitador1,
  ActivoDelimitador2,
  ActivoDelimitador3            : Boolean;
  DelimitadorPrioritario        : Byte;
  PivoteLargo,
  PivoteIzquierda,
  PivotePosicion1,
  PivotePosicion2,
  PivotePosicion3,
  PivotePosicion4,
  PivoteMenor                   : LongInt;

LABEL
  SalidaFracaso;

    { ANIDADO }
  FUNCTION AnidadoBusquedaInterna
    ( VAR PosicionActual        : LongInt;
      CONST
          Cadena                : ShortString;
          PrincipioFin          : Boolean                       ) : Boolean;
  VAR
    ByteBusqueda                : Byte;

  BEGIN  { FUNCTION AnidadoBusquedaInterna }
    IF Ord( Cadena[ 0 ] ) = 1 THEN BEGIN
      ByteBusqueda              := Ord( Cadena[ 1 ] );
      AnidadoBusquedaInterna    := BuscarSiguienteByte
                        ( PosicionActual, ByteBusqueda, TRUE, TRUE );
    END ELSE BEGIN  { IF ( Ord( Cadena[ 0 ] ) = 1 ELSE }
      AnidadoBusquedaInterna    := BuscarSiguienteCadena
                                        ( PosicionActual, Cadena, TRUE );
      IF NOT( PrincipioFin ) THEN
         PosicionActual         := PosicionActual+Ord( Cadena[ 0 ] )-1;
    END;            { IF ( Ord( Cadena[ 0 ] ) = 1 ELSE }
  END;   { FUNCTION AnidadoBusquedaInterna }
    { ANIDADO }

    { ANIDADO }
  PROCEDURE AnidadoEstablecerBytePrioritario;
  BEGIN  { PROCEDURE AnidadoEstablecerBytePrioritario }
    PivoteMenor                 := PivotePosicion1;
    IF ( PivotePosicion1 > 0 ) THEN BEGIN
      PivoteMenor               := PivotePosicion1;
      DelimitadorPrioritario    := 1;
    END;  { IF ( PivotePosicion1 > 0 ) }
    IF ( PivotePosicion2 >               0 ) AND
     ( ( PivoteMenor     =               0 ) OR
       ( PivoteMenor     > PivotePosicion2 ) ) THEN BEGIN
      PivoteMenor               := PivotePosicion2;
      DelimitadorPrioritario    := 2;
    END;  { IF PivotePosicion2 > 0 ) AND ( PivoteMenor > PivotePosicion2 }
    IF ( PivotePosicion3 >               0 ) AND
     ( ( PivoteMenor     =               0 ) OR
       ( PivoteMenor     > PivotePosicion3 ) ) THEN BEGIN
      PivoteMenor               := PivotePosicion3;
      DelimitadorPrioritario    := 3;
    END;  { IF PivotePosicion3 > 0 ) AND ( PivoteMenor > PivotePosicion3 }
    IF ( PivotePosicion4 >               0 ) AND
     ( ( PivoteMenor     =               0 ) OR
       ( PivoteMenor     > PivotePosicion4 ) ) THEN BEGIN
      PivoteMenor               := PivotePosicion4;
      DelimitadorPrioritario    := 4;
    END;  { IF PivotePosicion4 > 0 ) AND ( PivoteMenor > PivotePosicion4 }
  END;   { PROCEDURE AnidadoEstablecerBytePrioritario }
    { ANIDADO }


BEGIN  { PROCEDURE CAFE_ClassCharByte.EliminarComentariosCharByte }
  PosicionActual                := 0;
  PivotePosicion1               := 0;
  PivotePosicion2               := 0;
  PivotePosicion3               := 0;
  PivotePosicion4               := 0;
  ActivoDelimitador1            := ( CadenaIzquierda1 <> '' );
  ActivoDelimitador2            := ( CadenaIzquierda2 <> '' );
  ActivoDelimitador3            := ( CadenaIzquierda3 <> '' );
  REPEAT
    DelimitadorPrioritario      := 0;
    PivoteMenor                 := PosicionActual;
    IF ActivoDelimitador1 AND ( PivotePosicion1 <= PosicionActual ) THEN BEGIN
      PivotePosicion1           := PosicionActual;
      IF NOT( AnidadoBusquedaInterna
                        ( PivotePosicion1, CadenaIzquierda1, TRUE ) )
                                        THEN ActivoDelimitador1 := FALSE;
    END;  { IF ActivoDelimitador1 AND ( PivotePosicion1 <= PosicionActual ) }
    IF ActivoDelimitador2 AND ( PivotePosicion2 <= PosicionActual ) THEN BEGIN
      PivotePosicion2           := PosicionActual;
      IF NOT( AnidadoBusquedaInterna
                        ( PivotePosicion2, CadenaIzquierda2, TRUE ) )
                                        THEN ActivoDelimitador2 := FALSE;
    END;  { IF ActivoDelimitador2 AND ( PivotePosicion2 <= PosicionActual ) }
    IF ActivoDelimitador3 AND ( PivotePosicion3 <= PosicionActual ) THEN BEGIN
      PivotePosicion3           := PosicionActual;
      IF NOT( AnidadoBusquedaInterna
                        ( PivotePosicion3, CadenaIzquierda3, TRUE ) )
                                        THEN ActivoDelimitador3 := FALSE;
    END;  { IF ActivoDelimitador3 AND ( PivotePosicion3 <= PosicionActual ) }
    IF BanderaByteExtraccionDoble AND ( PivotePosicion4 <= PosicionActual )
    THEN BEGIN
      PivotePosicion4           := PosicionActual;
      REPEAT
        PivoteLargo             := ConteoBuscarSiguienteByte
                ( PivotePosicion4, ByteExtraccionDoble, TRUE, FALSE );
      UNTIL Odd( PivoteLargo ) OR ( PivoteLargo = 0 );
      IF PivoteLargo = 0 THEN BanderaByteExtraccionDoble        := FALSE;
    END;  { IF BanderaByteExtraccionDoble AND ... }
    AnidadoEstablecerBytePrioritario;
    PosicionActual              := PivoteMenor;
    PivoteIzquierda             := PosicionActual;
    CASE DelimitadorPrioritario OF
      1         : IF NOT( AnidadoBusquedaInterna
                                ( PosicionActual, CadenaDerecha1, FALSE ) )
                                        THEN GOTO SalidaFracaso;
      2         : IF NOT( AnidadoBusquedaInterna
                                ( PosicionActual, CadenaDerecha2, FALSE ) )
                                        THEN GOTO SalidaFracaso;
      3         : IF NOT( AnidadoBusquedaInterna
                                ( PosicionActual, CadenaDerecha3, FALSE ) )
                                        THEN GOTO SalidaFracaso;
      4         : BEGIN
                    REPEAT
                      PivoteLargo               := ConteoBuscarSiguienteByte
                        ( PosicionActual, ByteExtraccionDoble, TRUE, FALSE );
                    UNTIL Odd( PivoteLargo ) OR ( PivoteLargo = 0 );
                    IF PivoteLargo = 0 THEN GOTO SalidaFracaso;
                  END;  { CASE DelimitadorPrioritario = 4 }
    END;  { CASE DelimitadorPrioritario }
    IF DelimitadorPrioritario IN [ 1..3 ] THEN
        EscribirByteRepetidoCharByte( ByteBlanco, PivoteIzquierda,
                PosicionActual-PivoteIzquierda+1, FALSE );
  UNTIL DelimitadorPrioritario = 0;
  Exit;
SalidaFracaso :
  CAFE_IntentoInfructuosoSintactico     := TRUE;
  CAFE_PosicionInfructuosoSintactico    := CAFE_1ErrorFaltaFinComentario;
  CASE DelimitadorPrioritario OF
    1   : CAFE_MensajeInfructuosoSintactico     := CadenaDerecha1;
    2   : CAFE_MensajeInfructuosoSintactico     := CadenaDerecha2;
    3   : CAFE_MensajeInfructuosoSintactico     := CadenaDerecha3;
    4   : BEGIN
            CAFE_PosicionInfructuosoSintactico  := CAFE_1ErrorFaltaFinString;
            CAFE_MensajeInfructuosoSintactico   :=
                        'Falta delimitador final de String';
          END;  { CASE 4 }
  END;  { CASE DelimitadorPrioritario OF }
END;   { PROCEDURE CAFE_ClassCharByte.EliminarComentariosCharByte }

FUNCTION    CAFE_ClassCharByte.VerificarIdentificadorBasicoInsertado
  ( OUT CadenaIdentificador     : ShortString;
        PosicionIdentificador   : LongInt;
        TamanoIdentificador     : Byte;
    CONST
        PrimerByteIdentificador, MedioByteIdentificador,
        UltimoByteIdentificador         : CAFE_ConjuntoByte     ) : Boolean;
VAR
  RecorreIdentificador          : LongInt;

LABEL
  SalidaError,
  SalidaFalsa;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarIdentificadorBasicoInsertado }
  CadenaIdentificador           := '';
  IF TamanoIdentificador = 0 THEN GOTO SalidaFalsa;
  IF Ocupado             = 0 THEN GOTO SalidaFalsa;
  IF ( PosicionIdentificador <=        0 ) OR
     ( PosicionIdentificador >   Ocupado ) THEN GOTO SalidaError;
  IF ( TamanoIdentificador   >  ( Ocupado-PosicionIdentificador+1 ) ) THEN
        TamanoIdentificador     := Ocupado-PosicionIdentificador+1;
  IF NOT( Self[ PosicionIdentificador ] IN
                        PrimerByteIdentificador ) THEN GOTO SalidaFalsa;
  IF TamanoIdentificador > 1 THEN
        IF NOT( Self[ PosicionIdentificador+TamanoIdentificador-1 ] IN
                        UltimoByteIdentificador ) THEN GOTO SalidaFalsa;
  FOR RecorreIdentificador := ( PosicionIdentificador+1 ) TO
                ( PosicionIdentificador+TamanoIdentificador-2 ) DO BEGIN
    IF NOT( Byte( MemoriaChar[ RecorreIdentificador ] ) IN
                        MedioByteIdentificador ) THEN GOTO SalidaFalsa;
  END;  { FOR RecorreIdentificador }
  CadenaIdentificador           :=
                ExtraerString( PosicionIdentificador, TamanoIdentificador );
  VerificarIdentificadorBasicoInsertado                 := TRUE;
  Exit;
SalidaError :
  RAISE CAFE_Exception.Create
                ( 'Error al VerificarIdentificadorBasicoInsertado' );
SalidaFalsa :
  VerificarIdentificadorBasicoInsertado                 := FALSE;
END;   { FUNCTION CAFE_ClassCharByte.VerificarIdentificadorBasicoInsertado }

FUNCTION    CAFE_ClassCharByte.VerificarIdentificadorBasico
  ( OUT CadenaIdentificador     : ShortString;
    CONST
        PrimerByteIdentificador, MedioByteIdentificador,
        UltimoByteIdentificador         : CAFE_ConjuntoByte     ) : Boolean;

BEGIN  { FUNCTION CAFE_ClassCharByte.VerificarIdentificadorBasico }
  CadenaIdentificador           := '';
  IF Ocupado > 255 THEN BEGIN
    VerificarIdentificadorBasico                := FALSE;
  END ELSE BEGIN  { IF Ocupado > 255 ELSE }
    VerificarIdentificadorBasico                :=
        VerificarIdentificadorBasicoInsertado
                ( CadenaIdentificador, 1, Ocupado, PrimerByteIdentificador,
                        MedioByteIdentificador, UltimoByteIdentificador );
  END;            { IF Ocupado > 255 ELSE }
END;   { FUNCTION CAFE_ClassCharByte.VerificarIdentificadorBasico }

PROCEDURE   CAFE_ClassCharByte.ContraccionByteDuplicado
  (     ByteBusqueda            : Byte                                  );
VAR
  VectorCopia           : CAFE_ClassCharByte;
  PosicionActual,
  PosicionInicial,
  TamanoTransferencia,
  PivoteLargo           : LongInt;

BEGIN  { PROCEDURE CAFE_ClassCharByte.ContraccionByteDuplicado }
  IF Ocupado = 0 THEN Exit;
  VectorCopia           := CAFE_ClassCharByte.Create( Ocupado );
  PosicionActual        := 0;
  PosicionInicial       := 1;
  REPEAT
    PivoteLargo         := ConteoBuscarSiguienteByte
                ( PosicionActual, ByteBusqueda, TRUE, FALSE );
    IF PivoteLargo <> 0 THEN BEGIN
      TamanoTransferencia               := PosicionActual-PosicionInicial+1
                                                -( PivoteLargo DIV 2 );
      VectorCopia.InsertarExtraccionCharByte
        ( VectorCopia.Ocupado+1, Self, PosicionInicial, TamanoTransferencia );
      PosicionInicial   := PosicionActual+1;
    END;  { IF PivoteLargo <> 0 }
  UNTIL PivoteLargo = 0;
  IF PosicionInicial <= Ocupado THEN
        VectorCopia.InsertarExtraccionCharByte
                ( VectorCopia.Ocupado+1, Self, PosicionInicial,
                                        Ocupado-PosicionInicial+1 );
  TransferenciaCharByte( VectorCopia );
  FreeAndNil( VectorCopia );
  Self[ Ocupado+1 ]             := 0;
END;   { PROCEDURE CAFE_ClassCharByte.ContraccionByteDuplicado }

PROCEDURE   CAFE_ClassCharByte.ExpansionByteDuplicado
  (     ByteBusqueda            : Byte                                  );
VAR
  VectorCopia                   : CAFE_ClassCharByte;
  PosicionActual,
  PosicionInicial               : LongInt;

LABEL
  SalidaDone;

BEGIN  { PROCEDURE CAFE_ClassCharByte.ExpansionByteDuplicado }
  IF Ocupado = 0 THEN Exit;
  VectorCopia                   := CAFE_ClassCharByte.Create( TamanoVector );
  PosicionActual                := 0;
  PosicionInicial               := 1;
  WHILE BuscarSiguienteByte( PosicionActual, ByteBusqueda, TRUE, TRUE )
  DO BEGIN
    VectorCopia.InsertarExtraccionCharByte
        ( VectorCopia.Ocupado+1, Self, PosicionInicial,
                                PosicionActual-PosicionInicial+1 );
    PosicionInicial             := PosicionActual+1;
    IF VectorCopia.Ocupado = VectorCopia.TamanoVector THEN BEGIN
      GOTO SalidaDone;
    END;  { IF VectorCopia.Ocupado = VectorCopia.TamanoVector }
    Inc( VectorCopia.Ocupado );
    VectorCopia[ VectorCopia.Ocupado ]          := ByteBusqueda;
  END;  { WHILE BuscarSiguienteByte( PosicionActual, ByteBusqueda, ... ) }
  IF PosicionInicial <= Ocupado THEN
        VectorCopia.InsertarExtraccionCharByte
                ( VectorCopia.Ocupado+1, Self, PosicionInicial,
                                        Ocupado-PosicionInicial+1 );
  TransferenciaCharByte( VectorCopia );
SalidaDone :
  FreeAndNil( VectorCopia );
  Self[ Ocupado+1 ]             := 0;
END;   { PROCEDURE CAFE_ClassCharByte.ExpansionByteDuplicado }

PROCEDURE   CAFE_ClassCharByte.ExtraccionPrimerByteDuplicado
  (     VectorFuente            : CAFE_ClassCharByte;
    VAR PosicionExtraccion      : LongInt; Direccion            : Boolean );
VAR
  PosicionPivote,
  TamanoBloque                  : LongInt;
  ByteBusqueda                  : Byte;
  PivoteBandera                 : Boolean;

LABEL
  SalidaError;

BEGIN  { PROCEDURE CAFE_ClassCharByte.ExtraccionPrimerByteDuplicado }
  IF ( PosicionExtraccion <=                    0 ) OR
     ( PosicionExtraccion >  VectorFuente.Ocupado ) THEN GOTO SalidaError;
  Ocupado                       := 0;
  PosicionPivote                := PosicionExtraccion;
  ByteBusqueda                  := VectorFuente[ PosicionExtraccion ];
  PivoteBandera                 := VectorFuente.BuscarSiguienteByte
                ( PosicionPivote, ByteBusqueda, Direccion, FALSE );
  TamanoBloque                  := ABS( PosicionPivote-PosicionExtraccion );
  IF Direccion AND NOT( PivoteBandera ) THEN BEGIN
    PosicionPivote              := VectorFuente.Ocupado+1;
    TamanoBloque                := PosicionPivote-PosicionExtraccion;
    IF Odd( TamanoBloque ) THEN GOTO SalidaError;
  END;  { IF Direccion AND NOt( PivoteBandera ) }
  IF Odd( TamanoBloque ) THEN BEGIN
    REPEAT
      TamanoBloque              := VectorFuente.ConteoBuscarSiguienteByte
                ( PosicionPivote, ByteBusqueda, Direccion, NOT( Direccion ) );
      IF TamanoBloque = 0 THEN GOTO SalidaError;
    UNTIL Odd( TamanoBloque );
  END ELSE BEGIN  { IF NOT( Odd( TamanoBloque ) ) ELSE }
    IF Direccion THEN Dec( PosicionPivote )
                 ELSE Inc( PosicionPivote );
  END;            { IF NOT( Odd( TamanoBloque ) ) ELSE }
  TamanoBloque                  :=
                ABS( PosicionPivote-PosicionExtraccion )-1;
  IF Direccion THEN ExtraccionCharByte( VectorFuente,
                                PosicionExtraccion+1, TamanoBloque )
               ELSE ExtraccionCharByte( VectorFuente,
                                PosicionPivote+1    , TamanoBloque );
  ContraccionByteDuplicado( ByteBusqueda );
  Exit;
SalidaError :
  Ocupado                       := 0;
  PosicionExtraccion            := 0;
  CAFE_IntentoInfructuosoSintactico     := TRUE;
  CAFE_MensajeInfructuosoSintactico     := 'Mala sintaxis en STRING';
  CAFE_PosicionInfructuosoSintactico    := CAFE_1ErrorStringGeneral;
END;   { PROCEDURE CAFE_ClassCharByte.ExtraccionPrimerByteDuplicado }

PROCEDURE   CAFE_ClassCharByte.InsertarTotalByteDuplicado
  (     PosicionInsercion       : LongInt;
        VectorFuente            : CAFE_ClassCharByte;
        ByteBusqueda            : Byte                                  );
VAR
  VectorCopia                   : CAFE_ClassCharByte;

LABEL
  SalidaError;

BEGIN  { PROCEDURE CAFE_ClassCharByte.InsertarTotalByteDuplicado }
  VectorCopia                   :=
                CAFE_ClassCharByte.Create( 2*( VectorFuente.Ocupado+1 ) );
  VectorCopia.TransferenciaCharByte( VectorFuente );
  VectorCopia.ExpansionByteDuplicado( ByteBusqueda );
  InsertarDatosCharByte( NIL, PosicionInsercion, VectorCopia.Ocupado+2 );
  Self[ PosicionInsercion ]     := ByteBusqueda;
  Move( VectorCopia.MemoriaVector^, MemoriaChar[ PosicionInsercion+1 ],
                VectorCopia.Ocupado );
  Self[ VectorCopia.Ocupado+1+PosicionInsercion ]       := ByteBusqueda;
  FreeAndNil( VectorCopia );
  Self[ Ocupado+1 ]             := 0;
  Exit;
SalidaError :
  FreeAndNil( VectorCopia );
  RAISE CAFE_Exception.Create( 'Acceso fuera de rango en '+
                        'InsertarTotalByteDuplicado' );
END;   { PROCEDURE CAFE_ClassCharByte.InsertarTotalByteDuplicado }

FUNCTION    CAFE_ClassCharByte.ReadTextoChar             : ShortString;
BEGIN  { FUNCTION CAFE_ClassCharByte.ReadTextoChar }
  Self[ Ocupado+1 ]     := 0;
  ReadTextoChar         := StrPas( MemoriaVector );
END;   { FUNCTION CAFE_ClassCharByte.ReadTextoChar }

PROCEDURE   CAFE_ClassCharByte.WriteTextoChar
  ( CONST
        MyTexto                 : ShortString                           );
BEGIN  { PROCEDURE WriteTextoChar }
  Ocupado               := 0;
  InsertarString( MyTexto, 1 );
END;   { PROCEDURE WriteTextoChar }

FUNCTION    CAFE_ClassCharByte.ReadItems
  (     Ide                     : LongInt                       ) : SizeInt;
BEGIN  { FUNCTION CAFE_ClassCharByte.ReadItems }
  TRY
    IF Ide = 0 THEN BEGIN
      ReadItems                 := Ocupado
    END ELSE BEGIN  { IF Ide = 0 ELSE }
      ReadItems                 := Byte( MemoriaChar[ Ide ] );
    END;            { IF Ide = 0 ELSE }
  EXCEPT
    RAISE CAFE_Exception.Create( 'Acceso inv lido a propiedad Default'+
                ' en CharByte' );
  END;
END;   { FUNCTION CAFE_ClassCharByte.ReadItems }

PROCEDURE   CAFE_ClassCharByte.WriteItems
  (     Ide                     : LongInt;
        MyByte                  : SizeInt                               );
BEGIN  { PROCEDURE CAFE_ClassCharByte.WriteItems }
  TRY
    IF Ide = 0 THEN BEGIN
      IF MyByte > TamanoVector
      THEN RAISE CAFE_Exception.Create( 'Intento de asignar '+
                 'tamano invalido CHARBYTE' );
      Ocupado                   := MyByte;
    END ELSE BEGIN
      MemoriaChar[ Ide ]        := Chr( MyByte );
    END;
  EXCEPT
    RAISE CAFE_Exception.Create( 'Acceso inv lido a propiedad Default'+
                ' en CharByte' );
  END;
END;   { PROCEDURE CAFE_ClassCharByte.WriteItems }

FUNCTION    CAFE_ClassCharByte.AuxiliarExtraccionFuenteSeparador
  ( VAR PosicionActual          : LongInt;
        ByteSeparador, ByteParentesisAbrir, ByteParentesisCerrar  : Byte;
        Direccion                               : Boolean       ) : Boolean;
VAR
  PunteroByte           : PointerByte;
  BanderaPar            : Boolean;
  TotalParentesisAbrir,
  TotalParentesisCerrar : LongInt;

LABEL
  SalidaFalsa;

BEGIN  { CAFE_ClassCharByte.AuxiliarExtraccionFuenteSeparador }
  IF Ocupado        =       0 THEN GOTO SalidaFalsa;
  IF PosicionActual <       0 THEN PosicionActual     := 0;
  IF PosicionActual > Ocupado THEN PosicionActual       := Ocupado+1;
  BanderaPar            := TRUE;
  TotalParentesisAbrir  := 0;
  TotalParentesisCerrar := 0;
  REPEAT
    IF Direccion THEN BEGIN
      Inc( PosicionActual );
      IF PosicionActual > Ocupado THEN GOTO SalidaFalsa;
    END ELSE BEGIN  { IF Direccion ELSE }
      Dec( PosicionActual );
      IF PosicionActual <       1 THEN GOTO SalidaFalsa;
    END;            { IF Direccion ELSE }
    PunteroByte                 := Pointer( @MemoriaChar[ PosicionActual ] );
    IF PunteroByte^ = ByteParentesisAbrir THEN Inc( TotalParentesisAbrir  );
    IF PunteroByte^ = ByteParentesisCerrar THEN Inc( TotalParentesisCerrar );
    BanderaPar          := ( TotalParentesisAbrir = TotalParentesisCerrar );
  UNTIL BanderaPar AND ( PunteroByte^ = ByteSeparador );
  AuxiliarExtraccionFuenteSeparador             := TRUE;
  Exit;
SalidaFalsa :
  PosicionActual        := 0;
  AuxiliarExtraccionFuenteSeparador             := FALSE;
END;   { CAFE_ClassCharByte.AuxiliarExtraccionFuenteSeparador }

DESTRUCTOR  CAFE_ClassCharByte.Destroy;
VAR
  PunteroPivote         : Pointer;

BEGIN  { DESTRUCTOR CAFE_ClassCharByte.Destroy }
  PunteroPivote         := MemoriaChar;
  FreeMem( PunteroPivote, TamanoVector+CAFE_BytesExcesoCharByte );
  TamanoVector          := 0;
  Ocupado               := 0;
  MemoriaChar           := NIL;
  MemoriaVector         := NIL;
END;   { DESTRUCTOR CAFE_ClassCharByte.Destroy }

INITIALIZATION
FINALIZATION
END.



