2

我有一个有趣的问题。假设我的文件中的行填充如下:

name1[xp,y,z321](a,b,c){text};//comment
#comment
name2(aaaa);

我也有(简化的)课程:

class something {
public:
 something(const std::string& name);
 addOptionalParam(const std::string& value);
 addMandatoryParam(const std::string& value);
 setData((const std::string& value);
};

name 对应于某个类构造函数的参数名称。[] 括号中列出的内容是可选的,在 () 中是强制性的,{} 之间的所有内容都应作为字符串传递。

对于第一行,应该以“name1”为名称调用构造函数;3 次调用 addOptionalParam,每个项目用冒号分隔一次;还有 3 次 addMandatoryParam 和 setData 与“文本”。

我可以弄清楚如何发表评论,但其他一切对我来说都被破坏了......

现在我需要一些好的建议如何(或是否)这是可能的,如果我能弄清楚如何为简单的对象做到这一点,我就可以弄清楚如何处理所有额外的血腥细节,比如语义正确性等等。

4

3 回答 3

5

您是否考虑过诸如Boost Spirit 之类的解析器?

于 2010-02-03T16:14:02.713 回答
5

您的描述有点令人困惑(例如,您提到“用冒号分隔”,但我在输入中看不到任何冒号)。我假设您的意图是方括号中的项目是可选参数,括号中是强制参数,大括号中是“数据”。

在这种情况下,您的语法似乎是这样的:

func: name optionalParams '(' paramList ')' '{' data '}'

paramList: param |
          paramlist ',' param

optionalParams:  // empty
              | '[' paramList ']'

name: WORD
param: WORD
data: WORD

这是一个足够简单的语法,Spirit 可能会很好地使用它。对于较大的语法,Spirit 往往会导致非常长的编译时间,但是这种语法足够小,编译时间应该是相当合理的。

显而易见的替代方法是编写一个下降解析器(如递归下降解析器,但在这种情况下不需要递归)。在这种情况下,您基本上会为语法的每个级别编写一个函数,让它读取适当的输入,然后返回一个结构(例如,一个向量)来保存它读取的数据。例如,optionalParams可能是最难解析的(仅仅因为它是可选的):

typedef std::string param;

std::vector<param> read_optional_params(std::istream &in) { 
    std::vector<param> ret;

    char ch = in.peek();
    if (ch == '[' ) {
        in >> ch;
        param temp;
        while (in >> temp && temp != "]") 
            ret.push_back(temp);
            if ((ch=in.peek) == ',')
                in >> ch;
    }
    return ret;    
}

在顶层,你会有类似的东西:

function read_func(std::istream &in) { 
    std::string name = read_name(in);
    std::vector<param> optional_params = read_optional_params(in);
    std::vector<param> mandatory_params = read_mandatory_params(in);
    std::string data = read_data(in);

    if (in.fail()) {
        // malformed input
    }

    function func = function(name);
    for (int i=0; i<optional_params.size(); i++)
        func.addOptionalParam(optional_params[i]);
    for (int i=0; i<mandatory_params.size(); i++)
        func.addMandatoryParam(mandatoryParams[i]);
    func.setData(data);
    return func;
}
于 2010-02-03T16:37:36.350 回答
-1

哇,简直哇...

除了从文件中读取之外,我从不知道这会在其他therms中完成,并且直接来自 Boost 的边缘知识,我不知道有类似 boost::spirit 的东西。但是现在通过文档,我发现很难理解,大多数时候它就像“使用 real_p”并且没有关于命名空间的信息,所以在哪里可以找到给定的项目非常令人困惑......但是看看它可以完成我真的很惊讶。

我想扩展有关语法的信息(但是我并没有更接近于用代码术语来解读如何准确地做到这一点):

name:可以是任何不以数字开头的字符串,除了小写字母、数字和'_'之外没有任何字符
参数:可以是整数、双精度或仅包含'az'字符的字符串
数据:随便在大括号之间(即使可能,换行符),所以 {{{{{} 应该产生 '{{{{' 和 {}{}{}{} 应该失败(从语法上讲)
';':应该充当分隔符,和明确的结束,所以它是必须的

其他的东西是注释,因为我在示例中看不到如何实现它们。

感谢您的帮助,我想看看它的去向。

于 2010-02-03T23:55:19.947 回答