Я пытаюсь написать интерпретатор, который превратит строку вроде:
vector(random(0, 1), 2, 3)
в связанную функцию, используя boost::bind
например:
bind(&vector, bind(&random, 0, 1), 2, 3)
Предполагаемое использование для системы частиц, поэтому я хочу иметь возможность передавать ей частицы, что достигается добавлением лямбда-подобия:
bind(&vector, bind(&random, 0, 1, _1), 2, 3, _1)
Эти связанные функции затем определяются как: typedef boost::function<boost::any(Particle*)> bound_particle_func;
, поэтому я могу сформировать своего рода список вызовов функций, передавая каждую частицу в этот список, чтобы управлять их поведением и, таким образом, создавать эффект.
Я могу легкозаставить интерпретатор обрабатывать что-то вроде vector(1, 2, 3)
, но когда дело доходит до вложенных функций, вещи становятся беспорядочными, и я чувствую, что я запутываю вещи.
Поскольку синтаксический анализатор в настоящее время обрабатывает вложенные функции рекурсивным способом, я могу 't напрямую связывает лямбда-значение со встроенной функцией.
, поэтому вместо того, чтобы заканчиваться на bind(&vector, bind(&random, 0, 1, _1), 2, 3, _1)
, я фактически получаю bind(&vector, bound random function, 2, 3, _1)
, который не передает связанную функцию частице.
Я не знаю, как лучше справляться с вложенными функциями.
Фактический код, который у меня есть на данный момент (который не компилируется):
typedef std::vector<Token>::iterator token_it;
typedef boost::function<boost::any(Particle*)> bound_particle_func;
Vector3 vector(float x, float y, float z, Particle* p = 0);
bound_particle_func parse(token_it& it);
bound_particle_func ParseVector(std::vector<Token>& tokens) {
const static int arg_count = 3;
std::vector<boost::variant<float, bound_particle_func>> args(arg_count);
int type[] = { 0, 0, 0 };
for(token_it it = tokens.begin(); it != tokens.end(); ++it) {
Token& t = *it;
if(t.type == Type::FLOAT) {
args.push_back(t.float_value);
} else if(t.type == Type::FUNCTION) {
args.push_back(parse(it));
type[args.size() - 1] = 1;
} else {
throw std::runtime_error("Type error: expected float");
}
if(args.size() > arg_count) {
throw std::runtime_error("Too many arguments for function `vector`");
}
}
return boost::bind(&vector, (type[0] == 0 ? boost::get<float>(args[0]) : boost::get<bound_particle_func>(args[0])),
(type[1] == 0 ? boost::get<float>(args[1]) : boost::get<bound_particle_func>(args[1])),
(type[2] == 0 ? boost::get<float>(args[2]) : boost::get<bound_particle_func>(args[2])),
boost::lambda::_1);
}
Функция bound_particle_func parse(token_it& it);
просто передает соответствующие токены соответствующей функции, подобной приведенной выше.