c++ - 使用qi::lexeme解析 '.'链式标识符列表,并防止空间跳过

标签 c++ boost boost-spirit boost-spirit-qi

我目前正在开发一种基于Spirit的表达式解析器,该解析器应最终(在很远的将来)允许这样的表达式

"a*b*c"
"10+20*x.y.z"
"a.b.c[ a.b ][ e.c( d.e()*4 )].e.f( (a.b+23)*d, -23*b.e(a.b.c) ).x.y"

成员访问,数组订阅,函数调用和表达式的混合
[] -> subscription
() -> function call or expression bracket
. member chaining

目前我正在与成员链跳过的空间作斗争
"a  . b  . c"

在我的世界中无效-但是由于空间跳过功能而被解析

在线尝试我减少的样本:https://wandbox.org/permlink/o5kcYtUQEfKZqJgw

问题是第23行:
qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain 
    = identifier >> *('.' >> identifier);

我不能绕着规则使用qi::lexeme,我将得到一个无法转换为Skipper的编译错误
但是如果我将完整的标识符规则复制到identifier_chain规则中就可以使用
qi::rule<std::string::iterator, qi::blank_type, utree()> identifer_chain 
   = qi::lexeme[qi::ascii::alpha >> *(qi::ascii::alnum | '_') 
   >> *('.' >> qi::ascii::alpha >> *(qi::ascii::alnum | '_'))];

但这似乎很多余,我认为在解析器不断增长的将来,复制将使我陷入麻烦

任何关于如何使用lexeme或其他方式保持我的''的想法。连接没有空格
这样订阅结束和成员链接紧密连接
].a
a.b

那是我的解析器中唯一不希望空间跳过的地方,这是减少解析器代码的理想选择

thx的任何帮助/提示

最佳答案

这是船长的工作方式(请参阅Boost spirit skipper issues)

您的规则声明了船长:

qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain;

因此,要禁止它,您可以用lexeme包围,但是您也可以从声明中删除船长。标识符规则实际上也是如此,因为它也完全包装在lexeme[]中。

建议的最小修补程序:

Live On Coliru
#include <iostream>
#include <iomanip>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_utree.hpp>

namespace qi = boost::spirit::qi;
using boost::spirit::utree;

int main() {
    auto tests = std::vector<std::string>{
        "a",       // ok
        "a.b",     // ok
        " a.b ",   // ok
        "a . b",   // error
        "a . b. c" // error
    };
    for (std::string const str : tests) {
        auto iter = str.begin(), end = str.end();

        qi::rule<std::string::const_iterator, utree()> 
            identifier = qi::ascii::alpha >> *(qi::ascii::alnum | '_'),
            identifier_chain = identifier >> *('.' >> identifier);

        utree ut;
        bool r = qi::phrase_parse(iter, end, identifier_chain >> qi::eoi, qi::blank, ut);

        std::cout << std::quoted(str) << " ";
        if (r) {
            std::cout << "OK: " << ut << "\n";
        } else {
            std::cout << "Failed\n";
        }
        if (iter!=end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter,end)) << "\n";
        }
        std::cout << "----\n";
    }
    return 0;
}

打印品:
"a" OK: ( "a" ) 
----
"a.b" OK: ( "a" "b" ) 
----
" a.b " OK: ( "a" "b" ) 
----
"a . b" Failed
Remaining unparsed: "a . b"
----
"a . b. c" Failed
Remaining unparsed: "a . b. c"
----

关于c++ - 使用qi::lexeme解析 '.'链式标识符列表,并防止空间跳过,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60819236/

相关文章:

c++ - 我可以有一个子类的子类吗?如何继承父代和其他子类的特征而没有错误?

c++ - 在 Mac OS X 中创建虚拟 USB 设备

c++ - CMake 找不到请求的 Boost 库

c++ - 使用 boost::spirit 匹配单词

c++ - boost spirit 解析标识符

C++ - 从另一个 Wave 文件创建一个 Wave (.Wav) 文件,但带有自定义 header

c++ - 如何在 C++20 'requires' 表达式中使用未指定的类型?

c++ - 是否可以将多态类存储在共享内存中?

c++ - 对 `boost::iostreams::mapped_file_source::mapped_file_source()' 的 undefined reference

c++ - 使用来自 Boost.Spirit 的 Lex 和 Qi 在语法规则中使用词法分析器标记属性