forked from nique_372/JsonParserByLeo
448 lines
13 KiB
C++
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;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|