Я пытаюсь создать парсер для логических выражений. Символы внутри выражения считываются из XML-подобной структуры данных.
Это просто реализовать парсер для чего-то вроде
a.b == 'some value'
используя ExprTK с помощью «неизвестного преобразователя символов», который разрешает a.b как строку, возвращая строковое значение <a><b>some value</b></a>
,
Но теперь рассмотрим XML <a><b>5</b></a>
Есть ли способ написать неизвестный преобразователь символов, который позволяет оценить как a.b == 5
а также a.b == '5'
?
Первоначально в ExprTk переменная (определенная пользователем или локальное выражение) может быть только одного типа (скаляр, строка или вектор скаляров). Так что, если ваше выражение:
"a.b == 5 and a.b == '5'"
Тогда это недопустимое выражение, поскольку переменная a.b может иметь только один тип — либо скаляр, либо строку, но не оба.
Однако, если вы хотите иметь два отдельных выражения, которые используют одно и то же имя переменной, но в разных контекстах, вот так:
a.b == 5
a.b == '5'
затем да, ExprTk’s USR (Неизвестный символ Resolver) функциональность предоставляет одно из средств для определения типа неизвестного символа во время вызова USR обратный вызов, позволяющий правильно скомпилировать выражение.
В качестве примера, давайте предположим, что мы хотели бы определить USR, который будет разрешать только неизвестные символы с префиксами «Var_» а также «Str_» с типами Scalar и String соответственно.
Примеры выражений могут выглядеть следующим образом:
var_x := 2; var_x + 7
str_y := 'abc'; str_y + '123' == 'abc123'
Ниже приведен пример USR, использующий механизм расширенного обратного вызова, который разрешает переменные в указанном выше формате и, кроме того, добавляет их в таблицу первичных символов анализируемого выражения:
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::parser<double> parser_t;
template <typename T>
struct my_usr : public parser_t::unknown_symbol_resolver
{
typedef typename parser_t::unknown_symbol_resolver usr_t;
my_usr()
: usr_t(usr_t::e_usrmode_extended)
{}
virtual bool process(const std::string& unknown_symbol,
symbol_table_t& symbol_table,
std::string& error_message)
{
bool result = false;
//Is this unknown symbol in the format var_xyz ?
if (0 == unknown_symbol.find("var_"))
{
const T default_scalar = T(0);
result = symbol_table.create_variable(unknown_symbol, default_scalar);
if (!result)
{
error_message =
"Failed to create variable(" + unknown_symbol + ") in primary symbol table";
}
}
//Is this unknown symbol in the format str_xyz ?
else if (0 == unknown_symbol.find("str_"))
{
const std::string default_string = "N/A";
result = symbol_table.create_stringvar(unknown_symbol,default_string)
if (!result)
{
error_message =
"Failed to create string variable(" + unknown_symbol + ") in primary symbol table";
}
}
else
error_message = "Indeterminable symbol type.";
return result;
}
};
Остальной код такой же: один регистрирует экземпляр USR с помощью синтаксического анализатора, а затем переходит к компиляции их выражения с помощью указанного синтаксического анализатора.
Для получения дополнительной информации есть обзор Раздел 18 — Неизвестный Неизвестный
Других решений пока нет …