Spirit qi 解析为嵌套函数的抽象语法树

2024-04-27

我正在尝试使用 boost 的spirit qi 解析器创建一个解析器。它正在解析包含三种类型值的字符串。常量、变量或函数。这些函数可以相互嵌套。测试字符串是f(a, b) = f(g(z, x), g(x, h(x)), c), where a-e是常数,f-r是函数,并且s-z是变量。我成功创建了一个可以正确解析表达式的规则。当我将解析规则的函数更改为grammar http://www.boost.org/doc/libs/1_57_0/libs/spirit/doc/html/spirit/qi/reference/nonterminal/grammar.html。我能够修复几个错误。我几乎得到了语法来解析表达式并将其变成我创建的抽象语法树。但是,我收到了有关 boost 库中包含的文件的错误,并且我无法弄清楚它来自哪里,因为我不理解编译器消息。我遵循网站上发布的示例,使用员工示例将数据从解析器放入结构中:http://www.boost.org/doc/libs/1_41_0/libs/spirit/example/qi/employee.cpp http://www.boost.org/doc/libs/1_41_0/libs/spirit/example/qi/employee.cpp

main.cpp

#include "Parser.h"
#include "Term.h"

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>
#include <list>

using std::string;
using std::cout;
using std::endl;

int main()
{
    cout << "Unification Algorithm" << endl << endl;

    string phrase = "f(a, b) = f(g(z, x), g(x, h(x)), c)";
    string::const_iterator itr = phrase.begin();
    string::const_iterator last = phrase.end();

    cout << phrase << endl;

    // Parser grammar
    Parser<string::const_iterator> g;

    // Output data
    Expression expression;

    if (phrase_parse(itr, last, g, boost::spirit::ascii::space, expression))
    {
        cout << "Expression parsed." << endl;
    }
    else
    {
        cout << "Could not parse expression." << endl;
    }
}

Parser.h

#ifndef _Parser_h_
#define _Parser_h_

#include "Term.h"

#include <boost/spirit/include/qi.hpp>
#include <vector>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator>
struct Parser : qi::grammar<Iterator, Expression(), ascii::space_type>
{
    Parser() : Parser::base_type(expression)
    {
        using qi::char_;

        const_char = char_("a-eA-E");
        fn_char = char_("f-rF-R");
        var_char = char_("s-zS-Z");

        basic_fn = fn_char >> char_('(') >> (const_char | var_char) % char_(',') >> char_(')');
        first_fn_wrapper = fn_char >> char_('(') >> (basic_fn | const_char | var_char) % char_(',') >> char_(')');
        nested_fn = fn_char >> char_('(') >> (first_fn_wrapper | const_char | var_char) % char_(',') >> char_(')');

        expression = nested_fn >> char_("=") >> nested_fn;
    }
    // Constant character a - e
    qi::rule<Iterator, T_Cons, ascii::space_type> const_char;
    // Function character f - r
    qi::rule<Iterator, char(), ascii::space_type> fn_char;
    // Variable character s - z
    qi::rule<Iterator, T_Var, ascii::space_type> var_char;
    // Allows for basic function parsing eg. f(x, y, z)
    qi::rule<Iterator, T_Fn, ascii::space_type> basic_fn;
    // Allows for single nested functions eg. f(g(x), y, z)
    qi::rule<Iterator, T_Fn, ascii::space_type> first_fn_wrapper;
    // Allows for fully nested functions eg. f(g(x, h(y)), z) and so on
    qi::rule<Iterator, T_Fn, ascii::space_type> nested_fn;
    // Full rule for a nested function expression
    qi::rule<Iterator, Expression, ascii::space_type> expression;
};
#endif // _Parser_h_

Term.h

#ifndef _Term_h_
#define _Term_h_

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

struct Term
{
    char name;
};

BOOST_FUSION_ADAPT_STRUCT(Term, (char, name))

struct T_Cons : Term
{

};

BOOST_FUSION_ADAPT_STRUCT(T_Cons, (char, name))

struct T_Var : Term
{

};

BOOST_FUSION_ADAPT_STRUCT(T_Var, (char, name))

struct T_Fn : Term
{
    std::vector<Term> * params;

    T_Fn() { params = new std::vector<Term>(); }

    ~T_Fn() { delete params; }
};

BOOST_FUSION_ADAPT_STRUCT(T_Fn, (std::vector<Term>*, params))

struct Expression
{
    Term lh_term;
    Term rh_term;
};

 BOOST_FUSION_ADAPT_STRUCT(Expression, (char, name) (Term, lh_term) (Term, rh_term))

#endif // _Term_h_

我无法链接来自编译器的整个错误消息,因为它非常长,但这是最后几个。这些是它给出的编译错误:

boost_1_46_0\boost\mpl\assert.hpp|360|error: no matching function for call to 'assertion_failed(mpl_::failed************ (boost::spirit::qi::grammar<Iterator, T1, T2, T3, T4>::grammar(const boost::spirit::qi::rule<Iterator_, T1_, T2_, T3_, T4_>&, const string&) [with Iterator_ = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; T1_ = Expression; T2_ = boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::asci|
boost_1_46_0\boost\proto\extends.hpp|540|error: use of deleted function 'boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, Expression(), boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type> > >, 0l>:|
boost_1_46_0\boost\proto\detail\expr0.hpp|165|error: no matching function for call to 'boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, Expression(), boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type> >::reference()'|

UPDATE显示带有递归 ast 的简化解析器,用于解析所示的示例表达式

与往常一样,断言消息恰好导致了问题:

        // If you see the assertion below failing then the start rule
        // passed to the constructor of the grammar is not compatible with
        // the grammar (i.e. it uses different template parameters).
        BOOST_SPIRIT_ASSERT_MSG(
            (is_same<start_type, rule<Iterator_, T1_, T2_, T3_, T4_> >::value)
          , incompatible_start_rule, (rule<Iterator_, T1_, T2_, T3_, T4_>));

所以它告诉你应该将语法与开始规则相匹配:你有

struct Parser : qi::grammar<Iterator, Expression(), ascii::space_type>

but

qi::rule<Iterator, Expression, ascii::space_type> expression;

显然你忘记了括号:

qi::rule<Iterator, Expression(), ascii::space_type> expression;

使用通用库时的指南:

其中一些“规则”是普遍适用的,但没有例外。 2 与 Boost Spirit 特别相关:

  1. 婴儿学步;从小处开始(空的,均匀的)
  2. 从 AST 开始,精确匹配语法
  3. 逐步建立,
  4. 编译一路走来的每一步

UPDATE

这是一个非常简化的语法。如前所述,在之前的“第一条精神规则”中,从 AST 开始以完全匹配语法:

namespace ast {

    namespace tag {
        struct constant;
        struct variable;
        struct function;
    }

    template <typename Tag> struct Identifier { char name; };

    using Constant = Identifier<tag::constant>;
    using Variable = Identifier<tag::variable>;
    using Function = Identifier<tag::function>;

    struct FunctionCall;

    using Expression = boost::make_recursive_variant<
        Constant,
        Variable,
        boost::recursive_wrapper<FunctionCall>
    >::type;

    struct FunctionCall {
        Function function;
        std::vector<Expression> params;
    };

    struct Equation {
        Expression lhs, rhs;
    };
}

当然这可能是简单得多仍然因为所有标识符都只是char你可以动态地进行切换(印象 http://paste.ubuntu.com/10378816/).

现在,语法必须遵循。1.把事情简单化2.仔细格式化3.直接匹配ast,4.添加调试宏:

template <typename It, typename Skipper = ascii::space_type>
    struct Parser : qi::grammar<It, ast::Equation(), Skipper>
{
    Parser() : Parser::base_type(equation_)
    {
        using namespace qi;

        constant_ = qi::eps >> char_("a-eA-E");
        function_ = qi::eps >> char_("f-rF-R");
        variable_ = qi::eps >> char_("s-zS-Z");

        function_call = function_ >> '(' >> -(expression_ % ',') >> ')';
        expression_   = constant_ | variable_ | function_call;
        equation_     = expression_ >> '=' >> expression_;

        BOOST_SPIRIT_DEBUG_NODES((constant_)(function_)(variable_)(function_call)(expression_)(equation_))
    }
    qi::rule<It, ast::Constant()> constant_;
    qi::rule<It, ast::Function()> function_;
    qi::rule<It, ast::Variable()> variable_;

    qi::rule<It, ast::FunctionCall(), Skipper> function_call;
    qi::rule<It, ast::Expression(),   Skipper> expression_;
    qi::rule<It, ast::Equation(),     Skipper> equation_;
};

请注意这些评论是如何变得完全没有必要的。另请注意如何递归使用expression_解决了您最头疼的问题!

完整计划

住在科里鲁 http://coliru.stacked-crooked.com/a/2252a606d3429967

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>

namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

namespace ast {

    namespace tag {
        struct constant;
        struct variable;
        struct function;
    }

    template <typename Tag> struct Identifier { char name; };

    using Constant = Identifier<tag::constant>;
    using Variable = Identifier<tag::variable>;
    using Function = Identifier<tag::function>;

    struct FunctionCall;

    using Expression = boost::make_recursive_variant<
        Constant,
        Variable,
        boost::recursive_wrapper<FunctionCall>
    >::type;

    struct FunctionCall {
        Function function;
        std::vector<Expression> params;
    };

    struct Equation {
        Expression lhs, rhs;
    };
}

BOOST_FUSION_ADAPT_STRUCT(ast::Constant, (char, name))
BOOST_FUSION_ADAPT_STRUCT(ast::Variable, (char, name))
BOOST_FUSION_ADAPT_STRUCT(ast::Function, (char, name))
BOOST_FUSION_ADAPT_STRUCT(ast::FunctionCall, (ast::Function, function)(std::vector<ast::Expression>, params))
BOOST_FUSION_ADAPT_STRUCT(ast::Equation, (ast::Expression, lhs)(ast::Expression, rhs))

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename It, typename Skipper = ascii::space_type>
struct Parser : qi::grammar<It, ast::Equation(), Skipper>
{
    Parser() : Parser::base_type(equation_)
    {
        using namespace qi;

        constant_ = qi::eps >> char_("a-eA-E");
        function_ = qi::eps >> char_("f-rF-R");
        variable_ = qi::eps >> char_("s-zS-Z");

        function_call = function_ >> '(' >> -(expression_ % ',') >> ')';
        expression_   = constant_ | variable_ | function_call;
        equation_     = expression_ >> '=' >> expression_;

        BOOST_SPIRIT_DEBUG_NODES((constant_)(function_)(variable_)(function_call)(expression_)(equation_))
    }
    qi::rule<It, ast::Constant()> constant_;
    qi::rule<It, ast::Function()> function_;
    qi::rule<It, ast::Variable()> variable_;

    qi::rule<It, ast::FunctionCall(), Skipper> function_call;
    qi::rule<It, ast::Expression(),   Skipper> expression_;
    qi::rule<It, ast::Equation(),     Skipper> equation_;
};

int main() {
    std::cout << "Unification Algorithm\n\n";

    std::string const phrase = "f(a, b) = f(g(z, x), g(x, h(x)), c)";
    using It = std::string::const_iterator;
    It itr = phrase.begin(), last = phrase.end();

    std::cout << phrase << std::endl;

    Parser<It> g;
    ast::Equation parsed;

    if (phrase_parse(itr, last, g, ascii::space, parsed)) {
        std::cout << "Expression parsed.\n";
    } else {
        std::cout << "Could not parse equation.\n";
    }

    if (itr != last) {
        std::cout << "Remaining unparsed input: '" << std::string(itr,last) << "'\n";
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spirit qi 解析为嵌套函数的抽象语法树 的相关文章

随机推荐

  • System.Design 去哪儿了?

    我正在制作一个使用 ScintillaNet 的 C 项目 它显示 无法解析引用的程序集 ScintillaNet 因为它依赖于 System Design Version 4 0 0 0 Culture neutral PublicKey
  • 如何在reactjs中将可选元素作为 prop 传递给组件

    我试图找出正确的 反应 方式来传递一个可选的 prop 该 prop 是一个容器组件的 Element 该组件的处理方式与该组件的子组件不同 举一个简单的例子 我有一个面板组件 它渲染它的子组件 它还有一个可选的 title 道具 为了示例
  • 字母数字和空格的正则表达式

    不能包含除空格之外的任何特殊字符的文本的正则表达式是什么 Because Prajeesh https stackoverflow com users 112352 prajeesh只想匹配空格 s 不够 因为它匹配所有空白字符 包括换行符
  • 如何克隆 GitHub wiki?

    如何克隆 GitHub 存储库的 wiki 我知道它保存为单独的 Git 存储库 但我不记得路径了 我试过了 reponame wiki git and reponame git wiki 但两者都不正确 Append wiki git到存
  • 如何将带有动态内容的无序列表居中放置在 div 中?

    我正在尝试找出一种将 div 内的无序列表垂直居中的方法 我找到了很多方法来做到这一点 但是我的 ul 标签中的 li 标签中有 PHP 代码 可以从数据库获取文本 这会导致 li 标签中的文本长度发生变化 显着导致内部垂直筛选我的 div
  • SSIS Forloop:根据迭代次数为变量名称赋值

    我正在尝试使用 For 循环容器为最多 10 个不同的变量赋值 变量1 变量2 变量10 基于迭代次数 我需要循环根据一个变量迭代一定次数 该变量已根据查询的结果集分配了一个整数值 该部分工作得很好 我不知道如何告诉 for 循环使用哪个变
  • Android 中“屏幕尺寸”和“屏幕密度”之间的区别?

    我有几个问题 是什么屏幕尺寸 是什么屏幕密度 什么是不同之处之间屏幕尺寸 and 屏幕密度 Android 如何支持不同的密度和不同的屏幕尺寸 我已经读过官方文档 http developer android com training mu
  • 转换多索引时间序列的最有效方法

    我有一个由许多堆叠时间序列组成的 DataFrame 索引为 poolId Month 其中两者都是整数 月 是自 2000 年以来的月数 计算多个变量的一个月滞后版本的最佳方法是什么 现在 我做了类似的事情 cols to shift b
  • 按主题更改 ActionBar 的高度

    我想删除 ActionBar 下面的阴影 我知道我需要将高度更改为 0dp 但我想在主题中执行此操作 对于 Android 4 4 我使用
  • 您如何使用(描述的)技术来处理 .Net 中的 C 结构和指针?

    你如何使用这里描述的技术 https stackoverflow com questions 3235916 a way how to compile c library into net dll 3236027 3236027使用 Net
  • 在DOS中创建带有echo的文件而不插入回车符

    我想在 DOS 中的 CIFS 挂载上创建一个新文件 如果我做 echo hello gt foo txt hello 的末尾会有一个 CR 如何使用 echo 在 DOS cmd 中创建文件而不自动附加 CR 它导致 samba 和我的
  • 什么时候可以将函数绑定到另一个名称?

    在解释器中工作时 将函数绑定到名称通常很方便 例如 ghci gt let f 1 ghci gt f 1 2 这是别名f到函数 1 简单的 然而 这并不总是有效 我发现导致错误的一个例子是尝试使用别名nub来自Data List模块 例如
  • 在 IntelliJ 中创建新包

    我刚刚从使用 Eclipse 多年转向 IntelliJ 的美丽新世界 我正在努力解决那些拖慢我速度的小事情 当你知道如何去做时 最新的希望是显而易见的 我在源文件夹下创建一个新包 uk ac cam admin 我右键单击这个新包来创建另
  • 将仅限 HTTPS 的自定义域正确分配给 flex env

    将自定义域映射到 Google App Engine 项目的正确方法是什么 我已经添加了自定义域 设置了所有 DNS 记录等 并且它正在工作 但如何仅强制执行 HTTPS 就像生成的自定义域一样 从阅读周围many我看过的帖子secure
  • 当非特权用户运行 C/asm 程序时,会对 Linux 造成什么危害?

    我一直在考虑一种场景 让用户 可以是任何人 可能有恶意 提交在 Linux PC 我们称之为基准节点 上运行的代码 目标是为单线程例程创建一种自动化基准测试环境 假设一个网站向代理发布了一些代码 该代理将此代码交给基准节点 而基准节点仅与代
  • postgres union 是否保证调用有副作用的函数时的执行顺序?

    我正在使用 postgres 9 3 并尝试确保从 sql 语句调用时按顺序调用存储过程 以下操作是否有效 确保首先调用 foo 然后调用 bar select null void from select 1 from foo union
  • curl:(7)无法连接到192.168.99.100端口31591:连接被拒绝

    这些是我的豆荚 hello kubernetes 5569fb7d8f 4rkhs 0 1 ImagePullBackOff 0 5d2h hello minikube 5857d96c67 44kfg 1 1 Running 1 5d2h
  • “char *_EXFUN(index,(const char *, int));”的含义

    我发现这是 eclipse idexer intelisence 的一个命题 无论它叫什么 就是这样 char EXFUN index const char int 首先 它看起来像一个返回 char 指针的函数 但参数 如果它是一个函数
  • 使用 M1 在 dockerized Linux 上安装节点画布

    我有以下Dockerfile我在 MacBook Air M1 上运行 所以在 docker 中我有带有 M1 的 linux FROM node 16 7 0 WORKDIR work CMD while true do sleep 10
  • Spirit qi 解析为嵌套函数的抽象语法树

    我正在尝试使用 boost 的spirit qi 解析器创建一个解析器 它正在解析包含三种类型值的字符串 常量 变量或函数 这些函数可以相互嵌套 测试字符串是f a b f g z x g x h x c where a e是常数 f r是