我有一个有趣的问题。假设我的文件包含这样的行:
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对应于某些类构造函数的param名称。 []括号中列出的内容是可选的,in()是强制性的,{}之间的所有内容都应该作为字符串。
对于第一行,应该使用“name1”作为名称调用构造函数; 3次调用addOptionalParam,每次用冒号分隔一次;还有3次addMandatoryParam和setData“text”。
我可以弄清楚如何进行评论,但其他一切都是我的错误......
现在我需要一些好的建议如何(或者如果)这是可能的,如果我可以解决如何为简单对象做到这一点,我可以弄清楚如何处理所有额外的血腥细节,如语义正确性。
答案 0 :(得分:5)
您是否考虑过Boost Spirit等解析器?
答案 1 :(得分:5)
你的描述有点令人困惑(例如你提到“用冒号分隔”,但我没有在输入中看到任何冒号)。我假设你想要的是方括号中的项是可选参数,括号中是必需参数,花括号中是'数据'。
在这种情况下,您的语法似乎是这样的:
func: name optionalParams '(' paramList ')' '{' data '}'
paramList: param |
paramlist ',' param
optionalParams: // empty
| '[' paramList ']'
name: WORD
param: WORD
data: WORD
这是一个简单的语法,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;
}
答案 2 :(得分:-1)
我从来不知道这会在其他方面完成,而不是从文件中读取,直接来自Boost的边缘知识,我不知道有什么像boost :: spirit。然而,现在通过文档,我发现它很难遵循,大多数时候它就像“使用real_p”并且没有关于命名空间的信息,所以在哪里找到给定的项目很困惑......但是看看它能做什么完成我真的很惊讶。
我想扩展有关语法的信息(但是我并没有更接近破译如何在代码术语中完成它):
name:可以是任何不以数字开头的字符串,除了小写字母,数字和“_”之外没有任何字符
param:可以是整数,double或只包含'a-z'字符的字符串
数据:大括号之间的任何内容(即使可能,换行符),因此{{{{{}应该产生'{{{{'和{} {} {} {}应该失败(语法上讲)
';':应该作为分隔符和明确的结束,所以它是必须的
其他内容是评论,因为我在示例中看不到如何实现它们。
感谢您的帮助,我希望了解它的发展方向。