2026-10-05 17:54:12 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| Main.mqh |
|
| | | //| Copyright 2026, Niquel Mendoza. |
|
| | | //| https://www.mql5.com/ |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2026, Niquel Mendoza."
|
| | | #property link "https://www.mql5.com/"
|
| | | #property strict
|
| | |
|
2026-10-05 18:16:09 -05:00 | | | #ifndef BASESPARSERSLAN_SRC_BASECLASS_MAIN_MQH
|
| | | #define BASESPARSERSLAN_SRC_BASECLASS_MAIN_MQH
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #include "Def.mqh"
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
| | | //+------------------------------------------------------------------+
|
| | | //| Clase base de formato |
|
| | | //+------------------------------------------------------------------+
|
| | | // Como minimo para .ini, .set, .rsp , etc...
|
| | | class CBaseLanFormat
|
| | | {
|
| | | public:
|
| | | //--- Data del documento
|
2026-10-08 13:38:10 -05:00 | | | ulong m_cinta[];
|
2026-10-05 17:54:12 -05:00 | | | uchar m_raw[];
|
| | | int m_cinta_pos;
|
| | | int m_len;
|
| | | int m_offset;
|
| | | int m_pos;
|
| | | int m_cinta_reserve;
|
| | |
|
| | | //--- Perfect hash
|
| | | //- Pf
|
| | | CPerfectHashByLeo<ulong, CSBLHasherGenUl, CSBLHasherGenUl1> m_pfh;
|
| | | ushort m_max_att;
|
| | |
|
| | |
|
| | | protected:
|
| | | //--- Del parseo
|
| | | uchar m_next;
|
| | |
|
| | | public:
|
| | | CBaseLanFormat(void);
|
| | | ~CBaseLanFormat(void) {}
|
| | |
|
| | |
|
| | | //---
|
| | | __forceinline void CalcLen() { m_len = ArraySize(m_raw); }
|
| | | __forceinline void Assing(const string& raw, uint cp = CP_ACP);
|
| | |
|
| | | //---
|
| | | __forceinline uchar LastToken() { return m_next; }
|
| | |
|
| | | //---
|
| | | void NormalizeUft();
|
| | |
|
| | | //---
|
| | | void GetLastErrorLocation(int &col, int &line) const;
|
| | | };
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CBaseLanFormat::CBaseLanFormat(void)
|
| | | : m_cinta_reserve(2048), m_len(0), m_offset(0), m_max_att(5000)
|
| | | {
|
| | | ArrayResize(m_cinta, 2048, 512);
|
| | | }
|
2026-10-08 13:38:10 -05:00 | | | // [1,2] 4098
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | __forceinline void CBaseLanFormat::Assing(const string& raw, uint cp = CP_ACP)
|
| | | {
|
| | | m_len = StringToCharArray(raw, m_raw, 0, WHOLE_ARRAY, cp);
|
| | | m_offset = 0;
|
| | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void CBaseLanFormat::GetLastErrorLocation(int &col, int &line) const
|
| | | {
|
2026-10-08 13:38:10 -05:00 | | | //---
|
2026-10-05 17:54:12 -05:00 | | | col = 1;
|
| | | line = 1;
|
| | |
|
2026-10-08 13:38:10 -05:00 | | | //--- len podira ser negtvo en casos raros pero pos nunca
|
| | | for(int i = 0; i < (int)m_pos && i < m_len; i++)
|
2026-10-05 17:54:12 -05:00 | | | {
|
| | | if(m_raw[i] == '\n')
|
| | | {
|
| | | line++;
|
| | | col = 1;
|
| | | }
|
| | | else
|
| | | col++;
|
| | | }
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void CBaseLanFormat::NormalizeUft()
|
| | | {
|
| | | m_offset = 0;
|
| | |
|
| | | //---
|
| | | if(m_len >= 2)
|
| | | {
|
| | | // UTF16 BE
|
| | | if(m_raw[0] == 0xFF && m_raw[1] == 0xFE)
|
| | | {
|
| | | const int n = (m_len - 2) >> 1;
|
| | | for(int i = 0; i < n; i++)
|
| | | m_raw[i] = m_raw[2 + (i * 2)]; // byte bajo (el char real)
|
| | | m_len = ArrayResize(m_raw, n);
|
| | | }
|
| | | // UTF16 LE
|
| | | else
|
| | | if(m_raw[0] == 0xFE && m_raw[1] == 0xFF)
|
| | | {
|
| | | const int n = (m_len - 2) >> 1;
|
| | | for(int i = 0; i < n; i++)
|
| | | m_raw[i] = m_raw[3 + (i * 2)]; // byte alto (invertido)
|
| | | m_len = ArrayResize(m_raw, n);
|
| | | }
|
| | | }
|
| | | else
|
| | | if(m_len >= 3 && m_raw[0] == 0xEF && m_raw[1] == 0xBB && m_raw[2] == 0xBF)
|
| | | {
|
| | | // UTF-8 BOM
|
| | | m_offset = 3; // simplemente saltear
|
| | | }
|
| | | }
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // Esto en especiifco es para lengaujes qeu soprotes como minimo objetos,tipsode datos, arrays
|
| | | // y anidacion
|
2026-10-08 13:38:10 -05:00 | | | // layout: [bucket_l][final_l<<32]
|
| | | #define BSFL_T_GET_FINALTABLE_L(V) ((V)>>32)
|
| | | #define BSFL_T_GET_BUCKET_L(V) ((V)&0xffffffff)
|
| | | #define BSFL_T_PACK(B, F) (ulong(B) | ulong(F) << 32)
|
| | |
|
| | | //---
|
| | | #define BSFL_OPT_F_ENABLE_JIT (1)
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-10-05 17:54:12 -05:00 | | | class CBaseStructuredLan : public CBaseLanFormat
|
| | | {
|
| | | public:
|
| | | //- Structs
|
2026-10-08 13:38:10 -05:00 | | | struct ObjNode
|
2026-10-05 17:54:12 -05:00 | | | {
|
| | | ushort seeds[]; // Seeds..
|
| | | ulong key_hash[]; // Key hash
|
| | | int pos_index[]; // [h] (hash) = devuevle indice del objeto
|
| | | int pos_arr[]; // [i] (index de objeto) = devuelve indice en la cinta
|
2026-10-08 13:38:10 -05:00 | | | ulong sizes; // Tamaños
|
2026-10-05 17:54:12 -05:00 | | | int start; // Start en cinta
|
| | | int table_size; // Tamaño de tabla
|
| | | };
|
2026-10-08 13:38:10 -05:00 | | | ObjNode m_tables[];
|
2026-10-05 17:54:12 -05:00 | | | int m_tables_size;
|
| | | int m_tables_reserve;
|
| | |
|
2026-10-08 13:38:10 -05:00 | | | //- valor de hash
|
| | | ulong m_jit_enabled;
|
| | |
|
2026-10-05 17:54:12 -05:00 | | | protected:
|
| | | //---
|
| | | virtual int CalcRegType(const string& file_name) = 0;
|
| | |
|
| | | public:
|
| | | CBaseStructuredLan(void);
|
| | | ~CBaseStructuredLan(void) {}
|
| | |
|
| | | //---
|
| | | int AssingFile(const string& file_name, const bool comon_flag);
|
| | |
|
| | | //---
|
| | | bool SaveCompiled(const string & file_name_out, const bool out_common_flag) const;
|
| | | bool SaveCompiled(const string & file_name_out, const bool out_common_flag, const string & file_name_data, const bool data_common_flag) const;
|
| | | void SaveTables(const int fh) const;
|
| | | void LoadTables(const int fh);
|
| | |
|
| | | //---
|
2026-10-08 13:38:10 -05:00 | | | int PerfectHashAcces(const ulong key_hash, const ObjNode& node) const;
|
| | | int PerfectHashComputeHashIndex(const ulong key_hash, const ObjNode& node) const;
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //---
|
2026-10-08 13:38:10 -05:00 | | | __forceinline int FindNodePos(const int start) const;
|
2026-10-05 17:54:12 -05:00 | | | };
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CBaseStructuredLan::CBaseStructuredLan()
|
2026-10-08 13:38:10 -05:00 | | | : m_tables_size(0), m_tables_reserve(4), m_jit_enabled(TSN_SBL_BIT_JIT_INITIAL_V)
|
2026-10-05 17:54:12 -05:00 | | | {
|
| | | ArrayResize(m_tables, 4, 2);
|
| | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | int CBaseStructuredLan::AssingFile(const string& file_name, const bool comon_flag)
|
| | | {
|
| | | //---
|
| | | const int reg_type = CalcRegType(file_name);
|
| | |
|
| | | //---
|
| | | if(reg_type == TSN_SLF_EXT_TYPE_CACHE_FILE) // jsontp tape cache
|
| | | {
|
| | | ::ResetLastError();
|
| | | const int fh = FileOpen(file_name, FILE_BIN | FILE_ANSI | (comon_flag ? FILE_COMMON : 0) | FILE_READ);
|
| | | if(fh == INVALID_HANDLE)
|
| | | {
|
| | | return -1;
|
| | | }
|
| | | // Metadata (cinta\yaml)
|
| | | m_cinta_pos = FileReadInteger(fh); // Nota que cuadno se guarda se hace con el tamaño exacto
|
| | | m_cinta_reserve = m_cinta_pos; // Mismo tamaño
|
| | | const int type = FileReadInteger(fh); // Tipo ()
|
| | |
|
| | | //---
|
| | | if(type == TSN_SLF_RAW_EMBEBED)
|
| | | {
|
| | | m_len = FileReadInteger(fh);
|
| | | m_offset = FileReadInteger(fh);
|
| | | FileReadArray(fh, m_cinta, 0, m_cinta_pos); // Total
|
| | | // Yaml embebido (aqui no hace falta hacer nada ya todo esta hecho.. osea lo de encoding etc..)
|
| | | FileReadArray(fh, m_raw, 0, m_len);
|
| | | LoadTables(fh); // Perfect hash tables
|
| | | }
|
| | | else // Dir
|
| | | {
|
| | | const bool common = bool(FileReadInteger(fh, CHAR_VALUE));
|
| | | const int file_name_len = FileReadInteger(fh);
|
| | | if(AssingFile(FileReadString(fh, file_name_len), common) == TSN_SLF_EXT_TYPE_CACHE_FILE)
|
| | | {
|
| | | FileClose(fh);
|
| | | return -1; // fallo
|
| | | }
|
| | | FileReadArray(fh, m_cinta, 0, m_cinta_pos);
|
| | | LoadTables(fh); // Perfect hash tables
|
| | | }
|
| | |
|
| | | //---
|
| | | FileClose(fh);
|
| | | return TSN_SLF_EXT_TYPE_CACHE_FILE;
|
| | | }
|
| | | else // Ninguno de los dos... json normal O jsonasm
|
| | | {
|
| | | const int l = (int)FileLoad(file_name, m_raw, (comon_flag ? FILE_COMMON : 0));
|
| | | if(l == -1)
|
| | | return -1;
|
| | |
|
| | | //---
|
| | | m_len = l;
|
| | |
|
| | | //---
|
| | | NormalizeUft();
|
| | |
|
| | | //---
|
| | | return reg_type;
|
| | | }
|
| | | }
|
| | |
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-10-08 13:38:10 -05:00 | | | int CBaseStructuredLan::PerfectHashAcces(const ulong key_hash, const ObjNode& node) const
|
2026-10-05 17:54:12 -05:00 | | | {
|
2026-10-08 13:38:10 -05:00 | | | //---
|
| | | const ulong v = node.sizes;
|
| | | const int seed_index = int(key_hash & BSFL_T_GET_BUCKET_L(v));
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //--- Alg
|
2026-10-08 13:38:10 -05:00 | | | SBL_HASH_ALG(key_hash, node.seeds[seed_index])
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //--- Pos
|
2026-10-08 13:38:10 -05:00 | | | const int fi = int(h & BSFL_T_GET_FINALTABLE_L(v));
|
| | | return node.key_hash[fi] == key_hash ? node.pos_arr[node.pos_index[fi]] : -1;
|
2026-10-05 17:54:12 -05:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
2026-10-08 13:38:10 -05:00 | | | int CBaseStructuredLan::PerfectHashComputeHashIndex(const ulong key_hash, const ObjNode& node) const
|
2026-10-05 17:54:12 -05:00 | | | {
|
2026-10-08 13:38:10 -05:00 | | | //---
|
| | | const ulong v = node.sizes;
|
| | | const int seed_index = int(key_hash & BSFL_T_GET_BUCKET_L(v));
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //--- Alg
|
2026-10-08 13:38:10 -05:00 | | | SBL_HASH_ALG(key_hash, node.seeds[seed_index])
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //--- Pos
|
2026-10-08 13:38:10 -05:00 | | | const int fi = int(h & BSFL_T_GET_FINALTABLE_L(v));
|
| | | return node.key_hash[fi] == key_hash ? node.pos_index[fi] : -1;
|
2026-10-05 17:54:12 -05:00 | | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //--- Ambos
|
| | | // 4 bytes: m_cinta_pos
|
| | | // 4 bytes: type
|
| | |
|
| | |
|
| | | //---
|
| | | bool CBaseStructuredLan::SaveCompiled(const string & file_name_out, const bool out_common_flag) const
|
| | | {
|
| | | ::ResetLastError();
|
| | | const int fh = FileOpen(file_name_out, FILE_BIN | (out_common_flag ? FILE_COMMON : 0) | FILE_WRITE | FILE_ANSI);
|
| | | if(fh == INVALID_HANDLE)
|
| | | {
|
| | | return false;
|
| | | }
|
| | |
|
| | | //--- Comun
|
| | | FileWriteInteger(fh, m_cinta_pos);
|
| | | FileWriteInteger(fh, TSN_SLF_RAW_EMBEBED);
|
| | |
|
| | | //---
|
| | | // 4 bytes: len
|
| | | // 4 bytes: offset
|
| | | // array: cinta
|
| | | // array yaml
|
| | |
|
| | | //---
|
| | | FileWriteInteger(fh, m_len);
|
| | | FileWriteInteger(fh, m_offset);
|
| | | FileWriteArray(fh, m_cinta, 0, m_cinta_pos);
|
| | | FileWriteArray(fh, m_raw, 0, m_len);
|
| | |
|
| | | //--- Perfect hash tables (m_tables)
|
| | | SaveTables(fh);
|
| | |
|
| | | //---
|
| | | FileClose(fh);
|
| | |
|
| | | //---
|
| | | return true;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CBaseStructuredLan::SaveCompiled(const string & file_name_out, const bool out_common_flag,
|
| | | const string & file_name_data, const bool data_common_flag) const
|
| | | {
|
| | | //---
|
| | | ::ResetLastError();
|
| | | const int fh = FileOpen(file_name_out, FILE_BIN | (out_common_flag ? FILE_COMMON : 0) | FILE_WRITE | FILE_ANSI);
|
| | | if(fh == INVALID_HANDLE)
|
| | | {
|
| | | return false;
|
| | | }
|
| | |
|
| | | //--- Comun
|
| | | FileWriteInteger(fh, m_cinta_pos);
|
| | | FileWriteInteger(fh, TSN_SLF_RAW_FILE);
|
| | |
|
| | | //---
|
| | | // 1 bytes: comon
|
| | | // 4 bytes: len
|
| | | // string: name_file
|
| | | // array: cinta
|
| | |
|
| | |
|
| | | //---
|
| | | FileWriteInteger(fh, data_common_flag, CHAR_VALUE);
|
| | | const int len = StringLen(file_name_data);
|
| | | FileWriteInteger(fh, len);
|
| | | FileWriteString(fh, file_name_data, len);
|
| | | FileWriteArray(fh, m_cinta, 0, m_cinta_pos);
|
| | |
|
| | | //--- Perfect hash tables (m_tables)
|
| | | SaveTables(fh);
|
| | |
|
| | | //---
|
| | | FileClose(fh);
|
| | |
|
| | | //---
|
| | | return true;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void CBaseStructuredLan::SaveTables(const int fh) const
|
| | | {
|
| | | //---
|
| | | FileWriteInteger(fh, m_tables_size);
|
| | |
|
| | | //---
|
| | | for(int i = 0; i < m_tables_size; i++)
|
| | | {
|
| | | const int table_size = m_tables[i].table_size;
|
2026-10-08 13:38:10 -05:00 | | | const ulong v = m_tables[i].sizes;
|
| | | const int bucket_size = (int)BSFL_T_GET_BUCKET_L(v) + 1;
|
| | | const int final_size = (int)BSFL_T_GET_FINALTABLE_L(v) + 1;
|
2026-10-05 17:54:12 -05:00 | | |
|
2026-10-08 13:38:10 -05:00 | | | //---
|
2026-10-05 17:54:12 -05:00 | | | FileWriteInteger(fh, m_tables[i].start);
|
| | | FileWriteInteger(fh, table_size);
|
| | | FileWriteInteger(fh, bucket_size);
|
| | | FileWriteInteger(fh, final_size);
|
| | |
|
| | | //---
|
| | | FileWriteArray(fh, m_tables[i].seeds, 0, bucket_size);
|
| | | FileWriteArray(fh, m_tables[i].pos_index, 0, final_size);
|
| | | FileWriteArray(fh, m_tables[i].key_hash, 0, final_size);
|
| | | FileWriteArray(fh, m_tables[i].pos_arr, 0, table_size);
|
| | | }
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | void CBaseStructuredLan::LoadTables(const int fh)
|
| | | {
|
| | | //---
|
| | | m_tables_size = FileReadInteger(fh);
|
| | | m_tables_reserve = m_tables_size;
|
| | | ArrayResize(m_tables, m_tables_size, m_tables_size);
|
| | |
|
| | | //---
|
| | | for(int i = 0; i < m_tables_size; i++)
|
| | | {
|
2026-10-08 13:38:10 -05:00 | | | //---
|
2026-10-05 17:54:12 -05:00 | | | m_tables[i].start = FileReadInteger(fh);
|
| | | const int table_size = FileReadInteger(fh);
|
| | | m_tables[i].table_size = table_size;
|
2026-10-08 13:38:10 -05:00 | | |
|
| | | //---
|
2026-10-05 17:54:12 -05:00 | | | const int bucket_size = FileReadInteger(fh);
|
| | | const int final_size = FileReadInteger(fh);
|
2026-10-08 13:38:10 -05:00 | | |
|
| | | //---
|
| | | m_tables[i].sizes = BSFL_T_PACK(bucket_size - 1, final_size - 1);
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //---
|
| | | FileReadArray(fh, m_tables[i].seeds, 0, bucket_size);
|
| | | FileReadArray(fh, m_tables[i].pos_index, 0, final_size);
|
| | | FileReadArray(fh, m_tables[i].key_hash, 0, final_size);
|
| | | FileReadArray(fh, m_tables[i].pos_arr, 0, table_size);
|
| | | }
|
| | | }
|
| | |
|
2026-10-08 13:38:10 -05:00 | | |
|
2026-10-05 17:54:12 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-10-08 13:38:10 -05:00 | | | __forceinline int CBaseStructuredLan::FindNodePos(const int start) const
|
| | | {
|
| | | for(short i = 0; i < m_tables_size; i++)
|
| | | if(m_tables[i].start == start)
|
| | | return i;
|
| | | return -1;
|
| | | }
|
| | |
|
| | | //---
|
2026-10-05 17:54:12 -05:00 | | | #define BASESPARSERSLAN_START_NODE_HASH(TABLE_POS, START) \
|
| | | for(short i = 0; i < m_tables_size; i++) \
|
| | | { \
|
| | | if(m_tables[i].start == START) \
|
| | | { \
|
| | | TABLE_POS = i; \
|
2026-10-08 21:47:12 -05:00 | | | return; \
|
2026-10-05 17:54:12 -05:00 | | | } \
|
| | | } \
|
| | | if(m_tables_size >= m_tables_reserve) \
|
| | | { \
|
| | | m_tables_reserve += 8; \
|
| | | ArrayResize(m_tables, m_tables_reserve, m_tables_reserve); \
|
| | | } \
|
| | | TABLE_POS = m_tables_size; \
|
| | | m_tables[m_tables_size++].start = START;
|
| | |
|
| | |
|
2026-10-08 13:38:10 -05:00 | | | //---
|
2026-10-05 17:54:12 -05:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-10-05 18:16:09 -05:00 | | | #endif // BASESPARSERSLAN_SRC_BASECLASS_MAIN_MQH
|