【问题标题】:Converting a Boost Spirit Lex semantic action to Phoenix - How to access _val?将 Boost Spirit Lex 语义动作转换为 Phoenix - 如何访问 _val?
【发布时间】:2017-03-29 17:25:52
【问题描述】:

我为我的 Boost Spirit Lexer 编写了一个语义操作,用于将字符串中的转义序列转换为它们所代表的内容。它完美运行,我想将其转换为 Boost Phoenix 表达式,但无法编译。

以下是有效的:

// the semantic action
struct ConvertEscapes
{
    template <typename ItT, typename IdT, typename CtxT>
    void operator () (ItT& start, ItT& end, lex::pass_flags& matched, IdT& id, CtxT& ctx)
    {
        static boost::wregex escapeRgx(L"(\\\\r)|(\\\\n)|(\\\\t)|(\\\\\\\\)|(\\\\\")");
        static std::wstring escapeRepl = L"(?1\r)(?2\n)(?3\t)(?4\\\\)(?5\")";
        static std::wstring wval; // static b/c set_value doesn't seem to copy

        auto const& val = ctx.get_value();
        wval.assign(val.begin(), val.end());
        wval = boost::regex_replace(wval, 
                                    escapeRgx, 
                                    escapeRepl, 
                                    boost::match_default | boost::format_all);
        ctx.set_value(wval);
    }
};

// the token declaration
lex::token_def<std::wstring, wchar_t> literal_str;

// the token definition
literal_str  = L"\\\"([^\\\\\"]|(\\\\.))*\\\""; // string with escapes

// adding it to the lexer
this->self += literal_str [ ConvertEscapes() ];

这是我尝试转换的内容:

this->self += literal_str 
[ 
    lex::_val = boost::regex_replace(lex::_val /* this is the place I can't figure out */,
                                     boost::wregex(L"(\\\\r)|(\\\\n)|
                                     (\\\\t)|(\\\\\\\\)|(\\\\\")"), 
                                     L"(?1\r)(?2\n)(?3\t)(?4\\\\)(?5\")", 
                                     boost::match_default | boost::format_all) 
];

不能从_val 构造wstring_val也没有begin()end(),到底应该怎么用?

这个std::wstring(lex::_start, lex::_end) 也失败了,因为这些参数未被识别为迭代器。

this question 中,我找到了phoenix::construct&lt;std::wstring&gt;(lex::_start, lex::_end),但这也不会真正导致wstring

如何获取当前令牌的字符串或一对wchar_t 迭代器?

【问题讨论】:

    标签: c++ boost boost-spirit boost-phoenix boost-spirit-lex


    【解决方案1】:

    我要唱经常听到的“为什么”?

    这一次,有充分的理由。

    一般来说,避免语义操作:Boost Spirit: "Semantic actions are evil"?

    Phoenix Actors 不必要地比专用函子复杂。它们有一个甜蜜点(主要是简单的赋值或内置操作)。但是,如果演员是任何非平凡的,你会看到复杂性迅速增加,不仅对人类而且对编译器也是如此。这导致

    • 编译慢
    • 次优发出的代码
    • 更难维护源代码
    • 新的错误类别(例如,当表达式模板包含对本地/临时变量的引用时,Boost Proto(以及因此 Phoenix)确实阻止或发出信号。事实上,它通过假设来鼓励它所有模板表达式都是短暂的,但我离题了)。

    有趣的是:Spirit X3 完全放弃了 Phoenix,尽管 Phoenix 曾经是 Spirit³ 的智囊。

    新样式使用 c++14 多态 lambda,看起来 90% 类似于原始代码中的辅助函数对象,但内联为 lambda。

    这个具体案例

    无法正常工作。完全没有。

    问题在于您将惰性/延迟的参与者与直接调用混合在一起。那永远行不通。 phoenix::construct&lt;std::wstring&gt;(lex::_start, lex::_end) 的类型不应该std::wstring。当然。它应该是一个懒惰的actor¹,可以在以后使用它来创建std::wstring

    现在我们知道(以及为什么)phoenix::construct&lt;std::wstring&gt;(lex::_start, lex::_end) 是一种演员类型,应该清楚为什么在其上调用boost::regex_replace 是完全虚假的。你还不如说

    struct implementation_defined {} bogus;
    boost::regex_replace(bogus, re, fmt, boost::match_default | boost::format_all);
    

    想知道为什么它不能编译。

    总结:

    您可能应该只拥有专用函子。当然,您可以 Phoenix 调整您需要的正则表达式函数,但它所做的只是将复杂性税转移到一些语法糖上。

    我总是选择更幼稚的方法,这种方法对于经验丰富的 c++ 程序员来说更容易理解,并避免走高线行为带来的陷阱²。

    不过,如果你好奇,这里有一个指针:

    http://www.boost.org/doc/libs/1_63_0/libs/phoenix/doc/html/phoenix/modules/function.html

    Live On Coliru

    #include <iostream>
    #include <boost/regex.hpp>
    #include <boost/phoenix.hpp>
    #include <boost/spirit/include/lex_lexer.hpp>
    #include <boost/spirit/include/lex_lexertl.hpp>
    #include <boost/spirit/include/lex.hpp>
    
    namespace lex = boost::spirit::lex;
    
    BOOST_PHOENIX_ADAPT_FUNCTION(std::wstring, regex_replace_, boost::regex_replace, 4)
    
    template <typename... T>
    struct Lexer : lex::lexer<T...> {
        Lexer() {
            // the token definition
            literal_str  = L"\\\"([^\\\\\"]|(\\\\.))*\\\""; // string with escapes
    
            // adding it to the lexer
            this->self += literal_str [
                lex::_val = regex_replace_(lex::_val,
                     boost::wregex(L"(\\\\r)|(\\\\n)|(\\\\t)|(\\\\\\\\)|(\\\\\")"), 
                     L"(?1\r)(?2\n)(?3\t)(?4\\\\)(?5\")", 
                     boost::match_default | boost::format_all) 
    
            ];
        }
    
        // the token declaration
        lex::token_def<std::wstring, wchar_t> literal_str;
    };
    
    int main() {
        typedef lex::lexertl::token<std::wstring::const_iterator, boost::mpl::vector<std::wstring, wchar_t>> token_type;
        typedef Lexer<lex::lexertl::actor_lexer<token_type>> lexer_type;
        typedef lexer_type::iterator_type lexer_iterator_type;
    }
    

    ¹认为可以在以后调用的组合函数对象

    ² 如果您将其设计为 EDSL 以供非专家进一步配置,则平衡可能会倾斜,但您将有额外的责任记录您的 EDSL 以及可以使用它的限制

    ³ 我们应该说,大脑的灵魂之子吗?

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多