解析用户定义的脚本系统为结构数据类型
C++ Parse user-defined script system into structure data types
我已经为我正在制作的游戏开发了一个简单的脚本系统。基本上,一个简单的脚本看起来像这样:
QuestValue(100)>=10 -> ShowText("You pass the test!")
我使用一个标记器来读取这样的脚本,并将它们传递到一个结构中。
一个简单的解释是这样的:
Token token = script.tokenNext();
if (token == IDENT)
{
string ident = script.readIdent();
if (ident == "questvalue")
{
script.readSymbol("(");
Condition* condition = new Condition();
condition->type = CONDITION_QUESTVALUE;
condition->intParams[0] = script.readInt();
script.readSymbol(")");
condition->operatorType = script.readOperator();
condition->intParams[1] = script.readInt();
ScriptData.push_back(condition);
}
}
可以很好地传递一些像QuestValue(int)<<strong>Operator>int
我可以很好地使用它并根据需要评估条件,但我意识到我可能需要进一步的复杂性,例如:
QuestValue(100)>=QuestValue(101) -> ShowText("You pass the test!")
我该如何解释这样的事情?为了简化第一个例子:
enum ConditionType
{
CONDITION_QUESTVALUE;
};
struct Condition
{
public:
OperatorType operatorType;
int intParams[5];
ConditionType type;
};
它只是允许我支持整数作为参数,但如果值参数不是int,而是另一个条件从不同的任务值的第二个值呢? QuestValue (& lt; int >) & lt; 操作符> QuestValue (& lt; int >)
老实说,我的大脑似乎找不到解决这个问题的方法。有什么建议吗?
我误读了这个问题,因为我认为这是一个dsl(它几乎是有效的c++代码,除非稍微改变操作符优先级),但仍然可能你可以使用这样的东西
#include <iostream>
/*
grammer:
statement -> boolean_expr "->" action
boolean_expr -> primitve binary_op primitve
binary_op -> ">="
primiate -> QuestValue(integer) | integer
action -> ShowText(string)
*/
struct visitor{
virtual ~visitor(){} // not neccasary
virtual void binary_op(const std::string& s)const=0;
virtual void int_(int value)const=0;
virtual void quest_value(int value)const=0;
virtual void show_text(const std::string& text)const=0;
};
struct quest_value_prim{
explicit quest_value_prim(int value):value_(value){}
void visit(visitor& v)const{
v.quest_value(value_);
}
private:
int value_;
};
struct int_prim{
explicit int_prim(int value):value_(value){}
void visit(visitor& v)const{
v.int_(value_);
}
private:
int value_;
};
struct show_text_action{
explicit show_text_action(const std::string& text):text_(text){}
void visit(visitor* v)const{
v->show_text(text_);
}
private:
std::string text_;
};
#include <type_traits>
#define MAKE_TRAIT(NAME)
template<typename T>
struct NAME{
static const bool value = false;
};
#define TRAIT_ADD(TRAIT, NAME)
template<>
struct TRAIT<NAME>{
static const bool value = true;
};
#define TRAIT_ADD_UNARY( TRAIT, NAME )
template<typename T>
struct TRAIT<NAME<T> >{
static const bool value = true;
};
#define TRAIT_ADD_BINARY( TRAIT, NAME )
template<typename LP, typename RP>
struct TRAIT<NAME<LP,RP> >{
static const bool value = true;
};
MAKE_TRAIT(is_primitive)
MAKE_TRAIT(is_boolean_expr)
MAKE_TRAIT(is_action)
TRAIT_ADD(is_primitive,quest_value_prim)
TRAIT_ADD(is_primitive,int_prim)
TRAIT_ADD(is_primitive,int)
TRAIT_ADD(is_action,show_text_action)
template<typename T>
struct make_primitive_type{
typedef T type;
};
template<>
struct make_primitive_type<int>{
typedef int_prim type;
};
#include <algorithm>
#include <functional>
#include <memory>
#include <list>
#include <string>
template<typename L_Param, typename R_Param>
struct binary_op_ge{
binary_op_ge(const L_Param& l_param, const R_Param& r_param):
l_param_(l_param),
r_param_(r_param),
p_(this)
{}
template<typename Visitor>
void visit(Visitor& v)const{
// v expects 2 more calls (prefix notation)
v.binary_op(">=");
l_param_.visit(v);
r_param_.visit(v);
using std::placeholders::_1;
std::for_each(actions_.begin(),actions_.end(),
std::bind(std::mem_fn(&show_text_action::visit),_1,&v));
}
struct proxy{
explicit proxy(binary_op_ge* parent):parent_(parent){}
binary_op_ge& ShowText(const std::string& s){
parent_->actions_.emplace_back(s);
return *parent_;
}
private:
binary_op_ge* parent_;
};
proxy* operator->(){
return &p_;
}
private:
L_Param l_param_;
R_Param r_param_;
proxy p_;
std::list<show_text_action> actions_;
};
TRAIT_ADD_BINARY(is_boolean_expr,binary_op_ge)
template<typename L_Param, typename R_Param>
typename std::enable_if<
is_primitive<L_Param>::value && is_primitive<R_Param>::value,
binary_op_ge<
typename make_primitive_type<L_Param>::type,
typename make_primitive_type<R_Param>::type >
>::type
operator >= (const L_Param& l_param, const R_Param& r_param){
typedef typename make_primitive_type<L_Param>::type lp_type;
typedef typename make_primitive_type<R_Param>::type rp_type;
return binary_op_ge<lp_type,rp_type>(
lp_type(l_param),
rp_type(r_param));
}
static_assert( is_primitive<quest_value_prim>::value, "");
static_assert( is_primitive<int>::value, "");
static_assert( is_boolean_expr<binary_op_ge<void,void> >::value,"");
int main(){
typedef quest_value_prim QuestValue;
struct cout_visitor : public visitor{
void binary_op(const std::string& s)const{
std::cout << "binary_op(" << s << ")n";
}
void quest_value(int value)const{
std::cout << "quest_value(" << value << ")n";
}
void int_(int value)const{
std::cout << "int_(" << value << ")n";
}
void show_text(const std::string& text)const{
std::cout << "show_text(" << text << ")n";
}
};
cout_visitor v;
( ( QuestValue(100)>=10 )-> ShowText("You pass the test!") ).visit(v);
( ( QuestValue(100)>=QuestValue(101) )-> ShowText("You pass the test!") ).visit(v);
}
输出binary_op(>=)
quest_value(100)
int_(10)
show_text(You pass the test!)
binary_op(>=)
quest_value(100)
quest_value(101)
show_text(You pass the test!)
相关文章:
- C++ 本征线性系统求解,数值问题?
- 在node-gip binding.gyp文件中,如何根据系统结构(32位、64位)包含不同的库文件
- 如何读取/查询文件系统和文件结构
- 代表软件包安装和系统依赖关系的最佳数据结构
- 执行populate_sdk时如何使用yocto在本机系统根中安装文件?
- 分配本机C++结构的 CX 公共值结构内容
- 如何让 IntPtr 成为本机 directx11 结构?
- 如何将向量添加到结构中以创建一个库存系统,在该系统中,我可以仅使用一个结构向系统添加多种不同的葡萄酒
- 如何在非本机 QFileDialog 中重新填充系统的"Recent places"?
- 从本机C++结构构建时,是否可以优化平面缓冲区序列化
- 如何使用传递给 C# 代码回调的 C/C++本机结构
- 使用本机C 包装器作为NCurses,如何创建菜单/子菜单系统
- UNIX类似文件系统的目录结构
- 文件系统中的数据结构存储
- 安卓系统:使用静态libgnustl的本机C++程序的SEGFAULT
- C++/CLI(.NET)等效于将结构写入网络的本机C++
- 本机 WMI 提供程序中的 UINT64 不返回某些系统上的数据
- 订阅windows系统事件本机c++
- C++菜单类系统结构:渲染顺序,变量类函数
- 有没有可能在没有for循环的情况下将本机结构数组封送到托管数组?