我想知道 boost::spirit::lex 中是否有一种方法可以将标记值写回输入流(可能在编辑之后)并再次重新扫描。我主要寻找的是类似 Flex 中 unput() 提供的功能。
谢谢!
最佳答案
听起来您只是想接受顺序不同但含义相同的 token 。
事不宜迟,这里有一个完整的示例,展示了如何完成此操作,无论输入顺序如何都公开标识符。输出:
Input 'abc(' Parsed as: '(abc'
Input '(abc' Parsed as: '(abc'
代码
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <iostream>
#include <string>
using namespace boost::spirit;
///// LEXER
template <typename Lexer>
struct tokens : lex::lexer<Lexer>
{
tokens()
{
identifier = "[a-zA-Z][a-zA-Z0-9]*";
paren_open = '(';
this->self.add
(identifier)
(paren_open)
;
}
lex::token_def<std::string> identifier;
lex::token_def<lex::omit> paren_open;
};
///// GRAMMAR
template <typename Iterator>
struct grammar : qi::grammar<Iterator, std::string()>
{
template <typename TokenDef>
grammar(TokenDef const& tok) : grammar::base_type(ident_w_parenopen)
{
ident_w_parenopen =
(tok.identifier >> tok.paren_open)
| (tok.paren_open >> tok.identifier)
;
}
private:
qi::rule<Iterator, std::string()> ident_w_parenopen;
};
///// DEMONSTRATION
typedef std::string::const_iterator It;
template <typename T, typename G>
void DoTest(std::string const& input, T const& tokens, G const& g)
{
It first(input.begin()), last(input.end());
std::string parsed;
bool r = lex::tokenize_and_parse(first, last, tokens, g, parsed);
if (r) {
std::cout << "Input '" << input << "' Parsed as: '(" << parsed << "'\n";
}
else {
std::string rest(first, last);
std::cerr << "Parsing '" << input << "' failed\n" << "stopped at: \"" << rest << "\"\n";
}
}
int main(int argc, char* argv[])
{
typedef lex::lexertl::token<It, boost::mpl::vector<std::string> > token_type;
typedef lex::lexertl::lexer<token_type> lexer_type;
typedef tokens<lexer_type>::iterator_type iterator_type;
tokens<lexer_type> tokens;
grammar<iterator_type> g (tokens);
DoTest("abc(", tokens, g);
DoTest("(abc", tokens, g);
}
关于c++ - Boost spirit lex 将 token 值写回输入流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10611306/