2026-05-12 15:15:09 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| AST.mqh |
|
|
|
|
|
//| Copyright 2026, MetaQuotes Ltd. |
|
|
|
|
|
//| https://www.mql5.com |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#property copyright "Copyright 2026, MetaQuotes Ltd."
|
|
|
|
|
#property link "https://www.mql5.com"
|
|
|
|
|
#property strict
|
|
|
|
|
|
2026-05-13 16:27:54 -05:00
|
|
|
#ifndef EXPRESSEVALBYLEO_SRC_MATHEVAL_AST_MQH
|
|
|
|
|
#define EXPRESSEVALBYLEO_SRC_MATHEVAL_AST_MQH
|
2026-05-12 15:15:09 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 11:13:22 -05:00
|
|
|
#include "NodeFactory.mqh"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-12 22:27:01 -05:00
|
|
|
|
2026-05-12 15:15:09 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 11:13:22 -05:00
|
|
|
struct CMathExpresionEvalDync
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
|
|
|
|
private:
|
2026-05-14 11:13:22 -05:00
|
|
|
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
|
2026-05-12 15:15:09 -05:00
|
|
|
int m_pos;
|
|
|
|
|
int m_size;
|
|
|
|
|
ENUM_MATH_EVAL_EXP_ERR_PARSE m_last_err;
|
|
|
|
|
int m_err_pos;
|
2026-05-13 12:07:09 -05:00
|
|
|
int m_para_stack;
|
2026-05-12 15:15:09 -05:00
|
|
|
|
2026-05-14 11:13:22 -05:00
|
|
|
//---
|
2026-05-14 12:56:06 -05:00
|
|
|
bool ParseInternalRaw(const TokenMathExp& tokens[], const int math_op, ValueNode &val);
|
2026-05-12 15:15:09 -05:00
|
|
|
|
2026-05-14 11:13:22 -05:00
|
|
|
//---
|
2026-05-14 12:56:06 -05:00
|
|
|
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);
|
2026-05-12 15:15:09 -05:00
|
|
|
|
|
|
|
|
public:
|
2026-05-14 14:13:20 -05:00
|
|
|
CMathExpresionEvalDync(void) : m_val_symbols(NULL), m_val_functions(NULL) {}
|
2026-05-14 11:13:22 -05:00
|
|
|
//~CMathExpresionEvalDync(void) {}
|
2026-05-12 15:15:09 -05:00
|
|
|
|
2026-05-14 11:13:22 -05:00
|
|
|
//---
|
2026-05-14 14:13:20 -05:00
|
|
|
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; }
|
2026-05-12 15:30:06 -05:00
|
|
|
|
2026-05-14 11:13:22 -05:00
|
|
|
//---
|
2026-05-12 15:30:06 -05:00
|
|
|
__forceinline ENUM_MATH_EVAL_EXP_ERR_PARSE LastErr() const { return m_last_err; }
|
2026-05-13 16:27:54 -05:00
|
|
|
__forceinline int LastErrPos() const { return m_err_pos; }
|
2026-05-12 15:15:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 14:13:20 -05:00
|
|
|
void CMathExpresionEvalDync::CleanCache(const TokenMathExp &tokens[])
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
m_size = ArraySize(tokens);
|
|
|
|
|
m_pos = 0;
|
2026-05-13 12:07:09 -05:00
|
|
|
m_para_stack = 0;
|
2026-05-14 12:56:06 -05:00
|
|
|
m_err_pos = -1;
|
2026-05-13 16:27:54 -05:00
|
|
|
m_last_err = WRONG_VALUE;
|
|
|
|
|
|
2026-05-12 15:15:09 -05:00
|
|
|
|
2026-05-14 12:56:06 -05:00
|
|
|
|
2026-05-12 15:15:09 -05:00
|
|
|
//---
|
|
|
|
|
// 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 -
|
|
|
|
|
//
|
|
|
|
|
//---
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 12:56:06 -05:00
|
|
|
bool CMathExpresionEvalDync::RawOp(const TokenMathExp &tokens[], const int type_op, int pos1, int pos2, ValueNode &bit)
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
//--- 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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
|
|
|
|
|
m_err_pos = pos1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-05-12 15:15:09 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
2026-05-14 12:56:06 -05:00
|
|
|
// Se asume que pos1, pos2 son numeros
|
|
|
|
|
ValueNode it;
|
|
|
|
|
|
|
|
|
|
//--- Obtenemos...
|
|
|
|
|
switch((tokens[pos2].type & 0xFFFF))
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
case AST_TOKEN_MATH_T_VALUE_NUMBER:
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
2026-05-12 15:15:09 -05:00
|
|
|
return false;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
2026-05-12 15:15:09 -05:00
|
|
|
return false;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
default:
|
|
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
|
|
|
|
|
m_err_pos = pos2;
|
|
|
|
|
return false;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-14 16:54:23 -05:00
|
|
|
//Print(it.s_val.long_value, " | ", bit.s_val.long_value);
|
2026-05-14 12:56:06 -05:00
|
|
|
|
2026-05-12 15:15:09 -05:00
|
|
|
//---
|
2026-05-14 12:56:06 -05:00
|
|
|
return RawOpSobreBits(tokens, type_op, bit, it);
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 12:56:06 -05:00
|
|
|
bool CMathExpresionEvalDync::RawOpAply(const TokenMathExp &tokens[], const int type_op, int pos2, ValueNode& bit)
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
//--- Declaracion
|
|
|
|
|
ValueNode it;
|
2026-05-12 15:15:09 -05:00
|
|
|
|
2026-05-14 12:56:06 -05:00
|
|
|
//--- Obtenemos...
|
|
|
|
|
switch((tokens[pos2].type & 0xFFFF))
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
case AST_TOKEN_MATH_T_VALUE_NUMBER:
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
2026-05-12 15:15:09 -05:00
|
|
|
return false;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
case AST_TOKEN_MATH_T_VALUE_FUNCTION_BUIL_IN_CALL:
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
2026-05-12 15:15:09 -05:00
|
|
|
return false;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
default:
|
|
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
|
|
|
|
|
m_err_pos = pos2;
|
|
|
|
|
return false;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
2026-05-14 12:56:06 -05:00
|
|
|
return RawOpSobreBits(tokens, type_op, bit, it);
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 11:13:22 -05:00
|
|
|
bool CMathExpresionEvalDync::RawOpSobreBits(const TokenMathExp &tokens[], const int type_op, ValueNode& bit, const ValueNode &bit2)
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
|
|
|
|
//--- Ambos son enteros
|
2026-05-14 11:13:22 -05:00
|
|
|
if(bit.type == MATH_EXP_NODE_TYPE_STATIC)
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 11:13:22 -05:00
|
|
|
if(bit2.type == MATH_EXP_NODE_TYPE_STATIC) // SS
|
|
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
if((bit.s_val_type & bit2.s_val_type) == 1)
|
2026-05-14 11:13:22 -05:00
|
|
|
{
|
|
|
|
|
bit.s_val_type = AST_LOGIC_NUMBER_INTEGER;
|
2026-05-12 15:15:09 -05:00
|
|
|
|
2026-05-14 11:13:22 -05:00
|
|
|
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
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 11:13:22 -05:00
|
|
|
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);
|
|
|
|
|
}
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2026-05-14 12:56:06 -05:00
|
|
|
if(bit.type == MATH_EXP_NODE_TYPE_DYNAMIC)
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
if(bit2.type == MATH_EXP_NODE_TYPE_DYNAMIC) // Dinamicos | Dinamico
|
2026-05-14 11:13:22 -05:00
|
|
|
{
|
|
|
|
|
return CFactoryMathNode::Get_DD(type_op, bit, bit2);
|
|
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
else // Dinamico | Estatico
|
2026-05-14 11:59:38 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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);
|
|
|
|
|
}
|
2026-05-14 11:59:38 -05:00
|
|
|
}
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
2026-05-14 11:13:22 -05:00
|
|
|
return false;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 11:13:22 -05:00
|
|
|
bool CMathExpresionEvalDync::ParsNoRes(const TokenMathExp &tokens[], ValueNode& it)
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
// 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)
|
|
|
|
|
{
|
2026-05-13 12:07:09 -05:00
|
|
|
m_para_stack++;
|
|
|
|
|
m_pos++; // Le sigue un numero
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if((tokens[m_pos].type & 0xFFFF) > 3)
|
|
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
|
2026-05-13 12:07:09 -05:00
|
|
|
m_err_pos = m_pos - 1; // previa a para
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if(tkn_type > 3)
|
|
|
|
|
{
|
2026-05-14 16:54:23 -05:00
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
|
|
|
|
|
m_err_pos = m_pos;
|
2026-05-12 15:15:09 -05:00
|
|
|
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
|
2026-05-14 12:56:06 -05:00
|
|
|
switch(int(tokens[pos_val_1].type & 0xFFFF))
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-14 11:13:22 -05:00
|
|
|
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;
|
2026-05-14 12:56:06 -05:00
|
|
|
if(it.s_val_type == AST_LOGIC_NUMBER_INTEGER)
|
2026-05-14 11:13:22 -05:00
|
|
|
{
|
|
|
|
|
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;
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
} // 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)
|
|
|
|
|
{
|
2026-05-13 12:07:09 -05:00
|
|
|
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....
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2026-05-13 12:07:09 -05:00
|
|
|
//---
|
|
|
|
|
// En este caso lo que haremo sera parar lo que estuvimos haciendo...
|
2026-05-14 12:56:06 -05:00
|
|
|
switch(int(tokens[pos_val_1].type & 0xFFFF))
|
2026-05-13 12:07:09 -05:00
|
|
|
{
|
2026-05-14 11:13:22 -05:00
|
|
|
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;
|
2026-05-14 12:56:06 -05:00
|
|
|
if(it.s_val_type == AST_LOGIC_NUMBER_INTEGER)
|
2026-05-14 11:13:22 -05:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;;
|
2026-05-14 11:13:22 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 11:13:22 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 11:13:22 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 11:13:22 -05:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
|
|
|
|
|
m_err_pos = pos_val_1;
|
|
|
|
|
return false;
|
2026-05-13 12:07:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
//const int locked = m_para_stack;
|
2026-05-14 11:13:22 -05:00
|
|
|
ValueNode bit;
|
|
|
|
|
if(!ParsNoRes(tokens, bit))
|
2026-05-13 12:07:09 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
2026-05-14 12:56:06 -05:00
|
|
|
if(!RawOpSobreBits(tokens, type_op_1, it, bit))
|
2026-05-13 12:07:09 -05:00
|
|
|
return false;
|
|
|
|
|
|
2026-05-13 16:27:54 -05:00
|
|
|
//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);
|
2026-05-13 12:07:09 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
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]
|
2026-05-14 12:56:06 -05:00
|
|
|
return ParseInternalRaw(tokens, (tokens[m_pos++].type >> AST_LOGIC_EXTRA_TYPE_START_BIT), it);
|
2026-05-13 12:07:09 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if(tkn_type > 3)
|
|
|
|
|
{
|
2026-05-14 16:54:23 -05:00
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
|
|
|
|
|
m_err_pos = m_pos;
|
2026-05-12 15:15:09 -05:00
|
|
|
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)
|
2026-05-13 12:07:09 -05:00
|
|
|
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)))
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-13 12:07:09 -05:00
|
|
|
//if(is_closed)
|
|
|
|
|
// m_para_stack--;
|
|
|
|
|
|
2026-05-12 15:15:09 -05:00
|
|
|
// No hay espacio, solo tenemos V X V
|
|
|
|
|
// Ahora la idea aqui seria calcular el resultado
|
2026-05-14 12:56:06 -05:00
|
|
|
return RawOp(tokens, type_op_1, pos_val_1, pos_val_2, it);
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- 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)
|
|
|
|
|
{
|
2026-05-12 15:30:06 -05:00
|
|
|
//---
|
2026-05-12 15:15:09 -05:00
|
|
|
// 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
|
2026-05-13 16:27:54 -05:00
|
|
|
// [Valor][Op1][Valor2][Op2]
|
2026-05-12 15:30:06 -05:00
|
|
|
|
|
|
|
|
//--- Asignamos un valor
|
2026-05-14 12:56:06 -05:00
|
|
|
switch((tokens[pos_val_1].type & 0xFFFF))
|
2026-05-12 15:30:06 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
|
|
|
|
|
m_err_pos = pos_val_1;
|
|
|
|
|
return false;
|
2026-05-12 15:30:06 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-14 12:56:06 -05:00
|
|
|
|
|
|
|
|
|
2026-05-12 15:30:06 -05:00
|
|
|
//---
|
2026-05-13 16:27:54 -05:00
|
|
|
//Print("VALUE 1: ", (type == AST_LOGIC_NUMBER_DOUBLE ? it.double_value : it.long_value), " TYPE: ", type);
|
2026-05-12 15:30:06 -05:00
|
|
|
|
2026-05-13 16:27:54 -05:00
|
|
|
//--- Continuamos con op2
|
2026-05-14 12:56:06 -05:00
|
|
|
ValueNode bit;
|
|
|
|
|
switch((tokens[pos_val_2].type & 0xFFFF))
|
2026-05-13 16:27:54 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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;
|
2026-05-14 14:13:20 -05:00
|
|
|
if(bit.s_val_type == AST_LOGIC_NUMBER_INTEGER)
|
2026-05-14 12:56:06 -05:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
|
|
|
|
|
m_err_pos = pos_val_2;
|
|
|
|
|
return false;
|
2026-05-13 16:27:54 -05:00
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
if(!ParseInternalRaw(tokens, type_op_2, bit))
|
2026-05-13 12:07:09 -05:00
|
|
|
return false;
|
2026-05-12 15:15:09 -05:00
|
|
|
|
2026-05-13 16:27:54 -05:00
|
|
|
//Print("VALUE 2: ", (bit_type == AST_LOGIC_NUMBER_DOUBLE ? bit.double_value : bit.long_value), " TYPE: ", bit_type);
|
2026-05-12 15:30:06 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// Print("OP2: " , type_op_1);
|
|
|
|
|
|
2026-05-12 15:15:09 -05:00
|
|
|
//---
|
|
|
|
|
// Junsta ambos bits y reotrn true
|
2026-05-14 12:56:06 -05:00
|
|
|
return RawOpSobreBits(tokens, type_op_1, it, bit);
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// En este caso No lo es asi que aprovecharemos en dar valor a nuesto it actual
|
2026-05-14 12:56:06 -05:00
|
|
|
if(!RawOp(tokens, type_op_1, pos_val_1, pos_val_2, it))
|
2026-05-12 15:15:09 -05:00
|
|
|
return false;
|
|
|
|
|
// Luego continuareoms
|
|
|
|
|
|
2026-05-14 12:56:06 -05:00
|
|
|
return ParseInternalRaw(tokens, type_op_2, it);
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
// 200 - 10 + 2 * 2
|
2026-05-13 12:07:09 -05:00
|
|
|
// 190 + 2 * 2.0
|
2026-05-14 12:56:06 -05:00
|
|
|
bool CMathExpresionEvalDync::ParseInternalRaw(const TokenMathExp& tokens[], const int math_op, ValueNode &val)
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
// 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)
|
|
|
|
|
{
|
2026-05-13 12:07:09 -05:00
|
|
|
//---
|
|
|
|
|
//const int locked = m_para_stack;
|
2026-05-14 12:56:06 -05:00
|
|
|
ValueNode bit;
|
2026-05-13 12:07:09 -05:00
|
|
|
// aumenta stak
|
2026-05-14 12:56:06 -05:00
|
|
|
if(!ParsNoRes(tokens, bit))
|
2026-05-13 12:07:09 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
2026-05-14 12:56:06 -05:00
|
|
|
if(!RawOpSobreBits(tokens, math_op, val, bit))
|
2026-05-13 12:07:09 -05:00
|
|
|
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]
|
2026-05-14 12:56:06 -05:00
|
|
|
return ParseInternalRaw(tokens, (tokens[m_pos++].type >> AST_LOGIC_EXTRA_TYPE_START_BIT), val);
|
2026-05-13 12:07:09 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if(tkn_type > 3)
|
|
|
|
|
{
|
2026-05-14 16:54:23 -05:00
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_SE_ESPERABA_UN_VALOR;
|
|
|
|
|
m_err_pos = m_pos;
|
2026-05-12 15:15:09 -05:00
|
|
|
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)
|
2026-05-13 12:07:09 -05:00
|
|
|
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)))
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
2026-05-13 12:07:09 -05:00
|
|
|
// if(is_closed)
|
|
|
|
|
// m_para_stack--;
|
2026-05-12 15:15:09 -05:00
|
|
|
// No hay espacio, solo tenemos V X V
|
|
|
|
|
// Ahora la idea aqui seria calcular el resultado
|
2026-05-14 12:56:06 -05:00
|
|
|
return RawOpAply(tokens, math_op, pos_val_2, val);
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- 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
|
2026-05-13 16:27:54 -05:00
|
|
|
// m_pos -= 2; // 2 espacios [Valor2][Op2][AHORA MISMO APUNTAMOS AQUI]
|
2026-05-12 15:15:09 -05:00
|
|
|
// Luego
|
2026-05-14 12:56:06 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
ValueNode bit;
|
|
|
|
|
switch((tokens[pos_val_2].type & 0xFFFF))
|
2026-05-13 16:27:54 -05:00
|
|
|
{
|
2026-05-14 12:56:06 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-05-14 14:13:20 -05:00
|
|
|
break;
|
2026-05-14 12:56:06 -05:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
m_last_err = MATH_EVAL_EXP_ERR_PARSE_TIPO_VALOR_INVALIDO;
|
|
|
|
|
m_err_pos = pos_val_2;
|
|
|
|
|
return false;
|
2026-05-13 16:27:54 -05:00
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
if(!ParseInternalRaw(tokens, type_op_2, bit))
|
2026-05-13 12:07:09 -05:00
|
|
|
return false;
|
2026-05-12 15:15:09 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// Junsta ambos bits y reotrn true
|
2026-05-14 12:56:06 -05:00
|
|
|
return RawOpSobreBits(tokens, math_op, val, bit);
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//--- Revisamos si aun hay tokens
|
2026-05-14 12:56:06 -05:00
|
|
|
if(!RawOpAply(tokens, math_op, pos_val_2, val))
|
2026-05-12 15:15:09 -05:00
|
|
|
{
|
|
|
|
|
// No hay espacio, solo tenemos V X V
|
|
|
|
|
// Ahora la idea aqui seria calcular el resultado
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-05-14 12:56:06 -05:00
|
|
|
return ParseInternalRaw(tokens, type_op_2, val); // Continuamos
|
2026-05-12 15:15:09 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-05-14 11:13:22 -05:00
|
|
|
#endif // EXPRESSEVALBYLEO_SRC_MATHEVAL_AST_MQH
|