2014-01-09 50 views
2

我想將這個指數運算符添加到這個boost :: spirit計算器example,其語法如下。請注意,像「-2^2^3」這樣的表達式必須被解析爲「 - (2 ^(2^3))」== -256。如何將指數運算符的支持添加到boost :: spirit計算器之一中?

expr = 
     equality_expr.alias() 
     ; 

    equality_expr = 
      relational_expr 
     >> *(equality_op > relational_expr) 
     ; 

    relational_expr = 
      logical_expr 
     >> *(relational_op > logical_expr) 
     ; 

    logical_expr = 
      additive_expr 
     >> *(logical_op > additive_expr) 
     ; 

    additive_expr = 
      multiplicative_expr 
     >> *(additive_op > multiplicative_expr) 
     ; 

    multiplicative_expr = 
      unary_expr 
     >> *(multiplicative_op > unary_expr) 
     ; 

    unary_expr = 
      primary_expr 
     | (unary_op > primary_expr) 
     ; 

    primary_expr = 
      uint_ 
     | identifier 
     | bool_ 
     | '(' > expr > ')' 
     ; 

    identifier = 
      !keywords 
     >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] 
     ; 

已經閱讀文檔後,我的理解是,我要插入以下exponential_expr規則的語法爲它用正確的從右到左結合解析指數運算:

multiplicative_expr = 
      exponential_expr 
     >> *(multiplicative_op > exponential_expr) 
     ; 

    exponential_expr = 
      unary_expr 
     >> !(exponential_op >> exponential_expr) 
     ; 

凡規則是:

qi::rule<Iterator, ast::expression(), ascii::space_type> 
    expr, equality_expr, relational_expr, 
    logical_expr, additive_expr, multiplicative_expr, exponential_expr 
    ; 

    qi::rule<Iterator, ast::operand(), ascii::space_type> 
    unary_expr, primary_expr 
    ; 

    qi::rule<Iterator, ast::function_call(), ascii::space_type > 
    function_call 
    ; 

    qi::rule<Iterator, std::list<ast::expression>(), ascii::space_type > 
    argument_list 
    ; 

    qi::rule<Iterator, std::string(), ascii::space_type> 
    identifier 
    ; 

    qi::symbols<char, ast::optoken> 
    equality_op, relational_op, logical_op, 
    additive_op, multiplicative_op, unary_op, exponential_op 
    ; 

    qi::symbols<char> 
    keywords 
    ; 

我現在遇到的問題是,該方案無法編譯,因爲AST(ast.hpp)必須是我也相應地進行了修改,但我現在不完全如此。你有什麼主意嗎?

這是編譯器錯誤:

calculator/ExpressionDef.hpp:114:9: required from 'calculator::parser::expression::expression(calculator::error_handler&) [with Iterator = __gnu_cxx::__normal_iterator >]' Expression.cpp:4:37: required from here /usr/include/boost/spirit/home/qi/detail/assign_to.hpp:152:13: error: no matching function for call to 'calculator::ast::expression::expression(const boost::variant, boost::recursive_wrapper, boost::recursive_wrapper >&)' /usr/include/boost/spirit/home/qi/detail/assign_to.hpp:152:13: note: candidates are: In file included from ./calculator/Expression.hpp:20:0, from calculator/ExpressionDef.hpp:1, from Expression.cpp:1: ./calculator/Ast.hpp:83:12: note: calculator::ast::expression::expression() ./calculator/Ast.hpp:83:12: note: candidate expects 0 arguments, 1 provided ./calculator/Ast.hpp:83:12: note: calculator::ast::expression::expression(const calculator::ast::expression&) ./calculator/Ast.hpp:83:12: note: no known conversion for argument 1 from 'const boost::variant, boost::recursive_wrapper, boost::recursive_wrapper >' to 'const calculator::ast::expression&' ./calculator/Ast.hpp:83:12: note: calculator::ast::expression::expression(calculator::ast::expression&&) ./calculator/Ast.hpp:83:12: note: no known conversion for argument 1 from 'const boost::variant, boost::recursive_wrapper, boost::recursive_wrapper >' to 'calculator::ast::expression&&'

回答

1

我還沒有徹底的測試,但我認爲,以下修改提供你想要的功能。請記住,此版本的計算器使用整數作爲其唯一類型,因此您將無法使用負指數並存在溢出危險。

  1. ast.hpp
    你需要一個新的元素(op_exp)添加到枚舉optoken

    ... 
    op_times, 
    op_divides, 
    op_exp, //ADDED //Line 55 
    op_positive, 
    ... 
    
  2. expression.hpp
    您需要添加的聲明對於exponential_expr,exponential_operandexponential_op

    qi::rule<Iterator, ast::expression(), ascii::space_type> 
        expr, equality_expr, relational_expr, 
        logical_expr, additive_expr, multiplicative_expr, exponential_expr //MODIFIED 
        ; 
    
    qi::rule<Iterator, ast::operand(), ascii::space_type> 
        unary_expr, primary_expr, exponential_operand //MODIFIED 
        ; 
    ... 
    qi::symbols<char, ast::optoken> 
        equality_op, relational_op, logical_op, 
        additive_op, multiplicative_op, exponential_op, unary_op //MODIFIED 
        ; 
    
  3. expression_def.hpp
    您需要添加的初始化exponential_op,改變規則如下,並添加新的規則的BOOST_SPIRIT_DEBUG_NODES名單:

    ... 
    multiplicative_op.add 
        ("*", ast::op_times) 
        ("/", ast::op_divide) 
        ;  
    exponential_op.add  //ADDED //Line 69 
    ("^", ast::op_exp) 
    ; 
    ... 
    multiplicative_expr =  
         unary_expr 
        >> *(multiplicative_op > unary_expr) 
        ; 
    
    unary_expr = //MODIFIED 
         exponential_operand 
        | (unary_op > exponential_operand) 
        ; 
    
    exponential_operand = exponential_expr; //ADDED 
    
    exponential_expr =   //ADDED 
         primary_expr 
        >> *(exponential_op > unary_expr) 
        ; 
    
    primary_expr = 
         uint_ 
        | identifier 
        | bool_ 
        | '(' > expr > ')' 
        ; 
    ... 
    (additive_expr) 
    (multiplicative_expr) 
    (exponential_expr)  //ADDED //Line 150 
    (exponential_operand) //ADDED 
    (unary_expr) 
    ... 
    
  4. 編譯.cpp
    您需要將新案例添加到program::print_assemblercompiler::operator()中的交換機:

    ... 
    case op_div: 
        line += "  op_div"; 
        break; 
    
    case op_exp:  //ADDED //Line 105 
        line += "  op_exp"; 
        break; 
    
    case op_eq: 
        line += "  op_eq"; 
        break; 
    ... 
    case ast::op_times: program.op(op_mul); break; 
    case ast::op_divide: program.op(op_div); break; 
    case ast::op_exp: program.op(op_exp); break; //ADDED //Line 244 
    
    case ast::op_equal: program.op(op_eq); break; 
    ... 
    
  5. vm.hpp
    你需要一個新的元素(op_exp)添加到枚舉byte_code

    ... 
    op_mul,   // multiply top two stack entries 
    op_div,   // divide top two stack entries 
    op_exp,   //ADDED //Line 24 
    
    op_not,   // boolean negate the top stack entry 
    ... 
    
  6. VM。CPP
    你需要一個新的情況vmachine::execute添加到交換機(我只是用的std ::戰俘,包括以前CMATH):

    ... 
    case op_div: 
        --stack_ptr; 
        stack_ptr[-1] /= stack_ptr[0]; 
        break; 
    
    case op_exp: //ADDED //Line 60 
        --stack_ptr; 
        stack_ptr[-1] = std::pow(stack_ptr[-1],stack_ptr[0]); 
        break; 
    
    case op_eq: 
        --stack_ptr; 
        stack_ptr[-1] = bool(stack_ptr[-1] == stack_ptr[0]); 
        break; 
    ... 
    
+0

[這裏](HTTP:// coliru .stacked-crooked.com/a/4774f9b605937e75),你可以找到一個對calc6.cpp(最後一個編譯器例子適合在一個cpp文件中)的修改,它執行相同的操作(使用命名規則和硬編碼表達式)。 – llonesmiz

+0

我會在一瞬間測試一下,讓我說,我似乎在工作一段時間後做了同樣的事情,並且認爲像「-2^2^3」這樣的語法表達式被解析爲(-2)^( 2^3)而不是 - (2 ^(2^3))。我會盡快確認。 – Martin

+0

另請注意,calc6與calc8有不同的語法。後者是我需要幫助的人。基本上,expoential_expr規則出現在unary_expr之前,因此您爲calc8提出的語法錯誤地將上述示例解析爲(-2)^ [...]。 calc6似乎很好,但它是另一個計算器。順便說一句,你是不是想要寫「exponential_expr = unary_expr」*(exponential_op> exponential_expr)? – Martin

相關問題