解析字符串并相应设置变量的函数

时间:2011-11-22 21:41:13

标签: c++

我想用C ++做一个简单的脚本语言

致电后

string statement = "Set anObject.subObject.PublicVariable 10";
execute(statement);

执行会做

anObject.subObject.PublicVariable = 10;

我该怎么办? 我不知道(好吧,除了处理每个变量的开关/案例 - 但这太无耻和愚蠢)如何做到这一点。

4 个答案:

答案 0 :(得分:2)

我把它当作提升精神的练习。


这是更老,更简单(更现实......)的样本:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <map>

namespace qi=boost::spirit::qi;
namespace px=boost::phoenix;

std::map<std::string, int> variables;
static void record(const std::string& name, int value) 
    { variables[name] = value; };

int main()
{
    std::string input/* = "Set anObject.subObject.PublicVariable 10"*/;
    while (std::getline(std::cin, input))
    {
        auto f(input.begin()), l(input.end());

        if (!qi::phrase_parse(f,l, 
                "Set" >> 
                (
                     qi::as_string[ qi::lexeme[ +(!qi::space >> (qi::alnum | qi::char_("_."))) ] ] >>
                     qi::int_
                ) [ 
                     px::bind(record, qi::_1, qi::_2) 
                  ],
            qi::space))
        {
            std::cerr << "fail: '" << input << "'" << std::endl;
        }

        if (f!=l)
            std::cerr << "unparsed: '" << std::string(f,l) << "'" << std::endl;
    }

    for (auto kv : variables)
        std::cout << kv.first << ":\t" << kv.second << std::endl;
}

对于输入Set anObject.subObject.PublicVariable 10,将打印:

anObject.subObject.PublicVariable:  10

更新

我扔进了厨房水槽( pastebin ),万一你真的想要一个完整的类型层次结构:

struct object
{
    std::string name;
    // non-key:
    mutable variant_t value;
    mutable std::set<object> children;
    // ...
};

此演示现在支持整数,带引号的字符串和浮点类型的值,因此variant_t定义为

typedef boost::optional<boost::variant<std::string, double, int> > variant_t;

输入

Set bla.blo 123
Set veryLong.subObject.stringVal "hello"
Set veryLong.subObject 31415926E-7
Set answer 42
Set bla.blo "world"

输出

name: <globals>
{
    name: answer (value: 42)
    {
    }
    name: bla
    {
        name: blo (value: world)
        {
        }
    }
    name: veryLong
    {
        name: subObject (value: 3.14159)
        {
            name: stringVal (value: hello)
            {
            }
        }
    }
}

答案 1 :(得分:1)

如果您只是使用set的基本命令,那么您可以做这样的事情......

class BaseClass {
    vector<string> objects;
    vector<void*> locationOfObjects;
    ...
}

然后一旦命令被提交通过该类中的字符串向量进行交互并找到您尝试设置的对象的位置(对于子对象,您可以循环遍历该字符串继续查找目标对象的位置到设置)然后将该对象设置为某个值。请注意,每个类都需要是BaseClass的子类,以便每个对象或子对象都可以迭代对象。

答案 2 :(得分:0)

如果您希望脚本语言拥有它自己的变量:

struct variable {
    std::map<std::string, variable> children;
    int value;

    variable() : value(0) {}
    variable(int rhs) : value(rhs) {}
    variable(const variable& rhs) : children(rhs.children), value(rhs.value) {}

    operator=(int rhs) {value = rhs; return *this;
    variable& operator[](const std::string& rhs) {return children[rhs];}
};

如果您希望脚本语言修改C ++变量,您必须像DanZimm节目那样注册它们。

答案 3 :(得分:0)

好吧,你可能不会。

如果我正确地猜测您希望“脚本”搜索名为anObject的对象,请获取其字段subObject并将其字段PublicVariable设置为10.

当然你可以非常努力地让用户相信,代码会这样做,但是一旦编译了C ++程序,变量和函数名称就会消失,它们就变成了单纯的地址(那里有)是调试符号的东西,但那不是真正的c ++ ...),而类型只存在于编译器中,而不适用于正在运行的程序。所以如果你希望在动作脚本中有eval()之类的东西......,不,那就没有了!