2011-10-14 21 views
10

Tôi cố gắng triển khai một Lexer cho một chút ngôn ngữ lập trình với Boost Spirit.Tôi không thể nhận được giá trị chuỗi của mã thông báo

tôi phải nhận được giá trị của một token và tôi nhận được một ngoại lệ bad_get:

chấm dứt gọi là sau khi ném một thể hiện của 'đẩy mạnh :: bad_get'
gì(): tăng :: bad_get: giá trị không được sử dụng tăng :: nhận Đã hủy bỏ

tôi có được ngoại lệ này khi thực hiện:

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; 

l My exer được định nghĩa như sau:

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; 
}; 

Có cách nào khác để nhận giá trị của mã thông báo không?

+3

về đọc lại, tôi nhận thấy rằng bạn chỉ định 'lex :: omit' như các loại thuộc tính tượng trưng. Các mã thông báo này sẽ không hiển thị dữ liệu _any_ value (thậm chí không phải cặp lặp). Đây có thể là vấn đề của bạn. Nếu không, tôi chân thành khuyên bạn nên phân tích cú pháp bằng cách sử dụng Qi trên các trình vòng lặp mã thông báo: tận dụng tối đa cả hai thế giới. – sehe

+0

Tôi đã xác minh và đáng tiếc đây không phải là vấn đề. Tôi chỉ sử dụng boost :: nhận được trên một mã thông báo của loại tốt và cần có giá trị. –

Trả lời

9

Bạn luôn có thể sử dụng dữ liệu mã thông báo 'mặc định' (đây là iterator_range của loại trình lặp nguồn).

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

Sau khi nghiên cứu các trường hợp kiểm tra trong kho tăng, tôi phát hiện ra một số điều:

  • này là do thiết kế
  • có một cách dễ dàng hơn
  • các dễ dàng hơn theo cách tự động trong các hành động ngữ nghĩa của Lex (ví dụ: sử dụng _1) và khi sử dụng mã thông báo lexer trong Qi; việc chuyển nhượng sẽ tự động chuyển sang Qi loại
  • thuộc tính này có (thực sự) có 'lười biếng, một lần, đánh giá' ngữ nghĩa được đề cập trong tài liệu

Các cinch là dữ liệu mã thông báo là biến thể, mà bắt đầu như là phạm vi lặp đầu vào thô. Chỉ sau khi gán 'a', thuộc tính được chuyển đổi được lưu trong bộ nhớ cache trong biến thể. Bạn có thể chứng kiến ​​quá trình chuyển đổi:

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; 

Như bạn có thể thấy, phân bổ thuộc tính buộc phải ở đây, trực tiếp sử dụng triển khai đặc điểm assign_to.

Full cuộc biểu tình làm việc:

#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

Có vẻ hơi phức tạp một chút vì điều gì đó nên được thực hiện bởi Thánh Linh. Trong trường hợp của tôi, mã thông báo được nhập để nhận giá trị của chúng để tôi nhận được một biến thể từ giá trị() không trực tiếp một trình lặp. Tôi cũng có một mã thông báo. Với kỹ thuật của bạn, bạn không tận dụng lợi thế của biến thể được cung cấp bởi giá trị(), không? –

+1

Phần nào bị quá tải? Phần mà nó nói 'std :: string (iter-> value(). Begin(), iter-> value(). End())'?Tôi không đánh vần nó (bạn mong đợi chúng ta đọc mẫu Looooong của bạn để '_get_' ý bạn là gì, và bạn không muốn đọc 7 dòng 'showtoken' để xem nó được làm như thế nào? Mmmm.) Mẫu của tôi có lẽ dường như quá phức tạp vì nó là một ví dụ đầy đủ về cách sử dụng điều này trong một trình phân tích cú pháp thực tế để đạt được, ví dụ báo cáo lỗi. Xin lỗi vì đã cho thấy những điều không quan tâm đến bạn :) – sehe

+0

Điều tôi thấy quá phức tạp là chúng tôi phân tích bằng tay thứ gì đó mà Thần Khí mang lại cho chúng ta. Nếu tôi có các thẻ float, int, string và bool và tôi muốn lấy các giá trị nguyên thủy của chúng, tôi phải tạo ra 4 hàm phân tích cú pháp, phải không? Và thông thường các giá trị này được lưu trữ trong biến thể :: boost. Hoặc có lẽ tôi không hiểu giá trị trả về của hàm value(). –

Các vấn đề liên quan