TSNTranslations/Src/LanBackend/Parser.mqh
519 lines
17 KiB
MQL5
Nique_372
2026-10-26 22:11:57 -05:00
//+------------------------------------------------------------------+
//| Parser.mqh |
//| Copyright 2026, Niquel Mendoza. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Niquel Mendoza."
#property link "https://www.mql5.com"
#property strict
#ifndef TSNTRANSLATIONS_SRC_LANBACKEND_PARSER_MQH
#define TSNTRANSLATIONS_SRC_LANBACKEND_PARSER_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Defines.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CTSNLanParser : public CBaseLanFormat
{
private:
ENUM_TSN_JSONTRANSLATE_ERR m_last_err;
uchar m_next_p;
public:
CTSNLanParser(void) {}
~CTSNLanParser(void) {}
//---
// Parsea un json cualquier de iiudioams y genera un tempalte (plantilla)
// En su tape
bool ParseTemplate();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#define TSNTRANSLAN_ADD_STR m_cinta[m_cinta_pos++] = TSN_JSONTRANSLATE_VTYPE_STR;
//---
#define TSNTRANSLAN_AUMENT curr_count++;
//---
#define TSNTRANSLAN_ITER_KEY(H, C) \
if((C=m_raw[++m_pos])=='"') \
break; \
Nique_372
2026-10-27 10:48:31 -05:00
H ^= C; \
H *= FNV_PRIME;
Nique_372
2026-10-26 22:11:57 -05:00
//---
#define TSNTRANSLAN_ITER_KEY_U16(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C) \
TSNTRANSLAN_ITER_KEY(H, C)
//---
Nique_372
2026-10-27 10:48:31 -05:00
// 91 >> 5 = 2 ([) 0 (&1)
// 123 >> 5 = 3 ({) 1 (&1)
// Lo mismo aplica para ends
//--- Skip ws
// Basic skip ws (con salto previo)
#define TSNTRANSLATE_SWIPWS_WSKI_CURR while((_last_c = m_raw[++m_pos]) < 33) {}
// Primero cachea y luego ya.. n
#define TSNTRANSLATE_SWIPWS_WSKI_NONE \
_last_c = m_raw[m_pos]; \
while(_last_c < 33) { _last_c = m_raw[++m_pos]; }
//---
#define TSNTRANSLATE_NEXT_NO_NEXT_KEY_P \
if(_last_c==',') \
m_next=TSN_JSONTRANSLATE_TOK_COMMA; \
else if(_last_c==curr_state) \
m_next=TSN_JSONTRANSLATE_TOK_COR_END-((_last_c>>5)&1); \
else if(TSN_JSONTRANSLATE_IS_COMMENT(_last_c)) \
{ \
m_next_p=TSN_JSONTRANSLATE_TOK_EXT_NONEXT_KEY; \
m_next=TSN_JSONTRANSLATE_TOK_COMMENT_MQL; \
} \
else \
{ \
m_last_err=TSN_JSONTRANSLATE_MALFORMED_FIND_VAL; \
m_next=TSN_JSONTRANSLATE_TOK_INVALID; \
Nique_372
2026-10-26 22:11:57 -05:00
}
Nique_372
2026-10-27 10:48:31 -05:00
//--- Buscando un valor
// Siguiente valor (cualquiera)
Nique_372
2026-10-26 22:11:57 -05:00
#define TSNTRANSLATE_NEXT_VALUE(CASE) \
Nique_372
2026-10-27 10:48:31 -05:00
if(_last_c == '"') \
Nique_372
2026-10-26 22:11:57 -05:00
m_next = TSN_JSONTRANSLATE_TOK_STRING; \
else \
Nique_372
2026-10-27 10:48:31 -05:00
if((_last_c | 0x20) == '{') \
m_next = TSN_JSONTRANSLATE_TOK_COR_INI - ((_last_c>>5)&1); \
Nique_372
2026-10-26 22:11:57 -05:00
else \
Nique_372
2026-10-27 10:48:31 -05:00
if(TSN_JSONTRANSLATE_IS_COMMENT(_last_c)) \
Nique_372
2026-10-26 22:11:57 -05:00
{ \
m_next_p = CASE; \
m_next = TSN_JSONTRANSLATE_TOK_COMMENT_MQL; \
} \
else \
{ \
m_last_err = TSN_JSONTRANSLATE_MALFORMED_AFTER_COMMA_OBJ; \
m_next = TSN_JSONTRANSLATE_TOK_INVALID; \
}
//--- Obj key
Nique_372
2026-10-27 10:48:31 -05:00
// Solo key o comentario
#define TSNTRANSLATE_NEXT_OBJ_INITIAL(CASE) \
if(_last_c == '"') \
m_next = TSN_JSONTRANSLATE_TOK_KEY; \
else \
if(TSN_JSONTRANSLATE_IS_COMMENT(_last_c)) \
{ \
Nique_372
2026-10-26 22:11:57 -05:00
m_next_p = CASE; \
m_next = TSN_JSONTRANSLATE_TOK_COMMENT_MQL; \
} \
else \
{ \
m_last_err = TSN_JSONTRANSLATE_MALFORMED_AFTER_COMMA_OBJ; \
m_next = TSN_JSONTRANSLATE_TOK_INVALID; \
}
Nique_372
2026-10-27 10:48:31 -05:00
//--- Versiones completa
// No next key
#define TSNTRANSLATE_NEXT_NO_NEXT_KEY \
TSNTRANSLATE_SWIPWS_WSKI_NONE \
TSNTRANSLATE_NEXT_NO_NEXT_KEY_P
Nique_372
2026-10-26 22:11:57 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CTSNLanParser::ParseTemplate(void)
{
//---
m_last_err = TSN_JSONTRANSLATE_ERR_NOT;
m_pos = m_offset;
m_cinta_pos = 0;
//---
Nique_372
2026-10-27 10:48:31 -05:00
uchar curr_state = 0;
uchar _last_c = 0;
Nique_372
2026-10-26 22:11:57 -05:00
uint curr_count = 0;
uint curr_padre = 0;
//--- Inicial (Solo se acpeta {)
const uchar _f_c = m_raw[m_pos];
if(_f_c == '{')
m_next = TSN_JSONTRANSLATE_TOK_LLAVE_INI;
else // No easy
{
uchar __c = m_raw[++m_pos];
while(__c < 33)
__c = m_raw[++m_pos];
Nique_372
2026-10-27 10:48:31 -05:00
Nique_372
2026-10-26 22:11:57 -05:00
//---
Nique_372
2026-10-27 10:48:31 -05:00
if(__c == '{')
m_next = TSN_JSONTRANSLATE_TOK_LLAVE_INI;
else
m_next = TSN_JSONTRANSLATE_TOK_INVALID;
Nique_372
2026-10-26 22:11:57 -05:00
}
//--- Bucle
while(true)
{
switch(m_next)
{
case TSN_JSONTRANSLATE_TOK_STRING:
{
//---
m_pos++; // salta "
//--- Pase inicial 8 en 8
while(true)
{
// PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8));
const ulong chunk = (ulong)m_raw[m_pos]
| (ulong)m_raw[m_pos + 1] << 8
| (ulong)m_raw[m_pos + 2] << 16
| (ulong)m_raw[m_pos + 3] << 24
| (ulong)m_raw[m_pos + 4] << 32
| (ulong)m_raw[m_pos + 5] << 40
| (ulong)m_raw[m_pos + 6] << 48
| (ulong)m_raw[m_pos + 7] << 56;
//---
const ulong x_bs = chunk ^ TSNTABLES_SWAR_MASK_BACK_SLASH;
const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA;
ulong has_bs = TSNTABLES_SWAR_HAS(x_bs);
ulong has_qt = TSNTABLES_SWAR_HAS(x_qt);
//---
if((has_bs | has_qt) == 0) // Fast path
{
m_pos += 8;
continue;
}
//---
if(has_bs == 0) // Si not iene bs (pero confirmamos que no es 0) (Fast path)
{
const ulong flag_real = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE(has_qt);
m_pos += TSNTABLES_CTZ_64_GET_BYTE(flag_real);
TSNTRANSLAN_ADD_STR
m_pos++; // Luego del "
break;
}
//--- Slow path
has_bs = TSNTABLES_SWAR_HAS_EXACT(x_bs);
has_qt = TSNTABLES_SWAR_HAS_EXACT(x_qt);
//--- Hay bs si o si pero tambien puede haber "
const uchar compacted_bs = TSNTABLES_COMPACT_UL(has_bs);
const uchar prev = (((compacted_bs << 1) | TSNTABLES_MASK_IMPARES) - compacted_bs) ^ TSNTABLES_MASK_IMPARES;
const uchar escaped = prev ^ compacted_bs;
//---
const uchar compacted_qt = TSNTABLES_COMPACT_UL(has_qt);
const uchar qt_final = compacted_qt & ~escaped;
//Print("nada");
//---
if(qt_final) // Hay un qt real de cierre
{
//---
// Avanzamos y cerramos..
m_pos += g_tsntables_table_ctz_i8[qt_final];
TSNTRANSLAN_ADD_STR
m_pos++;
break;
}
else
{
m_pos += 8;// + ((prev & compacted_bs) >> 7U);
// Print(CharToString(m_raw[m_pos]));
// escape
if(((prev & compacted_bs) >> 7U) != 0) // Overflow el ultimo char es \ y el siguiente escapa
m_pos++; // Uno mas.. luego del currend
}
}
//---
TSNTRANSLAN_AUMENT
Nique_372
2026-10-27 10:48:31 -05:00
//---
Nique_372
2026-10-26 22:11:57 -05:00
TSNTRANSLATE_NEXT_NO_NEXT_KEY
//---
break;
}
case TSN_JSONTRANSLATE_TOK_KEY:
{
//---
// no salto dado que igual hace ++m_pos luego
ulong h = FNV_OFFSET_BASIS;
while(true)
{
Nique_372
2026-10-27 10:48:31 -05:00
TSNTRANSLAN_ITER_KEY_U16(h, _last_c)
Nique_372
2026-10-26 22:11:57 -05:00
}
//---
m_cinta[m_cinta_pos++] = TSN_JSONTRANSLATE_VTYPE_KEY;
m_cinta[m_cinta_pos++] = h;
m_pos++;
//--- Find :
while(m_raw[m_pos] != ':')
{
m_pos++;
if(m_pos >= m_len)
{
m_last_err = TSN_JSONTRANSLATE_EXPECTED_TWO_POINT_AFT_KEY;
return false;
}
}
//--- Buscamos valor
Nique_372
2026-10-27 10:48:31 -05:00
TSNTRANSLATE_SWIPWS_WSKI_CURR
Nique_372
2026-10-26 22:11:57 -05:00
TSNTRANSLATE_NEXT_VALUE(TSN_JSONTRANSLATE_TOK_EXT_NEXT_VV)
//---
break;
}
//---
case TSN_JSONTRANSLATE_TOK_COMMA: // luego se permite un valor (inicio)
{
//---
Nique_372
2026-10-27 10:48:31 -05:00
TSNTRANSLATE_SWIPWS_WSKI_CURR
Nique_372
2026-10-26 22:11:57 -05:00
//---
Nique_372
2026-10-27 10:48:31 -05:00
if(curr_state == TSNTRANSLAN_CTX_OBJ)
Nique_372
2026-10-26 22:11:57 -05:00
{
TSNTRANSLATE_NEXT_OBJ_INITIAL(TSN_JSONTRANSLATE_TOK_COMMA)
}
else // " [ { /
{
TSNTRANSLATE_NEXT_VALUE(TSN_JSONTRANSLATE_TOK_COMMA)
}
break;
}
//---
Nique_372
2026-10-27 10:48:31 -05:00
// para el ini []
// mismo formato qeu json [type(1)|cintapos(32)|curr_padre(31)]
Nique_372
2026-10-26 22:11:57 -05:00
case TSN_JSONTRANSLATE_TOK_LLAVE_INI:
{
//--- guardar lo uqe tenaismos (numero de elementos) (+1 para contar este nuevo elemento)
m_cinta[curr_padre] = curr_count + 1;
//--- nuevo, ahora guardamos la direccion de nuesto padre y la nuestar (rempalzao num el por mientas)
Nique_372
2026-10-27 10:48:31 -05:00
m_cinta[m_cinta_pos] = TSN_JSONTRANSLATE_VTYPE_OBJ |
Nique_372
2026-10-26 22:11:57 -05:00
ulong(m_cinta_pos) << TSN_SBL_PARSE_START_CINTAPOS |
ulong(curr_padre) << TSN_SBL_BIT_START_NUM_C;
curr_padre = ++m_cinta_pos; // apunta al inicio + 1 (lo modificamos para count, ahora apunta aqui..)
m_cinta_pos++; // salta la posicion 1
//--- reiniciamos los estados
Nique_372
2026-10-27 10:48:31 -05:00
curr_state = TSNTRANSLAN_CTX_OBJ;
Nique_372
2026-10-26 22:11:57 -05:00
curr_count = 0;
//---
Nique_372
2026-10-27 10:48:31 -05:00
TSNTRANSLATE_SWIPWS_WSKI_CURR
Nique_372
2026-10-26 22:11:57 -05:00
TSNTRANSLATE_NEXT_OBJ_INITIAL(TSN_JSONTRANSLATE_TOK_EXT_NEXT_OBJV)
break;
}
case TSN_JSONTRANSLATE_TOK_COR_INI:
{
//--- guardar lo uqe tenaismos (numero de elementos) (+1 para contar este nuevo elemento)
m_cinta[curr_padre] = curr_count + 1;
//--- nuevo, ahora guardamos la direccion de nuesto padre y la nuestar (rempalzao num el por mientas)
Nique_372
2026-10-27 10:48:31 -05:00
m_cinta[m_cinta_pos] = TSN_JSONTRANSLATE_VTYPE_ARR |
Nique_372
2026-10-26 22:11:57 -05:00
ulong(m_cinta_pos) << TSN_SBL_PARSE_START_CINTAPOS |
ulong(curr_padre) << TSN_SBL_BIT_START_NUM_C;
curr_padre = ++m_cinta_pos; // apunta al inicio + 1 (lo modificamos para count, ahora apunta aqui..)
m_cinta_pos++; // salta la posicion 1
//--- reiniciamos los estados
Nique_372
2026-10-27 10:48:31 -05:00
curr_state = TSNTRANSLAN_CTX_ARR;
Nique_372
2026-10-26 22:11:57 -05:00
curr_count = 0;
//--- Find
Nique_372
2026-10-27 10:48:31 -05:00
TSNTRANSLATE_SWIPWS_WSKI_CURR
Nique_372
2026-10-26 22:11:57 -05:00
TSNTRANSLATE_NEXT_VALUE(TSN_JSONTRANSLATE_TOK_EXT_NEXT_VV)
break;
}
Nique_372
2026-10-27 10:48:31 -05:00
//--- ends
Nique_372
2026-10-26 22:11:57 -05:00
case TSN_JSONTRANSLATE_TOK_LLAVE_END:
{
//--- cacheamos el valor de cinta [curr_padre-1] = apunta a los datos
Nique_372
2026-10-27 10:48:31 -05:00
m_cinta[curr_padre] = 1ull; // le damos su valor final
Nique_372
2026-10-26 22:11:57 -05:00
const uint idata = --curr_padre;
const ulong v = m_cinta[idata];
// ahora si rehacemos el valor con todo ya listo.. (curr padre apunta a la posicion correcta)
Nique_372
2026-10-27 10:48:31 -05:00
m_cinta[idata] = TSN_JSONTRANSLATE_VTYPE_OBJ | ulong(curr_count) << TSNTRANSLAN_BITSTART_NUMEL |
ulong(m_cinta_pos - ((v >> 1) & TSN_SBL_PARSE_MASK_CINTAPOS_S)) << TSNTRANSLAN_BITSTART_CINSALTAR;
Nique_372
2026-10-26 22:11:57 -05:00
curr_padre = uint(v >> TSN_SBL_BIT_START_NUM_C); // ahora obtenemos su padre..
//---
if(curr_padre == idata) // dado que cur_padre apunta a la psocion 2.. [0][1 aqui] entonces con 1...
return true;
//---
curr_count = (uint)m_cinta[curr_padre]; // le devolvemos..
Nique_372
2026-10-27 10:48:31 -05:00
curr_state = TSNTRANSLAN_MAKESTATE(m_cinta[curr_padre - 1] & TSN_SBL_PARSE_MASK_OA_T);
Nique_372
2026-10-26 22:11:57 -05:00
m_pos++;
//---
TSNTRANSLATE_NEXT_NO_NEXT_KEY
break;
}
case TSN_JSONTRANSLATE_TOK_COR_END:
{
//--- cacheamos el valor de cinta [curr_padre-1] = apunta a los datos
const uint idata = --curr_padre;
const ulong v = m_cinta[idata];
// ahora si rehacemos el valor con todo ya listo.. (curr padre apunta a la posicion correcta)
Nique_372
2026-10-27 10:48:31 -05:00
m_cinta[idata] = TSN_JSONTRANSLATE_VTYPE_ARR | ulong(curr_count) << TSNTRANSLAN_BITSTART_NUMEL |
ulong(m_cinta_pos - ((v >> 1) & TSN_SBL_PARSE_MASK_CINTAPOS_S)) << TSNTRANSLAN_BITSTART_CINSALTAR;
Nique_372
2026-10-26 22:11:57 -05:00
curr_padre = uint(v >> TSN_SBL_BIT_START_NUM_C); // ahora obtenemos su padre..
//---
if(curr_padre == idata) // dado que cur_padre apunta a la psocion 2.. [0][1 aqui] entonces con 1...
return true;
//---
curr_count = (uint)m_cinta[curr_padre]; // le devolvemos..
Nique_372
2026-10-27 10:48:31 -05:00
curr_state = TSNTRANSLAN_MAKESTATE(m_cinta[curr_padre - 1] & TSN_SBL_PARSE_MASK_OA_T);
Nique_372
2026-10-26 22:11:57 -05:00
m_pos++;
//---
TSNTRANSLATE_NEXT_NO_NEXT_KEY
break;
}
Nique_372
2026-10-27 10:48:31 -05:00
//--- Comment
Nique_372
2026-10-26 22:11:57 -05:00
case TSN_JSONTRANSLATE_TOK_COMMENT_MQL:
{
//---
m_pos++; // salta el iniciador
Nique_372
2026-10-27 10:48:31 -05:00
//--- Pase inicial 8 en 8 buscando el \n
Nique_372
2026-10-26 22:11:57 -05:00
while(true)
{
// PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8));
const ulong chunk = (ulong)m_raw[m_pos]
| (ulong)m_raw[m_pos + 1] << 8
| (ulong)m_raw[m_pos + 2] << 16
| (ulong)m_raw[m_pos + 3] << 24
| (ulong)m_raw[m_pos + 4] << 32
| (ulong)m_raw[m_pos + 5] << 40
| (ulong)m_raw[m_pos + 6] << 48
| (ulong)m_raw[m_pos + 7] << 56;
//---
const ulong x = chunk ^ TSNTABLES_SWAR_MASK_NEW_LINE;
const ulong has_x = TSNTABLES_SWAR_HAS(x);
Nique_372
2026-10-27 10:48:31 -05:00
if(!has_x)
Nique_372
2026-10-26 22:11:57 -05:00
{
m_pos += 8;
continue;
}
//---
const ulong flag_real = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE(has_x);
m_pos += TSNTABLES_CTZ_64_GET_BYTE(flag_real);
Nique_372
2026-10-27 10:48:31 -05:00
//--- skip ws
while((_last_c = m_raw[++m_pos]) < 33) {}
//--- verificamos
if(TSN_JSONTRANSLATE_IS_COMMENT(_last_c))
continue;
break; // Salimos ya con el caracter hecho
Nique_372
2026-10-26 22:11:57 -05:00
}
//---
m_next = m_next_p; // sigue
break;
}
//--- Extensiones
case TSN_JSONTRANSLATE_TOK_EXT_NONEXT_KEY: // solo se callea en comentarios..
{
TSNTRANSLATE_NEXT_NO_NEXT_KEY
break;
}
case TSN_JSONTRANSLATE_TOK_EXT_NEXT_OBJV:
{
TSNTRANSLATE_NEXT_OBJ_INITIAL(TSN_JSONTRANSLATE_TOK_EXT_NEXT_OBJV)
break;
}
case TSN_JSONTRANSLATE_TOK_EXT_NEXT_VV: // Se callea en comentariso
{
TSNTRANSLATE_NEXT_VALUE(TSN_JSONTRANSLATE_TOK_EXT_NEXT_VV)
break;
}
//--- invalid
default:
return false;
}
}
}
//---
}
/*
Templates:
1. Se itera por todo el texto se crea documento inicial
2. Ahora si en una segunda pasada se itera ahora sobre los "Strucutales" con un cursor sobre el tape..
La idea es armar el buf sin nada mas...
Nique_372
2026-10-27 10:48:31 -05:00
{
"valor" : "
como estas amigo ?
yo estoy bien
"
}
Nique_372
2026-10-26 22:11:57 -05:00
*/
//+------------------------------------------------------------------+
#endif // TSNTRANSLATIONS_SRC_LANBACKEND_PARSER_MQH