2014-12-18 2 views
1

오류를 재현하는 데 필요한 최소한의 코드로 코드를 줄였습니다 (슬프게도 여전히 최소한 60 개 라인이 아니지만 VCE는 최소한입니다).boost :: spirit :: lex의 액세스 위반

Visual Studio 2013 (플랫폼 도구 세트 v120)에서 Boost 1.56을 사용하고 있습니다.

표시된 줄의 주석 처리를 제거하지 않은 경우 아래 코드에서 액세스 위반이 발생합니다. 몇 가지 테스트를 수행하여 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

나는, 당신이 * 정말 * 0 tokentype 매 열거의 시작을 원하지 않는 가정 당신은? :) – bialpio

+0

@balpio 그 이유는 모르겠다. 왜 그런 질문을해서는 안되는가? – Borgleader

+0

아, 2 단계 검색을 올바르게 구현하는 컴파일러에서'this-> self'가 필요합니다. :) – sehe

답변

3

당신이 그 라인의 주석을 경우, 순수한 우연이 "작동"사실.

모든 토큰을 확보하기가 Spirit.Lex 라이브러리 내부적으로 boost::spirit::lex::min_token_id

에 의해 정의 된 상수로 시작, 토큰 정의 고유 번호를 할당하는 ID를 할당됩니다 : 워드 프로세서 spirit/lex/tutorials/lexer_quickstart2.html에서

이 이전 답변도 참조하십시오 :

오프셋을 사용하여 문제를 해결할 수는 있지만, 열거 테이블에서 실제 토큰 정의와 동기화되지 않도록 열거하기가 쉽기 때문에 취성있는 솔루션이 될 것입니다.

token_def<> 개체를 활용하는 the linked answer에 나와있는 것처럼 nameof() 접근 방식을 사용하는 것이 좋습니다.

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; 
    } 
} 
관련 문제