2026-04-03 21:12:36 -05:00
//+------------------------------------------------------------------+
//| YmlParser.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372 |
//+------------------------------------------------------------------+
# property copyright " Copyright 2025, Niquel Mendoza. "
# property link " https://www.mql5.com/es/users/nique_372 "
# property strict
2026-04-04 20:27:55 -05:00
# ifndef YMLPARSERBYLEO_SRC_YMLPARSER_MQH
# define YMLPARSERBYLEO_SRC_YMLPARSER_MQH
2026-04-03 21:12:36 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
# include "YmlDefines.mqh"
2026-04-04 16:19:18 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
uchar g_yml_hex [ 256 ] ;
bool g_yml_hex_init = false ;
2026-04-04 20:03:17 -05:00
struct CYmlNode ;
2026-04-04 16:19:18 -05:00
2026-04-03 21:12:36 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CYmlParser
{
public :
//--- Cinta
long m_cinta [ ] ;
2026-04-03 22:17:13 -05:00
int m_cinta_pos ;
2026-04-04 16:19:18 -05:00
ushort m_yml [ ] ;
2026-04-04 20:03:17 -05:00
2026-04-03 21:12:36 -05:00
private :
int m_cinta_reserve ;
//---
int m_yml_len ;
int m_yml_pos ;
2026-04-05 22:25:16 -05:00
bool m_aument_ident_in_next_call ;
2026-04-03 21:12:36 -05:00
//--- Posicioens de los anchors (hash | pos)
int m_anchors_posciones [ 64 ] [ 9 ] ;
//---
short m_values_anchors_prohibidos [ ] ;
int m_values_anchors_prohibidos_pos ;
//---
2026-04-05 06:57:19 -05:00
int m_yml_ident_chars ;
2026-04-03 21:12:36 -05:00
//---
bool ProccesKey ( int & start , int & end , bool & scape ) ;
2026-04-04 20:03:17 -05:00
//---
2026-04-03 21:12:36 -05:00
// Para todo
2026-04-05 06:57:19 -05:00
bool ProccesVal ( ) ;
2026-04-04 20:03:17 -05:00
//
2026-04-05 06:57:19 -05:00
bool ProccesValForReference ( ENUM_YML_TOKEN_STRUCTURE & type ) ;
2026-04-03 21:12:36 -05:00
// Para objetos
2026-04-04 20:03:17 -05:00
bool ProccesValArrOrObj ( const ushort char_cierre ) ;
//--- Procesar valores
// objeto
bool ParseInlineObj ( ) ;
2026-04-03 21:12:36 -05:00
// Arrays
bool ParseInlineArr ( ) ;
// Multiline
2026-04-05 06:57:19 -05:00
bool ParseMultiline ( const bool con_saltos ) ;
2026-04-03 21:12:36 -05:00
// Bloques
2026-04-05 06:57:19 -05:00
bool ParseBlock ( ) ;
2026-04-03 21:12:36 -05:00
// Item root
bool ParseItemRoot ( ) ;
// Ref use
bool ParseRefUse ( ) ;
// no tal cual
2026-04-04 20:03:17 -05:00
bool ProccesScalarNoTalCual ( const ushort char_cierre ) ;
2026-04-03 21:12:36 -05:00
// texto plano
bool ProccesScalarPlain ( ) ;
// Valor scalar
bool ProccesScalarVal ( ) ;
// Procesar ""
bool ProccesQuoted ( ) ;
// Añadir al ashmap
bool AddToAnchorHash ( const int start , const int end , const int pos_reference ) ;
// Crear referencia
2026-04-05 06:57:19 -05:00
bool ParseRefCreate ( ) ;
2026-04-03 21:12:36 -05:00
//---
void ReserveCinta ( const int size ) ;
//---
int FindRefPositionStart ( const int start , const int end , bool check ) ;
//---
ENUM_YML_TOKEN_STRUCTURE ObtenerTipoVal ( ) ;
//---
ENUM_YML_PARSER_LAST_ERR m_last_err ;
//---
void Init ( ) ;
2026-04-04 10:28:45 -05:00
static int HexToDec ( const ushort c ) ;
bool InternalParse ( ) ;
2026-04-04 16:19:18 -05:00
long FastAtoi ( const int start , const int end , const int sign ) ;
long FastAtoiHex ( const int start , const int end ) ;
2026-04-04 20:03:17 -05:00
int GetStepPure ( int idx ) ;
2026-04-03 21:12:36 -05:00
2026-04-03 22:37:29 -05:00
public :
//---
union LongToDbl
{
long l ;
double d ;
} ;
2026-04-03 21:12:36 -05:00
public :
CYmlParser ( void ) { }
~ CYmlParser ( void ) { }
2026-04-04 10:28:45 -05:00
//--- Utilidades para los nodos
2026-04-03 21:12:36 -05:00
// Comparar strigns tal cual
// aqui todos los indices tineen que ser validos en el kyaml
bool StrCompare ( int start , int end , int start2 , int end2 ) ;
// val un str interno e i_ son indices internos validos en el yml
bool StrCompare ( const string & val , int i_start , int i_end ) ;
2026-04-04 10:28:45 -05:00
// Obtener step de type
2026-04-03 22:17:13 -05:00
int GetStep ( int idx ) ;
2026-04-04 10:28:45 -05:00
// Desescapaar
string Unescape ( const int start , const int end ) const ;
// Extraer multiline
2026-04-04 08:07:02 -05:00
string ExtractMultiline ( int start , int end , int ident , bool con_saltos ) ;
2026-04-04 10:28:45 -05:00
//--- Parse functions
2026-04-05 11:18:49 -05:00
// (1) String tal cual | (2) Archivo
2026-04-03 21:12:36 -05:00
bool Parse ( const string & yml , int initial_reserve = 128 ) ;
2026-04-05 11:18:49 -05:00
bool ParseFile ( const string & file_name , bool comon_flag , int initial_reserve = 128 ) ;
2026-04-04 20:03:17 -05:00
//---
__forceinline ENUM_YML_PARSER_LAST_ERR LastErr ( ) const { return m_last_err ; }
2026-04-04 10:28:45 -05:00
//---
2026-04-04 20:03:17 -05:00
CYmlNode GetRoot ( ) ;
//--- Utiliadades
void PrintCintaTypes ( ) ;
2026-04-03 21:12:36 -05:00
} ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CYmlParser ::Init ( void )
{
2026-04-04 20:03:17 -05:00
//---
2026-04-03 21:12:36 -05:00
m_yml_pos = 0 ;
m_last_err = WRONG_VALUE ;
2026-04-05 06:57:19 -05:00
m_yml_ident_chars = 0 ;
2026-04-03 21:12:36 -05:00
m_values_anchors_prohibidos_pos = 0 ;
2026-04-05 22:25:16 -05:00
m_cinta_pos = 0 ; //ArrayResize(m_cinta, 0); esto lo debera reservar la cinta
2026-04-03 21:12:36 -05:00
//--- posiciones
for ( int i = 0 ; i < 64 ; i + + )
{
m_anchors_posciones [ i ] [ 0 ] = 0 ;
}
2026-04-04 10:28:45 -05:00
//---
2026-04-04 16:19:18 -05:00
if ( g_yml_hex_init )
return ;
2026-04-04 10:28:45 -05:00
//---
2026-04-04 16:19:18 -05:00
ArrayInitialize ( g_yml_hex , 0xFF ) ; // 0xFF = invalido
for ( uchar c = ' 0 ' ; c < = ' 9 ' ; c + + )
g_yml_hex [ c ] = c - ' 0 ' ;
for ( uchar c = ' a ' ; c < = ' f ' ; c + + )
g_yml_hex [ c ] = c - ' a ' + 10 ;
for ( uchar c = ' A ' ; c < = ' F ' ; c + + )
g_yml_hex [ c ] = c - ' A ' + 10 ;
2026-04-04 10:28:45 -05:00
//---
2026-04-04 16:19:18 -05:00
g_yml_hex_init = true ;
}
2026-04-04 10:28:45 -05:00
2026-04-04 16:19:18 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : Parse ( const string & yml , int initial_reserve = 128 )
{
2026-04-04 10:28:45 -05:00
//---
2026-04-04 16:19:18 -05:00
m_yml_len = StringLen ( yml ) ;
StringToShortArray ( yml , m_yml , 0 , m_yml_len ) ; // omitimos el \0
2026-04-04 20:03:17 -05:00
m_cinta_reserve = ArrayResize ( m_cinta , : : fmax ( initial_reserve , YML_MIN_INITIAL_RESERVE ) ) ;
2026-04-04 10:28:45 -05:00
//---
return InternalParse ( ) ;
}
2026-04-03 21:12:36 -05:00
2026-04-05 11:18:49 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ParseFile ( const string & file_name , bool comon_flag , int initial_reserve = 128 )
{
//---
const int fh = FileOpen ( file_name , FILE_READ | FILE_BIN ) ;
if ( fh = = INVALID_HANDLE )
{
m_last_err = YML_PARSER_ERR_OPEN_FILE ;
return false ;
}
StringToShortArray ( FileReadString ( fh , int ( FileSize ( fh ) ) ) , m_yml ) ;
//---
if ( m_yml [ 0 ] = = 0xFEFF ) // check si el primero es boom
m_yml [ 0 ] = ' \n ' ;
//---
m_yml_len = ArraySize ( m_yml ) ;
m_cinta_reserve = ArrayResize ( m_cinta , : : fmax ( initial_reserve , YML_MIN_INITIAL_RESERVE ) ) ;
//---
return InternalParse ( ) ;
}
2026-04-03 21:12:36 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-04 16:19:18 -05:00
bool CYmlParser : : InternalParse ( void )
2026-04-03 21:12:36 -05:00
{
2026-04-04 16:19:18 -05:00
Init ( ) ;
2026-04-03 21:12:36 -05:00
//---
2026-04-05 11:18:49 -05:00
//m_yml_ident_chars = 0;
2026-04-05 22:25:16 -05:00
if ( m_yml_len < 1 )
2026-04-04 16:19:18 -05:00
{
2026-04-05 22:25:16 -05:00
return false ;
}
2026-04-04 16:19:18 -05:00
2026-04-05 22:25:16 -05:00
//---
if ( m_yml [ m_yml_pos ] ! = ' \n ' ) // Si no es\n entonces no se podnra auto deberemos de hacerlo
m_yml_ident_chars = -1 ;
2026-04-04 16:19:18 -05:00
2026-04-05 22:25:16 -05:00
//---
m_aument_ident_in_next_call = true ;
2026-04-04 10:28:45 -05:00
//---
2026-04-05 06:57:19 -05:00
if ( ! ParseBlock ( ) ) // -1 para que el ident base no salga
2026-04-04 16:19:18 -05:00
return false ;
//--- true exito
return true ;
2026-04-04 10:28:45 -05:00
}
2026-04-04 16:19:18 -05:00
2026-04-04 10:28:45 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-05 06:57:19 -05:00
bool CYmlParser : : ParseBlock ( )
2026-04-04 10:28:45 -05:00
{
//---
2026-04-05 22:25:16 -05:00
// Nota: ahora miosmo estamos en el\n o first char de lobuqe implicito
2026-04-04 16:19:18 -05:00
//---
2026-04-05 22:25:16 -05:00
//Print("CALLLLLLLLLLLLLLLLLLLLLLLLLLLLL");
if ( m_yml [ m_yml_pos ] = = ' \n ' )
2026-04-04 16:19:18 -05:00
{
2026-04-05 22:25:16 -05:00
m_yml_pos + + ;
m_yml_ident_chars = m_cinta_pos = = 0 ? -1 : 0 ;
2026-04-04 16:19:18 -05:00
}
2026-04-05 22:25:16 -05:00
2026-04-04 16:19:18 -05:00
//---
ENUM_YML_CLASIFIER_TYPE_VAL token_type = WRONG_VALUE ;
2026-04-05 22:25:16 -05:00
//---
int count = 0 ;
const int ident_padre = m_yml_ident_chars ;
int hijo_ident = -1 ;
if ( m_aument_ident_in_next_call )
{
m_yml_ident_chars + + ;
m_aument_ident_in_next_call = false ;
}
//Print("LOCKED IDENT: ", locked_ident);
2026-04-04 16:19:18 -05:00
//---
ReserveCinta ( 1 ) ;
const int curr_pos_cinta = m_cinta_pos + + ; // aqui se ubicara el arr (tipo | numero elementos)
2026-04-03 21:12:36 -05:00
//---
while ( m_yml_pos < m_yml_len )
{
//--- Medir idetnacion de esta linea
2026-04-05 22:25:16 -05:00
// Print("Char BLOCK INIT: '", ShortToString(m_yml[m_yml_pos]), "' | Pos: ", m_yml_pos, " | Current ident: ", m_yml_ident_chars);
2026-04-03 21:12:36 -05:00
bool is = false ;
while ( m_yml_pos < m_yml_len )
{
if ( m_yml [ m_yml_pos ] = = ' \n ' )
{
break ;
}
2026-04-05 22:25:16 -05:00
if ( CYmlClass_IsNorFilterChar ( m_yml [ m_yml_pos ] ) )
2026-04-03 21:12:36 -05:00
{
is = true ;
break ;
}
m_yml_pos + + ;
2026-04-05 06:57:19 -05:00
m_yml_ident_chars + + ;
2026-04-03 21:12:36 -05:00
}
//--- En caso no haya idtenacion estamos en \n avanzmao sluego del
if ( m_yml_pos > = m_yml_len )
{
break ;
}
2026-04-04 16:19:18 -05:00
if ( ! is ) // Salio por salto de linea entonces buscamos la siguiente
2026-04-03 21:12:36 -05:00
{
2026-04-05 06:57:19 -05:00
m_yml_ident_chars = 0 ;
2026-04-03 21:12:36 -05:00
m_yml_pos + + ;
continue ;
}
2026-04-04 16:19:18 -05:00
2026-04-03 21:12:36 -05:00
//--- Revisamo comentarios
if ( m_yml [ m_yml_pos ] = = ' # ' ) // el primer char es comentarios salimos
{
CYmlClass_AvanzarHastaLaSiguienteChar ( ' \n ' )
m_yml_pos + + ; // primer char
2026-04-05 06:57:19 -05:00
m_yml_ident_chars = 0 ;
2026-04-03 21:12:36 -05:00
continue ;
}
2026-04-04 16:19:18 -05:00
//---
2026-04-05 22:25:16 -05:00
if ( m_yml_ident_chars < = ident_padre )
2026-04-04 16:19:18 -05:00
{
break ;
}
2026-04-05 22:25:16 -05:00
if ( hijo_ident = = -1 )
{
hijo_ident = m_yml_ident_chars ;
}
else
if ( m_yml_ident_chars < hijo_ident )
break ;
else
if ( m_yml_ident_chars > hijo_ident )
{
m_last_err = YML_PARSER_ERR_INDENTACION_INCORRECTA ;
return false ;
}
//---
// Print("Char BLOCK END: ", ShortToString(m_yml[m_yml_pos]), " Pos ", m_yml_pos, " Type: ",
// EnumToString(token_type), " Current ident: ", m_yml_ident_chars, " Hijo id: ", hijo_ident);
2026-04-04 16:19:18 -05:00
//---
2026-04-04 20:03:17 -05:00
bool has_k = false ;
2026-04-04 16:19:18 -05:00
2026-04-03 21:12:36 -05:00
//---
if ( m_yml [ m_yml_pos ] = = ' - ' )
{
2026-04-04 16:19:18 -05:00
if ( m_yml [ m_yml_pos + 1 ] = = ' \n ' )
{
// Mal formacion hay -\n tambien no creo que -\n sea key valida?¿ no lo creo.. asi que giual para ambos
m_last_err = YML_PARSER_ERR_ITEM_LISTA_VACIO ;
2026-04-03 21:12:36 -05:00
return false ;
2026-04-04 16:19:18 -05:00
}
else
if ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos + 1 ] ) ) // Espacio
{
//---
if ( token_type = = WRONG_VALUE ) // Solo si no esta seteado
{
2026-04-05 22:25:16 -05:00
token_type = YML_CLASIFIER_TOKEN_TYPE_ARR ;
2026-04-04 16:19:18 -05:00
}
2026-04-05 22:25:16 -05:00
else
if ( token_type ! = YML_CLASIFIER_TOKEN_TYPE_ARR )
{
m_last_err = YML_PARSER_ERR_BLOCK_SE_ESPERABA_UNA_LISTA ;
return false ;
}
2026-04-04 16:19:18 -05:00
//---
2026-04-05 22:25:16 -05:00
// Print(ShortToString(m_yml[m_yml_pos]));
// Print(ShortToString(m_yml[m_yml_pos + 1]));
// Print(ShortToString(m_yml[m_yml_pos + 2]));
2026-04-04 16:19:18 -05:00
m_yml_pos + = 2 ; // [-][" "] nos ubicaremos justo en el valor
2026-04-05 22:25:16 -05:00
//---
2026-04-04 16:19:18 -05:00
//... has_k
//---
2026-04-05 22:25:16 -05:00
if ( m_yml [ m_yml_pos ] = = ' ? ' & & m_yml [ m_yml_pos + 1 ] = = ' ' )
2026-04-04 16:19:18 -05:00
{
2026-04-05 22:25:16 -05:00
for ( int i = m_yml_pos ; i < m_yml_len ; i + + )
2026-04-04 16:19:18 -05:00
{
2026-04-05 22:25:16 -05:00
if ( m_yml [ i ] = = ' : ' & & i + 1 < m_yml_len & & m_yml [ i + 1 ] < 33 )
{
has_k = true ;
break ;
}
}
}
else
{
for ( int i = m_yml_pos ; i < m_yml_len & & m_yml [ i ] ! = ' \n ' ; i + + )
{
if ( m_yml [ i ] = = ' : ' & & i + 1 < m_yml_len & & m_yml [ i + 1 ] < 33 )
{
has_k = true ;
break ;
}
2026-04-04 16:19:18 -05:00
}
}
2026-04-05 06:57:19 -05:00
2026-04-05 22:25:16 -05:00
//---
// Print(ShortToString(m_yml[m_yml_pos]));
2026-04-05 06:57:19 -05:00
//---
if ( has_k )
{
2026-04-05 22:25:16 -05:00
m_aument_ident_in_next_call = true ;
m_yml_ident_chars + + ; // Hasta el first value
// m_yml_pos--; // Esto debido a que ahora mismo estaresmos en el
// key entonces al llegar lo aumenta en 1 asi volveremos a estar donde
// estabamos
2026-04-05 06:57:19 -05:00
// Es un array y tiene key generamos bloque implicito
if ( ! ParseBlock ( ) )
return false ;
2026-04-05 22:25:16 -05:00
//---
count + + ;
continue ;
2026-04-05 06:57:19 -05:00
}
2026-04-04 16:19:18 -05:00
}
else
{
2026-04-04 20:03:17 -05:00
has_k = true ;
2026-04-04 16:19:18 -05:00
if ( token_type = = WRONG_VALUE ) // Solo si no esta seteado
{
2026-04-05 22:25:16 -05:00
token_type = YML_CLASIFIER_TOKEN_TYPE_OBJ ;
2026-04-04 16:19:18 -05:00
}
2026-04-05 22:25:16 -05:00
else
if ( token_type ! = YML_CLASIFIER_TOKEN_TYPE_OBJ )
{
m_last_err = YML_PARSER_ERR_BLOCK_SE_ESPERABA_UNA_KEY ;
return false ;
}
2026-04-04 16:19:18 -05:00
}
2026-04-03 21:12:36 -05:00
}
2026-04-04 20:03:17 -05:00
else
{
has_k = true ;
if ( token_type = = WRONG_VALUE ) // Solo si no esta seteado
{
2026-04-05 22:25:16 -05:00
token_type = YML_CLASIFIER_TOKEN_TYPE_OBJ ;
2026-04-04 20:03:17 -05:00
}
2026-04-05 22:25:16 -05:00
else
if ( token_type ! = YML_CLASIFIER_TOKEN_TYPE_OBJ )
{
m_last_err = YML_PARSER_ERR_BLOCK_SE_ESPERABA_UNA_KEY ;
return false ;
}
2026-04-04 20:03:17 -05:00
}
// else nada segurmante es un key como "-hola"
2026-04-04 16:19:18 -05:00
2026-04-03 21:12:36 -05:00
//---
2026-04-04 16:19:18 -05:00
if ( has_k )
2026-04-03 21:12:36 -05:00
{
2026-04-04 16:19:18 -05:00
int start , end ;
bool scape ;
if ( ! ProccesKey ( start , end , scape ) )
return false ;
// Nos deja justo en :
m_yml_pos + + ; //justo luego del :
//---
ReserveCinta ( 2 ) ;
//---
uint hash = 2166136261 ; // offset basis FNV-1a 32bit
for ( int i = start ; i < = end ; i + + )
{
hash ^ = ( uint ) m_yml [ i ] ;
hash * = 16777619 ; // FNV prime 32bit
}
//---
2026-04-05 22:25:16 -05:00
//Print(m_cinta_pos, " | Real size: " , ArraySize(m_cinta));
2026-04-04 16:19:18 -05:00
m_cinta [ m_cinta_pos + + ] = long ( YML_CLASIFIER_TOKEN_TYPE_KEY ) | long ( scape < < YMLPARSER_BIT_END_TYPE ) | long ( hash ) < < YMLPARSER_KEY_BIT_INIT_HASH ;
m_cinta [ m_cinta_pos + + ] = long ( start ) < < 32 | long ( end ) ; // en el byte 2 ubicaremos el start y end (start en los 32 bits izquieda) y end en el de la derecha
2026-04-03 21:12:36 -05:00
}
//---
2026-04-05 06:57:19 -05:00
if ( ! ProccesVal ( ) )
2026-04-04 16:19:18 -05:00
return false ;
2026-04-03 21:12:36 -05:00
//---
2026-04-04 16:19:18 -05:00
count + + ;
}
//---
2026-04-05 22:25:16 -05:00
//Print("POs: ", curr_pos_cinta, " Count: ", count);
2026-04-04 16:19:18 -05:00
if ( token_type ! = WRONG_VALUE )
{
m_cinta [ curr_pos_cinta ] = long ( token_type )
| long ( count ) < < YMLPARSER_BIT_END_TYPE
| long ( m_cinta_pos ) < < YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS ;
2026-04-03 21:12:36 -05:00
}
2026-04-04 16:19:18 -05:00
else
m_cinta [ curr_pos_cinta ] = YML_CLASIFIER_TOKEN_TYPE_NULL ;
// Nul dado que esun
/*
hola : \ n
vlaor : # otro token ya
* /
2026-04-03 21:12:36 -05:00
//---
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ENUM_YML_TOKEN_STRUCTURE CYmlParser : : ObtenerTipoVal ( )
{
//---
while ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) )
{
if ( m_yml [ m_yml_pos ] = = ' \n ' )
break ; // salimos
m_yml_pos + + ;
}
//---
switch ( m_yml [ m_yml_pos ] )
{
case ' \n ' :
return YML_TOKEN_TYPE_BLOCK ;
case ' [ ' :
return YML_TOKEN_TYPE_LIST_INLINE ;
case ' { ' :
return YML_TOKEN_TYPE_OBJ_INLINE ;
case ' | ' :
return YML_TOKEN_TYPE_MULTILINE_CON ;
case ' > ' :
return YML_TOKEN_TYPE_MULTILINE_SIN ;
case ' & ' :
return YML_TOKEN_TYPE_REF_CREATE ;
case ' * ' :
return YML_TOKEN_TYPE_REF_USE ;
case ' " ' :
return YML_TOKEN_TYPE_SCALAR_QUOTED ;
default :
return YML_TOKEN_TYPE_SCALAR ;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CYmlParser : : ReserveCinta ( const int size )
{
if ( m_cinta_pos + size > = m_cinta_reserve )
{
m_cinta_reserve + = ( size < < 1 ) ;
ArrayResize ( m_cinta , m_cinta_reserve ) ;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ProccesQuoted ( )
{
// Nota:
// Ahora mismo m_yml_pos = " es el incio de comiila vale
//---
const int start = + + m_yml_pos ;
//--- String
while ( m_yml_pos < m_yml_len & & m_yml [ m_yml_pos ] ! = ' \n ' )
{
2026-04-05 22:25:16 -05:00
if ( m_yml [ m_yml_pos ] = = ' \\ ' )
2026-04-03 21:12:36 -05:00
{
2026-04-05 22:25:16 -05:00
m_yml_pos + = m_yml [ m_yml_pos + 1 ] = = ' " ' ? 2 : 1 ;
2026-04-03 21:12:36 -05:00
continue ;
}
//---
if ( m_yml [ m_yml_pos ] = = ' " ' )
break ;
//---
m_yml_pos + + ;
}
//---
if ( m_yml [ m_yml_pos ] ! = ' " ' )
{
m_last_err = YML_PARSER_ERR_NO_COMILLAS ;
return false ;
}
const int end = m_yml_pos - 1 ;
m_yml_pos + + ; // Luego del "
2026-04-06 09:56:37 -05:00
//Print("Escapar: " , ShortArrayToString(m_yml,start,(end - start) + 1));
2026-04-03 21:12:36 -05:00
//---
ReserveCinta ( 2 ) ;
m_cinta [ m_cinta_pos + + ] = ( long ) YML_CLASIFIER_TOKEN_TYPE_STR | ( ( long ) 1 < < YMLPARSER_BIT_END_TYPE ) ; // los strigns siempr se escapan
m_cinta [ m_cinta_pos + + ] = long ( start ) < < 32 | long ( end ) ;
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ParseInlineArr ( )
{
//---
// Nota se nos deja justo en [
//---
ReserveCinta ( 1 ) ; // ahora mismo podemos estar al limite m_cinta_pos = size
const int curr_pos_cinta = ( m_cinta_pos + + ) ; // aqui se ubicara el arr (tipo | numero elementos)
int count = 0 ;
m_yml_pos + + ; // Luiego dewl [
//---
while ( m_yml_pos < m_yml_len )
{
//---
// En caso sea un char filter o \n o , saltamos
while ( m_yml_pos < m_yml_len & & ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) | | m_yml [ m_yml_pos ] = = ' , ' ) )
m_yml_pos + + ;
//---
if ( m_yml_pos > = m_yml_len )
return false ; // no tiene elemtnos
//---
if ( m_yml [ m_yml_pos ] = = ' ] ' )
{
m_yml_pos + + ; // Lo dejamos fuera
break ;
}
//---
2026-04-04 20:03:17 -05:00
if ( ! ProccesValArrOrObj ( ' ] ' ) ) // esto nos deja en , (aqui no se permiten bloques)
2026-04-03 21:12:36 -05:00
return false ; // error al procesar
//---
count + + ; // nuevo elemento
}
//---
// 4 bits para tipo | 28 bits de count (casi 226 M creo que eso es un monton de items paraun arr) | 32bits para el closingpos
m_cinta [ curr_pos_cinta ] = long ( YML_CLASIFIER_TOKEN_TYPE_ARR )
| long ( count ) < < YMLPARSER_BIT_END_TYPE
2026-04-03 22:17:13 -05:00
| long ( m_cinta_pos ) < < YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS ;
2026-04-03 21:12:36 -05:00
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ParseInlineObj ( )
{
//---
// Nota se nos deja justo en {
//---
ReserveCinta ( 1 ) ; // ahora mismo podemos estar al limite m_cinta_pos = size
const int curr_pos_cinta = m_cinta_pos + + ; // aqui se ubicara el arr (tipo | numero elementos)
int count = 0 ;
m_yml_pos + + ; // Luiego dewl {
//---
while ( m_yml_pos < m_yml_len )
{
//--- Medir idetnacion de esta linea
while ( m_yml_pos < m_yml_len & & ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) | | m_yml [ m_yml_pos ] = = ' , ' ) )
m_yml_pos + + ;
//---
if ( m_yml_pos > = m_yml_len )
{
m_last_err = YML_PARSER_ERR_OBJ_MALFORMADO ;
return false ;
}
//---
if ( m_yml [ m_yml_pos ] = = ' } ' )
{
m_yml_pos + + ;
break ;
}
//--- Revisamo comentarios
if ( m_yml [ m_yml_pos ] = = ' # ' ) // el primer char es comentarios salimos
{
CYmlClass_AvanzarHastaLaSiguienteChar ( ' \n ' )
m_yml_pos + + ; // primer char
continue ;
}
//---
int start , end ;
bool scape ;
if ( ! ProccesKey ( start , end , scape ) )
{
// Este ya da su err
return false ;
}
// Nos deja justo en :
m_yml_pos + + ; //justo luego del :
//---
ReserveCinta ( 2 ) ;
uint hash = 2166136261 ; // offset basis FNV-1a 32bit
for ( int i = start ; i < = end ; i + + )
{
hash ^ = ( uint ) m_yml [ i ] ;
hash * = 16777619 ; // FNV prime 32bit
}
// asumimos que el (tipo no pasa de 8 bits) luego los otro 8 bits lo cure el scape
m_cinta [ m_cinta_pos + + ] = long ( YML_CLASIFIER_TOKEN_TYPE_KEY ) | long ( scape ) < < YMLPARSER_BIT_END_TYPE | long ( hash ) < < YMLPARSER_KEY_BIT_INIT_HASH ;
m_cinta [ m_cinta_pos + + ] = long ( start ) < < 32 | long ( end ) ; // en el byte 2 ubicaremos el start y end (start en los 32 bits izquieda) y end en el de la derecha
//---
2026-04-04 20:03:17 -05:00
if ( ! ProccesValArrOrObj ( ' } ' ) )
2026-04-03 21:12:36 -05:00
{
// Este ya da su err
return false ;
}
//---
count + + ; // nuevo elemento
}
//---
m_cinta [ curr_pos_cinta ] = long ( YML_CLASIFIER_TOKEN_TYPE_OBJ )
| long ( count ) < < YMLPARSER_BIT_END_TYPE
2026-04-03 22:17:13 -05:00
| long ( m_cinta_pos ) < < YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS ; // el tipo solo ocupra 8 bits el resto para el counPt
2026-04-03 21:12:36 -05:00
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ProccesScalarVal ( )
{
//--- Inicio de commila (str)
if ( m_yml [ m_yml_pos ] = = ' " ' )
{
return ProccesQuoted ( ) ;
}
//--- True
if ( m_yml [ m_yml_pos ] = = ' t ' )
{
if ( m_yml_pos + 4 < m_yml_len & & m_yml [ m_yml_pos + 1 ] = = ' r ' & & m_yml [ m_yml_pos + 2 ] = = ' u ' & & m_yml [ m_yml_pos + 3 ] = = ' e '
& & CYmlClass_IsFilterChar ( m_yml [ m_yml_pos + 4 ] ) )
{
ReserveCinta ( 1 ) ;
m_cinta [ m_cinta_pos + + ] = ( long ) YML_CLASIFIER_TOKEN_TYPE_BOOL | ( ( long ) 1 < < YMLPARSER_BIT_END_TYPE ) ;
m_yml_pos + = 4 ;
return true ;
}
return ProccesScalarPlain ( ) ;
}
//--- False
if ( m_yml [ m_yml_pos ] = = ' f ' )
{
if ( m_yml_pos + 5 < m_yml_len & & m_yml [ m_yml_pos + 1 ] = = ' a ' & & m_yml [ m_yml_pos + 2 ] = = ' l ' & & m_yml [ m_yml_pos + 3 ] = = ' s '
& & m_yml [ m_yml_pos + 4 ] = = ' e ' & & CYmlClass_IsFilterChar ( m_yml [ m_yml_pos + 5 ] ) )
{
ReserveCinta ( 1 ) ;
2026-04-04 16:19:18 -05:00
m_cinta [ m_cinta_pos + + ] = ( long ) YML_CLASIFIER_TOKEN_TYPE_BOOL ; // no hace falta // | ((long)0 << YMLPARSER_BIT_END_TYPE);
2026-04-03 21:12:36 -05:00
m_yml_pos + = 5 ;
return true ;
}
return ProccesScalarPlain ( ) ;
}
//--- Null
// Signo
if ( m_yml [ m_yml_pos ] = = ' ~ ' )
{
if ( m_yml_pos + 1 < m_yml_len & & CYmlClass_IsFilterChar ( m_yml [ m_yml_pos + 1 ] ) )
{
ReserveCinta ( 1 ) ;
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_NULL ;
m_yml_pos + + ; // Al espacio
return true ;
}
return ProccesScalarPlain ( ) ;
}
// Palabra
if ( ( m_yml [ m_yml_pos ] = = ' n ' | | m_yml [ m_yml_pos ] = = ' N ' ) & & m_yml_pos + 4 < m_yml_len )
{
if ( ( m_yml [ m_yml_pos + 1 ] = = ' u ' | | m_yml [ m_yml_pos + 1 ] = = ' U ' ) & & ( m_yml [ m_yml_pos + 2 ] = = ' l ' | | m_yml [ m_yml_pos + 2 ] = = ' L ' )
& & ( m_yml [ m_yml_pos + 3 ] = = ' l ' | | m_yml [ m_yml_pos + 3 ] = = ' L ' ) & & CYmlClass_IsFilterChar ( m_yml [ m_yml_pos + 4 ] ) )
{
ReserveCinta ( 1 ) ;
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_NULL ;
m_yml_pos + = 4 ;
return true ;
}
return ProccesScalarPlain ( ) ;
}
//--- numeros
//--- nan e inf
const bool is_punto = m_yml [ m_yml_pos ] = = ' . ' ;
if ( is_punto ) // .nan y .inf
{
if ( m_yml_pos + 4 < m_yml_len )
{
const bool is = CYmlClass_IsFilterChar ( m_yml [ m_yml_pos + 4 ] ) ;
//--- nan
int res = m_yml [ m_yml_pos + 1 ] = = ' n ' ? 32 : ( m_yml [ m_yml_pos + 1 ] = = ' N ' ? 0 : -1 ) ;
if ( res ! = -1 )
{
if ( is & &
( m_yml [ m_yml_pos + 2 ] - res ) = = ' A ' & &
( m_yml [ m_yml_pos + 3 ] - res ) = = ' N ' )
{
m_yml_pos + = 4 ;
LongToDbl un ;
un . d = double ( " nan " ) ;
ReserveCinta ( 2 ) ;
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_DBL ;
m_cinta [ m_cinta_pos + + ] = un . l ;
return true ;
}
return ProccesScalarPlain ( ) ;
}
//--- inf
res = m_yml [ m_yml_pos + 1 ] = = ' i ' ? 32 : ( m_yml [ m_yml_pos + 1 ] = = ' I ' ? 0 : -1 ) ;
if ( res ! = -1 )
{
if ( is & &
( m_yml [ m_yml_pos + 2 ] - res ) = = ' N ' & &
( m_yml [ m_yml_pos + 3 ] - res ) = = ' F ' )
{
m_yml_pos + = 4 ;
LongToDbl un ;
un . d = double ( " inf " ) ;
ReserveCinta ( 2 ) ;
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_DBL ;
m_cinta [ m_cinta_pos + + ] = un . l ;
return true ;
}
return ProccesScalarPlain ( ) ;
}
}
// Va a otro lado al principal
}
//--- -.inf
const bool is_signo = m_yml [ m_yml_pos ] = = ' - ' ;
if ( is_signo )
{
if ( m_yml_pos + 5 < m_yml_len & & m_yml [ m_yml_pos + 1 ] = = ' . ' )
{
//--- inf
const int res = m_yml [ m_yml_pos + 2 ] = = ' i ' ? 32 : ( m_yml [ m_yml_pos + 2 ] = = ' I ' ? 0 : -1 ) ;
if ( res ! = -1 )
{
if ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos + 5 ] ) & &
( m_yml [ m_yml_pos + 3 ] - res ) = = ' N ' & &
( m_yml [ m_yml_pos + 4 ] - res ) = = ' F ' )
{
m_yml_pos + = 5 ;
2026-04-04 16:19:18 -05:00
LongToDbl un ;
un . d = double ( " -inf " ) ;
ReserveCinta ( 2 ) ;
m_cinta [ m_cinta_pos + + ] = ( long ) YML_CLASIFIER_TOKEN_TYPE_DBL ;
m_cinta [ m_cinta_pos + + ] = un . l ;
return true ;
}
return ProccesScalarPlain ( ) ;
}
}
// puede haber algo como -.05 (por eso lo dejamos)
}
//---
2026-04-04 20:03:17 -05:00
const bool is_mas = m_yml [ m_yml_pos ] = = ' + ' ;
if ( CYmlClas_IsDigit ( m_yml [ m_yml_pos ] ) | | is_signo | | is_mas | | is_punto )
2026-04-04 16:19:18 -05:00
{
//---
// 1 = (punto) | 2 = uso de E | 4 = hex
uint8_t f = 0 ;
const int start = m_yml_pos ;
int sing = 1 ;
//--- Check inicial
2026-04-04 20:03:17 -05:00
if ( is_mas )
2026-04-04 16:19:18 -05:00
{
m_yml_pos + + ;
}
//---
else
if ( is_signo )
{
sing = -1 ;
m_yml_pos + + ;
}
//---
else
if ( is_punto )
{
f | = 1 ;
m_yml_pos + + ;
}
else
if ( m_yml [ m_yml_pos ] = = ' 0 ' & & m_yml_pos + 1 < m_yml_len & & ( m_yml [ m_yml_pos + 1 ] = = ' X ' | | m_yml [ m_yml_pos + 1 ] = = ' x ' ) )
{
f = 4 ;
m_yml_pos + = 2 ;
}
else
if ( ! CYmlClas_IsDigit ( m_yml [ m_yml_pos ] ) )
{
return ProccesScalarPlain ( ) ;
}
//--- Chech iterativo
const int prev = m_yml_pos ;
bool is_valid = true ;
2026-04-05 22:25:16 -05:00
while ( m_yml_pos < m_yml_len & & CYmlClass_IsNorFilterChar ( m_yml [ m_yml_pos ] ) )
2026-04-04 16:19:18 -05:00
{
const ushort c = m_yml [ m_yml_pos ] ;
//---
if ( f = = 4 & & ( c > 255 | | g_yml_hex [ c ] = = 0xFF ) )
{
// Solo 0-9 a-f A-F validos luego del 0x
is_valid = false ;
break ;
}
else
{
if ( ( f & 1 ) = = 0 & & c = = ' . ' )
f | = 1 ;
else
if ( ( f & 2 ) = = 0 & & ( c = = ' e ' | | c = = ' E ' ) )
{
f | = 2 ;
}
else
if ( ! CYmlClas_IsDigit ( c ) )
{
is_valid = false ;
break ;
}
}
m_yml_pos + + ;
}
//---
if ( ! is_valid | | m_yml_pos = = prev )
{
m_yml_pos = start ; // rollback
return ProccesScalarPlain ( ) ;
}
//---
const int end = m_yml_pos - 1 ;
//--- Reservamos
ReserveCinta ( 2 ) ;
//---
2026-04-04 20:03:17 -05:00
if ( f & & f < = 3 )
2026-04-04 16:19:18 -05:00
{
//---
string temp = " " ;
StringSetLength ( temp , ( end - start ) + 1 ) ;
int k = 0 ;
for ( int i = start ; i < = end ; i + + )
{
temp .SetChar ( k + + , m_yml [ i ] ) ;
}
//---
LongToDbl un ;
un . d = double ( temp ) ;
2026-04-05 22:25:16 -05:00
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_DBL ;
2026-04-04 16:19:18 -05:00
m_cinta [ m_cinta_pos + + ] = un . l ;
}
else
{
2026-04-05 22:25:16 -05:00
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_INTEGER ;
2026-04-04 16:19:18 -05:00
m_cinta [ m_cinta_pos + + ] = f = = 4 ? FastAtoiHex ( start , end ) : FastAtoi ( start , end , sing ) ;
}
return true ;
}
//---
return ProccesScalarPlain ( ) ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-04 20:03:17 -05:00
bool CYmlParser : : ProccesScalarNoTalCual ( const ushort char_cierre )
2026-04-04 16:19:18 -05:00
{
//--- Inicio de commila (str)
2026-04-04 20:03:17 -05:00
//printf(ShortToString(m_yml[m_yml_pos]));
2026-04-04 16:19:18 -05:00
if ( m_yml [ m_yml_pos ] = = ' " ' )
{
return ProccesQuoted ( ) ;
}
//--- True
if ( m_yml [ m_yml_pos ] = = ' t ' )
{
ReserveCinta ( 1 ) ;
m_cinta [ m_cinta_pos + + ] = ( long ) YML_CLASIFIER_TOKEN_TYPE_BOOL | ( ( long ) 1 < < YMLPARSER_BIT_END_TYPE ) ;
m_yml_pos + = 4 ; //true
return true ;
}
//--- False
if ( m_yml [ m_yml_pos ] = = ' f ' )
{
ReserveCinta ( 1 ) ;
2026-04-05 22:25:16 -05:00
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_BOOL ; // no hace falta // | ((long)0 << YMLPARSER_BIT_END_TYPE);
2026-04-04 16:19:18 -05:00
m_yml_pos + = 5 ; //false
return true ;
}
//--- Null
if ( m_yml [ m_yml_pos ] = = ' n ' | | m_yml [ m_yml_pos ] = = ' N ' | | m_yml [ m_yml_pos ] = = ' ~ ' )
{
ReserveCinta ( 1 ) ;
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_NULL ;
m_yml_pos + = ( m_yml [ m_yml_pos ] = = ' ~ ' ? 1 : 4 ) ; // 1 | null
return true ;
}
//--- numeros
//- .
2026-04-04 20:03:17 -05:00
if ( m_yml [ m_yml_pos ] = = ' . ' | | m_yml [ m_yml_pos ] = = ' - ' | | m_yml [ m_yml_pos ] = = ' + ' | | CYmlClas_IsDigit ( m_yml [ m_yml_pos ] ) ) // inf | nan | -inf
2026-04-04 16:19:18 -05:00
{
bool is_dbl = false ;
int start = m_yml_pos ;
2026-04-04 20:03:17 -05:00
int sing = 1 ;
2026-04-04 16:19:18 -05:00
//--- Corregimos posicion de incio si es (.inf | -.inf | .nan)
if ( + + m_yml_pos > = m_yml_len )
{
m_last_err = YML_PARSER_ERR_SE_HA_SUPERADO_EL_LEN ;
return false ;
}
else
{
if ( m_yml [ m_yml_pos ] = = ' n ' | | m_yml [ m_yml_pos ] = = ' i ' ) // nan | inf
{
start = m_yml_pos ;
2026-04-04 20:03:17 -05:00
is_dbl = true ;
2026-04-04 16:19:18 -05:00
}
2026-04-04 20:03:17 -05:00
else
if ( m_yml [ start ] = = ' - ' )
2026-04-04 16:19:18 -05:00
{
2026-04-04 20:03:17 -05:00
if ( m_yml [ m_yml_pos ] = = ' . ' )
{
if ( + + m_yml_pos > = m_yml_len )
{
m_last_err = YML_PARSER_ERR_SE_HA_SUPERADO_EL_LEN ;
return false ;
}
if ( m_yml [ m_yml_pos ] = = ' i ' )
{
// Ahora mismo esta asi -.i (incorrecto)
// Correcto: .-inf (Start en -)
2026-04-04 16:19:18 -05:00
2026-04-04 20:03:17 -05:00
//---
m_yml [ m_yml_pos - 1 ] = ' - ' ;
m_yml [ start ] = ' . ' ;
2026-04-03 21:12:36 -05:00
2026-04-04 20:03:17 -05:00
//---
start = m_yml_pos - 1 ;
2026-04-04 16:19:18 -05:00
2026-04-04 20:03:17 -05:00
//---
is_dbl = true ; // - inf
}
else
{
m_last_err = YML_PARSER_ERR_NO_SE_PUEDE_USAR_VALORES_PLAIN_EN_ARR_OR_OBJ ;
return false ;
}
}
else
{
sing = -1 ;
start + + ; // aumentamos
}
}
2026-04-03 21:12:36 -05:00
}
2026-04-04 20:03:17 -05:00
//--- Avanzamos hasta el sigueinte: [Fileter char | Final del yml | comma | cierre ]
2026-04-05 22:25:16 -05:00
while ( m_yml_pos < m_yml_len & & CYmlClass_IsNorFilterChar ( m_yml [ m_yml_pos ] ) & & m_yml [ m_yml_pos ] ! = ' , ' & & m_yml [ m_yml_pos ] ! = char_cierre )
2026-04-03 21:12:36 -05:00
{
if ( m_yml [ m_yml_pos ] = = ' . ' | | m_yml [ m_yml_pos ] = = ' e ' | | m_yml [ m_yml_pos ] = = ' E ' )
{
is_dbl = true ;
}
m_yml_pos + + ;
}
const int end = m_yml_pos - 1 ;
2026-04-04 16:19:18 -05:00
2026-04-03 21:12:36 -05:00
//--- Reservamos
ReserveCinta ( 2 ) ;
2026-04-04 20:03:17 -05:00
//printf(ShortToString(m_yml[start]));
2026-04-04 16:19:18 -05:00
//---
2026-04-03 21:12:36 -05:00
if ( is_dbl )
{
LongToDbl un ;
2026-04-04 16:19:18 -05:00
string temp = " " ;
StringSetLength ( temp , ( end - start ) + 1 ) ;
int k = 0 ;
for ( int i = start ; i < = end ; i + + )
{
temp .SetChar ( k + + , m_yml [ i ] ) ;
}
un . d = double ( temp ) ;
2026-04-05 22:25:16 -05:00
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_DBL ;
2026-04-03 21:12:36 -05:00
m_cinta [ m_cinta_pos + + ] = un . l ;
}
else
{
2026-04-05 22:25:16 -05:00
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_INTEGER ;
2026-04-04 16:19:18 -05:00
m_cinta [ m_cinta_pos + + ] = FastAtoi ( start , end , sing ) ;
2026-04-03 21:12:36 -05:00
}
return true ;
}
//---
2026-04-04 20:03:17 -05:00
m_last_err = YML_PARSER_ERR_NO_SE_PUEDE_USAR_VALORES_PLAIN_EN_ARR_OR_OBJ ;
2026-04-04 16:19:18 -05:00
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ProccesScalarPlain ( )
{
const int start = m_yml_pos ;
//---
while ( m_yml_pos < m_yml_len & & m_yml [ m_yml_pos ] ! = ' \n ' )
{
if ( m_yml [ m_yml_pos ] = = ' # ' & & m_yml [ m_yml_pos - 1 ] = = ' ' ) // comentario
break ;
//---
m_yml_pos + + ;
}
//---
// m_yml_pos esta justo en \n
//---
int end = m_yml_pos - 1 ;
while ( CYmlClass_IsFilterChar ( m_yml [ end ] ) )
end - - ;
//---
ReserveCinta ( 2 ) ;
2026-04-05 22:25:16 -05:00
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_STR ; // creo que no hace falta | ((long)0 << YMLPARSER_BIT_END_TYPE); // scape=0 no se escapa raw
2026-04-04 16:19:18 -05:00
m_cinta [ m_cinta_pos + + ] = ( ( long ) start < < 32 ) | ( uint ) end ;
return true ;
2026-04-03 21:12:36 -05:00
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-05 06:57:19 -05:00
bool CYmlParser : : ParseMultiline ( const bool con_saltos )
2026-04-03 21:12:36 -05:00
{
//---
// Nota estamos en el | o > asi que ahora mismo sabemos la idetacino del bloque key
//---
CYmlClass_AvanzarHastaLaSiguienteChar ( ' \n ' )
m_yml_pos + + ;
2026-04-05 06:57:19 -05:00
const int prev_curr_ident = m_yml_ident_chars + 1 ;
int min_value_pos = m_yml_pos + prev_curr_ident ; // Minimo valor es desde m_yml_pos (psocion luego del \n) iden charts mas 1
2026-04-03 21:12:36 -05:00
int start = m_yml_pos ;
int last_salto = m_yml_pos ;
2026-04-05 06:57:19 -05:00
// el ident esd
2026-04-03 21:12:36 -05:00
//---
while ( m_yml_pos < m_yml_len )
{
//---
2026-04-05 22:25:16 -05:00
while ( m_yml_pos < m_yml_len & & CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) )
2026-04-03 21:12:36 -05:00
{
2026-04-05 22:25:16 -05:00
if ( m_yml [ m_yml_pos ] = = ' \n ' )
break ;
m_yml_pos + + ;
m_yml_ident_chars + + ;
2026-04-03 21:12:36 -05:00
}
2026-04-05 22:25:16 -05:00
//---
2026-04-03 21:12:36 -05:00
if ( m_yml [ m_yml_pos ] = = ' \n ' )
{
last_salto = m_yml_pos ;
m_yml_pos + + ;
2026-04-05 06:57:19 -05:00
min_value_pos = m_yml_pos + prev_curr_ident ;
2026-04-05 22:25:16 -05:00
m_yml_ident_chars = 0 ;
2026-04-03 21:12:36 -05:00
continue ;
}
2026-04-05 22:25:16 -05:00
//---
if ( m_yml_pos < min_value_pos ) // fin
{
break ;
}
2026-04-03 21:12:36 -05:00
/*if(is_f)
{
m_yml_pos + + ;
continue ;
} * /
2026-04-05 22:25:16 -05:00
m_yml_pos + + ;
2026-04-03 21:12:36 -05:00
}
//---
2026-04-05 06:57:19 -05:00
// m_yml_pos = last_salto; // dejamos en \n
2026-04-03 21:12:36 -05:00
const int end = last_salto - 1 ; // previo a \n
//---
ReserveCinta ( 2 ) ;
// Nota siempre en el primer long del tape va el tipo y metada simple
2026-04-05 22:25:16 -05:00
// [32 bits para saltos][28 bits para ident][tipo 4 bit]
2026-04-03 21:12:36 -05:00
//
// - simplfiicamos lo de scape dado que no tiene sentido aqui:
2026-04-05 22:25:16 -05:00
m_cinta [ m_cinta_pos + + ] = ( long ) YML_CLASIFIER_TOKEN_TYPE_STR_MULTILINE | long ( prev_curr_ident ) < < YMLPARSER_BIT_END_TYPE | long ( con_saltos ) < < 32 ; // multiline no se escapa
2026-04-03 21:12:36 -05:00
m_cinta [ m_cinta_pos + + ] = long ( start ) < < 32 | ( end ) ;
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ProccesKey ( int & start , int & end , bool & scape )
{
//--- Si tiene ? entonces solo acanzmao shsta el char mas cercano nada mas
2026-04-05 22:25:16 -05:00
// Print("Primer char: ", ShortToString(m_yml[m_yml_pos]));
bool is_complex = false ;
2026-04-03 21:12:36 -05:00
if ( m_yml [ m_yml_pos ] = = ' ? ' & & m_yml [ m_yml_pos + 1 ] = = ' ' )
{
m_yml_pos + = 2 ;
2026-04-05 22:25:16 -05:00
is_complex = true ;
2026-04-03 21:12:36 -05:00
//---
while ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) )
{
if ( m_yml [ m_yml_pos ] = = ' \n ' ) // \n ya no nada?¿salimso
{
m_last_err = YML_PARSER_ERR_KEY_INVALIDA_NO_TIENE_CHARS ;
return false ;
}
m_yml_pos + + ;
}
}
//--- Caso con ""
if ( m_yml [ m_yml_pos ] = = ' " ' )
{
scape = true ;
m_yml_pos + + ;
start = m_yml_pos ;
//---
while ( m_yml_pos < m_yml_len & & m_yml [ m_yml_pos ] ! = ' \n ' )
{
if ( m_yml [ m_yml_pos ] = = ' \\ ' & & m_yml [ m_yml_pos + 1 ] = = ' " ' )
{
m_yml_pos + = 2 ;
continue ;
}
//---
if ( m_yml [ m_yml_pos ] = = ' " ' )
break ;
//---
m_yml_pos + + ;
}
//---
if ( m_yml [ m_yml_pos ] ! = ' " ' )
{
m_last_err = YML_PARSER_ERR_NO_COMILLAS ;
return false ;
}
end = m_yml_pos - 1 ;
m_yml_pos + + ;
//---
while ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) )
{
m_yml_pos + + ; // nota aqui tambien saltamos los \n dado que el : se peude ubuicar abajo del key
}
//---
if ( m_yml [ m_yml_pos ] ! = ' : ' | | m_yml [ m_yml_pos + 1 ] ! = ' ' )
{
m_last_err = YML_PARSER_ERR_KEY_SE_ESPERABA_EL_FIN_KEY ;
return false ;
}
//---
//m_yml_pos += 2; esto esta en duda es que las key no ncesitame te pueden tener valor?¿ osea si pero que
// pasa con los arrays quizas solo debajos de dejar m_ypos en : ?¿
return true ;
}
//--- Caso normal
start = m_yml_pos ;
2026-04-05 22:25:16 -05:00
//Print(ShortToString(m_yml[start]) , " | " , start);
while ( m_yml_pos < m_yml_len )
2026-04-03 21:12:36 -05:00
{
2026-04-05 22:25:16 -05:00
//PrintFormat("Char: '%s' | pos = %d | char = %u", ShortToString(m_yml[m_yml_pos]), m_yml_pos, m_yml[m_yml_pos]);
2026-04-03 21:12:36 -05:00
if ( m_yml [ m_yml_pos ] = = ' # ' & & m_yml [ m_yml_pos - 1 ] = = ' ' ) // comentario
{
m_last_err = YML_PARSER_ERR_KEY_MAL_FORMADA_COMENTARIO_FUE_PRIMERO ;
return false ;
}
//---
2026-04-05 22:25:16 -05:00
if ( m_yml [ m_yml_pos ] = = ' : ' & & ( m_yml [ m_yml_pos + 1 ] < 33 ) ) // keyval
2026-04-03 21:12:36 -05:00
{
2026-04-05 22:25:16 -05:00
// Print("Si");
2026-04-03 21:12:36 -05:00
end = m_yml_pos - 1 ;
//---
while ( CYmlClass_IsFilterChar ( m_yml [ end ] ) )
end - - ; // reducimos end aqui es seguro dado que el val no es \n
//---
// m_yml_pos += 2; lo mismo auque antes
return true ;
}
2026-04-05 22:25:16 -05:00
//---
if ( ! is_complex & & m_yml [ m_yml_pos ] = = ' \n ' ) // solo salir en \n si no es complejo (Si lo es el : se puede ubicar abajo)
{
// Dado que si no es complejo solo se peude "valor:"
// no se peude tener en vairas multilineas
m_last_err = YML_PARSER_ERR_NO_SE_PUEDE_TENER_STR_KEY_EN_VARIAS_LINEAS ;
return false ;
}
2026-04-03 21:12:36 -05:00
//---
m_yml_pos + + ;
}
//---
m_last_err = YML_PARSER_ERR_NO_SE_PUDO_PARSEAR_KEY_CAUSA_DESCONOCIDA ;
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : StrCompare ( int start , int end , int start2 , int end2 )
{
if ( ( end - start ) + 1 ! = ( end2 - start2 ) + 1 )
return false ;
for ( int i = start ; i < = end ; i + + )
{
if ( m_yml [ start2 + + ] ! = m_yml [ i ] )
return false ;
}
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : StrCompare ( const string & val , int i_start , int i_end )
{
const int len = StringLen ( val ) ;
if ( ( i_end - i_start ) + 1 ! = len )
return false ;
int k = 0 ;
for ( int i = i_start ; i < = i_end ; i + + )
{
if ( val [ k + + ] ! = m_yml [ i ] )
return false ;
}
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CYmlParser : : FindRefPositionStart ( const int start , const int end , bool check )
{
//---
uint hash = 2166136261 ; // offset basis FNV-1a 32bit
for ( int i = start ; i < = end ; i + + )
{
hash ^ = ( uint ) m_yml [ i ] ;
hash * = 16777619 ; // FNV prime 32bit
}
hash % = 64 ;
//---
const int size = m_anchors_posciones [ hash ] [ 0 ] ;
for ( int i = 0 ; i < size ; i + + )
{
const int cinta_pos = m_anchors_posciones [ hash ] [ i + 1 ] + 1 ; // siuignte token
const int start_i_ref = int ( m_cinta [ cinta_pos ] > > 32 ) ;
const int end_i_ref = int ( m_cinta [ cinta_pos ] & 0xFFFFFFFF ) ;
// Desempaquetamos
if ( StrCompare ( start_i_ref , end_i_ref , start , end ) )
{
//--- Chekeamos en caso que la ubicacion de este key posicion es prohibi
// osea no se peude usar dadao que se esta en un proce de creacion de referencia
if ( check )
{
for ( int k = 0 ; k < m_values_anchors_prohibidos_pos ; k + + )
{
if ( m_values_anchors_prohibidos [ k ] = = ( short ( hash ) | short ( i + 1 ) < < 8 ) )
{
m_last_err = YML_PARSER_ERR_REFUSE_CIRCULAR ;
return -1 ;
}
}
}
//---
return cinta_pos - 1 ; // previo;
}
}
//---
m_last_err = YML_PARSER_ERR_NO_SE_ENCONTRO_REFNAME_EN_HASHMAP ;
return -1 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : AddToAnchorHash ( const int start , const int end , const int pos_reference )
{
//--- Aplicamos el hash
uint hash = 2166136261 ; // offset basis FNV-1a 32bit
for ( int i = start ; i < = end ; i + + )
{
hash ^ = ( uint ) m_yml [ i ] ;
hash * = 16777619 ; // FNV prime 32bit
}
hash % = 64 ;
//---
const int pos = + + m_anchors_posciones [ hash ] [ 0 ] ;
if ( pos > = 9 )
{
m_last_err = YML_PARSER_ERR_HASHKEY_ANCHOR_HA_SUPERADO_COLISIONES_MAX ;
return false ;
}
m_anchors_posciones [ hash ] [ pos ] = pos_reference ;
//---
m_values_anchors_prohibidos [ m_values_anchors_prohibidos_pos + + ] = short ( hash ) | short ( pos ) < < 8 ;
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-05 06:57:19 -05:00
bool CYmlParser : : ParseRefCreate ( )
2026-04-03 21:12:36 -05:00
{
//---
// Nota ahora mismo estamos en &
2026-04-04 20:25:50 -05:00
/*
name : & anchor
key : |
valore
* /
2026-04-03 21:12:36 -05:00
//---
ReserveCinta ( 2 ) ;
// inciilamente solo alamenca el refence pos
// usaremos lamisma tencina que hicimos con arr y obj
const int pos_cinta_reference = m_cinta_pos + + ;
// ESTO lo haremos luego: solo reservamos una poscioun m_cinta[pos_cinta_reference] = (long)YML_CLASIFIER_TOKEN_TYPE_REFERENCE;
m_yml_pos + + ;
//---
const int start = m_yml_pos ;
while ( m_yml_pos < m_yml_len )
{
if ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) ) // espcaio o \n etc
{
break ;
}
m_yml_pos + + ;
}
if ( start = = m_yml_pos )
{
m_last_err = YML_PARSER_ERR_NOMBRE_DE_REFERENCE_NO_TIENE_CHARS ;
return false ;
}
const int end = m_yml_pos - 1 ;
// ahora mismo pos es \n o espacio etc
if ( ! AddToAnchorHash ( start , end , pos_cinta_reference ) )
return false ;
//---
m_cinta [ m_cinta_pos + + ] = long ( start ) < < 32 | ( end ) ; // incio y fin del nombre DE LA REFERENCIA NO DEL ANCHOR o KEY el key tiene posicion previa
int count = 0 ;
//---
ENUM_YML_CLASIFIER_TYPE_VAL type = YML_CLASIFIER_TOKEN_TYPE_REFERENCE_SIMPLE ;
ENUM_YML_TOKEN_STRUCTURE st_type ;
2026-04-05 06:57:19 -05:00
if ( ! ProccesValForReference ( st_type ) )
2026-04-03 21:12:36 -05:00
{
return false ;
}
if ( st_type = = YML_TOKEN_TYPE_BLOCK )
type = YML_CLASIFIER_TOKEN_TYPE_REFERENCE_COMPLEX ;
//--- posicion final
m_cinta [ pos_cinta_reference ] = long ( type )
2026-04-03 22:17:13 -05:00
| long ( m_cinta_pos ) < < YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS ;
2026-04-03 21:12:36 -05:00
//---
m_values_anchors_prohibidos_pos - - ;
//---
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser : : ParseRefUse ( )
{
//---
// Nota ahora mismo estamos en *
//---
// inciilamente solo alamenca el refence pos
// usaremos lamisma tencina que hicimos con arr y obj
// ESTO lo haremos luego: solo reservamos una poscioun m_cinta[pos_cinta_reference] = (long)YML_CLASIFIER_TOKEN_TYPE_REFERENCE;
m_yml_pos + + ;
//---
const int start = m_yml_pos ;
while ( m_yml_pos < m_yml_len )
{
if ( CYmlClass_IsFilterChar ( m_yml [ m_yml_pos ] ) ) // espcaio o \n etc
{
break ;
}
m_yml_pos + + ;
}
if ( start = = m_yml_pos )
{
m_last_err = YML_PARSER_ERR_NOMBRE_DE_REFERENCE_NO_TIENE_CHARS ;
return false ;
}
const int end = m_yml_pos - 1 ;
const int pos = FindRefPositionStart ( start , end , true ) ;
if ( pos = = -1 )
return false ;
//---
ReserveCinta ( 1 ) ;
2026-04-04 08:07:02 -05:00
//--- Resolucion de punteros la idea es que deje de apuntar a [RefCreate]
// Para que apunte al valor como tal que deberia
int resolved = pos ;
int8_t depth = 0 ;
// Iteracion
while ( depth < YMLPARSER_PTR_MAX_DEPTH )
{
2026-04-04 16:19:18 -05:00
const int pv = resolved + YML_OFFESET_PTR_TO_VAL ; // salta REF_CREATE(1) + NAME(1) ahor amismo nos ubiramoes en el primer pos cinta
2026-04-04 08:07:02 -05:00
if ( int ( m_cinta [ pv ] & 0xF ) ! = YML_CLASIFIER_TOKEN_TYPE_PTR )
break ; // Ya no es ptr se termino
resolved = int ( m_cinta [ pv ] > > YMLPARSER_BIT_END_TYPE ) ;
depth + + ;
}
//---
if ( depth = = YMLPARSER_PTR_MAX_DEPTH )
{
m_last_err = YML_PARSER_ERR_LA_RECURSION_DE_PTR_HA_SUPERADO_LA_PROFUNDIDA ;
return false ;
}
//---
m_cinta [ m_cinta_pos + + ] = YML_CLASIFIER_TOKEN_TYPE_PTR | long ( resolved ) < < YMLPARSER_BIT_END_TYPE ;
2026-04-03 21:12:36 -05:00
//---
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Procesar valor normal (Se acepta todo)
2026-04-05 06:57:19 -05:00
bool CYmlParser : : ProccesVal ( )
2026-04-03 21:12:36 -05:00
{
// En teroai pos apunta al valor luego del :
//---
2026-04-04 20:03:17 -05:00
const ENUM_YML_TOKEN_STRUCTURE type = ObtenerTipoVal ( ) ;
2026-04-03 21:12:36 -05:00
//---
switch ( type )
{
case YML_TOKEN_TYPE_BLOCK :
2026-04-05 06:57:19 -05:00
return ParseBlock ( ) ;
2026-04-03 21:12:36 -05:00
case YML_TOKEN_TYPE_LIST_INLINE :
return ParseInlineArr ( ) ;
case YML_TOKEN_TYPE_OBJ_INLINE :
return ParseInlineObj ( ) ;
case YML_TOKEN_TYPE_MULTILINE_CON :
2026-04-05 06:57:19 -05:00
return ParseMultiline ( true ) ;
2026-04-03 21:12:36 -05:00
case YML_TOKEN_TYPE_MULTILINE_SIN :
2026-04-05 06:57:19 -05:00
return ParseMultiline ( false ) ;
2026-04-03 21:12:36 -05:00
case YML_TOKEN_TYPE_REF_CREATE :
2026-04-05 06:57:19 -05:00
return ParseRefCreate ( ) ;
2026-04-03 21:12:36 -05:00
case YML_TOKEN_TYPE_REF_USE :
return ParseRefUse ( ) ;
case YML_TOKEN_TYPE_SCALAR_QUOTED :
return ProccesQuoted ( ) ;
case YML_TOKEN_TYPE_SCALAR :
return ProccesScalarVal ( ) ;
}
//---
m_last_err = YML_PARSER_ERR_ESTRUCUTRA_INVALIDA_NO_SE_PARSEO ;
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Procesar valor para un obj o arrary inline
2026-04-04 20:03:17 -05:00
bool CYmlParser : : ProccesValArrOrObj ( const ushort char_cierre )
2026-04-03 21:12:36 -05:00
{
// En teroai pos apunta al valor luego del :
const ENUM_YML_TOKEN_STRUCTURE type = ObtenerTipoVal ( ) ;
switch ( type )
{
case YML_TOKEN_TYPE_BLOCK :
m_last_err = YML_PARSER_ERR_NO_SE_PUEDE_USAR_BLOQUES ;
return false ;
case YML_TOKEN_TYPE_LIST_INLINE :
return ParseInlineArr ( ) ;
case YML_TOKEN_TYPE_OBJ_INLINE :
return ParseInlineObj ( ) ;
case YML_TOKEN_TYPE_MULTILINE_CON :
m_last_err = YML_PARSER_ERR_NO_SEPUEDE_USAR_MULTILINEA ;
return false ;
case YML_TOKEN_TYPE_MULTILINE_SIN :
m_last_err = YML_PARSER_ERR_NO_SEPUEDE_USAR_MULTILINEA ;
return false ;
case YML_TOKEN_TYPE_REF_CREATE :
m_last_err = YML_PARSER_ERR_NO_SE_PUEDE_USAR_REFCREATE ;
return false ;
case YML_TOKEN_TYPE_REF_USE :
return ParseRefUse ( ) ;
case YML_TOKEN_TYPE_SCALAR_QUOTED :
return ProccesQuoted ( ) ;
case YML_TOKEN_TYPE_SCALAR :
2026-04-04 20:03:17 -05:00
return ProccesScalarNoTalCual ( char_cierre ) ;
2026-04-03 21:12:36 -05:00
}
//---
m_last_err = YML_PARSER_ERR_ESTRUCUTRA_INVALIDA_NO_SE_PARSEO ;
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Procesar valor para una referencia
2026-04-05 06:57:19 -05:00
bool CYmlParser : : ProccesValForReference ( ENUM_YML_TOKEN_STRUCTURE & type )
2026-04-03 21:12:36 -05:00
{
// En teroai pos apunta al valor luego del :
type = ObtenerTipoVal ( ) ;
switch ( type )
{
case YML_TOKEN_TYPE_BLOCK :
2026-04-05 06:57:19 -05:00
return ParseBlock ( ) ;
2026-04-03 21:12:36 -05:00
case YML_TOKEN_TYPE_LIST_INLINE :
return ParseInlineArr ( ) ;
case YML_TOKEN_TYPE_OBJ_INLINE :
return ParseInlineObj ( ) ;
case YML_TOKEN_TYPE_MULTILINE_CON :
2026-04-05 06:57:19 -05:00
return ParseMultiline ( true ) ;
2026-04-03 21:12:36 -05:00
case YML_TOKEN_TYPE_MULTILINE_SIN :
2026-04-05 06:57:19 -05:00
return ParseMultiline ( false ) ;
2026-04-03 21:12:36 -05:00
case YML_TOKEN_TYPE_REF_CREATE :
m_last_err = YML_PARSER_ERR_NO_SE_PUEDE_USAR_REFCREATE ;
return false ;
case YML_TOKEN_TYPE_REF_USE :
return ParseRefUse ( ) ;
case YML_TOKEN_TYPE_SCALAR_QUOTED :
return ProccesQuoted ( ) ;
case YML_TOKEN_TYPE_SCALAR :
return ProccesScalarVal ( ) ;
}
//---
m_last_err = YML_PARSER_ERR_ESTRUCUTRA_INVALIDA_NO_SE_PARSEO ;
return false ;
}
2026-04-03 22:17:13 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*
enum ENUM_YML_CLASIFIER_TYPE_VAL
{
YML_CLASIFIER_TOKEN_TYPE_KEY = 0 ,
YML_CLASIFIER_TOKEN_TYPE_STR = 1 ,
YML_CLASIFIER_TOKEN_TYPE_INTEGER = 2 ,
YML_CLASIFIER_TOKEN_TYPE_DBL = 3 ,
YML_CLASIFIER_TOKEN_TYPE_BOOL = 4 ,
YML_CLASIFIER_TOKEN_TYPE_NULL = 5 ,
YML_CLASIFIER_TOKEN_TYPE_STR_MULTILINE = 6 ,
YML_CLASIFIER_TOKEN_TYPE_ARR = 7 ,
YML_CLASIFIER_TOKEN_TYPE_OBJ = 8 ,
YML_CLASIFIER_TOKEN_TYPE_REFERENCE_SIMPLE = 9 ,
YML_CLASIFIER_TOKEN_TYPE_REFERENCE_COMPLEX = 10 ,
YML_CLASIFIER_TOKEN_TYPE_PTR = 11
} ;
* /// TOKEN SIZES EN LA CINTA:
//
// KEY 2 pos [tipo|scape|hash][start<<32|end]
// STR 2 pos [tipo|scape][start<<32|end]
// STR_MULTI 2 pos [tipo|ident|saltos][start<<32|end]
// INTEGER 2 pos [tipo][valor_long]
// DBL 2 pos [tipo][valor_long (bits del double)]
// BOOL 1 pos [tipo|valor]
// NULL 1 pos [tipo]
// ARR 1 pos [tipo|count|closing_pos] (elementos siguen inmediatamente)
// OBJ 1 pos [tipo|count|closing_pos] (key+val siguen inmediatamente)
// ---
// REF_CREATE 1 pos [tipo|closing_pos] (sigue NAME 2pos + valor) (puede ser simple o compleja pero ocupa mismos dos pos)
// NAME 1 pos [start<<32|end] (nombre del anchor, siempre tras REF_CREATE)
// ---
// PTR 1 pos [tipo|pos_ref_create] (apunta a REF_CREATE)
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CYmlParser : : GetStep ( int idx )
{
const int tipo = int ( m_cinta [ idx ] & B ' 1111 ' ) ;
switch ( tipo )
{
//---
case YML_CLASIFIER_TOKEN_TYPE_KEY :
case YML_CLASIFIER_TOKEN_TYPE_STR :
case YML_CLASIFIER_TOKEN_TYPE_INTEGER :
case YML_CLASIFIER_TOKEN_TYPE_DBL :
return 2 ;
//---
case YML_CLASIFIER_TOKEN_TYPE_BOOL :
case YML_CLASIFIER_TOKEN_TYPE_NULL :
return 1 ;
//---
case YML_CLASIFIER_TOKEN_TYPE_STR_MULTILINE :
{
return 2 ;
}
//---
case YML_CLASIFIER_TOKEN_TYPE_ARR :
case YML_CLASIFIER_TOKEN_TYPE_OBJ :
case YML_CLASIFIER_TOKEN_TYPE_REFERENCE_SIMPLE :
case YML_CLASIFIER_TOKEN_TYPE_REFERENCE_COMPLEX :
{
return int ( m_cinta [ idx ] > > YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS )
- idx ;
}
//---
case YML_CLASIFIER_TOKEN_TYPE_PTR :
return 1 ;
}
return 1 ;
}
2026-04-04 20:03:17 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CYmlParser : : GetStepPure ( int idx )
{
const int tipo = int ( m_cinta [ idx ] & B ' 1111 ' ) ;
switch ( tipo )
{
//---
case YML_CLASIFIER_TOKEN_TYPE_KEY :
case YML_CLASIFIER_TOKEN_TYPE_STR :
case YML_CLASIFIER_TOKEN_TYPE_INTEGER :
case YML_CLASIFIER_TOKEN_TYPE_DBL :
return 2 ;
//---
case YML_CLASIFIER_TOKEN_TYPE_BOOL :
case YML_CLASIFIER_TOKEN_TYPE_NULL :
return 1 ;
//---
case YML_CLASIFIER_TOKEN_TYPE_STR_MULTILINE :
return 2 ;
//---
case YML_CLASIFIER_TOKEN_TYPE_ARR :
case YML_CLASIFIER_TOKEN_TYPE_OBJ :
return 1 ;
case YML_CLASIFIER_TOKEN_TYPE_REFERENCE_SIMPLE :
case YML_CLASIFIER_TOKEN_TYPE_REFERENCE_COMPLEX :
return 2 ;
//---
case YML_CLASIFIER_TOKEN_TYPE_PTR :
return 1 ;
}
return 1 ;
}
2026-04-03 21:12:36 -05:00
//+------------------------------------------------------------------+
2026-04-03 22:37:29 -05:00
//| |
//+------------------------------------------------------------------+
2026-04-04 16:19:18 -05:00
static int CYmlParser : : HexToDec ( const ushort c )
2026-04-04 08:07:02 -05:00
{
if ( c > = ' 0 ' & & c < = ' 9 ' )
return c - ' 0 ' ;
if ( c > = ' a ' & & c < = ' f ' )
return c - ' a ' + 10 ;
if ( c > = ' A ' & & c < = ' F ' )
return c - ' A ' + 10 ;
return 0 ;
}
2026-04-04 20:03:17 -05:00
2026-04-04 08:07:02 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-04 10:28:45 -05:00
string CYmlParser : : Unescape ( const int start , const int end ) const
2026-04-03 22:37:29 -05:00
{
//---
2026-04-04 08:07:02 -05:00
string res = " " ;
StringSetLength ( res , ( end - start ) + 1 ) ;
2026-04-03 22:37:29 -05:00
int pos = 0 ;
//---
for ( int i = start ; i < = end ; i + + )
{
2026-04-04 08:07:02 -05:00
if ( m_yml [ i ] = = ' \\ ' & & i + 1 < = end )
2026-04-03 22:37:29 -05:00
{
i + + ;
2026-04-04 08:07:02 -05:00
const ushort next = m_yml [ i ] ;
2026-04-03 22:37:29 -05:00
switch ( next )
{
case ' " ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' " ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' \\ ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' \\ ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' / ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' / ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' b ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' \x08 ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' f ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' \f ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' n ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' \n ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' r ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' \r ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' t ' :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , ' \t ' ) ;
2026-04-03 22:37:29 -05:00
break ;
case ' u ' :
2026-04-04 20:03:17 -05:00
{
// \uFFFF
if ( i + 4 < = end )
2026-04-03 22:37:29 -05:00
{
2026-04-04 20:03:17 -05:00
int code = ( HexToDec ( m_yml [ i + 1 ] ) < < 12 ) |
( HexToDec ( m_yml [ i + 2 ] ) < < 8 ) |
( HexToDec ( m_yml [ i + 3 ] ) < < 4 ) |
HexToDec ( m_yml [ i + 4 ] ) ;
res .SetChar ( pos + + , ( ushort ) code ) ;
i + = 4 ;
2026-04-03 22:37:29 -05:00
}
2026-04-04 20:03:17 -05:00
else
res .SetChar ( pos + + , ' u ' ) ;
break ;
}
2026-04-03 22:37:29 -05:00
default :
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , next ) ;
2026-04-03 22:37:29 -05:00
break ;
}
}
else
2026-04-04 08:07:02 -05:00
res .SetChar ( pos + + , m_yml [ i ] ) ;
2026-04-03 22:37:29 -05:00
}
2026-04-04 08:07:02 -05:00
//---
res .Truncate ( pos ) ;
//---
return res ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string CYmlParser : : ExtractMultiline ( int start , int end , int ident , bool con_saltos )
{
//---
string res = " " ;
StringSetLength ( res , ( end - start ) + 2 ) ;
int p = 0 ;
int cur = start + ident ;
2026-04-05 22:25:16 -05:00
//Print(ident);
2026-04-04 08:07:02 -05:00
//---
while ( cur < = end ) // hasta end dado que representa el ultimo char previo al \n
{
if ( m_yml [ cur ] = = ' \n ' )
{
res .SetChar ( p + + , ( con_saltos ? ' \n ' : ' ' ) ) ;
cur + + ;
cur + = ident ;
continue ;
}
res .SetChar ( p + + , m_yml [ cur ] ) ;
cur + + ;
}
//---
res .Truncate ( p ) ;
//---
return res ;
2026-04-03 22:37:29 -05:00
}
//+------------------------------------------------------------------+
2026-04-04 16:19:18 -05:00
//| |
//+------------------------------------------------------------------+
long CYmlParser : : FastAtoi ( const int start , const int end , const int sign )
{
//--- Varialbes inciales
long val = 0 ;
int i = start ;
const int n_len = ( end - start ) + 1 ;
//--- Salto de 4 en 4
const int end4 = start + n_len - 4 ;
for ( ; i < = end4 ; i + = 4 )
{
val = val * 10000
+ m_yml [ i ] * 1000
+ m_yml [ i + 1 ] * 100
+ m_yml [ i + 2 ] * 10
+ m_yml [ i + 3 ] - ' 0 ' * 1111 ;
}
//--- Llo que sobra
for ( ; i < = end ; i + + )
{
val = val * 10 + ( m_yml [ i ] - ' 0 ' ) ;
}
//--- Reotrnamos
return val * sign ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
long CYmlParser : : FastAtoiHex ( const int start , const int end )
{
//---
long val = 0 ;
int i = start + 2 ; // salta 0x
//---
const int end2 = end - 1 ;
for ( ; i < = end2 ; i + = 2 )
{
val = ( val < < 8 )
| ( g_yml_hex [ m_yml [ i ] ] < < 4 )
| g_yml_hex [ m_yml [ i + 1 ] ] ;
}
//---
for ( ; i < = end ; i + + )
{
val = ( val < < 4 ) | g_yml_hex [ m_yml [ i ] ] ;
}
return val ;
}
2026-04-04 20:03:17 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CYmlParser : : PrintCintaTypes ( void )
{
int p = 0 ;
while ( p < m_cinta_pos )
{
const ENUM_YML_CLASIFIER_TYPE_VAL tipo = ENUM_YML_CLASIFIER_TYPE_VAL ( m_cinta [ p ] & 0xF ) ;
Print ( tipo ) ;
Print ( EnumToString ( tipo ) ) ;
p + = GetStepPure ( p ) ;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CYmlNode CYmlParser : : GetRoot ( )
{
if ( m_cinta_pos = = 0 )
return EMPTY_YMLNODE ;
return CYmlNode ( & this , 0 , GetStep ( 0 ) ) ;
}
2026-04-04 16:19:18 -05:00
//+------------------------------------------------------------------+
2026-04-05 06:57:19 -05:00
# endif // YMLPARSERBYLEO_SRC_YMLPARSER_MQH