如何解决BNF带有自定义修改使用 Spirit 的解析器
使用 here 中的 bnf 解析器,我尝试添加一个字段以作为 List 的属性读取。所以我所做的就是改变:
using List = std::list<Term>;
到
struct List : public std::list<Term>{
int number;
}
例如:
<code> ::= <letter><digit> 34 | <letter><digit><code> 23
所以这些数字被读取为 List 的属性。问题是我无法读取数字作为 List 的属性。
解决方法
我更喜欢组合而不是继承(出于多种原因)。
所以
BOOST_FUSION_ADAPT_STRUCT(Ast::List,terms,number)
与
_list = +_term;
然后修改规则来自
_list = +_term >> qi::uint_;
成为
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <fmt/ranges.h>
#include <fmt/ostream.h>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace Ast {
struct Name : std::string {
using std::string::string;
using std::string::operator=;
friend std::ostream& operator<<(std::ostream& os,Name const& n) {
return os << '<' << n.c_str() << '>';
}
};
using Term = boost::variant<Name,std::string>;
struct List {
std::list<Term> terms;
int number;
friend std::ostream& operator<<(std::ostream& os,List const& l) {
for (auto& t : l.terms)
os << t;
return os << " " << l.number;
}
};
using Expression = std::list<List>;
struct Rule {
Name name; // lhs
Expression rhs;
};
using Syntax = std::list<Rule>;
}
BOOST_FUSION_ADAPT_STRUCT(Ast::List,number)
BOOST_FUSION_ADAPT_STRUCT(Ast::Rule,name,rhs)
namespace Parser {
template <typename Iterator>
struct BNF: qi::grammar<Iterator,Ast::Syntax()> {
BNF(): BNF::base_type(start) {
using namespace qi;
start = skip(blank) [ _rule % +eol ];
_rule = _rule_name >> "::=" >> _expression;
_expression = _list % '|';
_list = +_term >> qi::uint_;
_term = _literal | _rule_name ;
_literal = '"' >> *(_character - '"') >> '"'
| "'" >> *(_character - "'") >> "'";
_character = alnum | char_("\"'| !#$%&()*+,./:;>=<?@]\\^_`{}~[-");
_rule_name = '<' >> (alpha >> *(alnum | char_('-'))) >> '>';
BOOST_SPIRIT_DEBUG_NODES(
(_rule)(_expression)(_list)(_term)
(_literal)(_character)
(_rule_name))
}
private:
qi::rule<Iterator,Ast::Syntax()> start;
qi::rule<Iterator,Ast::Rule(),qi::blank_type> _rule;
qi::rule<Iterator,Ast::Expression(),qi::blank_type> _expression;
qi::rule<Iterator,Ast::List(),qi::blank_type> _list;
// lexemes
qi::rule<Iterator,Ast::Term()> _term;
qi::rule<Iterator,Ast::Name()> _rule_name;
qi::rule<Iterator,std::string()> _literal;
qi::rule<Iterator,char()> _character;
};
}
int main() {
Parser::BNF<std::string::const_iterator> const parser;
std::string const input =
R"(<code> ::= <letter><digit> 34 | <letter><digit><code> 23
<letter> ::= "a" 1 | "b" 2 | "c" 3 | "d" 4 | "e" 5 | "f" 6 | "g" 7 | "h" 8 | "i" 9
<digit> ::= "9" 10 | "1" 11 | "2" 12 | "3" 13 | "4" 14
)";
auto it = input.begin(),itEnd = input.end();
Ast::Syntax syntax;
if (parse(it,itEnd,parser,syntax)) {
for (auto& rule : syntax)
fmt::print("{} ::= {}\n",rule.name,fmt::join(rule.rhs," | "));
} else {
std::cout << "Failed\n";
}
if (it != itEnd)
std::cout << "Remaining: " << std::quoted(std::string(it,itEnd)) << "\n";
}
足以得到你所描述的:
code ::= <letter><digit> 34 | <letter><digit><code> 23
letter ::= a 1 | b 2 | c 3 | d 4 | e 5 | f 6 | g 7 | h 8 | i 9
digit ::= 9 10 | 1 11 | 2 12 | 3 13 | 4 14
Remaining: "
"
印刷品
.match?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。