是否有人知道在线资源,我可以找到如何使用Boost :: Spirit编写简单的表达式解析器。
我不一定需要评估表达式,但我需要解析它并能够返回一个布尔值来指示表达式是否可解析(例如括号不匹配等)。
我需要解析器能够识别函数名称(例如foo和foobar),所以这也是帮助我学习编写BNF表示法的有用示例。
表达式将是常规算术等式,即包括以下符号:
答案 0 :(得分:6)
这里有一些旧的Spirit原型代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <exception>
#include <iterator>
#include <sstream>
#include <list>
#include <boost/spirit.hpp>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost::spirit;
using namespace boost;
void g(unsigned int i)
{
cout << "row: " << i << endl;
}
struct u
{
u(const char* c): s(c) {}
void operator()(const char* first, const char* last) const
{
cout << s << ": " << string(first, last) << endl;
}
private:
string s;
};
struct Exp
{
};
struct Range: public Exp
{
};
struct Index: public Exp
{
};
struct String: public Exp
{
};
struct Op
{
virtual ~Op() = 0;
virtual string name() = 0;
};
Op::~Op() {}
struct CountIf: public Op
{
string name() { return "CountIf"; }
};
struct Sum: public Op
{
string name() { return "Sum"; }
};
struct Statement
{
virtual ~Statement() = 0;
virtual void print() = 0;
};
Statement::~Statement() {}
struct Formula: public Statement
{
Formula(const char* first, const char* last): s(first, last), op(new CountIf)
{
typedef rule<phrase_scanner_t> r_t;
r_t r_index = (+alpha_p)[u("col")] >> uint_p[&g];
r_t r_range = r_index >> ':' >> r_index;
r_t r_string = ch_p('\"') >> *alnum_p >> '\"';
r_t r_exp = r_range | r_index | r_string; // will invoke actions for index twice due to range
r_t r_list = !(r_exp[u("arg")] % ',');
r_t r_op = as_lower_d["countif"] | as_lower_d["sum"];
r_t r_formula = r_op >> '(' >> r_list >> ')';
cout << s << ": matched: " << boolalpha << parse(s.c_str(), r_formula, space_p).full << endl;
}
void print() { cout << "Formula: " << s << " / " << op->name() << endl; }
private:
string s;
shared_ptr<Op> op;
list<shared_ptr<Exp> > exp_list;
};
struct Comment: public Statement
{
Comment(const char* first, const char* last): comment(first, last) {}
void print() {cout << "Comment: " << comment << endl; }
private:
string comment;
};
struct MakeFormula
{
MakeFormula(list<shared_ptr<Statement> >& list_): list(list_) {}
void operator()(const char* first, const char* last) const
{
cout << "MakeFormula: " << string(first, last) << endl;
list.push_back(shared_ptr<Statement>(new Formula(first, last)));
}
private:
list<shared_ptr<Statement> >& list;
};
struct MakeComment
{
MakeComment(list<shared_ptr<Statement> >& list_): list(list_) {}
void operator()(const char* first, const char* last) const
{
cout << "MakeComment: " << string(first, last) << endl;
list.push_back(shared_ptr<Statement>(new Comment(first, last)));
}
private:
list<shared_ptr<Statement> >& list;
};
int main(int argc, char* argv[])
try
{
//typedef vector<string> v_t;
//v_t v(argv + 1, argv + argc);
// copy(v.begin(), v.end(), ostream_iterator<v_t::value_type>(cout, "\n"));
string s;
getline(cin, s);
// =COUNTIF(J2:J36, "Abc")
typedef list<shared_ptr<Statement> > list_t;
list_t list;
typedef rule<phrase_scanner_t> r_t;
r_t r_index = (+alpha_p)[u("col")] >> uint_p[&g];
r_t r_range = r_index >> ':' >> r_index;
r_t r_string = ch_p('\"') >> *alnum_p >> '\"';
r_t r_exp = r_range | r_index | r_string; // will invoke actions for index twice due to range
r_t r_list = !(r_exp[u("arg")] % ',');
r_t r_op = as_lower_d["countif"] | as_lower_d["sum"];
r_t r_formula = r_op >> '(' >> r_list >> ')';
r_t r_statement = (ch_p('=') >> r_formula [MakeFormula(list)])
| (ch_p('\'') >> (*anychar_p)[MakeComment(list)])
;
cout << s << ": matched: " << boolalpha << parse(s.c_str(), r_statement, space_p).full << endl;
for (list_t::const_iterator it = list.begin(); it != list.end(); ++it)
{
(*it)->print();
}
}
catch(const exception& ex)
{
cerr << "Error: " << ex.what() << endl;
}
尝试运行它并输入如下行:
=COUNTIF(J2:J36, "Abc")
答案 1 :(得分:5)
当前版本的Spirit(V2.x)包含一系列计算器示例,从非常简单到完整的mini-c解释器。您应该看一下,因为这些是编写自己的表达式解析器的完美起点。
答案 2 :(得分:1)
我不确定这个资格是否也很简单,但我在http://code.google.com/p/uri-grammar/source/browse/trunk/src/uri/grammar.hpp使用了这个uri-grammar。它可能不是 trivial ,但至少它解析了你可能已经理解过的东西(URIs)。阅读这些语法时,最好从下往上阅读,因为这是最通用的标记往往被定义的地方。