YamlParserByLeo/Src/YmlParser.mqh
Nique_372 4c4cab111d
2026-04-06 09:56:37 -05:00

2106 行
56 KiB
MQL5

//+------------------------------------------------------------------+
//| 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
#ifndef YMLPARSERBYLEO_SRC_YMLPARSER_MQH
#define YMLPARSERBYLEO_SRC_YMLPARSER_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "YmlDefines.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
uchar g_yml_hex[256];
bool g_yml_hex_init = false;
struct CYmlNode;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CYmlParser
{
public:
//--- Cinta
long m_cinta[];
int m_cinta_pos;
ushort m_yml[];
private:
int m_cinta_reserve;
//---
int m_yml_len;
int m_yml_pos;
bool m_aument_ident_in_next_call;
//--- Posicioens de los anchors (hash | pos)
int m_anchors_posciones[64][9];
//---
short m_values_anchors_prohibidos[];
int m_values_anchors_prohibidos_pos;
//---
int m_yml_ident_chars;
//---
bool ProccesKey(int& start, int& end, bool& scape);
//---
// Para todo
bool ProccesVal();
//
bool ProccesValForReference(ENUM_YML_TOKEN_STRUCTURE& type);
// Para objetos
bool ProccesValArrOrObj(const ushort char_cierre);
//--- Procesar valores
// objeto
bool ParseInlineObj();
// Arrays
bool ParseInlineArr();
// Multiline
bool ParseMultiline(const bool con_saltos);
// Bloques
bool ParseBlock();
// Item root
bool ParseItemRoot();
// Ref use
bool ParseRefUse();
// no tal cual
bool ProccesScalarNoTalCual(const ushort char_cierre);
// 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
bool ParseRefCreate();
//---
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();
static int HexToDec(const ushort c);
bool InternalParse();
long FastAtoi(const int start, const int end, const int sign);
long FastAtoiHex(const int start, const int end);
int GetStepPure(int idx);
public:
//---
union LongToDbl
{
long l;
double d;
};
public:
CYmlParser(void) {}
~CYmlParser(void) {}
//--- Utilidades para los nodos
// 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);
// Obtener step de type
int GetStep(int idx);
// Desescapaar
string Unescape(const int start, const int end) const;
// Extraer multiline
string ExtractMultiline(int start, int end, int ident, bool con_saltos);
//--- Parse functions
// (1) String tal cual | (2) Archivo
bool Parse(const string& yml, int initial_reserve = 128);
bool ParseFile(const string& file_name, bool comon_flag, int initial_reserve = 128);
//---
__forceinline ENUM_YML_PARSER_LAST_ERR LastErr() const { return m_last_err; }
//---
CYmlNode GetRoot();
//--- Utiliadades
void PrintCintaTypes();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CYmlParser::Init(void)
{
//---
m_yml_pos = 0;
m_last_err = WRONG_VALUE;
m_yml_ident_chars = 0;
m_values_anchors_prohibidos_pos = 0;
m_cinta_pos = 0; //ArrayResize(m_cinta, 0); esto lo debera reservar la cinta
//--- posiciones
for(int i = 0; i < 64; i++)
{
m_anchors_posciones[i][0] = 0;
}
//---
if(g_yml_hex_init)
return;
//---
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;
//---
g_yml_hex_init = true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser::Parse(const string& yml, int initial_reserve = 128)
{
//---
m_yml_len = StringLen(yml);
StringToShortArray(yml, m_yml, 0, m_yml_len); // omitimos el \0
m_cinta_reserve = ArrayResize(m_cinta, ::fmax(initial_reserve, YML_MIN_INITIAL_RESERVE));
//---
return InternalParse();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser::InternalParse(void)
{
Init();
//---
//m_yml_ident_chars = 0;
if(m_yml_len < 1)
{
return false;
}
//---
if(m_yml[m_yml_pos] != '\n') // Si no es\n entonces no se podnra auto deberemos de hacerlo
m_yml_ident_chars = -1;
//---
m_aument_ident_in_next_call = true;
//---
if(!ParseBlock()) // -1 para que el ident base no salga
return false;
//--- true exito
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser::ParseBlock()
{
//---
// Nota: ahora miosmo estamos en el\n o first char de lobuqe implicito
//---
//Print("CALLLLLLLLLLLLLLLLLLLLLLLLLLLLL");
if(m_yml[m_yml_pos] == '\n')
{
m_yml_pos++;
m_yml_ident_chars = m_cinta_pos == 0 ? -1 : 0;
}
//---
ENUM_YML_CLASIFIER_TYPE_VAL token_type = WRONG_VALUE;
//---
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);
//---
ReserveCinta(1);
const int curr_pos_cinta = m_cinta_pos++; // aqui se ubicara el arr (tipo | numero elementos)
//---
while(m_yml_pos < m_yml_len)
{
//--- Medir idetnacion de esta linea
// Print("Char BLOCK INIT: '", ShortToString(m_yml[m_yml_pos]), "' | Pos: ", m_yml_pos, " | Current ident: ", m_yml_ident_chars);
bool is = false;
while(m_yml_pos < m_yml_len)
{
if(m_yml[m_yml_pos] == '\n')
{
break;
}
if(CYmlClass_IsNorFilterChar(m_yml[m_yml_pos]))
{
is = true;
break;
}
m_yml_pos++;
m_yml_ident_chars++;
}
//--- En caso no haya idtenacion estamos en \n avanzmao sluego del
if(m_yml_pos >= m_yml_len)
{
break;
}
if(!is) // Salio por salto de linea entonces buscamos la siguiente
{
m_yml_ident_chars = 0;
m_yml_pos++;
continue;
}
//--- Revisamo comentarios
if(m_yml[m_yml_pos] == '#') // el primer char es comentarios salimos
{
CYmlClass_AvanzarHastaLaSiguienteChar('\n')
m_yml_pos++; // primer char
m_yml_ident_chars = 0;
continue;
}
//---
if(m_yml_ident_chars <= ident_padre)
{
break;
}
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);
//---
bool has_k = false;
//---
if(m_yml[m_yml_pos] == '-')
{
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;
return false;
}
else
if(CYmlClass_IsFilterChar(m_yml[m_yml_pos + 1])) // Espacio
{
//---
if(token_type == WRONG_VALUE) // Solo si no esta seteado
{
token_type = YML_CLASIFIER_TOKEN_TYPE_ARR;
}
else
if(token_type != YML_CLASIFIER_TOKEN_TYPE_ARR)
{
m_last_err = YML_PARSER_ERR_BLOCK_SE_ESPERABA_UNA_LISTA;
return false;
}
//---
// Print(ShortToString(m_yml[m_yml_pos]));
// Print(ShortToString(m_yml[m_yml_pos + 1]));
// Print(ShortToString(m_yml[m_yml_pos + 2]));
m_yml_pos += 2; // [-][" "] nos ubicaremos justo en el valor
//---
//... has_k
//---
if(m_yml[m_yml_pos] == '?' && m_yml[m_yml_pos + 1] == ' ')
{
for(int i = m_yml_pos; i < m_yml_len; i++)
{
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;
}
}
}
//---
// Print(ShortToString(m_yml[m_yml_pos]));
//---
if(has_k)
{
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
// Es un array y tiene key generamos bloque implicito
if(!ParseBlock())
return false;
//---
count++;
continue;
}
}
else
{
has_k = true;
if(token_type == WRONG_VALUE) // Solo si no esta seteado
{
token_type = YML_CLASIFIER_TOKEN_TYPE_OBJ;
}
else
if(token_type != YML_CLASIFIER_TOKEN_TYPE_OBJ)
{
m_last_err = YML_PARSER_ERR_BLOCK_SE_ESPERABA_UNA_KEY;
return false;
}
}
}
else
{
has_k = true;
if(token_type == WRONG_VALUE) // Solo si no esta seteado
{
token_type = YML_CLASIFIER_TOKEN_TYPE_OBJ;
}
else
if(token_type != YML_CLASIFIER_TOKEN_TYPE_OBJ)
{
m_last_err = YML_PARSER_ERR_BLOCK_SE_ESPERABA_UNA_KEY;
return false;
}
}
// else nada segurmante es un key como "-hola"
//---
if(has_k)
{
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
}
//---
//Print(m_cinta_pos, " | Real size: " , ArraySize(m_cinta));
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
}
//---
if(!ProccesVal())
return false;
//---
count++;
}
//---
//Print("POs: ", curr_pos_cinta, " Count: ", count);
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;
}
else
m_cinta[curr_pos_cinta] = YML_CLASIFIER_TOKEN_TYPE_NULL;
// Nul dado que esun
/*
hola:\n
vlaor: # otro token ya
*/
//---
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')
{
if(m_yml[m_yml_pos] == '\\')
{
m_yml_pos += m_yml[m_yml_pos + 1] == '"' ? 2 : 1;
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 "
//Print("Escapar: " , ShortArrayToString(m_yml,start,(end - start) + 1));
//---
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;
}
//---
if(!ProccesValArrOrObj(']')) // esto nos deja en , (aqui no se permiten bloques)
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
| long(m_cinta_pos) << YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS ;
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
//---
if(!ProccesValArrOrObj('}'))
{
// 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
| long(m_cinta_pos) << YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS ; // el tipo solo ocupra 8 bits el resto para el counPt
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);
m_cinta[m_cinta_pos++] = (long)YML_CLASIFIER_TOKEN_TYPE_BOOL; // no hace falta // | ((long)0 << YMLPARSER_BIT_END_TYPE);
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;
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)
}
//---
const bool is_mas = m_yml[m_yml_pos] == '+';
if(CYmlClas_IsDigit(m_yml[m_yml_pos]) || is_signo || is_mas || is_punto)
{
//---
// 1 = (punto) | 2 = uso de E | 4 = hex
uint8_t f = 0;
const int start = m_yml_pos;
int sing = 1;
//--- Check inicial
if(is_mas)
{
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;
while(m_yml_pos < m_yml_len && CYmlClass_IsNorFilterChar(m_yml[m_yml_pos]))
{
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);
//---
if(f && f <= 3)
{
//---
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);
m_cinta[m_cinta_pos++] = YML_CLASIFIER_TOKEN_TYPE_DBL;
m_cinta[m_cinta_pos++] = un.l;
}
else
{
m_cinta[m_cinta_pos++] = YML_CLASIFIER_TOKEN_TYPE_INTEGER;
m_cinta[m_cinta_pos++] = f == 4 ? FastAtoiHex(start, end) : FastAtoi(start, end, sing);
}
return true;
}
//---
return ProccesScalarPlain();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser::ProccesScalarNoTalCual(const ushort char_cierre)
{
//--- Inicio de commila (str)
//printf(ShortToString(m_yml[m_yml_pos]));
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);
m_cinta[m_cinta_pos++] = YML_CLASIFIER_TOKEN_TYPE_BOOL; // no hace falta // | ((long)0 << YMLPARSER_BIT_END_TYPE);
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
//- .
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
{
bool is_dbl = false;
int start = m_yml_pos;
int sing = 1;
//--- 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;
is_dbl = true;
}
else
if(m_yml[start] == '-')
{
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 -)
//---
m_yml[m_yml_pos - 1] = '-';
m_yml[start] = '.';
//---
start = m_yml_pos - 1;
//---
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
}
}
}
//--- Avanzamos hasta el sigueinte: [Fileter char | Final del yml | comma | cierre ]
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)
{
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;
//--- Reservamos
ReserveCinta(2);
//printf(ShortToString(m_yml[start]));
//---
if(is_dbl)
{
LongToDbl un;
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);
m_cinta[m_cinta_pos++] = YML_CLASIFIER_TOKEN_TYPE_DBL;
m_cinta[m_cinta_pos++] = un.l;
}
else
{
m_cinta[m_cinta_pos++] = YML_CLASIFIER_TOKEN_TYPE_INTEGER;
m_cinta[m_cinta_pos++] = FastAtoi(start, end, sing);
}
return true;
}
//---
m_last_err = YML_PARSER_ERR_NO_SE_PUEDE_USAR_VALORES_PLAIN_EN_ARR_OR_OBJ;
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);
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
m_cinta[m_cinta_pos++] = ((long)start << 32) | (uint)end;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser::ParseMultiline(const bool con_saltos)
{
//---
// Nota estamos en el | o > asi que ahora mismo sabemos la idetacino del bloque key
//---
CYmlClass_AvanzarHastaLaSiguienteChar('\n')
m_yml_pos++;
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
int start = m_yml_pos;
int last_salto = m_yml_pos;
// el ident esd
//---
while(m_yml_pos < m_yml_len)
{
//---
while(m_yml_pos < m_yml_len && CYmlClass_IsFilterChar(m_yml[m_yml_pos]))
{
if(m_yml[m_yml_pos] == '\n')
break;
m_yml_pos++;
m_yml_ident_chars++;
}
//---
if(m_yml[m_yml_pos] == '\n')
{
last_salto = m_yml_pos;
m_yml_pos++;
min_value_pos = m_yml_pos + prev_curr_ident;
m_yml_ident_chars = 0;
continue;
}
//---
if(m_yml_pos < min_value_pos) // fin
{
break;
}
/*if(is_f)
{
m_yml_pos++;
continue;
}*/
m_yml_pos++;
}
//---
// m_yml_pos = last_salto; // dejamos en \n
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
// [32 bits para saltos][28 bits para ident][tipo 4 bit]
//
// - simplfiicamos lo de scape dado que no tiene sentido aqui:
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
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
// Print("Primer char: ", ShortToString(m_yml[m_yml_pos]));
bool is_complex = false;
if(m_yml[m_yml_pos] == '?' && m_yml[m_yml_pos + 1] == ' ')
{
m_yml_pos += 2;
is_complex = true;
//---
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;
//Print(ShortToString(m_yml[start]) , " | " , start);
while(m_yml_pos < m_yml_len)
{
//PrintFormat("Char: '%s' | pos = %d | char = %u", ShortToString(m_yml[m_yml_pos]), m_yml_pos, m_yml[m_yml_pos]);
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;
}
//---
if(m_yml[m_yml_pos] == ':' && (m_yml[m_yml_pos + 1] < 33)) // keyval
{
// Print("Si");
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;
}
//---
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;
}
//---
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CYmlParser::ParseRefCreate()
{
//---
// Nota ahora mismo estamos en &
/*
name: &anchor
key: |
valore
*/
//---
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;
if(!ProccesValForReference(st_type))
{
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)
| long(m_cinta_pos) << YMLPARSER_ARROBJREF_BIT_INIT_CURR_POS;
//---
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);
//--- 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)
{
const int pv = resolved + YML_OFFESET_PTR_TO_VAL; // salta REF_CREATE(1) + NAME(1) ahor amismo nos ubiramoes en el primer pos cinta
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;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Procesar valor normal (Se acepta todo)
bool CYmlParser::ProccesVal()
{
// En teroai pos apunta al valor luego del :
//---
const ENUM_YML_TOKEN_STRUCTURE type = ObtenerTipoVal();
//---
switch(type)
{
case YML_TOKEN_TYPE_BLOCK:
return ParseBlock();
case YML_TOKEN_TYPE_LIST_INLINE:
return ParseInlineArr();
case YML_TOKEN_TYPE_OBJ_INLINE:
return ParseInlineObj();
case YML_TOKEN_TYPE_MULTILINE_CON:
return ParseMultiline(true);
case YML_TOKEN_TYPE_MULTILINE_SIN:
return ParseMultiline(false);
case YML_TOKEN_TYPE_REF_CREATE:
return ParseRefCreate();
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
bool CYmlParser::ProccesValArrOrObj(const ushort char_cierre)
{
// 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:
return ProccesScalarNoTalCual(char_cierre);
}
//---
m_last_err = YML_PARSER_ERR_ESTRUCUTRA_INVALIDA_NO_SE_PARSEO;
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Procesar valor para una referencia
bool CYmlParser::ProccesValForReference(ENUM_YML_TOKEN_STRUCTURE& type)
{
// En teroai pos apunta al valor luego del :
type = ObtenerTipoVal();
switch(type)
{
case YML_TOKEN_TYPE_BLOCK:
return ParseBlock();
case YML_TOKEN_TYPE_LIST_INLINE:
return ParseInlineArr();
case YML_TOKEN_TYPE_OBJ_INLINE:
return ParseInlineObj();
case YML_TOKEN_TYPE_MULTILINE_CON:
return ParseMultiline(true);
case YML_TOKEN_TYPE_MULTILINE_SIN:
return ParseMultiline(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:
return ProccesScalarVal();
}
//---
m_last_err = YML_PARSER_ERR_ESTRUCUTRA_INVALIDA_NO_SE_PARSEO;
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
static int CYmlParser::HexToDec(const ushort c)
{
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string CYmlParser::Unescape(const int start, const int end) const
{
//---
string res = "";
StringSetLength(res, (end - start) + 1);
int pos = 0;
//---
for(int i = start; i <= end; i++)
{
if(m_yml[i] == '\\' && i + 1 <= end)
{
i++;
const ushort next = m_yml[i];
switch(next)
{
case '"':
res.SetChar(pos++, '"');
break;
case '\\':
res.SetChar(pos++, '\\');
break;
case '/':
res.SetChar(pos++, '/');
break;
case 'b':
res.SetChar(pos++, '\x08');
break;
case 'f':
res.SetChar(pos++, '\f');
break;
case 'n':
res.SetChar(pos++, '\n');
break;
case 'r':
res.SetChar(pos++, '\r');
break;
case 't':
res.SetChar(pos++, '\t');
break;
case 'u':
{
// \uFFFF
if(i + 4 <= end)
{
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;
}
else
res.SetChar(pos++, 'u');
break;
}
default:
res.SetChar(pos++, next);
break;
}
}
else
res.SetChar(pos++, m_yml[i]);
}
//---
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;
//Print(ident);
//---
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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));
}
//+------------------------------------------------------------------+
#endif // YMLPARSERBYLEO_SRC_YMLPARSER_MQH