让我们考虑以下代码:
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
namespace lex = boost::spirit::lex;
namespace qi = boost::spirit::qi;
template<typename Lexer>
class expression_lexer
: public lex::lexer<Lexer>
{
public:
typedef lex::token_def<> operator_token_type;
typedef lex::token_def<> value_token_type;
typedef lex::token_def<> variable_token_type;
typedef lex::token_def<lex::omit> parenthesis_token_type;
typedef std::pair<parenthesis_token_type, parenthesis_token_type> parenthesis_token_pair_type;
typedef lex::token_def<lex::omit> whitespace_token_type;
expression_lexer()
: operator_add('+'),
operator_sub('-'),
operator_mul("[x*]"),
operator_div("[:/]"),
value("\\d+(\\.\\d+)?"),
variable("%(\\w+)"),
parenthesis({
std::make_pair(parenthesis_token_type('('), parenthesis_token_type(')')),
std::make_pair(parenthesis_token_type('['), parenthesis_token_type(']'))
}),
whitespace("[ \\t]+")
{
this->self
= operator_add
| operator_sub
| operator_mul
| operator_div
| value
| variable
;
std::for_each(parenthesis.cbegin(), parenthesis.cend(),
[&](parenthesis_token_pair_type const& token_pair)
{
this->self += token_pair.first | token_pair.second;
}
);
this->self("WS") = whitespace;
}
operator_token_type operator_add;
operator_token_type operator_sub;
operator_token_type operator_mul;
operator_token_type operator_div;
value_token_type value;
variable_token_type variable;
std::vector<parenthesis_token_pair_type> parenthesis;
whitespace_token_type whitespace;
};
template<typename Iterator, typename Skipper>
class expression_grammar
: public qi::grammar<Iterator, Skipper>
{
public:
template<typename Tokens>
explicit expression_grammar(Tokens const& tokens)
: expression_grammar::base_type(start)
{
start %= expression >> qi::eoi;
expression %= sum_operand >> -(sum_operator >> expression);
sum_operator %= tokens.operator_add | tokens.operator_sub;
sum_operand %= fac_operand >> -(fac_operator >> sum_operand);
fac_operator %= tokens.operator_mul | tokens.operator_div;
if(!tokens.parenthesis.empty())
fac_operand %= parenthesised | terminal;
else
fac_operand %= terminal;
terminal %= tokens.value | tokens.variable;
if(!tokens.parenthesis.empty())
{
parenthesised %= tokens.parenthesis.front().first >> expression >> tokens.parenthesis.front().second;
std::for_each(tokens.parenthesis.cbegin() + 1, tokens.parenthesis.cend(),
[&](typename Tokens::parenthesis_token_pair_type const& token_pair)
{
parenthesised %= parenthesised.copy() | (token_pair.first >> expression >> token_pair.second);
}
);
}
}
private:
qi::rule<Iterator, Skipper> start;
qi::rule<Iterator, Skipper> expression;
qi::rule<Iterator, Skipper> sum_operand;
qi::rule<Iterator, Skipper> sum_operator;
qi::rule<Iterator, Skipper> fac_operand;
qi::rule<Iterator, Skipper> fac_operator;
qi::rule<Iterator, Skipper> terminal;
qi::rule<Iterator, Skipper> parenthesised;
};
int main()
{
typedef lex::lexertl::token<std::string::const_iterator> token_type;
typedef expression_lexer<lex::lexertl::lexer<token_type>> expression_lexer_type;
typedef expression_lexer_type::iterator_type expression_lexer_iterator_type;
typedef qi::in_state_skipper<expression_lexer_type::lexer_def> skipper_type;
typedef expression_grammar<expression_lexer_iterator_type, skipper_type> expression_grammar_type;
expression_lexer_type lexer;
expression_grammar_type grammar(lexer);
while(std::cin)
{
std::string line;
std::getline(std::cin, line);
std::string::const_iterator first = line.begin();
std::string::const_iterator const last = line.end();
bool const result = lex::tokenize_and_phrase_parse(first, last, lexer, grammar, qi::in_state("WS")[lexer.self]);
if(!result)
std::cout << "Parsing failed! Reminder: >" << std::string(first, last) << "<" << std::endl;
else
{
if(first != last)
std::cout << "Parsing succeeded! Reminder: >" << std::string(first, last) << "<" << std::endl;
else
std::cout << "Parsing succeeded!" << std::endl;
}
}
}
它是一个带有值和变量的算术表达式的简单解析器。它是使用expression_lexer
构建来提取令牌,然后使用expression_grammar
来解析令牌。
对于如此小的案例使用词法分析器似乎有点矫枉过正,可能就是一个。但这是简化示例的成本。另请注意,使用词法分析器可以轻松定义具有正则表达式的标记,同时允许通过外部代码(特别是用户提供的配置)轻松定义它们。通过提供的示例,从外部配置文件中读取令牌的定义并且例如允许用户将变量从%name
更改为$name
完全没有问题。
代码似乎工作正常(在Visual Studio 2013上使用Boost 1.61进行检查)。除了我注意到,如果我提供类似5++5
的字符串,它会正确失败,但报告为5
而不是+5
提醒,这意味着违规的+
是&#34;无法恢复的&#34;消耗。显然,生成但与语法不匹配的令牌绝不会返回到原始输入。但这不是我要问的问题。我在检查代码时意识到了这一点。
现在的问题是空白跳过。我非常不喜欢它是如何完成的。虽然我已经这样做了,因为它似乎是许多例子提供的,包括StackOverflow上的问题答案。
最糟糕的事情似乎是(没有记录?)qi::in_state_skipper
。此外,似乎我必须添加whitespace
令牌(使用名称),而不是像所有其他令牌一样,因为使用lexer.whitespace
代替"WS"
似乎并不像工作
最后不得不&#34;混乱&#34; Skipper
参数的语法似乎并不好看。难道我不能解脱它吗?毕竟我想基于令牌而不是直接输入来制作语法,我希望将空格从令牌流中排除 - 不再需要它了!
我还有哪些其他选项可以跳过空格?这样做有什么好处呢?
答案 0 :(得分:4)
由于一些奇怪的原因,我现在发现了一个不同的问题,Boost.Spirit SQL grammar/lexer failure,其中some other solution提供了空格跳过。一个更好的!
以下是根据建议重新编写的示例代码:
public function store(Illuminate\Http\Request $request)
{
$this->validate($request, [
'time_start' => 'date_format:H:i',
'time_end' => 'date_format:H:i|after:time_start',
]);
// do other stuff
}
差异如下:
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
namespace lex = boost::spirit::lex;
namespace qi = boost::spirit::qi;
template<typename Lexer>
class expression_lexer
: public lex::lexer<Lexer>
{
public:
typedef lex::token_def<> operator_token_type;
typedef lex::token_def<> value_token_type;
typedef lex::token_def<> variable_token_type;
typedef lex::token_def<lex::omit> parenthesis_token_type;
typedef std::pair<parenthesis_token_type, parenthesis_token_type> parenthesis_token_pair_type;
typedef lex::token_def<lex::omit> whitespace_token_type;
expression_lexer()
: operator_add('+'),
operator_sub('-'),
operator_mul("[x*]"),
operator_div("[:/]"),
value("\\d+(\\.\\d+)?"),
variable("%(\\w+)"),
parenthesis({
std::make_pair(parenthesis_token_type('('), parenthesis_token_type(')')),
std::make_pair(parenthesis_token_type('['), parenthesis_token_type(']'))
}),
whitespace("[ \\t]+")
{
this->self
+= operator_add
| operator_sub
| operator_mul
| operator_div
| value
| variable
| whitespace [lex::_pass = lex::pass_flags::pass_ignore]
;
std::for_each(parenthesis.cbegin(), parenthesis.cend(),
[&](parenthesis_token_pair_type const& token_pair)
{
this->self += token_pair.first | token_pair.second;
}
);
}
operator_token_type operator_add;
operator_token_type operator_sub;
operator_token_type operator_mul;
operator_token_type operator_div;
value_token_type value;
variable_token_type variable;
std::vector<parenthesis_token_pair_type> parenthesis;
whitespace_token_type whitespace;
};
template<typename Iterator>
class expression_grammar
: public qi::grammar<Iterator>
{
public:
template<typename Tokens>
explicit expression_grammar(Tokens const& tokens)
: expression_grammar::base_type(start)
{
start %= expression >> qi::eoi;
expression %= sum_operand >> -(sum_operator >> expression);
sum_operator %= tokens.operator_add | tokens.operator_sub;
sum_operand %= fac_operand >> -(fac_operator >> sum_operand);
fac_operator %= tokens.operator_mul | tokens.operator_div;
if(!tokens.parenthesis.empty())
fac_operand %= parenthesised | terminal;
else
fac_operand %= terminal;
terminal %= tokens.value | tokens.variable;
if(!tokens.parenthesis.empty())
{
parenthesised %= tokens.parenthesis.front().first >> expression >> tokens.parenthesis.front().second;
std::for_each(tokens.parenthesis.cbegin() + 1, tokens.parenthesis.cend(),
[&](typename Tokens::parenthesis_token_pair_type const& token_pair)
{
parenthesised %= parenthesised.copy() | (token_pair.first >> expression >> token_pair.second);
}
);
}
}
private:
qi::rule<Iterator> start;
qi::rule<Iterator> expression;
qi::rule<Iterator> sum_operand;
qi::rule<Iterator> sum_operator;
qi::rule<Iterator> fac_operand;
qi::rule<Iterator> fac_operator;
qi::rule<Iterator> terminal;
qi::rule<Iterator> parenthesised;
};
int main()
{
typedef lex::lexertl::token<std::string::const_iterator> token_type;
typedef expression_lexer<lex::lexertl::actor_lexer<token_type>> expression_lexer_type;
typedef expression_lexer_type::iterator_type expression_lexer_iterator_type;
typedef expression_grammar<expression_lexer_iterator_type> expression_grammar_type;
expression_lexer_type lexer;
expression_grammar_type grammar(lexer);
while(std::cin)
{
std::string line;
std::getline(std::cin, line);
std::string::const_iterator first = line.begin();
std::string::const_iterator const last = line.end();
bool const result = lex::tokenize_and_parse(first, last, lexer, grammar);
if(!result)
std::cout << "Parsing failed! Reminder: >" << std::string(first, last) << "<" << std::endl;
else
{
if(first != last)
std::cout << "Parsing succeeded! Reminder: >" << std::string(first, last) << "<" << std::endl;
else
std::cout << "Parsing succeeded!" << std::endl;
}
}
}
令牌作为所有其他令牌添加到词法分析器的whitespace
。self
不再需要expression_grammar
模板参数。因此它也从规则中删除。Skipper
用于代替lex::lexertl::actor_lexer
,因为现在有一个与令牌相关联的操作。lex::lexertl::lexer
代替tokenize_and_parse
,因为我不再需要通过队长。tokenize_and_phrase_parse
的第一个作业从this->self
更改为=
,因为它似乎更灵活(抵制订单更改)。但它并没有影响到这里的解决方案。