ExpressEvalByLeo/Src/MathEval/AST.mqh
Nique_372 68d060365e
2026-05-14 16:54:23 -05:00

1026 lines
32 KiB
MQL5

//+------------------------------------------------------------------+
//| AST.mqh |
//| Copyright 2026, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property strict
#ifndef EXPRESSEVALBYLEO_SRC_MATHEVAL_AST_MQH
#define EXPRESSEVALBYLEO_SRC_MATHEVAL_AST_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "NodeFactory.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
struct CMathExpresionEvalDync
{
private:
CHashMap<string, IValor*>* m_val_symbols; // Hashmap a las punteros de los simbolos
CHashMap<string, IValor*>* m_val_functions; // Hashmap a las punteros de los funciones
int m_pos;
int m_size;
ENUM_MATH_EVAL_EXP_ERR_PARSE m_last_err;
int m_err_pos;
int m_para_stack;
//---
bool ParseInternalRaw(const TokenMathExp& tokens[], const int math_op, ValueNode &val);
//---
bool RawOp(const TokenMathExp &tokens[], const int type_op, int pos1, int pos2, ValueNode &bit);
bool RawOpAply(const TokenMathExp &tokens[], const int type_op, int pos2, ValueNode& bit);
bool RawOpSobreBits(const TokenMathExp &tokens[], const int type_op, ValueNode& bit, const ValueNode &bit2);
public:
CMathExpresionEvalDync(void) : m_val_symbols(NULL), m_val_functions(NULL) {}
//~CMathExpresionEvalDync(void) {}
//---
void CleanCache(const TokenMathExp &tokens[]);
bool ParsNoRes(const TokenMathExp &tokens[], ValueNode& it);
//---
// Simbolos
void TableSymbols(CHashMap<string, IValor*>* p) { m_val_symbols = p; }
CHashMap<string, IValor*>* TableSymbols() { return m_val_symbols; }
// Funciones
void TableFunctions(CHashMap<string, IValor*>* p) { m_val_functions = p; }
CHashMap<string, IValor*>* TableFunctions() { return m_val_functions; }
//---
__forceinline ENUM_MATH_EVAL_EXP_ERR_PARSE LastErr() const { return m_last_err; }
__forceinline int LastErrPos() const { return m_err_pos; }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CMathExpresionEvalDync::CleanCache(const TokenMathExp &tokens[])
{
//---
m_size = ArraySize(tokens);
m_pos = 0;
m_para_stack = 0;
m_err_pos = -1;
m_last_err = WRONG_VALUE;
//---
// ParseNoRes // 10 * 20 -
// ParseInternalRaw // 200 - 10 + 2
// ParseInternalRaw // 190 + 2 *
// ParsNoRes // 2 * 2
// ParseInternalRaw // 190 + 4
// .
// .
// 10 * 20 - 10 + 2 * 2
// 200 - 10 + 2 * 2
// 190 + 2 * 2
// 200 -
//
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMathExpresionEvalDync::RawOp(const TokenMathExp &tokens[], const int type_op, int pos1, int pos2, ValueNode &bit)
{
//--- Obtenemos...
switch((tokens[pos1].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
bit.type = MATH_EXP_NODE_TYPE_STATIC;
bit.s_val_type = tokens[pos1].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(bit.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
bit.s_val.long_value = tokens[pos1].v.long_value;
}
else
{
bit.s_val.double_value = tokens[pos1].v.double_value;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos1].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos1;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos1].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos1;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos1].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos1;
return false;
}
break;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos1;
return false;
}
//---
// Se asume que pos1, pos2 son numeros
ValueNode it;
//--- Obtenemos...
switch((tokens[pos2].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
it.type = MATH_EXP_NODE_TYPE_STATIC;
it.s_val_type = tokens[pos2].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(it.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
it.s_val.long_value = tokens[pos2].v.long_value;
}
else
{
it.s_val.double_value = tokens[pos2].v.double_value;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos2].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos2].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos2].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos2;
return false;
}
break;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos2;
return false;
}
//Print(it.s_val.long_value, " | ", bit.s_val.long_value);
//---
return RawOpSobreBits(tokens, type_op, bit, it);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMathExpresionEvalDync::RawOpAply(const TokenMathExp &tokens[], const int type_op, int pos2, ValueNode& bit)
{
//--- Declaracion
ValueNode it;
//--- Obtenemos...
switch((tokens[pos2].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
it.type = MATH_EXP_NODE_TYPE_STATIC;
it.s_val_type = tokens[pos2].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(it.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
it.s_val.long_value = tokens[pos2].v.long_value;
}
else
{
it.s_val.double_value = tokens[pos2].v.double_value;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos2].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos2].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos2].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos2;
return false;
}
break;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos2;
return false;
}
//---
return RawOpSobreBits(tokens, type_op, bit, it);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMathExpresionEvalDync::RawOpSobreBits(const TokenMathExp &tokens[], const int type_op, ValueNode& bit, const ValueNode &bit2)
{
//--- Ambos son enteros
if(bit.type == MATH_EXP_NODE_TYPE_STATIC)
{
if(bit2.type == MATH_EXP_NODE_TYPE_STATIC) // SS
{
if((bit.s_val_type & bit2.s_val_type) == 1)
{
bit.s_val_type = AST_LOGIC_NUMBER_INTEGER;
switch(type_op)
{
case BINARY_NODE_OP_BIT_OR:
bit.s_val.long_value = bit.s_val.long_value | bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_BIT_XOR:
bit.s_val.long_value = bit.s_val.long_value ^ bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_BIT_AND:
bit.s_val.long_value = bit.s_val.long_value & bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_BIT_DEZPLAZAMIENTO_DRC:
bit.s_val.long_value = bit.s_val.long_value >> bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_BIT_DEZPLAZAMIENTO_IZQ:
bit.s_val.long_value = bit.s_val.long_value << bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_RESTA:
bit.s_val.long_value = bit.s_val.long_value - bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_SUMA:
bit.s_val.long_value = bit.s_val.long_value + bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_MODULO:
bit.s_val.long_value = bit.s_val.long_value % bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_DIVICION:
bit.s_val.long_value = bit.s_val.long_value / bit2.s_val.long_value;
return true;
case BINARY_NODE_OP_MUL:
bit.s_val.long_value = bit.s_val.long_value * bit2.s_val.long_value;
return true;
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_DE_OPERACION_MATH_DESCONOCIDA;
return false;
}
}
else
{
//---
const double left = (bit.s_val_type == AST_LOGIC_NUMBER_DOUBLE) ? bit.s_val.double_value : (double)bit.s_val.long_value;
const double right = (bit2.s_val_type == AST_LOGIC_NUMBER_DOUBLE) ? bit2.s_val.double_value : (double)bit2.s_val.long_value;
//---
bit.s_val_type = AST_LOGIC_NUMBER_DOUBLE;
//---
switch(type_op)
{
case BINARY_NODE_OP_RESTA:
bit.s_val.double_value = left - right;
return true;
case BINARY_NODE_OP_SUMA:
bit.s_val.double_value = left + right;
return true;
case BINARY_NODE_OP_DIVICION:
bit.s_val.double_value = left / right;
return true;
case BINARY_NODE_OP_MUL:
bit.s_val.double_value = left * right;
return true;
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_DE_OPERACION_INVALIDA_PARA_DBL;
return false;
}
}
}
else // SD
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(bit.s_val_type == AST_LOGIC_NUMBER_DOUBLE) // DA (Double Any)
{
return CFactoryMathNode::Get_SD_da(type_op, bit, bit2);
}
else
if(bit.s_val_type == AST_LOGIC_NUMBER_INTEGER) // IA (Integer Any)
{
return CFactoryMathNode::Get_SD_ia(type_op, bit, bit2);
}
}
}
else
if(bit.type == MATH_EXP_NODE_TYPE_DYNAMIC)
{
if(bit2.type == MATH_EXP_NODE_TYPE_DYNAMIC) // Dinamicos | Dinamico
{
return CFactoryMathNode::Get_DD(type_op, bit, bit2);
}
else // Dinamico | Estatico
{
if(bit2.s_val_type == AST_LOGIC_NUMBER_DOUBLE) // AD (Any Double)
{
return CFactoryMathNode::Get_DS_ad(type_op, bit, bit2);
}
else
if(bit2.s_val_type == AST_LOGIC_NUMBER_INTEGER) // AI (Any Integer)
{
return CFactoryMathNode::Get_DS_ai(type_op, bit, bit2);
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CMathExpresionEvalDync::ParsNoRes(const TokenMathExp &tokens[], ValueNode& it)
{
//---
// La idea con esta funcion es pase normal tal cual
//--- Extraccion
// Tipo de numero 1
int tkn_type = tokens[m_pos].type & 0xFFFF;
if(tkn_type == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_INI)
{
m_para_stack++;
m_pos++; // Le sigue un numero
//---
if((tokens[m_pos].type & 0xFFFF) > 3)
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
m_err_pos = m_pos - 1; // previa a para
return false;
}
}
else
if(tkn_type > 3)
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
m_err_pos = m_pos;
return false;
}
const int pos_val_1 = m_pos++;
// NOTA: Ahora mismo solo extraemos el tipo
//---
// Check de len
// neceistmos 2 tokens mas
// [m_pos]: tipo op
// [m_pos + 1]: valor | o para ini
if(m_pos + 1 >= m_size)
{
// En este caso solo hay un valor asi que lo damos
switch(int(tokens[pos_val_1].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
it.type = MATH_EXP_NODE_TYPE_STATIC;
it.s_val_type = tokens[pos_val_1].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(it.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
it.s_val.long_value = tokens[pos_val_1].v.long_value;
}
else
{
it.s_val.double_value = tokens[pos_val_1].v.double_value;
}
return true;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
return true;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
return true;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
return true;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos_val_1;
return false;
}
} // Contianuamos
//---
// Tipó de op
// Aqui esta el tipo de operacion matematica
tkn_type = tokens[m_pos].type & 0xFFFF;
if(tkn_type != AST_TOKEN_MATH_T_VALUE_OPERDOR_MATEMATICO)
{
if(m_para_stack == 0)
{
// Luego de un valor siempre debe de haber un operador matematico
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_OPERADOR_MATEMATICO;
m_err_pos = m_pos;
return false;
}
else
if(tkn_type == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_END) // Para end o operador
{
m_para_stack--;
if((tkn_type = (tokens[++m_pos].type & 0xFFFF)) != AST_TOKEN_MATH_T_VALUE_OPERDOR_MATEMATICO)
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_OPERADOR_LUEGO_DE_PARA;
m_err_pos = m_pos - 1;
return false;
}
// Ahora mismo estamos en el operador
}
// No hay parantesis nodo abierto....
}
const int type_op_1 = tokens[m_pos++].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
//---
// Tipo de valor 2
tkn_type = tokens[m_pos].type & 0xFFFF;
if(tkn_type == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_INI)
{
//---
// En este caso lo que haremo sera parar lo que estuvimos haciendo...
switch(int(tokens[pos_val_1].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
it.type = MATH_EXP_NODE_TYPE_STATIC;
it.s_val_type = tokens[pos_val_1].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(it.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
it.s_val.long_value = tokens[pos_val_1].v.long_value;
}
else
{
it.s_val.double_value = tokens[pos_val_1].v.double_value;
}
break;;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
break;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos_val_1;
return false;
}
//---
//const int locked = m_para_stack;
ValueNode bit;
if(!ParsNoRes(tokens, bit))
return false;
//---
if(!RawOpSobreBits(tokens, type_op_1, it, bit))
return false;
//Print("VALUE 1: ", (type == AST_LOGIC_NUMBER_DOUBLE ? it.double_value : it.long_value), " TYPE: ", type);
//Print("VALUE 2: ", (bit_type == AST_LOGIC_NUMBER_DOUBLE ? bit.double_value : bit.long_value), " TYPE: ", bit_type);
//---
m_para_stack--; // Restamos la idea es acabar en )
// Asi quye ahora mismo pos apunta a ello m_pos=)
if(m_pos + 2 < m_size)
{
// Necesitaremos dos espacios mas..
// Ahora misto esmtaos en = [)][Opeador][( Or Valor]
const int t = (tokens[++m_pos].type & 0xFFFF);
if(t == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_END)
{
// Para end no hay nada mas que hacer
return true;
}
else
if(t != AST_TOKEN_MATH_T_VALUE_OPERDOR_MATEMATICO)
{
// Error luego de un ) tiene que haber un operador matematico (no un numoero valor)
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_OPERADOR_LUEGO_DE_PARA;
m_err_pos = m_pos - 1;
return false;
}
// Continuamos el parseo agregando al valor actual
// pos++ para el siguiente valor seira [( or valor]
return ParseInternalRaw(tokens, (tokens[m_pos++].type >> AST_LOGIC_EXTRA_TYPE_START_BIT), it);
}
else
{
return true;
}
//---
}
else
if(tkn_type > 3)
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
m_err_pos = m_pos;
return false;
}
const int pos_val_2 = m_pos++; // Valores [Raw | Variable | Funcion Build-in | Funcion Custom]
//---
// Operador 2... este es opcional en caso exista haremos recursion
// 1. Ero comprobaremos si hay espacio para el token actual
// neceistamos dos tokens
// [op][val] (Dado que si hay un op si o si tinee uqe haber un val o parentesis)
bool is_closed = false;
if(m_pos + 1 >= m_size || (is_closed = ((tokens[m_pos].type & 0xFFFF) == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_END)))
{
//if(is_closed)
// m_para_stack--;
// No hay espacio, solo tenemos V X V
// Ahora la idea aqui seria calcular el resultado
return RawOp(tokens, type_op_1, pos_val_1, pos_val_2, it);
}
//--- Extraemos op2
tkn_type = tokens[m_pos].type & 0xFFFF;
if(tkn_type != AST_TOKEN_MATH_T_VALUE_OPERDOR_MATEMATICO)
{
// Luego de un valor siempre debe de haber un operador matematico
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_OPERADOR_MATEMATICO;
m_err_pos = m_pos;
return false;
}
const int type_op_2 = tokens[m_pos++].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
// m_pos = apunta ahora mismo al siguiente valor o () o ~
//--- En caso haya otro operador +\* etc..
// La idea sera ver cual es mas improtante el op1 uno actual?¿ o el otro
if(type_op_2 > type_op_1)
{
//---
// El operador siguiente 2 es mas impornate que el actual... enotnces lo que haremos
// Sera reducir primermente nuestor puntero de lectura para que apunte al valor 2
// [Valor][Op1][Valor2][Op2]
//--- Asignamos un valor
switch((tokens[pos_val_1].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
it.type = MATH_EXP_NODE_TYPE_STATIC;
it.s_val_type = tokens[pos_val_1].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(it.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
it.s_val.long_value = tokens[pos_val_1].v.long_value;
}
else
{
it.s_val.double_value = tokens[pos_val_1].v.double_value;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
it.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_1].vs, it.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_1;
return false;
}
break;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos_val_1;
return false;
}
//---
//Print("VALUE 1: ", (type == AST_LOGIC_NUMBER_DOUBLE ? it.double_value : it.long_value), " TYPE: ", type);
//--- Continuamos con op2
ValueNode bit;
switch((tokens[pos_val_2].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
bit.type = MATH_EXP_NODE_TYPE_STATIC;
bit.s_val_type = tokens[pos_val_2].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(bit.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
bit.s_val.long_value = tokens[pos_val_2].v.long_value;
}
else
{
bit.s_val.double_value = tokens[pos_val_2].v.double_value;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos_val_2].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos_val_2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_2].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_2].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_2;
return false;
}
break;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos_val_2;
return false;
}
if(!ParseInternalRaw(tokens, type_op_2, bit))
return false;
//Print("VALUE 2: ", (bit_type == AST_LOGIC_NUMBER_DOUBLE ? bit.double_value : bit.long_value), " TYPE: ", bit_type);
//---
// Print("OP2: " , type_op_1);
//---
// Junsta ambos bits y reotrn true
return RawOpSobreBits(tokens, type_op_1, it, bit);
}
else
{
// En este caso No lo es asi que aprovecharemos en dar valor a nuesto it actual
if(!RawOp(tokens, type_op_1, pos_val_1, pos_val_2, it))
return false;
// Luego continuareoms
return ParseInternalRaw(tokens, type_op_2, it);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// 200 - 10 + 2 * 2
// 190 + 2 * 2.0
bool CMathExpresionEvalDync::ParseInternalRaw(const TokenMathExp& tokens[], const int math_op, ValueNode &val)
{
//---
// Ahora mismo nos ubicamos en la posicion de valor (Valor | () | ~)
//--- Valor
int tkn_type = tokens[m_pos].type & 0xFFFF;
if(tkn_type == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_INI)
{
//---
//const int locked = m_para_stack;
ValueNode bit;
// aumenta stak
if(!ParsNoRes(tokens, bit))
return false;
//---
if(!RawOpSobreBits(tokens, math_op, val, bit))
return false;
//---
m_para_stack--; // Restamos la idea es acabar en )
// Asi quye ahora mismo pos apunta a ello m_pos=)
if(m_pos + 2 < m_size)
{
// Necesitaremos dos espacios mas..
// Ahora misto esmtaos en = [)][Opeador][( Or Valor]
const int t = (tokens[++m_pos].type & 0xFFFF);
if(t == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_END)
{
// Para end no hay nada mas que hacer
return true;
}
else
if(t != AST_TOKEN_MATH_T_VALUE_OPERDOR_MATEMATICO)
{
// Error luego de un ) tiene que haber un operador matematico (no un numoero valor)
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_OPERADOR_LUEGO_DE_PARA;
m_err_pos = m_pos - 1;
return false;
}
// Continuamos el parseo agregando al valor actual
// pos++ para el siguiente valor seira [( or valor]
return ParseInternalRaw(tokens, (tokens[m_pos++].type >> AST_LOGIC_EXTRA_TYPE_START_BIT), val);
}
else
{
return true;
}
}
else
if(tkn_type > 3)
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
m_err_pos = m_pos;
return false;
}
const int pos_val_2 = m_pos++; // Valores [Raw | Variable | Funcion Build-in | Funcion Custom]
//---
// Operador 2... este es opcional en caso exista haremos recursion
// 1. Ero comprobaremos si hay espacio para el token actual
// neceistamos dos tokens
// [op][val] (Dado que si hay un op si o si tinee uqe haber un val o parentesis)
bool is_closed = false;
if(m_pos + 1 >= m_size || (is_closed = ((tokens[m_pos].type & 0xFFFF) == AST_TOKEN_MATH_T_VALUE_OPERDOR_PARA_END)))
{
// if(is_closed)
// m_para_stack--;
// No hay espacio, solo tenemos V X V
// Ahora la idea aqui seria calcular el resultado
return RawOpAply(tokens, math_op, pos_val_2, val);
}
//--- Extraemos op2
tkn_type = tokens[m_pos].type & 0xFFFF;
if(tkn_type != AST_TOKEN_MATH_T_VALUE_OPERDOR_MATEMATICO)
{
// Luego de un valor siempre debe de haber un operador matematico
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_OPERADOR_MATEMATICO;
m_err_pos = m_pos;
return false;
}
const int type_op_2 = tokens[m_pos++].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
// m_pos = apunta ahora mismo al siguiente valor o () o ~
//--- En caso haya otro operador +\* etc..
// La idea sera ver cual es mas improtante el op1 uno actual?¿ o el otro
if(type_op_2 > math_op)
{
// El operador siguiente 2 es mas impornate que el actual... enotnces lo que haremos
// Sera reducir primermente nuestor puntero de lectura para que apunte al valor 2
// m_pos -= 2; // 2 espacios [Valor2][Op2][AHORA MISMO APUNTAMOS AQUI]
// Luego
//---
ValueNode bit;
switch((tokens[pos_val_2].type & 0xFFFF))
{
case AST_TOKEN_MATH_T_VALUE_NUMBER:
{
bit.type = MATH_EXP_NODE_TYPE_STATIC;
bit.s_val_type = tokens[pos_val_2].type >> AST_LOGIC_EXTRA_TYPE_START_BIT;
if(bit.s_val_type == AST_LOGIC_NUMBER_INTEGER)
{
bit.s_val.long_value = tokens[pos_val_2].v.long_value;
}
else
{
bit.s_val.double_value = tokens[pos_val_2].v.double_value;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_VARIABLE:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_symbols.TryGetValue(tokens[pos_val_2].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_VARIABLE_NO_EXISTE;
m_err_pos = pos_val_2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_2].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_2;
return false;
}
break;
}
case AST_TOKEN_MATH_T_VALUE_FUNCTION_CUSTOM_CALL:
{
bit.type = MATH_EXP_NODE_TYPE_DYNAMIC;
if(!m_val_functions.TryGetValue(tokens[pos_val_2].vs, bit.d_val))
{
m_last_err = MATH_EVAL_EXP_ERR_PARSE_FUNCION_NO_EXISTE;
m_err_pos = pos_val_2;
return false;
}
break;
}
default:
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
m_err_pos = pos_val_2;
return false;
}
if(!ParseInternalRaw(tokens, type_op_2, bit))
return false;
//---
// Junsta ambos bits y reotrn true
return RawOpSobreBits(tokens, math_op, val, bit);
}
else
{
//--- Revisamos si aun hay tokens
if(!RawOpAply(tokens, math_op, pos_val_2, val))
{
// No hay espacio, solo tenemos V X V
// Ahora la idea aqui seria calcular el resultado
return false;
}
return ParseInternalRaw(tokens, type_op_2, val); // Continuamos
}
}
//+------------------------------------------------------------------+
#endif // EXPRESSEVALBYLEO_SRC_MATHEVAL_AST_MQH