解析用户定义的脚本系统为结构数据类型

C++ Parse user-defined script system into structure data types

本文关键字:本系统 结构 数据类型 脚本 用户 定义      更新时间:2023-10-16

我已经为我正在制作的游戏开发了一个简单的脚本系统。基本上,一个简单的脚本看起来像这样:

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!)