簡體   English   中英

boost::spirit 懶惰解析器帶參數?

[英]boost::spirit lazy parser with arguments?

除了不祥的暗示它可能完全不可能之外,我找不到任何關於它的東西,但我不想簡單地相信它,因為在這種情況下懶惰的解析器似乎毫無用處。 我想要做的是在解析時根據某些先前非終端的結果選擇解析器。 它基本上歸結為:

static rule<Constant *(Scope &)> &get_constant_parser(Typename type);

rule<Constant *(Scope &, Typename)> constant {
    lazy(phoenix::bind(&get_constant_parser, _r2))(_r1)
};

因此get_constant_parser返回一個適合給定類型名稱的解析器,但是該解析器需要一個Scope &類型的參數。 很直觀,我會像上面那樣寫下來,將參數添加到惰性解析器中。 然而,這給了我一個無效的表達:

/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:177:13: error: static assertion failed: error_invalid_expression
             BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
             ^~~~~~~~~~~~~~~~~~~~~~~~~

那么我如何為惰性解析器提供參數呢? 如果確實不可能,那么有人知道為什么嗎?

抱歉,這不是一個合適的 MWE,現在我希望有人以前做過並且知道答案。 如果您想積極調查並需要 MWE,請告訴我 ;-)

在不了解鳳凰和精靈的實際交流方式的情況下嘗試進行這種魔法是非常困難的。 讓我們試着深入研究一下:

  1. 規則參數化通過qi::rule operator()創建qi::parameterized_nonterminal解析器的實例。
  2. 惰性解析器評估是這樣執行的: qi::lazyphoenix::actor包裝到proto::terminal ,然后(由元編譯器)轉換為qi::lazy_parser / qi::lazy_directive

因此,在您的示例中,Phoenix actor 被轉換為 Proto 終端,然后調用運算符創建了一個 Spirit 元編譯器無法理解的 Proto 表達式。

我的猜測是它應該是lazy(phoenix::bind(&get_constant_parser, _r2)(_r1))因為你需要在實際規則上調用那個operator() ,但是 Phoenix 不允許你像這樣調用operator()

應該做的是: lazy(phoenix::bind(phoenix::bind(&get_constant_parser, _r2), _r1))


很久以前,我嘗試過像你這樣的事情,但也失敗了。 我還用谷歌搜索了那些說這是不可能的話題,然后就停了下來。 但是你的問題引起了我的興趣,經過短暫的反復試驗(即摸不着頭腦並深入研究精神來源)后,我得出了這個概念證明:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/support_argument.hpp>
#include <iostream>

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

int main()
{
    using passed_rule_t = qi::rule<char const*, int(int)>;
    qi::rule<char const*, int(int, passed_rule_t const&)> lazyinvoke
        = qi::lazy(phx::bind(qi::labels::_r2,   // binding is a way to call `operator()` lazily
                             qi::labels::_r1)); // non-lazy equivalent of this is `_r2(_r1)`
    int v;
    char const* s = nullptr;
    passed_rule_t inout = qi::attr(qi::labels::_r1);
    if (qi::parse(s, s, lazyinvoke(phx::val(123), phx::cref(inout)), v))
        std::cout << "OK: " << v << "\n";
    else
        std::cout << "Failed\n";
}

https://wandbox.org/permlink/m40DpeMikKRYyvH0

所以我很抱歉地說我認為這確實是不可能的 [*]

然而,並沒有失去一切。 如果您可以使用qi::locals而不是傳遞“參數”(繼承的屬性),那么您應該沒問題。

根據您的實際目標,您可以通過調用non_lazy(symbols*)對“ lazy(arg) ”的non_lazy(symbols*) 這個想法是由我的預感引起的,即您正在嘗試進行命名空間/域相關的查找。 見例如


[*]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM