C++ 如何向boost::spirit计算器之一添加对指数运算符的支持?
我试图将指数运算符添加到这个boost::spirit计算器中,其语法如下所示。请注意,像“-2^2^3”这样的表达式必须解析为“-(2^(2^3))”=-256 阅读文档后,我的理解是,我必须在语法中插入以下指数表达式规则,以便它使用正确的从右到左关联性解析指数运算: 如果规则是:C++ 如何向boost::spirit计算器之一添加对指数运算符的支持?,c++,boost,grammar,boost-spirit-qi,C++,Boost,Grammar,Boost Spirit Qi,我试图将指数运算符添加到这个boost::spirit计算器中,其语法如下所示。请注意,像“-2^2^3”这样的表达式必须解析为“-(2^(2^3))”=-256 阅读文档后,我的理解是,我必须在语法中插入以下指数表达式规则,以便它使用正确的从右到左关联性解析指数运算: 如果规则是: qi::rule<Iterator, ast::expression(), ascii::space_type> expr, equality_expr, relational_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
;
qi::规则
表达式,相等表达式,关系表达式,
逻辑表达式、加法表达式、乘法表达式、指数表达式
;
齐:规则
一元表达式,主表达式
;
齐:规则
函数调用
;
qi::rule]'表达式。cpp:4:37:此处为必填项
/usr/include/boost/spirit/home/qi/detail/assign\u to.hpp:152:13:错误:
没有用于调用的匹配函数
'计算器::ast::表达式::表达式(常量)
boost::variant,
boost::递归_包装器,
boost::recursive_wrapper>&)'
/usr/include/boost/spirit/home/qi/detail/assign\u to.hpp:152:13:注:
候选人:在文件中包括从
/计算器/表达式.hpp:20:0,
从计算器/表达式定义hpp:1,
from Expression.cpp:1:./calculator/Ast.hpp:83:12:注意:calculator::Ast::Expression::Expression()
./calculator/Ast.hpp:83:12:注意:候选者需要0个参数,1个
提供./计算器/Ast.hpp:83:12:注:
计算器::ast::表达式::表达式(常量)
计算器::ast::表达式(&)/calculator/ast.hpp:83:12:注:否
参数1从“常量”的已知转换
boost::variant,
boost::递归_包装器,
boost::recursive_wrapper>'to'常量
计算器::ast::表达式&'./计算器/ast.hpp:83:12:注意:
计算器::ast::表达式::表达式(计算器::ast::表达式&)
./calculator/Ast.hpp:83:12:注意:参数1没有已知的转换
从“const boost::variant”,
boost::递归_包装器,
boost::recursive_wrapper>'到
'计算器::ast::表达式&&'
我还没有完全测试过它,但我认为下面的修改提供了您想要的功能。请记住,此版本的计算器使用int作为其唯一类型,因此您将无法使用负指数,并且存在溢出的危险
ast.hpp
您需要向枚举添加新元素(op_exp
)optoken
:
...
op_times,
op_divides,
op_exp, //ADDED //Line 55
op_positive,
...
表达式.hpp
您需要为指数运算表达式
、指数运算数
和指数运算
添加声明:
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
;
编译器.cpp
您需要在program::print\u assembler
和compiler::operator()
中的开关中添加新的大小写:
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
...
vm.cpp
您需要在vmachine::execute
中的开关中添加一个新的case(我只是简单地使用了std::pow,包括前面的cmath):
您可以找到对calc6.cpp
(最后一个适合单个cpp文件的编译器示例)的修改,它也有相同的功能(使用了非常详细的命名规则和硬编码的表达式)。我稍后将对其进行测试,只是让我说,经过一段时间的工作,我似乎已经完成了相同的操作,并且给出了语法表达式,如“-2^2^3”被解析为(-2)^(2^3),而不是它应该被解析为-(2^(2^3))。我会尽快确认这一点。还要注意,calc6的语法与calc8不同。后者是我需要帮助的。基本上,expential_expr规则位于一元_expr之前,因此您为calc8提出的语法错误地将上述示例解析为(-2)^[…]。calc6看起来不错,但它是另一个计算器。顺便说一句,你不是想写“指数表达式=一元表达式>>*(指数表达式)?在它的当前状态下,语法赋予一元运算符更高的优先级,而不是指数运算符,但这只是我的疏忽,我认为它(适度地)很容易反转(我会尝试)。我不确定你关于指数表达式的问题,但我认为我使用的是正确的。对“expression.hpp”和“expression.def.hpp”添加了新的更改。我相信它是有效的,但你应该彻底测试它。
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
;
...
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)
...
...
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;
...
...
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
...
...
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;
...