gpt4 book ai didi

c++ - X3,如何填充更复杂的 AST?

转载 作者:搜寻专家 更新时间:2023-10-31 02:10:30 25 4
gpt4 key购买 nike

尝试生成一个 AST,就像员工示例一样,它不仅仅包含员工。在我目前的心态中,RExpressions 示例对我没有帮助。我的示例无法编译,但据我所知,我已将团队、部门和公司添加到员工示例中。

我的问题是理解如何将不同的结构添加到变体中并将变体添加到 phrase_parse,如果这是想法的话。

在这个例子中,可以有几行相同的行相互跟随。所以想知道这是否需要使 AST 递归。

#include <boost/config/warning_disable.hpp>       
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <iostream>
#include <string>
#include <complex>

namespace client { namespace ast
{
struct employee;
struct team;
struct department;
struct corporation;

typedef x3::variant<
employee,
team,
department,
corporation
> var_types;

struct employee
{
int age;
std::string surname;
std::string forename;
double salary;
};

struct team
{
std::string name;
int num_employees;
};

struct department
{
std::string name;
int num_teams;
double budget;
};

struct corporation
{
std::string name;
int num_depts;
};
}}

BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, age, surname, forename, salary)
BOOST_FUSION_ADAPT_STRUCT(client::ast::team, name, num_employees)
BOOST_FUSION_ADAPT_STRUCT(client::ast::department, name, num_teams, budget)
BOOST_FUSION_ADAPT_STRUCT(client::ast::corporation, name, num_depts)

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

using x3::int_;
using x3::lit;
using x3::double_;
using x3::lexeme;
using ascii::char_;
using x3::eol;
using x3::blank;
using x3::skip;

x3::rule<class employee, ast::employee> const employee = "employee";
auto const employee_def = int_ >> *(char_ - eol) >> *(char_ - eol) >> double_;
BOOST_SPIRIT_DEFINE(employee);

x3::rule<class team, ast::team> const team = "team";
auto const team_def = *(char_ - eol) >> int_;
BOOST_SPIRIT_DEFINE(team);

x3::rule<class department, ast::department> const department = "department";
auto const department_def = *(char_ - eol) >> int_ >> double_;
BOOST_SPIRIT_DEFINE(department);

x3::rule<class corporation, ast::corporation> const corporation = "corporation";
auto const corporation_def = *(char_ - eol) >> int_;
BOOST_SPIRIT_DEFINE(corporation);

auto pemployee = skip(blank) [
*(employee >> eol)
];

auto pteam = skip(blank) [
*(team >> eol)
];

auto pdepartment = skip(blank) [
*(department >> eol)
];

auto pcorporation = skip(blank) [
*(corporation >> eol)
];

auto const input = pemployee >> pteam >> pdepartment >> pcorporation;
}
}

int main()
{
namespace x3 = boost::spirit::x3;
using boost::spirit::x3::ascii::blank;
using x3::char_;
using client::parser::input;
using client::ast::var_types;

var_types types;

std::istringstream iss("30 joe smith 100000.00\n20 mary jo 100000.00\n25 john doe 100000.00\nteamA 1\nteamB 1\nteamC 1\naccounting 1 100000.00\nengineering 2 200000.00\nAcmeCorp 3\n");

boost::spirit::istream_iterator iter(iss >> std::noskipws), eof;

bool ok = phrase_parse(iter, eof, input, x3::char_(' '), types);

std::cout << "ok = " << ok << std::endl;

return 0;
}

最佳答案

除了缺少包含和命名空间别名外,您应该只确保绑定(bind)属性 ref 允许多个条目,因为语法匹配多个员工、团队、部门和公司...:

std::vector<var_types> types;

让它为我编译。

直接修复

假设你的 ast 是你想要的(为什么?!它不反射(reflect)语法)这是一个工作示例。

注意

  • 您需要使用词素并将字符串的匹配限制为非空白,否则您将始终匹配到行尾
  • 部门需要在团队之前排序,否则您会匹配“团队”而不是部门
  • 使用变体有点模糊,正如您从打印循环中看到的那样
  • 只要您的规则不是递归的,就不需要 BOOST_SPIRIT_DEFINE
  • 使用phrase_parse 是伪造的,因为您无论如何都会覆盖船长。无论如何,出于正确性和易用性的原因,我喜欢在语法定义中使用 skipper。

Live On Coliru

#include <iostream>
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

namespace x3 = boost::spirit::x3;

namespace client { namespace ast {
struct employee;
struct team;
struct department;
struct corporation;

typedef x3::variant<
employee,
team,
department,
corporation
> var_types;

struct employee
{
int age;
std::string surname;
std::string forename;
double salary;
};

struct team
{
std::string name;
int num_employees;
};

struct department
{
std::string name;
int num_teams;
double budget;
};

struct corporation
{
std::string name;
int num_depts;
};
}}

BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, age, surname, forename, salary)
BOOST_FUSION_ADAPT_STRUCT(client::ast::team, name, num_employees)
BOOST_FUSION_ADAPT_STRUCT(client::ast::department, name, num_teams, budget)
BOOST_FUSION_ADAPT_STRUCT(client::ast::corporation, name, num_depts)

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

using namespace x3;

auto const string
= x3::rule<struct string_, std::string> {"string"}
= lexeme[+graph];
auto const employee
= x3::rule<class employee, ast::employee>{"employee"}
= int_ >> string >> string >> double_;

auto const team
= x3::rule<class team, ast::team>{"team"}
= string >> int_;

auto const department
= x3::rule<class department, ast::department>{"department"}
= string >> int_ >> double_;

auto const corporation
= x3::rule<class corporation, ast::corporation>{"corporation"}
= string >> int_;

auto any = employee|department|team|corporation;
auto const input = skip(blank) [ *(any >> eol) ];
}
}

int main()
{
namespace x3 = boost::spirit::x3;
using boost::spirit::x3::ascii::blank;
using x3::char_;
using client::ast::var_types;

std::vector<var_types> types;

std::string const iss(R"(30 joe smith 100000.00
20 mary jo 100000.00
25 john doe 100000.00
teamA 1
teamB 1
teamC 1
accounting 1 100000.00
engineering 2 200000.00
AcmeCorp 3
)");

auto iter = iss.begin(), eof = iss.end();

bool ok = parse(iter, eof, client::parser::input, types);

if (iter != eof) {
std::cout << "Remaining unparsed: '" << std::string(iter, eof) << "'\n";
}
std::cout << "Parsed: " << (100.0 * std::distance(iss.begin(), iter) / iss.size()) << "%\n";
std::cout << "ok = " << ok << std::endl;

for (auto& item : types) {
boost::apply_visitor([](auto& v) { std::cout << boost::fusion::as_deque(v) << "\n"; }, item);
}
}

打印

Parsed: 100%
ok = 1
(30 joe smith 100000)
(20 mary jo 100000)
(25 john doe 100000)
(teamA 1)
(teamB 1)
(teamC 1)
(accounting 1 100000)
(engineering 2 200000)
(AcmeCorp 3)

如果启用的话会有很多调试信息:

<employee>
<try>30 joe smith 100000.</try>
<string>
<try> joe smith 100000.00</try>
<success> smith 100000.00\n20 </success>
<attributes>[j, o, e]</attributes>
</string>
<string>
<try> smith 100000.00\n20 </try>
<success> 100000.00\n20 mary j</success>
<attributes>[s, m, i, t, h]</attributes>
</string>
<success>\n20 mary jo 100000.0</success>
<attributes>[30, [j, o, e], [s, m, i, t, h], 100000]</attributes>
</employee>
<employee>
<try>20 mary jo 100000.00</try>
<string>
<try> mary jo 100000.00\n2</try>
<success> jo 100000.00\n25 joh</success>
<attributes>[m, a, r, y]</attributes>
</string>
<string>
<try> jo 100000.00\n25 joh</try>
<success> 100000.00\n25 john d</success>
<attributes>[j, o]</attributes>
</string>
<success>\n25 john doe 100000.</success>
<attributes>[20, [m, a, r, y], [j, o], 100000]</attributes>
</employee>
<employee>
<try>25 john doe 100000.0</try>
<string>
<try> john doe 100000.00\n</try>
<success> doe 100000.00\nteamA</success>
<attributes>[j, o, h, n]</attributes>
</string>
<string>
<try> doe 100000.00\nteamA</try>
<success> 100000.00\nteamA 1\nt</success>
<attributes>[d, o, e]</attributes>
</string>
<success>\nteamA 1\nteamB 1\ntea</success>
<attributes>[25, [j, o, h, n], [d, o, e], 100000]</attributes>
</employee>
<employee>
<try>teamA 1\nteamB 1\nteam</try>
<fail/>
</employee>
<department>
<try>teamA 1\nteamB 1\nteam</try>
<string>
<try>teamA 1\nteamB 1\nteam</try>
<success> 1\nteamB 1\nteamC 1\na</success>
<attributes>[t, e, a, m, A]</attributes>
</string>
<fail/>
</department>
<team>
<try>teamA 1\nteamB 1\nteam</try>
<string>
<try>teamA 1\nteamB 1\nteam</try>
<success> 1\nteamB 1\nteamC 1\na</success>
<attributes>[t, e, a, m, A]</attributes>
</string>
<success>\nteamB 1\nteamC 1\nacc</success>
<attributes>[[t, e, a, m, A], 1]</attributes>
</team>
<employee>
<try>teamB 1\nteamC 1\nacco</try>
<fail/>
</employee>
<department>
<try>teamB 1\nteamC 1\nacco</try>
<string>
<try>teamB 1\nteamC 1\nacco</try>
<success> 1\nteamC 1\naccountin</success>
<attributes>[t, e, a, m, B]</attributes>
</string>
<fail/>
</department>
<team>
<try>teamB 1\nteamC 1\nacco</try>
<string>
<try>teamB 1\nteamC 1\nacco</try>
<success> 1\nteamC 1\naccountin</success>
<attributes>[t, e, a, m, B]</attributes>
</string>
<success>\nteamC 1\naccounting </success>
<attributes>[[t, e, a, m, B], 1]</attributes>
</team>
<employee>
<try>teamC 1\naccounting 1</try>
<fail/>
</employee>
<department>
<try>teamC 1\naccounting 1</try>
<string>
<try>teamC 1\naccounting 1</try>
<success> 1\naccounting 1 1000</success>
<attributes>[t, e, a, m, C]</attributes>
</string>
<fail/>
</department>
<team>
<try>teamC 1\naccounting 1</try>
<string>
<try>teamC 1\naccounting 1</try>
<success> 1\naccounting 1 1000</success>
<attributes>[t, e, a, m, C]</attributes>
</string>
<success>\naccounting 1 100000</success>
<attributes>[[t, e, a, m, C], 1]</attributes>
</team>
<employee>
<try>accounting 1 100000.</try>
<fail/>
</employee>
<department>
<try>accounting 1 100000.</try>
<string>
<try>accounting 1 100000.</try>
<success> 1 100000.00\nenginee</success>
<attributes>[a, c, c, o, u, n, t, i, n, g]</attributes>
</string>
<success>\nengineering 2 20000</success>
<attributes>[[a, c, c, o, u, n, t, i, n, g], 1, 100000]</attributes>
</department>
<employee>
<try>engineering 2 200000</try>
<fail/>
</employee>
<department>
<try>engineering 2 200000</try>
<string>
<try>engineering 2 200000</try>
<success> 2 200000.00\nAcmeCor</success>
<attributes>[e, n, g, i, n, e, e, r, i, n, g]</attributes>
</string>
<success>\nAcmeCorp 3\n</success>
<attributes>[[e, n, g, i, n, e, e, r, i, n, g], 2, 200000]</attributes>
</department>
<employee>
<try>AcmeCorp 3\n</try>
<fail/>
</employee>
<department>
<try>AcmeCorp 3\n</try>
<string>
<try>AcmeCorp 3\n</try>
<success> 3\n</success>
<attributes>[A, c, m, e, C, o, r, p]</attributes>
</string>
<fail/>
</department>
<team>
<try>AcmeCorp 3\n</try>
<string>
<try>AcmeCorp 3\n</try>
<success> 3\n</success>
<attributes>[A, c, m, e, C, o, r, p]</attributes>
</string>
<success>\n</success>
<attributes>[[A, c, m, e, C, o, r, p], 3]</attributes>
</team>
<employee>
<try></try>
<fail/>
</employee>
<department>
<try></try>
<string>
<try></try>
<fail/>
</string>
<fail/>
</department>
<team>
<try></try>
<string>
<try></try>
<fail/>
</string>
<fail/>
</team>
<corporation>
<try></try>
<string>
<try></try>
<fail/>
</string>
<fail/>
</corporation>

AST修复

如果你修改你的 AST 以更好地模仿语法:

namespace client { namespace ast {
struct employee { int age; std::string surname; std::string forename; double salary; };
struct team { std::string name; int num_employees; };
struct department { std::string name; int num_teams; double budget; };
struct corporation { std::string name; int num_depts; };

struct input {
std::vector<employee> employees;
std::vector<team> teams;
std::vector<department> departments;
std::vector<corporation> corporations;
};
} }

现在,碰巧所有的属性强制规则都变得多余了,你可以简单地使用这个语法:

namespace parser
{
using namespace x3;

static auto string = lexeme[+graph];
static auto employee = int_ >> string >> string >> double_;
static auto team = string >> int_;
static auto department = string >> int_ >> double_;
static auto corporation = string >> int_;

auto const input = skip(blank) [
*(employee >> eol)
>> *(team >> eol)
>> *(department >> eol)
>> *(corporation >> eol)
];
}

这就是全部。我更喜欢帮助者在行结束时更具表现力:

static auto lines = [](auto p) { return *(p >> eol); };
auto const input = skip(blank) [
lines(employee)
>> lines(team)
>> lines(department)
>> lines(corporation)
];

注意

  • 没有更多变体,打印就像您期望的那样简单:

    for (auto& item : types.employees)    { std::cout << boost::fusion::as_deque(item) << "\n"; }
    for (auto& item : types.teams) { std::cout << boost::fusion::as_deque(item) << "\n"; }
    for (auto& item : types.departments) { std::cout << boost::fusion::as_deque(item) << "\n"; }
    for (auto& item : types.corporations) { std::cout << boost::fusion::as_deque(item) << "\n"; }
  • 团队/部门之间不再有歧义,因为它们只能按固定顺序出现

Live On Coliru

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

namespace x3 = boost::spirit::x3;

namespace client { namespace ast {
struct employee { int age; std::string surname; std::string forename; double salary; };
struct team { std::string name; int num_employees; };
struct department { std::string name; int num_teams; double budget; };
struct corporation { std::string name; int num_depts; };

struct input {
std::vector<employee> employees;
std::vector<team> teams;
std::vector<department> departments;
std::vector<corporation> corporations;
};
} }

BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, age, surname, forename, salary)
BOOST_FUSION_ADAPT_STRUCT(client::ast::team, name, num_employees)
BOOST_FUSION_ADAPT_STRUCT(client::ast::department, name, num_teams, budget)
BOOST_FUSION_ADAPT_STRUCT(client::ast::corporation, name, num_depts)
BOOST_FUSION_ADAPT_STRUCT(client::ast::input, employees, teams, departments, corporations)

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

using namespace x3;

auto const string
//= x3::rule<struct string_, std::string> {"string"}
= lexeme[+graph];

auto const employee
//= x3::rule<class employee, ast::employee>{"employee"}
= int_ >> string >> string >> double_;

auto const team
//= x3::rule<class team, ast::team>{"team"}
= string >> int_;

auto const department
//= x3::rule<class department, ast::department>{"department"}
= string >> int_ >> double_;

auto const corporation
//= x3::rule<class corporation, ast::corporation>{"corporation"}
= string >> int_;

auto lines = [](auto p) { return *(p >> eol); };
auto const input
//= x3::rule<struct _input, ast::input>{"input"}
= skip(blank) [
lines(employee)
>> lines(team)
>> lines(department)
>> lines(corporation)
];
}
}

int main()
{
namespace x3 = boost::spirit::x3;
using boost::spirit::x3::ascii::blank;
using x3::char_;

std::string const iss(R"(30 joe smith 100000.00
20 mary jo 100000.00
25 john doe 100000.00
teamA 1
teamB 1
teamC 1
accounting 1 100000.00
engineering 2 200000.00
AcmeCorp 3
)");

auto iter = iss.begin(), eof = iss.end();

client::ast::input types;
bool ok = parse(iter, eof, client::parser::input, types);

if (iter != eof) {
std::cout << "Remaining unparsed: '" << std::string(iter, eof) << "'\n";
}
std::cout << "Parsed: " << (100.0 * std::distance(iss.begin(), iter) / iss.size()) << "%\n";
std::cout << "ok = " << ok << std::endl;

for (auto& item : types.employees) { std::cout << boost::fusion::as_deque(item) << "\n"; }
for (auto& item : types.teams) { std::cout << boost::fusion::as_deque(item) << "\n"; }
for (auto& item : types.departments) { std::cout << boost::fusion::as_deque(item) << "\n"; }
for (auto& item : types.corporations) { std::cout << boost::fusion::as_deque(item) << "\n"; }
}

打印

Parsed: 100%
ok = 1
(30 joe smith 100000)
(20 mary jo 100000)
(25 john doe 100000)
(teamA 1)
(teamB 1)
(teamC 1)
(accounting 1 100000)
(engineering 2 200000)
(AcmeCorp 3)

关于c++ - X3,如何填充更复杂的 AST?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45124406/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com