【问题标题】:Boost Spirit X3 parse grammar a^(2n+1)Boost Spirit X3解析语法a^(2n+1)
【发布时间】:2021-10-28 01:32:56
【问题描述】:

我正在使用 Boost Spirit X3 解析一些语法,但遇到了一些我无法解释的错误。下面的代码是我正在尝试做的简化版本。

#ifndef BOOST_SPIRIT_X3_NO_RTTI
#define BOOST_SPIRIT_X3_NO_RTTI
#endif

#include "boost/spirit/home/x3.hpp"
#include <iostream>
#include <string>

namespace spirit3 = boost::spirit::x3;

// Grammar for the language: a^(2n+1)
// S -> aPa
// P -> aPa | a

struct P_id;
constexpr auto P = spirit3::rule<P_id, spirit3::unused_type>{};
constexpr auto P_def = ('a' >> P >> 'a') | 'a';
constexpr auto S = 'a' >> P_def >> 'a';
BOOST_SPIRIT_DEFINE(P);

int
main()
{
    int n_chars_list[] = {5, 7, 9};
    for (auto n_chars : n_chars_list)
    {
        std::string content;
        for (int i = 0; i < n_chars; ++i)
            content += 'a';

        auto iter = content.begin();
        bool is_matched = spirit3::parse(iter, content.end(), S);
        bool is_exhausted = (iter == content.end());

        std::cout << "n_chars: " << n_chars << '\t';
        std::cout << std::boolalpha << "is_matched: " << is_matched << '\t';
        std::cout << std::boolalpha << "is_exhausted: " << is_exhausted << '\n';
    }
}

// Output:
// n_chars: 5   is_matched: true    is_exhausted: false
// n_chars: 7   is_matched: true    is_exhausted: true
// n_chars: 9   is_matched: true    is_exhausted: false

谁能解释为什么在 n_chars 为 5 或 9 的情况下解析器无法识别整个字符串,但在 7 的情况下成功?谢谢。

【问题讨论】:

  • 你/期望/看到什么?
  • 我希望解析器在所有 3 种情况下都能识别整个字符串。
  • 为什么?据我所知,这不是语法所表达的。描述(S?P?“语言:a^(2n+1)”)有点有限。

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


【解决方案1】:

这是语法。为了帮助您诊断问题,我建议对其进行调试:

活在 Coliru 上

#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;

// Grammar for the language: a^(2n+1)
// S -> aPa
// P -> aPa | a

constexpr auto P     = x3::rule<struct P_id>{"P"};
constexpr auto P_def = ('a' >> P >> 'a') | 'a';
constexpr auto S     = x3::rule<struct S_id>{"S"} 
                     = 'a' >> P >> 'a';
BOOST_SPIRIT_DEFINE(P)

int main() {
    for (int n_chars : {5, 7, 9}) {
        std::string const content(n_chars, 'a');

        bool matched = x3::parse(content.begin(), content.end(), S >> x3::eoi);

        std::cout << "n_chars: " << n_chars << '\t';
        std::cout << std::boolalpha << "matched: " << matched << "\n";
    }
}

标准输出:

n_chars: 5      matched: false
n_chars: 7      matched: true
n_chars: 9      matched: false

标准错误调试信息:

<S>
  <try>aaaaa</try>
  <P>
    <try>aaaa</try>
    <P>
      <try>aaa</try>
      <P>
        <try>aa</try>
        <P>
          <try>a</try>
          <P>
            <try></try>
            <fail/>
          </P>
          <success></success>
        </P>
        <success>a</success>
      </P>
      <success></success>
    </P>
    <success>aaa</success>
  </P>
  <success>aa</success>
</S>
n_chars: 5  matched: false
<S>
  <try>aaaaaaa</try>
  <P>
    <try>aaaaaa</try>
    <P>
      <try>aaaaa</try>
      <P>
        <try>aaaa</try>
        <P>
          <try>aaa</try>
          <P>
            <try>aa</try>
            <P>
              <try>a</try>
              <P>
                <try></try>
                <fail/>
              </P>
              <success></success>
            </P>
            <success>a</success>
          </P>
          <success></success>
        </P>
        <success>aaa</success>
      </P>
      <success>aa</success>
    </P>
    <success>a</success>
  </P>
  <success></success>
</S>
n_chars: 7  matched: true
<S>
  <try>aaaaaaaaa</try>
  <P>
    <try>aaaaaaaa</try>
    <P>
      <try>aaaaaaa</try>
      <P>
        <try>aaaaaa</try>
        <P>
          <try>aaaaa</try>
          <P>
            <try>aaaa</try>
            <P>
              <try>aaa</try>
              <P>
                <try>aa</try>
                <P>
                  <try>a</try>
                  <P>
                    <try></try>
                    <fail/>
                  </P>
                  <success></success>
                </P>
                <success>a</success>
              </P>
              <success></success>
            </P>
            <success>aaa</success>
          </P>
          <success>aa</success>
        </P>
        <success>a</success>
      </P>
      <success></success>
    </P>
    <success>aaaaaaa</success>
  </P>
  <success>aaaaaa</success>
</S>
n_chars: 9  matched: false

旁注,我简化了一些代码(不必要的循环)以及单独的“用尽”测试,而不是在解析器表达式的末尾声明x3::eoi。

【讨论】:

  • 以防万一:解析任何长度为正奇数的'a'序列,我会写'a' &gt;&gt; *lit("aa") &gt;&gt; eoi (live demo)
  • 按照你的建议,我在我的语法中命名所有规则并尝试调试它。有时我需要意识到我错在哪里。考虑 S -> a P1 a; P1 -> 一个 P2此时,P2 使用规则 P2 -> a P3 a 成功生成 aaa,但是当 P1 恢复时,此推导在下一步失败。其他有效的解析 P2 -> a 从未考虑过,因为 Boost Spirit 使用 PEG 而不是传统的乔姆斯基语法。如果规则 P2 -> a 也被考虑在内,程序的行为会如我所料。
  • 感谢您的回答,非常有帮助。如果我坚持使用递归规则来识别语言 a^(2n+1),我该怎么办?这不仅仅是关于这个特定的问题,我正在尝试做其他事情。谢谢。
  • 问题正如您所说:PEG 基本上是左向的,并且急切地消耗输入。当然,您可以使用各种有状态的前瞻,但对于这个简单的示例,我不会费心想出这样的装置。所以,如果你对任何“真正的”语法感到困惑,我很乐意再看一遍。
猜你喜欢
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多