2106 行
56 KiB
MQL5
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
|