【问题标题】:BNF (with custom modification) Parser using SpiritBNF(带有自定义修改)使用 Spirit 的解析器
【发布时间】:2021-04-21 12:08:16
【问题描述】:

使用来自here 的 bnf 解析器,我正在尝试添加一个要作为列表属性读取的字段。所以我所做的就是改变:

using List = std::list<Term>;

struct List : public std::list<Term>{
int number;
}

例如:

<code>   ::=  <letter><digit> 34 | <letter><digit><code> 23

所以这些数字被读取为 List 的属性。问题是我无法将数字读取为 List 的属性。

【问题讨论】:

  • 那么你的问题是什么?请阅读How to Ask

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


【解决方案1】:

我更喜欢组合而不是继承(有很多原因)。

所以

struct List {
    std::list<Term> terms;
    int number;
};

BOOST_FUSION_ADAPT_STRUCT(Ast::List, terms, number)

然后从

修改规则
_list       = +_term;

成为

_list       = +_term >> qi::uint_;

足以得到你所描述的:

Live On Compiler Explorer

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <fmt/ranges.h>
#include <fmt/ostream.h>
#include <iomanip>
namespace qi = boost::spirit::qi;

namespace Ast {
    struct Name : std::string {
        using std::string::string;
        using std::string::operator=;

        friend std::ostream& operator<<(std::ostream& os, Name const& n) {
            return os << '<' << n.c_str() << '>';
        }
    };

    using Term = boost::variant<Name, std::string>;

    struct List {
        std::list<Term> terms;
        int number;

        friend std::ostream& operator<<(std::ostream& os, List const& l) {
            for (auto& t : l.terms)
                os << t;
            return os << " " << l.number;
        }
    };

    using Expression = std::list<List>;

    struct Rule {
        Name name; // lhs
        Expression rhs;
    };

    using Syntax = std::list<Rule>;
}

BOOST_FUSION_ADAPT_STRUCT(Ast::List, terms, number)
BOOST_FUSION_ADAPT_STRUCT(Ast::Rule, name, rhs)

namespace Parser {
    template <typename Iterator>
    struct BNF: qi::grammar<Iterator, Ast::Syntax()> {
        BNF(): BNF::base_type(start) {
            using namespace qi;
            start = skip(blank) [ _rule % +eol ];

            _rule       = _rule_name >> "::=" >> _expression;
            _expression = _list % '|';
            _list       = +_term >> qi::uint_;
            _term       = _literal | _rule_name ;
            _literal    = '"' >> *(_character - '"') >> '"'
                        | "'" >> *(_character - "'") >> "'";
            _character  = alnum | char_("\"'| !#$%&()*+,./:;>=<?@]\\^_`{}~[-");
            _rule_name  = '<' >> (alpha >> *(alnum | char_('-'))) >> '>';

            BOOST_SPIRIT_DEBUG_NODES(
                (_rule)(_expression)(_list)(_term)
                (_literal)(_character)
                (_rule_name))
        }

    private:
        qi::rule<Iterator, Ast::Syntax()>     start;
        qi::rule<Iterator, Ast::Rule(),       qi::blank_type> _rule;
        qi::rule<Iterator, Ast::Expression(), qi::blank_type> _expression;
        qi::rule<Iterator, Ast::List(),       qi::blank_type> _list;
        // lexemes
        qi::rule<Iterator, Ast::Term()>       _term;
        qi::rule<Iterator, Ast::Name()>       _rule_name;
        qi::rule<Iterator, std::string()>     _literal;
        qi::rule<Iterator, char()>            _character;
    };
}

int main() {
    Parser::BNF<std::string::const_iterator> const parser;

    std::string const input =
        R"(<code>   ::=  <letter><digit> 34 | <letter><digit><code> 23
<letter> ::= "a" 1 | "b" 2 | "c" 3 | "d" 4 | "e" 5 | "f" 6 | "g" 7 | "h" 8 | "i" 9
<digit>  ::= "9" 10 | "1" 11 | "2" 12 | "3" 13 | "4" 14
    )";

    auto it = input.begin(), itEnd = input.end();

    Ast::Syntax syntax;
    if (parse(it, itEnd, parser, syntax)) {
        for (auto& rule : syntax)
            fmt::print("{} ::= {}\n", rule.name, fmt::join(rule.rhs, " | "));
    } else {
        std::cout << "Failed\n";
    }

    if (it != itEnd)
        std::cout << "Remaining: " << std::quoted(std::string(it, itEnd)) << "\n";
}

打印

code ::= <letter><digit> 34 | <letter><digit><code> 23
letter ::= a 1 | b 2 | c 3 | d 4 | e 5 | f 6 | g 7 | h 8 | i 9
digit ::= 9 10 | 1 11 | 2 12 | 3 13 | 4 14
Remaining: "
    "

【讨论】:

  • 由于某些未知原因,将此代码 Parser::BNF&lt;std::string::const_iterator&gt; const parser; 移动到单独的类时,我收到此错误 /usr/include/boost/spirit/home/support/container.hpp(131): error: class "Ast::List" has no member "value_type" : detail::remove_value_const&lt;typename Container::value_type&gt;
  • 听起来就像你忘记了其中一个步骤(仍然有错误继承、忘记了 Fusion 改编或有旧规则)所得到的结果。基本上,您既可以发现差异,也可以显示实际代码,以便我帮助您发现差异。
  • 这里是实际的code
  • _expression = _list % '|';改回来:) godbolt.org/z/7WMT34vbj
  • 谢谢。
猜你喜欢
  • 2021-07-16
  • 2012-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
相关资源
最近更新 更多