扩展Boost Spirit计算器示例:添加字符串相等比较遇问题求助
修复Boost Spirit Calc示例以支持字符串相等比较
以下是修改后可编译运行的完整代码,支持带引号的字符串字面量及==相等比较:
#define BOOST_SPIRIT_USE_PHOENIX_V3 #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> #include <boost/variant.hpp> #include <string> #include <iostream> #include <stdexcept> namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; namespace ascii = boost::spirit::ascii; // 定义支持多种类型的值变体 struct eval; typedef boost::variant<int, std::string, bool> value_type; // 求值访问器 struct eval : boost::static_visitor<value_type> { value_type operator()(int lhs, qi::tag::equal_to, int rhs) const { return lhs == rhs; } value_type operator()(const std::string& lhs, qi::tag::equal_to, const std::string& rhs) const { return lhs == rhs; } // 处理不同类型比较的情况(可选:抛出异常或返回false) template <typename T, typename U> value_type operator()(const T&, qi::tag::equal_to, const U&) const { throw std::runtime_error("类型不匹配,无法执行比较"); // 若不需要异常,可替换为:return false; } // 基础值直接返回 value_type operator()(int n) const { return n; } value_type operator()(const std::string& s) const { return s; } value_type operator()(bool b) const { return b; } }; // 辅助求值函数 value_type evaluate(const value_type& v) { return boost::apply_visitor(eval(), v); } template <typename Iterator> struct calc_grammar : qi::grammar<Iterator, value_type(), ascii::space_type> { calc_grammar() : calc_grammar::base_type(expr) { using qi::int_; using qi::char_; using qi::_val; using qi::_1; using qi::_2; using phoenix::bind; // 字符串字面量规则:匹配双引号包裹的任意非引号字符 string_lit = '"' >> *(char_ - '"') >> '"'; // 基础值:整数或字符串 value = int_ | string_lit; // 相等表达式:支持value == value equal_expr = value[ _val = _1 ] >> ( ('==' >> value[ _val = bind(eval(), _val, qi::tag::equal_to(), _1) ]) )*; // 表达式入口:若需添加其他运算符,需按优先级调整规则顺序 expr = equal_expr; } qi::rule<Iterator, std::string(), ascii::space_type> string_lit; qi::rule<Iterator, value_type(), ascii::space_type> value; qi::rule<Iterator, value_type(), ascii::space_type> equal_expr; qi::rule<Iterator, value_type(), ascii::space_type> expr; }; int main() { typedef std::string::iterator iterator_type; calc_grammar<iterator_type> calc; std::string input; std::cout << "输入表达式(如\"abc\" == \"abc\"): "; std::getline(std::cin, input); iterator_type iter = input.begin(); iterator_type end = input.end(); value_type result; bool r = phrase_parse(iter, end, calc, ascii::space, result); if (r && iter == end) { std::cout << "解析成功,结果: "; // 输出结果 try { auto evaluated = evaluate(result); boost::apply_visitor([](const auto& v) { using namespace std; if (holds_alternative<bool>(v)) { cout << boolalpha << get<bool>(v); } else if (holds_alternative<int>(v)) { cout << get<int>(v); } else if (holds_alternative<string>(v)) { cout << "\"" << get<string>(v) << "\""; } }, evaluated); } catch (const std::exception& e) { std::cout << "错误:" << e.what(); } std::cout << std::endl; } else { std::cout << "解析失败" << std::endl; } return 0; }
关键修改说明
- 扩展值类型:用
boost::variant<int, std::string, bool>替代原有的单一数值类型,支持整数、字符串和布尔结果存储。 - 添加字符串解析规则:
string_lit规则匹配双引号包裹的字符串,确保正确提取无引号的字符串内容。 - 新增相等运算符规则:
equal_expr处理==比较逻辑,通过语义动作调用求值访问器完成类型安全的比较。 - 类型安全的求值访问器:
eval结构体重载operator(),分别处理同类型(整数-整数、字符串-字符串)的相等比较,对跨类型比较可选择抛出异常或返回默认值。 - 规则优先级调整:将相等比较规则作为表达式入口,若后续需添加
!=、加减乘除等运算符,需按运算符优先级调整规则定义顺序。
常见编译错误及修复
类型不匹配错误
- 原因:原Calc示例的表达式规则仅返回数值类型,扩展后未更新规则的属性类型为
value_type。 - 修复:确保所有规则(如
value、equal_expr、expr)的属性都声明为value_type()。
- 原因:原Calc示例的表达式规则仅返回数值类型,扩展后未更新规则的属性类型为
语义动作中类型提取失败
- 原因:未用
boost::static_visitor正确提取variant中的值,或尝试直接强制转换跨类型值。 - 修复:使用
boost::apply_visitor实现类型安全的访问,避免直接强制转换操作。
- 原因:未用
规则定义顺序错误
- 原因:Spirit要求规则在使用前必须声明,若
string_lit在value之后定义会导致编译失败。 - 修复:按依赖顺序定义规则,先定义基础规则(如
string_lit),再定义组合规则(如value)。
- 原因:Spirit要求规则在使用前必须声明,若
缺少必要头文件
- 原因:未包含
boost/variant.hpp或boost/spirit/include/phoenix.hpp等依赖头文件。 - 修复:确保代码顶部包含所有所需的Boost Spirit和Variant头文件。
- 原因:未包含
内容的提问来源于stack exchange,提问作者cpp boost
相关产品推荐
相关产品推荐

