当我尝试从iterator_range转换令牌的值时,词法分析器在尝试读取下一个令牌时失败。
这是包含令牌定义的Tokens结构:(我不认为这是相关的,但我包括以防万一。)
template <typename Lexer>
struct Tokens : boost::spirit::lex::lexer<Lexer>
{
Tokens();
boost::spirit::lex::token_def<std::string> identifier;
boost::spirit::lex::token_def<std::string> string;
boost::spirit::lex::token_def<bool> boolean;
boost::spirit::lex::token_def<double> real;
boost::spirit::lex::token_def<> comment;
boost::spirit::lex::token_def<> whitespace;
};
template <typename Lexer>
Tokens<Lexer>::Tokens()
{
// Define regex macros
this->self.add_pattern
("LETTER", "[a-zA-Z_]")
("DIGIT", "[0-9]")
("INTEGER", "-?{DIGIT}+")
("FLOAT", "-?{DIGIT}*\\.{DIGIT}+");
// Define the tokens' regular expressions
identifier = "{LETTER}({LETTER}|{DIGIT})*";
string = "\"[a-zA-Z_0-9]*\"";
boolean = "true|false";
real = "{INTEGER}|{FLOAT}";
comment = "#[^\n\r\f\v]*$";
whitespace = "\x20\n\r\f\v\t+";
// Define tokens
this->self
= identifier
| string
| boolean
| real
| '{'
| '}'
| '<'
| '>';
// Define tokens to be ignored
this->self("WS")
= whitespace
| comment;
}
以下是我的令牌和词法分析器类型的定义:
typedef lex::lexertl::token<char const*> TokenType;
typedef lex::lexertl::actor_lexer<TokenType> LexerType;
这是我用于读取令牌并将其值转换为字符串的代码。
Tokens<LexerType> tokens;
std::string string = "9index";
char const* first = string.c_str();
char const* last = &first[string.size()];
LexerType::iterator_type token = tokens.begin(first, last);
LexerType::iterator_type end = tokens.end();
//typedef boost::iterator_range<char const*> iterator_range;
//const iterator_range& range = boost::get<iterator_range>(token->value());
//std::cout << std::string(range.begin(), range.end()) << std::endl;
++token;
token_is_valid(*token); // Returns false ONLY if I uncomment the above code
此代码的输出为“9”(它读取第一个数字,在流中留下“index”)。如果我此时打印出字符串(first,last)的值,则显示“ndex”。由于某些原因,词法分析者在'i'字符上失败了吗?
我甚至尝试使用std :: stringstream进行转换,但这也会导致下一个令牌无效:
std::stringstream out;
out << token->value();
std::cout << out.str() << std::endl;
++token;
token_is_valid(*token); // still fails
最后,如果我只是将令牌的值发送到cout:
,则下一个令牌有效std::cout << token->value() << std::endl;
++token;
token_is_valid(*token); // success, what?
我对miss-&gt; value()返回的iterator_range如何工作缺少什么?我用来将它转换为字符串的方法都不会修改integer_range或词法分析器的输入字符流。
编辑:我在此处添加此内容,因为评论回复太短,无法完全解释发生的事情。
我明白了。正如sehe和drhirsch指出的那样,我原来问题中的代码是我正在做的事情的消毒版本。我正在使用测试夹具类的gtest单元测试来测试词法分析器。作为该类的成员,我有void scan(const std :: string&amp; str),它从给定的字符串中分配第一个和最后一个迭代器(fixture的数据成员)。问题是我们退出这个函数时const std :: string&amp; str参数从堆栈中弹出并且不再存在,使这些迭代器失效,即使它们是灯具的数据成员。
故事的道德:只要您希望读取令牌,迭代器传递给lexer :: begin()的对象就应该存在。
我宁愿删除这个问题而不是在互联网上记录我的愚蠢错误,但为了帮助社区,我想我应该离开它。
答案 0 :(得分:5)
从给定代码判断,您似乎正在查看编译器/库错误。我无法使用以下任何组合重现该问题:
编辑现在包含clang ++和boost 1_49_0。对于选定数量的测试案例,Valgrind会清理干净。
clang ++ 2.9,-O0,boost 1_49_0
gcc 4.4.5,-O0,boost 1_42_1
完整的代码测试:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
template <typename Lexer>
struct Tokens : lex::lexer<Lexer>
{
Tokens();
lex::token_def<std::string> identifier;
lex::token_def<std::string> string;
lex::token_def<bool> boolean;
lex::token_def<double> real;
lex::token_def<> comment;
lex::token_def<> whitespace;
};
template <typename Lexer>
Tokens<Lexer>::Tokens()
{
// Define regex macros
this->self.add_pattern
("LETTER", "[a-zA-Z_]")
("DIGIT", "[0-9]")
("INTEGER", "-?{DIGIT}+")
("FLOAT", "-?{DIGIT}*\\.{DIGIT}+");
// Define the tokens' regular expressions
identifier = "{LETTER}({LETTER}|{DIGIT})*";
string = "\"[a-zA-Z_0-9]*\"";
boolean = "true|false";
real = "{INTEGER}|{FLOAT}";
comment = "#[^\n\r\f\v]*$";
whitespace = "\x20\n\r\f\v\t+";
// Define tokens
this->self
= identifier
| string
| boolean
| real
| '{'
| '}'
| '<'
| '>';
// Define tokens to be ignored
this->self("WS")
= whitespace
| comment;
}
////////////////////////////////////////////////
typedef lex::lexertl::token<char const*> TokenType;
typedef lex::lexertl::actor_lexer<TokenType> LexerType;
int main(int argc, const char *argv[])
{
Tokens<LexerType> tokens;
std::string string = "9index";
char const* first = string.c_str();
char const* last = &first[string.size()];
LexerType::iterator_type token = tokens.begin(first, last);
LexerType::iterator_type end = tokens.end();
typedef boost::iterator_range<char const*> iterator_range;
const iterator_range& range = boost::get<iterator_range>(token->value());
std::cout << std::string(range.begin(), range.end()) << std::endl;
++token;
// Returns false ONLY if I uncomment the above code
std::cout << "Next valid: " << std::boolalpha << token_is_valid(*token) << '\n';
return 0;
}