加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 09:56:40 所属栏目:百科 来源:网络整理
导读:我正在尝试使用boost的精神qi解析器创建一个解析器.它正在解析包含三种类型值的字符串.常量,变量或函数.这些函数可以嵌套在一起.测试串是f(a,b)= f(g(z,x),g(x,h(x)),c),其中a-e是常数,f-r是函数,s-z是变量.我成功创建了一个可以正确解析表达式的规则.当我将
我正在尝试使用boost的精神qi解析器创建一个解析器.它正在解析包含三种类型值的字符串.常量,变量或函数.这些函数可以嵌套在一起.测试串是f(a,b)= f(g(z,x),g(x,h(x)),c),其中a-e是常数,f-r是函数,s-z是变量.我成功创建了一个可以正确解析表达式的规则.当我将解析规则的函数更改为 grammar时,出现了麻烦.我可以解决几个错误.我几乎得到语法来解析表达式并将其转换为我创建的抽象语法树.但是我得到了关于boost库中包含的文件的错误,我无法弄清楚它来自哪里因为我不理解编译器消息.我按照网站上的示例,使用员工示例将数据从解析器放到结构中: 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,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),ascii::space_type> first_fn_wrapper;
    // Allows for fully nested functions eg. f(g(x,h(y)),z) and so on
    qi::rule<Iterator,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,name))

struct T_Var : Term
{

};

BOOST_FUSION_ADAPT_STRUCT(T_Var,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,name) (Term,lh_term) (Term,rh_term))

#endif // _Term_h_

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

boost_1_46_0boostmplassert.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_0boostprotoextends.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> >,boost::proto::exprns_::expr<boost::proto::tag::terminal,boost::spirit::char_encoding::ascii> >,0l>,boost::spirit::unused_type,boost::spirit::unused_type> > >,0l>:|
boost_1_46_0boostprotodetailexpr0.hpp|165|error: no matching function for call to 'boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*,boost::spirit::unused_type> >::reference()'|

解决方法

UPDATE Showing a simplified parser with a a recursive ast parsing the sample expression shown

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

// 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_,T4_> >::value),incompatible_start_rule,(rule<Iterator_,T4_>));

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

struct Parser : qi::grammar<Iterator,ascii::space_type>

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

显然你忘记了括号:

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

使用通用库时的准则:

其中一些“规则”通常适用,但没有. 2与Boost Spirit特别相关:

>宝贝步骤;从小开始(空,均匀)
>从AST开始,完全匹配语法
>逐渐建立,
>编制沿途的每一步

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,你可以动态切换(impression).

现在,语法必须遵循. 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,Skipper> equation_;
};

Note how the comments have become completely unneeded. Also note how recursively using expression_ solved your biggest headache!

完整计划

Live On Coliru

//#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,rhs;
    };
}

BOOST_FUSION_ADAPT_STRUCT(ast::Constant,name))
BOOST_FUSION_ADAPT_STRUCT(ast::Variable,name))
BOOST_FUSION_ADAPT_STRUCT(ast::Function,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,Skipper> equation_;
};

int main() {
    std::cout << "Unification Algorithmnn";

    std::string const phrase = "f(a,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,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";
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读