JsonParserByLeo/Src/DLL/Parser.cpp
2026-08-26 21:25:09 -05:00

448 lines
13 KiB
C++

//+------------------------------------------------------------------+
//| Parser.cpp |
//| Copyright 2026, Niquel Mendoza. |
//| https://www.mql5.com/ |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Parser.h"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// array ya allocado tambein raw solo hace falta rellenar
using namespace TSN;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Solo lo resizea.. y maneja el tema de reserva.. nada mas.. (en m_index)
// m_raw ya se maneja por mql
// len tambien
// m_last err tamiben se inicia
// m_cintapos tambien se incia por qml
// pos no asi que lo hacemos aqui
// offsert se nos pasa
// cinta tambien se nos pasa pero lo contrala mql
// index se nos pasa nosotrs oslo modifcamos
extern "C" __declspec(dllexport)
bool __stdcall JsonParserResolve(const uint8_t* m_raw, const int len, int* m_last_err, int* m_cinta_pos,
int* m_pos, const int m_offset, int64_t* m_cinta, int* m_index)
{
//--- Stacks
uint32_t m_stak_num[JSONPARSERBYLEO_MAX_STACK];
int32_t m_stak_pos[JSONPARSERBYLEO_MAX_STACK];
uint16_t m_stak_state[JSONPARSERBYLEO_MAX_STACK];
int32_t m_stak_curr = -1;
uint16_t m_stak_curr_state = 0;
uint8_t m_next = TSN_JSON_TOK_INVALID;
//--- Inicio de miembros
(*m_pos) = m_offset;
//--- Temp
ulong prev_in_string = 0ULL;
ulong prev_scape = 0ULL;
int index_s = 0;
//--- Intrisicos masks
const __m256i mask_20 = _mm256_set1_epi8(0x20);
const __m256i bs_mask = _mm256_set1_epi8('\\');
const __m256i qt_mask = _mm256_set1_epi8('"');
const __m128i all_ones = _mm_set1_epi8(0xFF);
const __m256i op_table = _mm256_broadcastsi128_si256(_mm_setr_epi8(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, ':', '{',
',', '}', 0, 0
));
//--- Fase inicial
do
{
// carga inicial
__m256i chunk_lo = _mm256_loadu_si256((const __m256i*)(m_raw + (*m_pos))); // bytes 0-31
__m256i chunk_hi = _mm256_loadu_si256((const __m256i*)(m_raw + (*m_pos) + 32)); // bytes 32-63
//--- Detectamos bs
const uint32_t bs_bits_lo = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_lo, bs_mask));
const uint32_t bs_bits_hi = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_hi, bs_mask));
//--- Detectamos qt
const uint32_t qt_bits_lo = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_lo, qt_mask));
const uint32_t qt_bits_hi = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_hi, qt_mask));
//---
// compactamos ambos
const ulong compacted_bs = ((ulong)bs_bits_hi << 32) | bs_bits_lo;
const ulong compacted_qt = ((ulong)qt_bits_hi << 32) | qt_bits_lo;
//---
const ulong compacted_bs_masked = compacted_bs & ~prev_scape;
const ulong prev = (((compacted_bs_masked << 1) | TSNTABLES_MASK_IMPARES_F) - compacted_bs_masked) ^ TSNTABLES_MASK_IMPARES_F;
const ulong escaped = prev ^ (compacted_bs | prev_scape);
prev_scape = (prev & compacted_bs_masked) >> 63;
//---
ulong qt_final = compacted_qt & ~escaped;
const ulong quoted_pos = qt_final;
//--- prefix xor
__m128i clmul = _mm_clmulepi64_si128(_mm_set_epi64x(0, qt_final), all_ones, 0);
qt_final = (uint64_t)_mm_cvtsi128_si64(clmul);
const ulong in_string = qt_final ^ prev_in_string;
//--- Ahora obtenemos los strucutrurales
// ahora lo qeu haremos sera un or entre la masra de 0x20
// La idea econ esto es que (en las siugientes) lineas hay un problema
// noramlte con shuffle si tenemos lo sigueinte {}
// se genera
// {} (tal cual bien)
// pero si tenemos
// [] se genra {} (esto es por que se genera eso en base a los bajos)
// entonces esto luego con el cmp que se hace estair ocmprand [ con { lo qeu daria 0 asi qeu se perderia
// los caracteres estrucutalres, por eso le debemos de aumenar 0x20, esto hace que [ pase a {
// con eso soluicionas dicho problema..
__m256i curl_lo = _mm256_or_si256(chunk_lo, mask_20);
__m256i curl_hi = _mm256_or_si256(chunk_hi, mask_20);
// ahora usarmeos shuffle para hacer lo sigeuinte
// : = 1010
// ] y } = 1011
// , = 1100
// Como para generar strucuturales rapdios, la idea es quedarse solo con los estrucuturales
// Aparte metemos un eq para confirmar.. pro qeu ahroa mismo la mascara previa
// peude dar falsso posiivots (dado qeu eso de 1010... puede repetirse)
__m256i op_lo = _mm256_cmpeq_epi8(_mm256_shuffle_epi8(op_table, chunk_lo), curl_lo);
__m256i op_hi = _mm256_cmpeq_epi8(_mm256_shuffle_epi8(op_table, chunk_hi), curl_hi);
// ahora lo basmoas a 1\0 no bytes.. para trabajar..
uint32_t bits_lo = (uint32_t)_mm256_movemask_epi8(op_lo);
uint32_t bits_hi = (uint32_t)_mm256_movemask_epi8(op_hi);
uint64_t result = ((uint64_t)bits_hi << 32) | bits_lo;
//--- overflow
prev_in_string = uint64_t(static_cast<int64_t>(in_string) >> 63);
ulong structural = (result & ~in_string) | quoted_pos;
//--- Numero de unos aqui..
const int cnt = _mm_popcnt_u64(structural);
int written = 0;
//---
while(written + 4 <= cnt)
{
m_index[index_s++] = (*m_pos) + _tzcnt_u64(structural);
structural &= structural - 1;
m_index[index_s++] = (*m_pos) + _tzcnt_u64(structural);
structural &= structural - 1;
m_index[index_s++] = (*m_pos) + _tzcnt_u64(structural);
structural &= structural - 1;
m_index[index_s++] = (*m_pos) + _tzcnt_u64(structural);
structural &= structural - 1;
written += 4;
}
// Resto (0-3 elementos sobrantes), bucle normal
while(written < cnt)
{
m_index[index_s++] = (*m_pos) + _tzcnt_u64(structural);
structural &= structural - 1;
written++;
}
(*m_pos) += 64; // avanzamos 64 caracteres..
// Seguimos con check
}
while(((*m_pos) + 64) < len);
//---
if(index_s < 2)
{
// errro
*m_last_err = TSN_JSON_ERR_NOT_STRUCUTURAL_CHARS_FOUND;
return false;
}
//--- Fase 2
int sp = 0;
(*m_pos) = m_index[sp]; // Posicion
m_next = g_table_json_tokens[m_raw[(*m_pos)]]; // primer
//--- Iteracion
while(true)
{
switch(m_next)
{
case TSN_JSON_TOK_NUMBER_NEG:
{
(*m_pos)++;
JSONPARSERBYLEO_PARSE_NUMBER(-1)
//---
JSONPARSERBYLEO_FULL_NEXT
break;
}
case TSN_JSON_TOK_NUMBER:
{
//---
JSONPARSERBYLEO_PARSE_NUMBER(0)
//---
JSONPARSERBYLEO_FULL_NEXT
break;
}
//---
case TSN_JSON_TOK_STRING:
{
//---
//TSN_JSON_RESERVAR(2)
//---
const int start = m_index[sp++] + 1; // luego del "
(*m_pos) = m_index[sp++]; // justo en "
//---
m_cinta[(*m_cinta_pos)++] = JSON_VTYPE_STRING
| int64_t((*m_pos) - start) << TSN_SBL_BIT_STR_LEN
| int64_t(start) << TSN_SBL_BIT_STR_START;
//---
JSONPARSERBYLEO_FULL_NEXT
//---
break;
}
case TSN_JSON_TOK_BOOL_TRUE:
{
//TSN_JSON_RESERVAR(1)
// t r u e W
// [-4] [-3] [-2] [-1] [0]
(*m_pos) += 4;
// 5 | 1 << TSN_SBL_BIT_START_BOOL(4) = 21
m_cinta[(*m_cinta_pos)++] = 21;
//---
JSONPARSERBYLEO_FULL_NEXT
break;
}
case TSN_JSON_TOK_BOOL_FALSE:
{
//TSN_JSON_RESERVAR(1)
// f a l s e W
// [] [-4] [-3] [-2 ] [-1] [0]
(*m_pos) += 5;
m_cinta[(*m_cinta_pos)++] = JSON_VTYPE_BOOLEAN;
//---
JSONPARSERBYLEO_FULL_NEXT
break;
}
case TSN_JSON_TOK_NULL:
{
//TSN_JSON_RESERVAR(1)
// n u l l W
// [-4][-3][-2][-1][]
//---
(*m_pos) += 4;
m_cinta[(*m_cinta_pos)++] = JSON_VTYPE_NULL;
//---
JSONPARSERBYLEO_FULL_NEXT
break;
}
case TSN_JSON_TOK_COMMA:
{
//---
m_stak_num[m_stak_curr]++;
//---
(*m_pos)++;
//---
if(m_stak_curr_state == TSN_JSON_CTX_IN_OBJ)
{
//---
const int start = m_index[sp++] + 1; // luego del "
(*m_pos) = m_index[sp++]; // justo en "
//Print("start: " , start, " len: " , ((*m_pos) - start));
//---
m_cinta[(*m_cinta_pos)++] = (int64_t)JSON_VTYPE_KEY
| int64_t((*m_pos) - start) << TSN_SBL_BIT_STR_LEN
| int64_t(start) << TSN_SBL_BIT_STR_START;
// Print(EnumToString(ENUM_JSON_VTYPE(m_cinta[(*m_cinta_pos) - 1] & 0xf)));
//---
(*m_pos) = m_index[sp++];
if(m_raw[(*m_pos)++] != ':')
{
*m_last_err = TSN_JSON_ERR_MALFODERD_KEY_EXPECTED_DOS_PUNTOS;
return false;
}
// Ahora si buscamos valor
}
TSN_JSON_NEXT_VALUE_COMM_KEY
break;
}
case TSN_JSON_TOK_LLAVE_INI:
{
//---
sp++;
//TSN_JSON_RESERVAR(1)
m_cinta[(*m_cinta_pos)] = JSON_VTYPE_OBJ;
//---
m_stak_curr++;
if(m_stak_curr >= JSONPARSERBYLEO_MAX_STACK)
{
*m_last_err = TSN_JSON_ERR_OVERFLOW_IN_STACK;
return false; // overflow
}
//---
m_stak_curr_state = TSN_JSON_CTX_IN_OBJ;
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_OBJ;
m_stak_num[m_stak_curr] = 0;
m_stak_pos[m_stak_curr] = (*m_cinta_pos)++;
//---
m_cinta[(*m_cinta_pos)++] = (*m_pos)++;
//---
(*m_pos) = m_index[sp++];
if(m_raw[(*m_pos)] == '}')
{
m_next = TSN_JSON_TOK_LLAVE_END;
}
else
{
const int start = ++(*m_pos);
(*m_pos) = m_index[sp++]; // justo en "
//--- Capturamos
m_cinta[(*m_cinta_pos)++] = JSON_VTYPE_KEY
| int64_t((*m_pos) - start) << TSN_SBL_BIT_STR_LEN
| int64_t(start) << TSN_SBL_BIT_STR_START;
//---
(*m_pos) = m_index[sp++];
if(m_raw[(*m_pos)++] != ':')
{
*m_last_err = TSN_JSON_ERR_MALFODERD_KEY_EXPECTED_DOS_PUNTOS;
return false;
}
// Ahora a buscar valor
TSN_JSON_NEXT_VALUE_COMM_KEY
}
//---
break;
}
case TSN_JSON_TOK_COR_INI:
{
//---
sp++;
//TSN_JSON_RESERVAR(1)
m_cinta[(*m_cinta_pos)] = JSON_VTYPE_ARR;
//---
m_stak_curr++;
if(m_stak_curr >= JSONPARSERBYLEO_MAX_STACK)
{
*m_last_err = TSN_JSON_ERR_OVERFLOW_IN_STACK;
return false; // overflow
}
//---
m_stak_curr_state = TSN_JSON_CTX_IN_ARR;
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_ARR;
m_stak_num[m_stak_curr] = 0;
m_stak_pos[m_stak_curr] = (*m_cinta_pos)++;
//---
m_cinta[(*m_cinta_pos)++] = (*m_pos)++;
//Print(CharToString(m_raw[(*m_pos)]));
//---
const int n = m_index[sp];
if(m_raw[n] != ']')
{
TSN_JSON_NEXT_COR_INI
}
else
{
sp++;
(*m_pos) = n;
m_next = TSN_JSON_TOK_LLAVE_END;
}
//---
break;
}
// tema de ends ya lo scaa en next el sp
case TSN_JSON_TOK_LLAVE_END:
case TSN_JSON_TOK_COR_END:
{
//---
//sp++;
//---
if((*m_cinta_pos) > m_stak_pos[m_stak_curr] + 2) // [a][a][v][c]
{
m_stak_num[m_stak_curr]++;
}
//---
const int lp = m_stak_pos[m_stak_curr];
m_cinta[lp] |= int64_t(m_stak_num[m_stak_curr]) << TSN_SBL_BIT_START_NUM_EL | int64_t((*m_cinta_pos) - lp) << TSN_SBL_BIT_START_NUM_C;
m_cinta[lp + 1] |= int64_t((*m_pos)) << TSN_JSON_BIT_END_T;
//---
//m_stak_curr--;
//---
if(--m_stak_curr < 0)
return true;
//---
m_stak_curr_state = m_stak_state[m_stak_curr];
//---
(*m_pos)++;
//---
JSONPARSERBYLEO_FULL_NEXT
//---
break;
}
//---
default:
{
*m_last_err = TSN_JSON_ERR_INVALID_CHAR;
return false;
}
}
}
//---
*m_last_err = TSN_JSON_ERR_JSON_NOT_FINISH;
return false;
}
//+------------------------------------------------------------------+