2011-10-14 39 views
10

我嘗試使用Boost Spirit來爲一個小編程語言實現Lexer。我無法獲得令牌的字符串值

我必須得到一個代幣的價值,我也得到一個bad_get例外:

終止叫做拋出的 '助推:: bad_get' 的實例後
什麼()的boost :: bad_get:失敗值獲得使用boost ::得到這樣做的時候中止

我得到這個異常:

std::string contents = "void"; 

base_iterator_type first = contents.begin(); 
base_iterator_type last = contents.end(); 

SimpleLexer<lexer_type> lexer; 

iter = lexer.begin(first, last); 
end = lexer.end(); 

std::cout << "Value = " << boost::get<std::string>(iter->value()) << std::endl; 

我升exer是這樣定義的:

typedef std::string::iterator base_iterator_type; 
typedef boost::spirit::lex::lexertl::token<base_iterator_type, boost::mpl::vector<unsigned int, std::string>> Tok; 
typedef lex::lexertl::actor_lexer<Tok> lexer_type; 

template<typename L> 
class SimpleLexer : public lex::lexer<L> { 
    private: 

    public: 
     SimpleLexer() { 
      keyword_for = "for"; 
      keyword_while = "while"; 
      keyword_if = "if"; 
      keyword_else = "else"; 
      keyword_false = "false"; 
      keyword_true = "true"; 
      keyword_from = "from"; 
      keyword_to = "to"; 
      keyword_foreach = "foreach"; 

      word = "[a-zA-Z]+"; 
      integer = "[0-9]+"; 
      litteral = "..."; 

      left_parenth = '('; 
      right_parenth = ')'; 
      left_brace = '{'; 
      right_brace = '}'; 

      stop = ';'; 
      comma = ','; 

      swap = "<>"; 
      assign = '='; 
      addition = '+'; 
      subtraction = '-'; 
      multiplication = '*'; 
      division = '/'; 
      modulo = '%'; 

      equals = "=="; 
      not_equals = "!="; 
      greater = '>'; 
      less = '<'; 
      greater_equals = ">="; 
      less_equals = "<="; 

      whitespaces = "[ \\t\\n]+"; 
      comments = "\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/"; 

      //Add keywords 
      this->self += keyword_for | keyword_while | keyword_true | keyword_false | keyword_if | keyword_else | keyword_from | keyword_to | keyword_foreach; 
      this->self += integer | litteral | word; 

      this->self += equals | not_equals | greater_equals | less_equals | greater | less ; 
      this->self += left_parenth | right_parenth | left_brace | right_brace; 
      this->self += comma | stop; 
      this->self += assign | swap | addition | subtraction | multiplication | division | modulo; 

      //Ignore whitespaces and comments 
      this->self += whitespaces [lex::_pass = lex::pass_flags::pass_ignore]; 
      this->self += comments [lex::_pass = lex::pass_flags::pass_ignore]; 
     } 

     lex::token_def<std::string> word, litteral, integer; 

     lex::token_def<lex::omit> left_parenth, right_parenth, left_brace, right_brace; 

     lex::token_def<lex::omit> stop, comma; 

     lex::token_def<lex::omit> assign, swap, addition, subtraction, multiplication, division, modulo; 
     lex::token_def<lex::omit> equals, not_equals, greater, less, greater_equals, less_equals; 

     //Keywords 
     lex::token_def<lex::omit> keyword_if, keyword_else, keyword_for, keyword_while, keyword_from, keyword_to, keyword_foreach; 
     lex::token_def<lex::omit> keyword_true, keyword_false; 

     //Ignored tokens 
     lex::token_def<lex::omit> whitespaces; 
     lex::token_def<lex::omit> comments; 
}; 

是否有其他方法來獲取令牌的值?

+3

再次閱讀,我注意到你指定'::法作爲omit'令牌屬性類型。這些令牌不會公開_any_值數據(甚至不包括迭代器對)。這可能是你的問題。否則,我衷心推薦在標記迭代器之上使用Qi進行解析:獲得兩全其美的好處。 – sehe

+0

我證實並且可悲的是這不是問題。我只使用boost :: get在一個好類型的令牌上,它應該有這個值。 –

回答

9

您始終可以使用「默認」標記數據(它是源迭代器類型的iterator_range)。

std::string tokenvalue(iter->value().begin(), iter->value().end()); 

在升壓庫研究測試用例後,我發現了一些東西:

  • 這是由設計
  • 還有一個更簡單的方法
  • 容易 Lex的語義動作(例如使用_1)以及在Qi中使用詞法分析器令牌時會自動執行;分配將自動轉換爲齊屬性類型
  • 這有(確實)得到了「懶,一時間,評價」在文檔

束帶是令牌數據是變種提到的語義,從最初的輸入迭代器範圍開始。只有在'a'強制分配之後,轉換的屬性才被緩存在變體中。您可以親眼目睹過渡:

lexer_type::iterator_type iter = lexer.begin(first, last); 
lexer_type::iterator_type end = lexer.end(); 

assert(0 == iter->value().which()); 
std::cout << "Value = " << boost::get<boost::iterator_range<base_iterator_type> >(iter->value()) << std::endl; 

std::string s; 
boost::spirit::traits::assign_to(*iter, s); 
assert(1 == iter->value().which()); 
std::cout << "Value = " << s << std::endl; 

正如你看到的,屬性分配在這裏勉強,直接使用assign_to特徵實現。

全部工作示範:

#include <boost/spirit/include/lex_lexertl.hpp> 

#include <iostream> 
#include <string> 

namespace lex = boost::spirit::lex; 

typedef std::string::iterator base_iterator_type; 
typedef boost::spirit::lex::lexertl::token<base_iterator_type, boost::mpl::vector<int, std::string>> Tok; 
typedef lex::lexertl::actor_lexer<Tok> lexer_type; 

template<typename L> 
class SimpleLexer : public lex::lexer<L> { 
    private: 

    public: 
     SimpleLexer() { 
      word = "[a-zA-Z]+"; 
      integer = "[0-9]+"; 
      literal = "..."; 

      this->self += integer | literal | word; 
     } 

     lex::token_def<std::string> word, literal; 
     lex::token_def<int> integer; 
}; 

int main(int argc, const char* argv[]) { 
    SimpleLexer<lexer_type> lexer; 

    std::string contents = "void"; 

    base_iterator_type first = contents.begin(); 
    base_iterator_type last = contents.end(); 

    lexer_type::iterator_type iter = lexer.begin(first, last); 
    lexer_type::iterator_type end = lexer.end(); 

    assert(0 == iter->value().which()); 
    std::cout << "Value = " << boost::get<boost::iterator_range<base_iterator_type> >(iter->value()) << std::endl; 

    std::string s; 
    boost::spirit::traits::assign_to(*iter, s); 
    assert(2 == iter->value().which()); 
    std::cout << "Value = " << s << std::endl; 

    return 0; 
} 
+0

看起來有點過於複雜,應該由Spirit來完成。在我的情況下,令牌被鍵入以獲得它們的值,所以我從value()獲得一個變體,而不是直接迭代器。我也有一個int令牌。用你的技術,你不會利用value()提供的變體,否? –

+1

什麼部分過於複雜?它表示'std :: string(iter-> value()。begin(),iter-> value()。end())''的部分。我沒有把它拼出來(你希望我們讀到你的Looooong樣本中'_get_'的意思,你不想讀7行'showtoken'來看看它是如何完成的?嗯。)我的樣本可能看起來過於複雜,因爲它是一個完整的例子,說明如何在實際的解析器中使用它來實現,例如錯誤報告。對不起,對你不感興趣的東西:) – sehe

+0

我發現過於複雜的事情是我們用手分析了Boost Spirit給我們的東西。如果我有float,int,string和bool標記,並且我想獲得它們的原始值,我必須創建4個解析函數,不是嗎?通常這些值存儲在boost :: variant中。或者,也許我不明白value()函數的返回值。 –