我为我的Boost Spirit Lexer写了一个语义 Action ,将字符串中的转义序列转换为它们所代表的含义。它运行完美,我想将其转换为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)
];

不能从wstring构造_val_val也没有begin()end(),无论如何应如何使用?

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

this question中,我找到了phoenix::construct<std::wstring>(lex::_start, lex::_end),但这实际上并没有导致生成wstring

如何获得当前 token 的字符串或一对wchar_t迭代器?

最佳答案

我要高呼“为什么”?

这次,有充分的理由。

通常,避免语义 Action :Boost Spirit: "Semantic actions are evil"?

凤凰 Actor 比专门的函子要复杂得多。它们有一个优点(主要是简单的赋值或内置操作)。但是,如果参与者是任何不平凡的参与者,您将看到复杂性迅速增加,不仅对于人类,而且对于编译器。这将导致

  • 慢速编译
  • 次优发射代码
  • 很难维护源
  • 错误的新类别(例如,当表达式模板包含对本地人/临时人员的引用时,Boost Proto(因此是Phoenix)无法阻止或发出信号。实际上,它通过假设所有模板表达式都是短暂的而鼓励这样做,但是我离题了)。



  • 这种情况

    不能工作完全没有

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

    现在我们知道phoenix::construct<std::wstring>(lex::_start, lex::_end)(以及为什么)是一个actor类型,现在应该弄清楚为什么对它调用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及其使用限制

    ³我们应该说,是大脑的灵性 child 吗?

    关于c++ - 将Boost Spirit Lex语义 Action 转换为Phoenix-如何访问_val?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43100216/

    10-11 18:34