我已将代码缩减到重现错误所需的绝对最小值(遗憾的是仍然是60行,不是很小,但至少是它的VCE)。
我在Visual Studio 2013中使用Boost 1.56(Platform Toolset v120)。
下面的代码为我提供了访问冲突,除非我取消注释标记的行。通过做一些测试,似乎boost :: spirit不喜欢它,如果枚举从0开始(在我的完整代码中我在枚举中有更多的值,我只是设置IntLiteral = 1
并且它也摆脱了访问冲突错误,虽然名称错误,因为在索引到数组时ToString被关闭了。)
这是boost :: spirit中的错误还是我做错了什么?
#include <iostream>
#include <string>
#include <vector>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
namespace lex = boost::spirit::lex;
typedef lex::lexertl::token<char const*> LexToken;
typedef lex::lexertl::actor_lexer<LexToken> LexerType;
typedef boost::iterator_range<char const*> IteratorRange;
enum TokenType
{
//Unused, // <-- Uncommenting this fixes the error (1/2)
IntLiteral,
};
std::string tokenTypeNames[] = {
//"unused", // <-- Uncommenting this line fixes the error (2/2)
"int literal",
};
std::string ToString(TokenType t)
{
return tokenTypeNames[t];
}
template <typename T>
struct Lexer : boost::spirit::lex::lexer < T >
{
Lexer()
{
self.add
// Literals
("[1-9][0-9]*", TokenType::IntLiteral);
}
};
int main(int argc, char* argv[])
{
std::cout << "Boost version: " << BOOST_LIB_VERSION << std::endl;
std::string input = "33";
char const* inputIt = input.c_str();
char const* inputEnd = &input[input.size()];
Lexer<LexerType> tokens;
LexerType::iterator_type token = tokens.begin(inputIt, inputEnd);
LexerType::iterator_type end = tokens.end();
for (; token->is_valid() && token != end; ++token)
{
auto range = boost::get<IteratorRange>(token->value());
std::cout << ToString(static_cast<TokenType>(token->id())) << " (" << std::string(range.begin(), range.end()) << ')' << std::endl;
}
std::cin.get();
return 0;
}
如果我取消注释我得到的行:
Boost version: 1_56
int literal (33)
答案 0 :(得分:3)
它&#34;工作&#34;如果你取消注释这些线,那是纯粹的意外。
来自文档spirit/lex/tutorials/lexer_quickstart2.html:
为确保为每个令牌分配一个id,Spirit.Lex库在内部为令牌定义分配唯一的数字,从
定义的常量开始boost::spirit::lex::min_token_id
另见这个较旧的答案:
所以你可以使用偏移来修复它,但我想它会继续成为一个脆弱的解决方案,因为很容易让枚举与lexer表中的实际令牌定义不同步。
我建议使用the linked answer中给出的nameof()
方法,该方法利用了名为token_def<>
的对象。
<强> Live On Coliru 强>
#include <iostream>
#include <string>
#include <vector>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
namespace lex = boost::spirit::lex;
typedef lex::lexertl::token<char const*> LexToken;
typedef lex::lexertl::actor_lexer<LexToken> LexerType;
typedef boost::iterator_range<char const*> IteratorRange;
enum TokenType {
IntLiteral = boost::spirit::lex::min_token_id
};
std::string const& ToString(TokenType t) {
static const std::string tokenTypeNames[] = {
"int literal",
};
return tokenTypeNames[t - boost::spirit::lex::min_token_id];
}
template <typename T>
struct Lexer : boost::spirit::lex::lexer<T> {
Lexer() {
this->self.add
// Literals
("[1-9][0-9]*", TokenType::IntLiteral);
}
};
int main() {
std::cout << "Boost version: " << BOOST_LIB_VERSION << std::endl;
std::string input = "33";
char const* inputIt = input.c_str();
char const* inputEnd = &input[input.size()];
Lexer<LexerType> tokens;
LexerType::iterator_type token = tokens.begin(inputIt, inputEnd);
LexerType::iterator_type end = tokens.end();
for (; token->is_valid() && token != end; ++token)
{
auto range = boost::get<IteratorRange>(token->value());
std::cout << ToString(static_cast<TokenType>(token->id())) << " (" << std::string(range.begin(), range.end()) << ')' << std::endl;
}
}