7

構造を AST に解析しながら、セマンティック アクションで Boost Spirit X3 を使用しようとしています。個別の定義とインスタンス化なしでルールを使用すると、次のように問題なく動作します。

#include <vector>
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace ast 
{

struct ast_struct
{
  int number;
  std::vector<int> numbers;
};

}

BOOST_FUSION_ADAPT_STRUCT(
    ast::ast_struct,
    (int, number)
    (std::vector<int>, numbers)
)

namespace x3 = boost::spirit::x3;
using namespace std;

void parse( const std::string &data )
{
  string::const_iterator begin = data.begin();
  string::const_iterator end = data.end();

  unsigned n(0);

  auto f = [&n]( auto &ctx )
    {
      n = x3::_attr(ctx);
    };

  ast::ast_struct ast;
  bool r = x3::parse( begin, end, 
                      x3::int_[f] >> +( x3::omit[+x3::blank] >> x3::int_ ), ast );

  if ( r && begin == end )
  {
    cout << "n: " << n << ", ";
    std::copy(ast.numbers.begin(), ast.numbers.end(), 
              std::ostream_iterator<int>(std::cout << ast.numbers.size() << " elements: ", " "));
    cout << endl;
  }
  else
    cout << "Parse failed" << endl;
}

int main()
{
  parse( "3 1 2 3" );
  parse( "4 1 2 3 4" );
  return 0;
}

上記のコード (フラグ -std=c++14 でコンパイル) を実行すると、期待される結果が出力されます。

n: 3, 3 elements: 1 2 3 
n: 4, 4 elements: 1 2 3 4 

ここで、Spirit X3 パーサーを、Boost Spirit X3 のcalc 9 の例とほぼ同じ方法で編成しようとしていますが、機能しません。

  • ast.hxx: 抽象構文ツリーを定義します。
  • grammar.hxx: パーサー メソッドを公開するユーザー インターフェイス。
  • grammar.cxx: ルールをインスタンス化します。
  • grammar_def.hxx: パーサー文法定義。
  • config.hxx: パーサー構成。
  • main.cxx: パーサーの使用例。

ast.hxx:

#ifndef AST_HXX
#define AST_HXX

#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>

namespace ast 
{

struct ast_struct
{
  int number;
  std::vector<int> numbers;
};

}

BOOST_FUSION_ADAPT_STRUCT(
    ast::ast_struct,
    (int, number)
    (std::vector<int>, numbers)
)

#endif

grammar.hxx:

#ifndef GRAMMAR_HXX
#define GRAMMAR_HXX

#include "ast.hxx"
#include <boost/spirit/home/x3.hpp>

namespace parser 
{

namespace x3 = boost::spirit::x3;

using my_rule_type = x3::rule<class my_rule_class, ast::ast_struct>;

BOOST_SPIRIT_DECLARE( my_rule_type );

const my_rule_type &get_my_rule();

}

#endif

grammar.cxx:

#include "grammar_def.hxx"
#include "config.hxx"

namespace parser 
{

BOOST_SPIRIT_INSTANTIATE( my_rule_type, iterator_type, context_type )

}

grammar_def.hxx:

#ifndef GRAMMAR_DEF_HXX
#define GRAMMAR_DEF_HXX

#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include "grammar.hxx"
#include "ast.hxx"

namespace parser 
{
namespace x3 = boost::spirit::x3;

const my_rule_type  my_rule( "my_rule" );

unsigned n;

auto f = []( auto &ctx )
{
  n = x3::_attr(ctx);
};

auto my_rule_def =  x3::int_[f] >> +( x3::omit[+x3::blank] >> x3::int_ );

BOOST_SPIRIT_DEFINE( my_rule )

const my_rule_type &get_my_rule()
{
  return my_rule;
}

}

#endif

config.hxx:

#ifndef CONFIG_HXX
#define CONFIG_HXX

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

namespace parser 
{

namespace x3 = boost::spirit::x3;

using iterator_type = std::string::const_iterator;
using context_type = x3::unused_type;

}

#endif

main.cxx:

#include "ast.hxx"
#include "grammar.hxx"
#include "config.hxx"
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <string>

namespace x3 = boost::spirit::x3;
using namespace std;

void parse( const std::string &data )
{
  parser::iterator_type begin = data.begin();
  parser::iterator_type end = data.end();

  ast::ast_struct ast;
  cout << "Parsing [" << string(begin,end) << "]" << endl;

  bool r = x3::parse( begin, end, parser::get_my_rule(), ast );

  if ( r && begin == end )
  {
    std::copy(ast.numbers.begin(), ast.numbers.end(), 
              std::ostream_iterator<int>(std::cout << ast.numbers.size() << " elements: ", " "));
    cout << endl;
  }
  else
    cout << "Parse failed" << endl;
}

int main()
{
  parse( "3 1 2 3" );
  parse( "4 1 2 3 4" );
  return 0;
}

main.cxx と grammar.cxx (フラグ: -std=c++14) をコンパイルし、上記のコードを実行すると、次のように出力されます。

Parsing [3 1 2 3]
0 elements: 
Parsing [4 1 2 3 4]
0 elements: 

ソースコードが長くなってしまい申し訳ありません。できるだけ小さくしようとしました。

unsigned n グローバル変数の使用法がいくつかあることに注意してください。これは、カスタムの繰り返しディレクティブと共に使用されます (質問はこちら解決策の 1 つを参照)。質問の焦点を絞るために、この質問から繰り返し部分を削除したため、この例ではセマンティック アクションを削除できましたが、それは可能な解決策ではありません。

上記のコードが機能しない理由がわかりません。前もって感謝します。

4

1 に答える 1