我想知道boost :: spirit :: lex是否有辦法將令牌值寫回輸入流(可能在編輯之後)並再次重新掃描。我基本上尋找的是類似於Flex中unput()提供的功能。Boost spirit lex將令牌值寫回輸入流
謝謝!
我想知道boost :: spirit :: lex是否有辦法將令牌值寫回輸入流(可能在編輯之後)並再次重新掃描。我基本上尋找的是類似於Flex中unput()提供的功能。Boost spirit lex將令牌值寫回輸入流
謝謝!
我最終實現我自己的unput()的功能如下:
struct unputImpl
{
template <typename Iter1T, typename Iter2T, typename StrT>
struct result {
typedef void type;
};
template <typename Iter1T, typename Iter2T, typename StrT>
typename result<Iter1T, Iter2T, StrT>::type operator()(Iter1T& start, Iter2T& end, StrT str) const {
start -= (str.length() - std::distance(start, end));
std::copy(str.begin(), str.end(), start);
end = start;
}
};
phoenix::function<unputImpl> const unput = unputImpl();
這可以被使用,如:
this->self += lex::token_def<lex::omit>("{SYMBOL}\\(")
[
unput(_start, _end, "(" + construct<string>(_start, _end - 1) + " "),
_pass = lex::pass_flags::pass_ignore
];
如果未輸入的字符串長度較大而不是匹配的標記長度,它將覆蓋一些先前解析的輸入。需要注意的是確保輸入字符串在一開始就有足夠的空間來處理第一個匹配標記調用unput()的情況。
聽起來像你只是想以不同的順序接受令牌,但具有相同的含義。
這裏是一個完整的示例,展示了這將如何完成,並暴露標識符,而不管輸入順序如何。輸出:
代碼
#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);
}
謝謝sehe。不幸的是,將問題導出到解析器對我來說不是一個好的選擇,原因有兩個: 1)I需要區分開放paren直接跟隨標識符與其間由任何空格字符分隔的情況(在這種情況下,解析器應該匹配不同的規則) 2)還有很多其他關鍵字需要以相同的方式處理(不僅僅是標識符),所以這會使解析這些關鍵字所需的製作次數增加一倍(當paren先於關鍵字出現時, )。 –
@HaithamGad讓我這樣說:寫一個質量問題很難。 _這就是爲什麼。我會給你一些新的限制 – sehe
是的抱歉,:)並感謝您的幫助! –
你想達到什麼目的?我的意思是,在什麼情況下你需要使用unput()?如果你展示一個例子,我可能會告訴你怎麼做(可能使用Lexer狀態) – sehe
基本上,我需要詞法分析器來匹配標識符,然後直接跟一個開放的paren「abc(」作爲一個標記,並把它放回到輸入流中,paren位於字符串的開頭,如「(abc」)。下一步是詞法分析器再次掃描它,但是作爲兩個單獨的標記(一個paren標記,然後是一個標識符標記) –
好吧,我在這裏發表了我的看法,讓我知道是否我錯誤地理解了_goal_ – sehe