4

我正在嘗試編寫一個數學表達式的解析器,其中命名變量爲boost::spirit(版本1_51_0)中的nullaries,我完全是新的。我定義typedef boost::function<double()> Value和我的規則將被宣佈像這樣:qi::rule<Iterator, Value()> expression, term, others, ...;Boost :: spirit :: qi爲nullaries定義計算器

我定義上nullaries二元算這個宏

#define BINARY_FUNCTOR(name, op)      \ 
struct name            \ 
{              \ 
    name(Value x, Value y): x_(x), y_(y) {}    \ 
    double operator()() { return x_() op y_(); }   \ 
    Value x_, y_;           \ 
}; 

,並有ADDSUB等從我所看到的例子,我倒是想到的規則是這樣定義:

expression = term 
      >> *((lit('+') >> term[ADD(_val, _1)]) 
       | (lit('-') >> term[SUB(_val, _1)]) 
       ); 

,但似乎並沒有被正確的語法,因爲我得到一個錯誤

boost/spirit/home/support/action_dispatch.hpp:162: error: no match for call to ‘(const<unnamed>::SUB) (boost::function<double()()>&, boost::spirit::context<boost::fusion::cons<boost::function<double()()>&, boost::fusion::nil>, boost::fusion::vector0<void> >&, bool&)’ 
SRParser.cpp:38: note: candidates are: double<unnamed>::SUB::operator()() 

看起來像我一樣_1是不是我所期望的那樣,即與下一期有關的Value。什麼是正確的語法來定義這樣的規則?

+0

這不是語法這裏,儘可能多因爲它是關於語義的。其實,語義動作。請參閱http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/action.html獲取有關''''和''''之間所期望的內容的文檔。看到我的答案工作演示:) – sehe 2013-03-18 23:29:57

回答

5

解析器表達式看起來沒問題。

你感到困惑的是構建AST。很顯然,你已經決定使用語義動作來做到這一點,但是你的努力對我來說太粗略了,看不出你是如何(或者甚至決定你是基於什麼樣的)。

本質:它是什麼,你想要做你似乎神奇「會」到你的規則「添加」 /「子」的情況?

現在,你只需要使用實例直接作爲語義動作。這會導致顯示的錯誤消息,它直接告訴您該實例是無效作爲語義操作。

我假設你真的想用Phoenix賦值來將二進制操作賦值給暴露的屬性。看起來像這樣:

expression = term 
    >> *((lit('+') >> term[ _val = phx::construct<ADD>(_val, _1)]) 
     | (lit('-') >> term[ _val = phx::construct<SUB>(_val, _1)]) 
     ); 

您會發現這與傳統表達式語法的匹配更加密切。

爲了好玩,我適應根據您的Value類型的完整表達式解析器和創造了這個工作示範:http://liveworkspace.org/code/3kgPJR$0

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/karma.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

namespace qi = boost::spirit::qi; 
namespace karma = boost::spirit::karma; 
namespace phx = boost::phoenix; 

typedef std::function<double()> Value; 

#define BINARY_FUNCTOR(name, op)      \ 
struct name            \ 
{              \ 
    name(Value x, Value y): x_(x), y_(y) {}    \ 
    double operator()() { return x_() op y_(); }   \ 
    Value x_, y_;           \ 
}; 

BINARY_FUNCTOR(ADD, +) 
BINARY_FUNCTOR(SUB, -) 
BINARY_FUNCTOR(MUL, *) 
BINARY_FUNCTOR(DIV, /) 

struct LIT 
{ 
    LIT(double x): x_(x) {} 
    double operator()() { return x_; } 
    double x_; 
}; 

struct NEG 
{ 
    NEG(Value x): x_(x) {} 
    double operator()() { return -x_(); } 
    Value x_; 
}; 


template <typename It, typename Skipper = qi::space_type> 
    struct parser : qi::grammar<It, Value(), Skipper> 
{ 
    parser() : parser::base_type(expression) 
    { 
     using namespace qi; 
     expression = 
      term     [_val = _1] 
      >> *(('+' >> term [_val = phx::construct<ADD>(_val, _1)]) 
       | ('-' >> term [_val = phx::construct<SUB>(_val, _1)]) 
       ); 

     term = 
      factor    [_val = _1] 
      >> *(('*' >> factor [_val = phx::construct<MUL>(_val, _1)]) 
       | ('/' >> factor [_val = phx::construct<DIV>(_val, _1)]) 
       ); 

     factor = 
      double_    [_val = phx::construct<LIT>(_1)] 
      | '(' >> expression [_val = _1] >> ')' 
      | ('-' >> factor [_val = phx::construct<NEG>(_1)]) 
      | ('+' >> factor [_val = _1]); 

     BOOST_SPIRIT_DEBUG_NODE(expression); 
     BOOST_SPIRIT_DEBUG_NODE(term); 
     BOOST_SPIRIT_DEBUG_NODE(factor); 
    } 

    private: 
    qi::rule<It, Value(), Skipper> expression, term, factor; 
}; 

Value doParse(const std::string& input) 
{ 
    typedef std::string::const_iterator It; 
    parser<It, qi::space_type> p; 
    Value eval; 

    auto f(begin(input)), l(end(input)); 

    if (!qi::phrase_parse(f,l,p,qi::space,eval)) 
     std::cerr << "parse failed: '" << std::string(f,l) << "'\n"; 
    if (f!=l) 
     std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n"; 

    return eval; 
} 

int main() 
{ 
    auto area = doParse("2 * (3.1415927 * (10*10))"); 
    std::cout << "Area of a circle r=10: " << area() << "\n"; 
} 

它將打印

Area of a circle r=10: 628.319 
+0

這似乎確實是我正在尋找做的。你的工作樣本幾乎和我在做的一樣,除了缺少變量查找和我使用'boost :: lambda :: constant'而不是你的LIT結構! – 2013-03-19 00:08:40

相關問題