2010-02-27 1 views
11

Boost :: Spirit?을 사용하여 간단한 표현 파서를 작성하는 방법을 알고있는 온라인 리소스에 대해 알고 계신 분이 계십니까?Boost :: Spirit을 사용하는 간단한 표현식 파서 예제?

표현식을 반드시 평가할 필요는 없지만이를 구문 분석하고 표현식을 구문 분석 할 수 있는지 여부를 나타내는 부울을 반환 할 수 있어야합니다 (예 : 대괄호가 일치하지 않음 등).

파서가 함수 이름 (예 : foo 및 foobar)을 인식 할 수 있어야하므로 BNF 표기법을 배우는 데 도움이되는 유용한 예가 될 것입니다.

식은 법선 연산 식, 즉, 다음 기호를 포함 할 것이다 :

  • 연산기
  • 인식 기능 이름

    1. 개방/폐쇄 브래킷, 이들 필수 인자를 확인
  • +1

    영혼 문서와 예제를 살펴 보았습니까? –

    +1

    Spirit의 설명서는 내가 원하는만큼 간단하지 않습니다. 나는 그걸로 배울 수 있었지만, 더 나은 튜토리얼은 확실히 학습을 더 쉽게 만들었을 것입니다. – Tronic

    +0

    감사합니다. Tronic. 그것은 성령의 홈 페이지에서 문서를 읽었을 때 매우 많이 볼 수있었습니다. –

    답변

    5

    여기에 내가 쌓아 놓은 오래된 Spirit 프로토 타입 코드가 있습니다.

    #include <iostream> 
    #include <algorithm> 
    #include <vector> 
    #include <string> 
    #include <exception> 
    #include <iterator> 
    #include <sstream> 
    #include <list> 
    
    #include <boost/spirit.hpp> 
    #include <boost/shared_ptr.hpp> 
    
    using namespace std; 
    using namespace boost::spirit; 
    using namespace boost; 
    
    void g(unsigned int i) 
    { 
        cout << "row: " << i << endl; 
    } 
    
    struct u 
    { 
        u(const char* c): s(c) {} 
        void operator()(const char* first, const char* last) const 
        { 
         cout << s << ": " << string(first, last) << endl; 
        } 
    private: 
        string s; 
    }; 
    
    
    struct Exp 
    { 
    }; 
    
    struct Range: public Exp 
    { 
    }; 
    
    struct Index: public Exp 
    { 
    }; 
    
    struct String: public Exp 
    { 
    }; 
    
    struct Op 
    { 
        virtual ~Op() = 0; 
        virtual string name() = 0; 
    }; 
    
    Op::~Op() {} 
    
    struct CountIf: public Op 
    { 
        string name() { return "CountIf"; } 
    }; 
    
    struct Sum: public Op 
    { 
        string name() { return "Sum"; } 
    }; 
    
    struct Statement 
    { 
        virtual ~Statement() = 0; 
        virtual void print() = 0; 
    }; 
    
    Statement::~Statement() {} 
    
    struct Formula: public Statement 
    { 
        Formula(const char* first, const char* last): s(first, last), op(new CountIf) 
        { 
         typedef rule<phrase_scanner_t> r_t; 
    
         r_t r_index  = (+alpha_p)[u("col")] >> uint_p[&g]; 
         r_t r_range  = r_index >> ':' >> r_index; 
         r_t r_string = ch_p('\"') >> *alnum_p >> '\"'; 
         r_t r_exp  = r_range | r_index | r_string; // will invoke actions for index twice due to range 
         r_t r_list  = !(r_exp[u("arg")] % ','); 
         r_t r_op  = as_lower_d["countif"] | as_lower_d["sum"]; 
         r_t r_formula = r_op >> '(' >> r_list >> ')'; 
    
         cout << s << ": matched: " << boolalpha << parse(s.c_str(), r_formula, space_p).full << endl; 
        } 
        void print() { cout << "Formula: " << s << "/" << op->name() << endl; } 
    private: 
        string s; 
        shared_ptr<Op> op; 
        list<shared_ptr<Exp> > exp_list; 
    }; 
    
    struct Comment: public Statement 
    { 
        Comment(const char* first, const char* last): comment(first, last) {} 
        void print() {cout << "Comment: " << comment << endl; } 
    private: 
        string comment; 
    }; 
    
    
    struct MakeFormula 
    { 
        MakeFormula(list<shared_ptr<Statement> >& list_): list(list_) {} 
        void operator()(const char* first, const char* last) const 
        { 
         cout << "MakeFormula: " << string(first, last) << endl; 
         list.push_back(shared_ptr<Statement>(new Formula(first, last))); 
        } 
    private: 
        list<shared_ptr<Statement> >& list; 
    }; 
    
    struct MakeComment 
    { 
        MakeComment(list<shared_ptr<Statement> >& list_): list(list_) {} 
        void operator()(const char* first, const char* last) const 
        { 
         cout << "MakeComment: " << string(first, last) << endl; 
         list.push_back(shared_ptr<Statement>(new Comment(first, last))); 
        } 
    private: 
        list<shared_ptr<Statement> >& list; 
    }; 
    
    
    int main(int argc, char* argv[]) 
    try 
    { 
        //typedef vector<string> v_t; 
        //v_t v(argv + 1, argv + argc); 
        // copy(v.begin(), v.end(), ostream_iterator<v_t::value_type>(cout, "\n")); 
    
        string s; 
        getline(cin, s); 
    
        //  =COUNTIF(J2:J36, "Abc") 
    
        typedef list<shared_ptr<Statement> > list_t; 
        list_t list; 
    
        typedef rule<phrase_scanner_t> r_t; 
    
        r_t r_index  = (+alpha_p)[u("col")] >> uint_p[&g]; 
        r_t r_range  = r_index >> ':' >> r_index; 
        r_t r_string = ch_p('\"') >> *alnum_p >> '\"'; 
        r_t r_exp  = r_range | r_index | r_string; // will invoke actions for index twice due to range 
        r_t r_list  = !(r_exp[u("arg")] % ','); 
        r_t r_op  = as_lower_d["countif"] | as_lower_d["sum"]; 
        r_t r_formula = r_op >> '(' >> r_list >> ')'; 
        r_t r_statement = (ch_p('=') >> r_formula [MakeFormula(list)]) 
            | (ch_p('\'') >> (*anychar_p)[MakeComment(list)]) 
            ; 
    
        cout << s << ": matched: " << boolalpha << parse(s.c_str(), r_statement, space_p).full << endl; 
    
        for (list_t::const_iterator it = list.begin(); it != list.end(); ++it) 
        { 
         (*it)->print(); 
        } 
    } 
    catch(const exception& ex) 
    { 
        cerr << "Error: " << ex.what() << endl; 
    } 
    

    그것을 실행하고 같은 라인을 입력하십시오 :

    =COUNTIF(J2:J36, "Abc") 
    
    +1

    좋은 예! 글쎄,하지만이게 정말 _ 단순한가요? – Vlad

    +0

    글쎄, 그다지 사소한 것은 아니지만, 국내선에서 썼던 인쇄 된 코드의 페이지 (양면일지도 모름) 일뿐입니다. :) –

    1

    나는이 중 하나를 간단 자격이 있는지 모르겠지만, http://code.google.com/p/uri-grammar/source/browse/trunk/src/uri/grammar.hpp에서 사용할 수있는이 URI-문법을 사용했습니다. 적어도 이 아닐 수도 있지만 적어도 파싱에는 이미 이해하고있는 내용 (URI)이있을 수 있습니다. 이 문법을 읽을 때, 가장 일반적인 토큰이 정의되는 경향이 있기 때문에, 아래에서 위로 읽는 것이 가장 좋습니다.

    5

    Spirit (V2.x)의 최신 버전에는 매우 간단한 소형 C 인터프리터에서 전체적으로 일련의 계산기 예제가 포함되어 있습니다. 당신은 자신의 표현 파서를 작성하기위한 완벽한 출발점이기 때문에 거기를보아야합니다.