//+------------------------------------------------------------------+ //| 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