昨天看到 王博炜 Blog中《五进制》这 篇文章。其中关于5进制到10进制的转换自然没有什么意思,这篇文章给的代码主要是讨论如何进行表达式分析和计算的。作者自制了一个Stack,并且用其 形成了两个堆栈分别用于存储数值和运算符。比较典型的表达式处理的方法。从实现上看,代码有些臃肿,而且必要的优化很少,另外就是没有充分利用标准提供的 便利。比如那个Stack完全没有必要自制,STL提供的std::stack<T>可以很好的完成任务。

而今天我要做的 是,使用boost::spirit来实现同样的表达式分析和计算。众所周知,boost是C++中质量很高的库,被称为准标准库,因为其存在的一个很重 要的目的就是为下一代C++库提供预案。目前已经有大量的boost库成为了C++标准库的一部分。我现在要用的是Boost的Spirit库。这个库可以直接在C++代码中撰写EBNF。学过编译原理的朋友应该对此都很熟悉,这是一种比堆栈更灵活的解析表达式甚至程序的方式。

如果我们要处理四则运算的表达式,那么我们只需要在C++中写入下列EBNF的定义:

group = '(' >> expression >> ')'; factor = integer | group; term = factor >> *(('*' >> factor) | ('/' >> factor)); expression = term >> *(('+' >> term) | ('-' >> term));

我们就构成了这个表达式的格式定义,它可以很轻松的处理下列表达式的运算:

12345 -12345 +12345 1 + 2 1 * 2 1/2 + 3/4 1 + 2 + 3 + 4 1 * 2 * 3 * 4 (1 + 2) * (3 + 4) (-1 + 2) * (3 + -4) 1 + ((6 * 200) - 20) / 6 (1 + (2 + (3 + (4 + 5))))

很简单吧?

使用过yacc或者*lex的朋友对这类定义肯定很熟悉。但是所不同的是,他们都是让用户写一个模板,然后用yacc或者*lex处理模板生成相应语言的程序。程序臃肿且很难阅读。而且由于不是自己写的程序,调整起来总要经过一步手续,比较繁琐。

而 使用C++的朋友则不用有这种烦恼,Boost的Spirit充分利用了C++强大的语法功能。我们可以直接在程序中写入上述的表达式定义,然后我们的程 序就支持这些表达式的处理了。不需要任何额外的程序处理。所需要的仅仅是include一些头文件而已。是的,仅仅是include一些头文件。不要担心 需要安装什么额外的东西,或者需要链接什么库,因为Spirit的实现完全是头文件组成的,我们不需要链接任何库。把boost的头文件路径放到编译期 中,直接编译就ok了。很轻巧。

下面就是我用Boost Spirit实现的四则运算表达式的代码,由于我的重点是表达式的解析和计算,因此我没有特别处理五进制到十进制的转换问题。但是添加起来显然不麻烦。我 只给出了一个五进制整数部分的输出。如果表达式出错,可以直接用箭头指出哪里有错。很方便调试:) 而且代码量是原文章的五分之一。编译后也仅仅是35KB,也不是很臃肿的。

大家多了解标准库,多了解Boost,C++的编码也是很有趣味的。

#include <boost/config/warning_disable.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <iostream> #include <string> #include <cmath> #include <limits> using namespace boost::spirit; using namespace boost::spirit::qi; using namespace boost::spirit::ascii; using namespace boost::spirit::arg_names; template <typename Iterator> struct calculator : grammar<Iterator, double(), space_type> { calculator() : calculator::base_type(expression) { expression = term[_val = _1] >> *( ('+' >> term[_val += _1]) | ('-' >> term[_val -= _1]) ); term = factor[_val = _1] >> *( ('*' >> factor[_val *= _1]) | ('/' >> factor[_val /= _1]) ); factor = double_[_val = _1] | '(' >> expression[_val = _1] >> ')' | ('-' >> factor[_val = -_1]) | ('+' >> factor[_val = _1]); } rule<Iterator, double(), space_type> expression, term, factor, number; }; // http://www.jb.man.ac.uk/~slowe/cpp/itoa.html std::string itoa(int value, int base) { const int MAX_DIGITS = 35; const char* DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"; std::string buf; buf.reserve( MAX_DIGITS ); // Pre-allocate enough space. if (base < 2 || base > 36) return buf; int quotient = value; do { buf.push_back(DIGITS[ std::abs(quotient % base) ]); quotient /= base; } while ( quotient ); if ( value < 0) buf.push_back('-'); std::reverse( buf.begin(), buf.end() ); return buf; } int main(int argc, char* argv[]) { std::cout << "请输入一个表达式,如:3+2.5*(6-25/4)-8.32" << std::endl << std::endl; std::cout << "或输入q退出。" << std::endl << std::endl; std::cout << "> "; calculator<std::string::const_iterator> calc; std::string str; double result; while (std::getline(std::cin, str)) { if (str.empty() || str[0] == 'q' || str[0] == 'Q') break; std::string::const_iterator iter = str.begin(); std::string::const_iterator end = str.end(); bool r = phrase_parse(iter, end, calc, result, space); if (r && iter == end) { std::cout << "输入语法正确,表达式的值为:"; if (result == std::numeric_limits<double>::infinity()) std::cout << "∞"; else if (result == std::numeric_limits<double>::quiet_NaN()) std::cout << "结果非数值"; else { std::cout << result << std::endl; std::cout << "整数部分转换为5进制为:" << itoa(static_cast<int>(result), 5); } std::cout << std::endl; } else { std::cout << "[输入的表达式错误]" << std::endl; std::cout << str << std::endl; std::cout << std::string(iter - str.begin(), '-') << "^" << std::endl; } std::cout << std::endl << "> "; } return 0; }

运行结果如下:

请输入一个表达式,如:3+2.5*(6-25/4)-8.32 或输入q退出。 > 3+2.5*(6-25/4)-8.32 输入语法正确,表达式的值为:-5.945 整数部分转换为5进制为:-10 > -6 输入语法正确,表达式的值为:-6 整数部分转换为5进制为:-11 > 6 输入语法正确,表达式的值为:6 整数部分转换为5进制为:11 > 1/0 输入语法正确,表达式的值为:∞ > 23 + 4 ((5)-3* 6) + (-1) [输入的表达式错误] 23 + 4 ((5)-3* 6) + (-1) -------^ > 23 + 4 ( ( 5-3*6) +1) [输入的表达式错误] 23 + 4 ( ( 5-3*6) +1) -------^ > 23 + 4 + ( -5 *3) 输入语法正确,表达式的值为:12 整数部分转换为5进制为:22 >

转载于:https://www.cnblogs.com/dancefire/archive/2009/02/04/1985872.html

也谈表达式分析和计算相关推荐

  1. 谈表达式树的缓存(7):五种缓存方式的总体分析及改进方案

    终于到了这个系列的最后一篇文章了,这个系列的文章本是许多话题的基础,却拖了那么长时间还没有完结.这篇文章主要讨论五种缓存方式各自的优劣,以及他们的性能关键在什么地方,如果要进行改进又有什么可选方案.在 ...

  2. 255.0.0.0子网掩码相应的cidr前缀表示法是?_【洛谷日报#246】浅谈表达式的求值(Vol.2 进阶)...

    Warning 在观看本博客之前,请保证自己理解了表达式的三种表达方式. 本文旨在让大家更深层次的了解表达式,基础的知识就是上方的链接中所写的.所以,在了解后缀表达式的运算原理之后,我将不会讲述类似的 ...

  3. 谈表达式树的缓存(6):五种缓存方式的性能比较

    开始还债,因为还有至少两个可写的重要话题依赖在这个系列上,不解决就难以前进. 目前我们已经涉及了五种不同的缓存实现,它们分别是: SimpleKeyCache:构造字符串作为Key,使用字典作为存储. ...

  4. 【编译原理笔记18】代码优化:活跃变量分析,可用表达式分析

    本次笔记内容: 8-8 活跃变量分析 8-9 可用表达式分析 本节课幻灯片,见于我的 GitHub 仓库:第18讲 代码优化_3.pdf 文章目录 活跃变量分析 活跃变量 例:各基本块的出口处的活跃变 ...

  5. 半桥llc 增益 matlab程序,“狠”完整的LLC谐振半桥电路分析与计算!

    原标题:"狠"完整的LLC谐振半桥电路分析与计算! 完整的LLC谐振半桥电路分析与计算 一.概述 在传统的开关电源中,通常采用磁性元件实现滤波,能量储存和传输.开关器件的工作频率越 ...

  6. 浅谈5G及边缘计算接入网络的治理

    内容来源:2021年10月23日,由边缘计算社区主办的全球边缘计算大会·上海站圆满落幕.会上,虎牙5G首席架构师林正显受邀发表了主题为<浅谈5G及边缘计算接入网络的治理>的演讲. 分享嘉宾 ...

  7. Principles of Program Analysis -- 可用表达式分析

    目录 可用表达式分析 available expressions analysis 例子 静态分析框架 什么是计算 副作用分析 形式化 求值 结论 课后作业 编程作业 本文将通过一个简单的例子来体现静 ...

  8. 分析-外星人计算Pi的程序

    FROM http://hyry.dip.jp/tech/blog/index.html?month=200201 分析-外星人计算Pi的程序 RY  程序人生 2002/01/22 0条评论 * 本 ...

  9. 四则混合运算表达式分析程序的原理及其实现

    意义: 四则混合运算表达式可以看作一定语言中的表达式分析及求值,虽然它很小,却是一个语法分析的很好的例子! 一.目标:可以对输入的四则混合运算表达式进行分析,并求出其结果.程序须支持:整数及小数运算. ...

最新文章

  1. 【转】简单的java缓存实现
  2. 有了这款Python神器,新手也会调试代码!
  3. leetcode 399. 除法求值(bfs)
  4. S​D​I​与​A​S​I 接口详解介绍
  5. 使用 ServiceStack 构建跨平台 Web 服务
  6. 第4章 分治策略 monge阵列
  7. python学习-10 运算符1
  8. python 内置_python 内置
  9. 超级全面的 Lombok 注解介绍,学一波!
  10. 【常见问题】hive、Hadoop(HA)、sqoop出现的问题的总结---各种问题以及解决方案-
  11. Java基础知识笔记第八章:常用的实体类
  12. 淘宝自动发货源码,网店自动值守发货系统 不限制域名 支持客户自助提货及自动评价...
  13. 矩阵小朋友,真是拿你没有办法
  14. 【eclipse】版本代号
  15. 联手腾讯八百客CRM实现“本土化”弯道超车
  16. 最好的前端开发资源推荐
  17. 窗口函数cluster_sample
  18. WIN10 3个手指拖动_老树谷歌地图数据采集大师下载-谷歌地图数据采集 v1.3.0.3 官方版...
  19. 闲谈GDP(4)-GDP统计的几种方法
  20. tf.concat, tf.stack和tf.unstack的用法

热门文章

  1. python3.0内建函数大全_python3内置函数大全
  2. 数据结构(C语言实现)第1章课后习题参考答案
  3. (转载)微信公众平台开发入门教程
  4. Leetcode 257. 二叉树的所有路径 解题思路及C++实现
  5. python excel合并_Python把多个Excel合并成一个Excel
  6. Element-UI 的基本使用||基于图形化界面自动安装
  7. windows 任务管理器,查看进程id,进程标识符pid
  8. Python 技术篇-使用opencv读取图片实例演示,python安装opencv库
  9. freeRtos学习笔记 (9) 移植和CPU利用率统计
  10. CTFshow php特性 web143