草庐IT

c++ - 提振 spirit ,递归和堆栈溢出

coder 2024-02-21 原文

为什么下面的代码会在运行时崩溃(它会给出堆栈溢出错误)?

#include <boost/any.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/fusion/include/define_struct.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>

#include <iostream>
#include <string>
#include <vector>

namespace qi = boost::spirit::qi;
// Helper structs

// types

enum class types { void_t, int_t, double_t, bool_t, string_t };

struct types_ : qi::symbols<char, types>
{
  types_()
  {
    add
      ("void"    , types::void_t)
      ("int"     , types::int_t)
      ("double"  , types::double_t)
      ("bool"    , types::bool_t)
      ("string"  , types::string_t)
    ;
  }
} type;

inline
std::ostream& operator<<(std::ostream& os, const types& type)
{
  switch (type)
  {
  case types::void_t:
    os << "void";
    break;

  case types::int_t:
    os << "int";
    break;

  case types::double_t:
    os << "double";
    break;

  case types::bool_t:
    os << "bool";
    break;

  case types::string_t:
    os << "string";
    break;
  }

  return os;
}

// assignment_operators

enum class assignment_operators { basic, addition, subtraction, multiplication, division, modulo, bitwise_and, bitwise_or, bitwise_xor, bitwise_left_shift, bitwise_right_shift };

struct assignment_operators_ : boost::spirit::qi::symbols<char, assignment_operators>
{
  assignment_operators_()
  {
    add
      ("="    , assignment_operators::basic)
      ("+="   , assignment_operators::addition)
      ("-="   , assignment_operators::subtraction)
      ("*="   , assignment_operators::multiplication)
      ("/="   , assignment_operators::division)
      ("%="   , assignment_operators::modulo)
      ("&="   , assignment_operators::bitwise_and)
      ("|="   , assignment_operators::bitwise_or)
      ("^="   , assignment_operators::bitwise_xor)
      ("<<="  , assignment_operators::bitwise_left_shift)
      (">>="  , assignment_operators::bitwise_right_shift)
    ;
  }
} assignment_operator;

inline
std::ostream& operator<<(std::ostream& os, const assignment_operators& assignment_operator)
{
  switch (assignment_operator)
  {
  case assignment_operators::basic:
    os << "=";
    break;

  case assignment_operators::addition:
    os << "+=";
    break;

  case assignment_operators::subtraction:
    os << "-=";
    break;

  case assignment_operators::multiplication:
    os << "*=";
    break;

  case assignment_operators::division:
    os << "/=";
    break;

  case assignment_operators::modulo:
    os << "%=";
    break;

  case assignment_operators::bitwise_and:
    os << "&=";
    break;

  case assignment_operators::bitwise_or:
    os << "|=";
    break;

  case assignment_operators::bitwise_xor:
    os << "^=";
    break;

  case assignment_operators::bitwise_left_shift:
    os << "<<=";
    break;

  case assignment_operators::bitwise_right_shift:
    os << ">>=";
    break;
  }

  return os;
}

// relational_operators

enum class relational_operators { equal_to, not_equal_to, greater_than, less_than, greater_than_or_equal_to, less_than_or_equal_to };

struct relational_operators_ : boost::spirit::qi::symbols<char, relational_operators>
{
  relational_operators_()
  {
    add
      ("=="  , relational_operators::equal_to)
      ("!="  , relational_operators::not_equal_to)
      (">"   , relational_operators::greater_than)
      ("<"   , relational_operators::less_than)
      (">="  , relational_operators::greater_than_or_equal_to)
      ("<="  , relational_operators::less_than_or_equal_to)
    ;
  }
} relational_operator;

inline
std::ostream& operator<<(std::ostream& os, const relational_operators& relational_operator)
{
  switch (relational_operator)
  {
  case relational_operators::equal_to:
    os << "==";
    break;

  case relational_operators::not_equal_to:
    os << "!=";
    break;

  case relational_operators::greater_than:
    os << ">";
    break;

  case relational_operators::less_than:
    os << "<";
    break;

  case relational_operators::greater_than_or_equal_to:
    os << ">=";
    break;

  case relational_operators::less_than_or_equal_to:
    os << "<=";
    break;
  }

  return os;
}

// parameter

BOOST_FUSION_DEFINE_STRUCT(
  (), parameter,
  (types, type)
  (std::string, name)
)

// function_call

BOOST_FUSION_DEFINE_STRUCT(
  (), function_call,
  (std::string, name)
  (std::vector<boost::any>, actual_parameters)
)

// variable_definition

BOOST_FUSION_DEFINE_STRUCT(
  (), variable_definition,
  (std::string, name)
  (boost::any, initializer)
)

// variables_definitions

BOOST_FUSION_DEFINE_STRUCT(
  (), variables_definitions,
  (types, type)
  (std::vector<::variable_definition>, variables)
)

// return_expression

BOOST_FUSION_DEFINE_STRUCT(
  (), return_statement,
  (boost::any, value)
)

// assignment_expression

BOOST_FUSION_DEFINE_STRUCT(
  (), assignment_expression,
  (std::string, name)
  (assignment_operators, op)
  (boost::any, value)
)

// relational_expression

BOOST_FUSION_DEFINE_STRUCT(
  (), relational_expression,
  (boost::any, left)
  (relational_operators, op)
  (boost::any, right)
)

// function

typedef boost::any expressions_types;

BOOST_FUSION_DEFINE_STRUCT(
  (), function,
  (types, ret_type)
  (std::string, name)
  (std::vector<parameter>, parameters)
  (std::vector<expressions_types>, expressions)
)

// preprocessor_directive

BOOST_FUSION_DEFINE_STRUCT(
  (), include_preprocessor_directive,
  (std::string, file)
)

BOOST_FUSION_DEFINE_STRUCT(
  (), define_preprocessor_directive,
  (std::string, name)
  (boost::any, value)
)

BOOST_FUSION_DEFINE_STRUCT(
  (), property_preprocessor_directive,
  (std::string, name)
  (boost::any, value)
)

typedef boost::variant<::include_preprocessor_directive, ::define_preprocessor_directive, ::property_preprocessor_directive> preprocessor_directives_t;

// mql source

typedef boost::variant<::function, preprocessor_directives_t, ::variables_definitions> mql_source_elements_types;

BOOST_FUSION_DEFINE_STRUCT(
  (), mql_source,
  (std::vector<mql_source_elements_types>, mql_source_elements)
)

template <typename Iterator, typename Skipper>
struct mql_parser : qi::grammar<Iterator, mql_source(), Skipper>
{
  mql_parser() : mql_parser::base_type(start_)
  {
    identifier_                      %= qi::alpha >> *qi::alnum;                                                                             // foo, bar, some1var
    literal_                         %= qi::int_                                                                                             // 1
                                     | qi::double_                                                                                           // 1.5
                                     | qi::bool_                                                                                             // true
                                     | ('\'' >> qi::char_ >> '\'')                                                                           // 's'
                                     | qi::as_string[qi::lexeme['"' >> +(qi::char_ - '"') >> '"']];                                          // "str"
    relational_expression_           %= expression_ >> relational_operator >> expression_;                                                   // i == 0
    assignment_expression_           %= identifier_ >> assignment_operator >> expression_;                                                   // i = 1
    expression_                      %= relational_expression_ | identifier_ | function_call_ | literal_ | ('(' >> expression_ >> ')');
    function_call_                   %= identifier_ >> '(' >> (expression_ % ',') >> ')';
    variable_definition_             %= identifier_ >> -('=' >> expression_);                                                                // int i = 0
    variables_definitions_           %= type >> (variable_definition_ % ',');                                                                // int i = 0, j = 1
    return_statement_                %= "return" >> -(expression_);

    param_                           %= type >> -identifier_;
    function_definition_             %= type >> identifier_ >> '(' >> (param_ % ',') >> ')' >> '{' >> (expression_ % ';') >> ';' >> '}';     // void foo(int bar, double) { foo(); int i = 0; }
    include_preprocessor_directive_  %= '#' >> qi::lit("include") >> qi::lexeme[+qi::graph];                                                 // #include <WinUser32.mqh>
    define_preprocessor_directive_   %= '#' >> qi::lit("define") >> identifier_ >> literal_;                                                 // #define FOO 0
    property_preprocessor_directive_ %= '#' >> qi::lit("property") >> identifier_ >> -literal_;                                              // #property stacksize 1024
    preprocessor_directive_          %= include_preprocessor_directive_ | define_preprocessor_directive_ | property_preprocessor_directive_; // #include <WinUser32.mqh>
    start_                           %= qi::eps >> +(function_definition_ | preprocessor_directive_ | (variables_definitions_ >> ';'));      // void foo(int bar, double) { foo(); } void bar(int baz, double) { foo(); }

  }

  qi::rule<Iterator, std::string()                                          > identifier_;
  qi::rule<Iterator, parameter()                                   , Skipper> param_;
  qi::rule<Iterator, function_call()                               , Skipper> function_call_;
  qi::rule<Iterator, boost::any()                                  , Skipper> literal_;
  qi::rule<Iterator, variable_definition()                         , Skipper> variable_definition_;
  qi::rule<Iterator, variables_definitions()                       , Skipper> variables_definitions_;
  qi::rule<Iterator, return_statement()                            , Skipper> return_statement_;
  qi::rule<Iterator, assignment_expression()                       , Skipper> assignment_expression_;
  qi::rule<Iterator, relational_expression()                       , Skipper> relational_expression_;
  qi::rule<Iterator, expressions_types()                           , Skipper> expression_;
  qi::rule<Iterator, function()                                    , Skipper> function_definition_;
  qi::rule<Iterator, include_preprocessor_directive()              , Skipper> include_preprocessor_directive_;
  qi::rule<Iterator, define_preprocessor_directive()               , Skipper> define_preprocessor_directive_;
  qi::rule<Iterator, property_preprocessor_directive()             , Skipper> property_preprocessor_directive_;
  qi::rule<Iterator, preprocessor_directives_t()                   , Skipper> preprocessor_directive_;
  qi::rule<Iterator, mql_source()                                  , Skipper> start_;
};

std::string get_file_content(const boost::filesystem::path& file_path)
{
  std::string file_content;

  boost::filesystem::ifstream f(file_path);
  if (f)
  {
    file_content.append(
      (std::istreambuf_iterator<char>(f))
      , std::istreambuf_iterator<char>()
    );
  }

  return file_content;
}

int main()
{
    const std::string& input_data = get_file_content("input.txt");

    mql_source mql_src;
    auto itr = input_data.begin();
    auto end = input_data.end();

    qi::rule<decltype(itr)> skipper = 
        qi::ascii::space 
        | ("//" >> *(qi::char_ - qi::eol) >> qi::eol | qi::blank)
        | ("/*" >> *(qi::char_ - "*/") >> "*/");

    mql_parser<decltype(itr), decltype(skipper)> g;

    bool res = qi::phrase_parse(
            itr
            , end
            , g
            , skipper
            , mql_src
            );
    if (res && itr == end)
    {
        std::cout << "Parsing succeeded \n";
    }
    else
    {
        std::cout << "Parsing failed \n";
    }
}

输入数据:

#include <WinUser32.mqh>

void foo(int bar, double baz) { int lol = 0; }

See it live on Coliru

有什么想法可以解决吗?

最佳答案

你看到的是左递归。

左递归不与 PEG 语法混合。看看这两条规则:

expression_  %= relational_expression_ | identifier_ | function_call_ | literal_ | ('(' >> expression_ >> ')');
relational_expression_ %= expression_ >> relational_operator >> expression_;                                                   // i == 0

展开关系表达式:

 expression_ %= expression_ >> ...

你能发现问题吗? spirit 贪婪地从左到右匹配。所以你告诉它,要检查输入是否可能是一个表达式_,首先检查它是否...它可能是一个表达式_:)

因此,通过使左节点更具限制性来修复它:

simple_expr_                     %= identifier_ | function_call_ | literal_ | ('(' >> expression_ >> ')');
expression_                      %= relational_expression_ | simple_expr_;
relational_expression_           %= simple_expr_ >> relational_operator >> expression_;                                                   // i == 0

当然,这里你需要额外的规则:

qi::rule simple_expr_;

语法中还有其他问题阻止它解析,因此您需要查看 BOOST_SPIRIT_DEBUG,但我没有时间为您的 AST 类型添加流运算符

关于c++ - 提振 spirit ,递归和堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21773660/

有关c++ - 提振 spirit ,递归和堆栈溢出的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  4. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  5. ruby - 递归地将所有数字字符串转换为 Ruby 哈希中的整数 - 2

    我有一个随机大小的散列,它可能有类似"100"的值,我想将其转换为整数。我知道我可以使用value.to_iifvalue.to_i.to_s==value来做到这一点,但我不确定我将如何在我的散列中递归地做到这一点,考虑到一个值可以是一个字符串,或一个数组(哈希或字符串),或另一个哈希。 最佳答案 这是一个非常简单的递归实现(尽管必须同时处理数组和散列会增加一些技巧)。deffixnumifyobjifobj.respond_to?:to_i#IfwecancastittoaFixnum,doit.obj.to_ielsifobj

  6. Ruby:标准递归模式 - 2

    我经常迷上ruby​​的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情

  7. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  8. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  9. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

    我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

  10. ruby - 为什么我用递归得到 "stack level too deep"? - 2

    我有这个ruby代码:defget_sumnreturn0ifn似乎正在为999之前的值工作。当我尝试9999时,它给了我这个:stackleveltoodeep(SystemStackError)所以,我添加了这个:RubyVM::InstructionSequence.compile_option={:tailcall_optimization=>true,:trace_instruction=>false}但什么也没发生。我的ruby版本是:ruby1.9.3p392(2013-02-22revision39386)[x86_64-darwin12.2.1]我还增加了机器的堆栈大

随机推荐