如何写一个计算器?

考虑这样一个问题,给定一个字符串,“1+1+(3+4)-2*3+8/2”,如何将它转化为如下形式:

“1+1=2”

“3+4=7”

“2+7=9”

“2*3=6”

“9-6=3”

“8/2=4”

“3+4=7”

换句话说,就是如何将字符串按照四则运算计算出来,如何写一个计算器。
拿 java 来举例,并且为了简单,我们只考虑个位数。这个过程大概分为这几个步骤,首先需要扫描字符串去除空白字符,其次将各个字符转换成对应的操作符或操作数,然后按照四则运算规则逐次计算并输出。

好,我们首先构造一个 scanner,它主要功能是顺序扫描字符串,返回字符并跳过其中的空白字符,如下
2015年就要结束了,

public class Scanner {public Scanner(String source){this.source = source.toCharArray();}private char[] source;private int index = 0;private static char END = '\n';public char getNext(){char result;do{if (index >= source.length){return END;}result = source[index];index += 1;}while (Character.isWhitespace(result));return result;}}

在进行下一步之前,让我们思考一下这个算式的规律,算式中存在两种对象,一种是数字,一种是操作符,由于存在运算的优先级,我们分成三种对象,并用下面的形式来说明.


expr —> term + expr | term - expr | term
term —> factor * term | factor/term | factor
factor—> digit |(expr)

‘—>’的意思是’由...组成’,’|’ 代表’或关系’,expr 代表加减法运算式,term 代表乘除法运算式,factor 代表操作的最小元素,最后一句的意思就是 factor 由数字或者带括号的 expr 组成。这三个定义式是递归的,它可以代表任意深度的算式。让我们用树的形式来观察一下,
如何写一个计算器
有了这三种抽象对象我们可以写出对应方法了,我们在parser类里定义三个函数,来代表三种对象的产生过程,并且定义char类型变量head代表正在被扫描的字符。

public class Parser {private Scanner scanner;public Parser(Scanner scanner){this.scanner = scanner;}private char head;public void parse(){if (Scanner.END != (head = scanner.getNext())){expr();}if (head != Scanner.END){throw new RuntimeException(“syntax error at "+head);}}public int expr(){int result = term();int tempResult;char operate;while ((operate = head) == '+' || operate == '-') {head = scanner.getNext();tempResult = term();switch (operate) {case '+':System.out.println(result + "+" + tempResult + "=" + (result + tempResult));result += tempResult;break;case '-':System.out.println(result + "-" + tempResult + "=" + (result - tempResult));result -= tempResult;}}return result;}public int term(){int result = factor();int tempResult;char operate ;while ((operate=head) == '*' ||operate == '/') {head = scanner.getNext();tempResult = factor();switch (operate) {case '*':System.out.println(result + "*" + tempResult + "=" + (result * tempResult));result *= tempResult;break;case '/':System.out.println(result + "/" + tempResult + "=" + (result / tempResult));result /= tempResult;}}return result;}public int factor(){int factor;if (Character.isDigit(head)){factor = head - 48; //字符变量-48可以转换成对应的字面数字head = scanner.getNext();} else {match('(');factor = expr();match(')');}return factor;}

//match 方法用来断言 head 是什么字符,如果为真,将读取下一个字符赋值给 head
public boolean match(char symbol){
if (symbol == head){
head = scanner.getNext();
return true;
}
throw new RuntimeException("syntax error at "+head);
}

public static void main(String... args){Scanner scanner = new Scanner("1+1+(3+4)-2*3+8/2");Parser parser = new Parser(scanner);parser.parse();
}

}

如果回过头来重新考虑这件事情,你会发现我们这个小程序的本质是将一段文本转化成可以执行的程序,正如我们的编译器一样。而实际上编译器要复杂的多,它的基本工作过程可以分为几个步骤,
1,词法分析 (scanning),读入源程序字符流,将字符转换成有意义的词素 (lexeme) 的序列,并生成对应的词法单元 (token)
2,语法分析 (parsing),主要目的是生成词法单元的语法结构,一般会使用树形结构来表示,称为语法树。
3,语义分析 (semantic analysis),使用语法树检查源程序是否和语言定义的语义一致。其中一个重要部分是类型检查。
4,生成中间代码,语义分析完成后,编译器会将语法树生成为一种接近机器语言的中间代码。我们程序最后产生的一系列小的表达式与之类似。
5,代码优化,编译器会尝试改进中间代码,用以生成更高效的机器代码。
6,代码生成,将优化过对中间代码生成机器代码。

在这些过程中,递归的方法起到了非常重要的作用,有一句话说明了编译器的本质,编译器就是让你的源程序变成可执行程序的另一个程序。你会发现这个定义本身就是递归的。透过这些编译原理,可以让我们更加深入的理解编程语言,甚至发明一种编程语言。

OneAPM Mobile Insight以真实用户体验为度量标准进行 Crash 分析,监控网络请求及网络错误,提升用户留存。访问 OneAPM 官方网站感受更多应用性能优化体验,想技术文章,请访问 OneAPM 官方技术博客。
本文转自 OneAPM 官方博客

转载于:https://www.cnblogs.com/oneapm/p/5091199.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/430990.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

由于在客户端检测到一个协议错误_HTTP协议,你了解多少?

HTTP简介HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。HTTP是一个属于应用层的面向对象的协议&am…

php 405,options跨域请求405

今天在使用 froala.com/wysiwyg-editor 上传图片时,出现:1、wysiwyg-editor 上传图片先使用 OPTIONS 作试探2、服务器返回 405 NOT ALLOW解决:1、php:\Yii::$app->response->headers->set(Access-Control-Allow-Origin, 运行的域名…

There is no row in position 0

更改程序池 管道模式 ---->经典 常见设置问题: 32位启用 转载于:https://www.cnblogs.com/kunlunmountain/p/5109392.html

idea中没有j2ee_idea神器功能大全

IDEA 全称 IntelliJ IDEA,是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE支持、各类版本工具(git、svn、github等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面…

php 5.3.3 46.el6 6,centos php 5.3升级到 php5.4版本

php5.3听说有bug,因此单独升级php5.3相关的版本到5.4具体步骤:下面是我之前的版本之前php版本是:[[email protected] ~]# rpm -qa |grep php*php-5.3.3-46.el6_6.i686php-pear-1.9.4-4.el6.noarchphp-odbc-5.3.3-46.el6_6.i686php-xml-5.3.3-46.el6_6.i686php-cli-5…

netty概念

Netty的ChannelFuture在Netty中的所有的I/O操作都是异步执行的,这就意味着任何一个I/O操作会立刻返回,不保证在调用结束的时候操作会执行完成。因此,会返回一个ChannelFuture的实例,通过这个实例可以获取当前I/O操作的状态。Chann…

重燃你的PHP安全之火.pdf,读《重燃你的php之火》总结笔记

1.文件包含变量导致远程文件包含include ("$cfgdir/site${site}.php"); //把$cfgdir 这个路径里的site${site}.php 包含进来可以把变量$site 指定远程文件http://evil.com/cmd.gif 去调用,也可以是本地的一个文件解决方案:php.ini 里的allow_u…

linux 固定ip_linux固定IP

在新安装的Linux系统命令行下,敲入:ifconfig,显示如下界面。上面这张图显示网卡没有启动,那么我们敲入代码:ifup eth0启动网卡。网卡启动后,我们可以看出,IP地址和网关等其他信息都已经出现。但是我们需要的…

C#正则表达式开源工具

先交代一下背景,最近工作中经常用到正则表达式,而正则表达式这个东西我个人觉得很鸡肋,不用吧,有些功能实现起来会很麻烦。用吧,又不是说工作中经常用到,只是有时候有些需要求用到而已。但是正则表达式只要…

python中代理模式分为几种_Python设计模式之代理模式实例详解

本文实例讲述了Python设计模式之代理模式。分享给大家供大家参考,具体如下:代理模式(Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问#!/usr/bin/env python# -*- coding:utf-8 -*-__author__ Andy"""大话设计模式设计模式…

php编译称opcode文件,PHP源码保护和性能加速

什么是Opcache?每一次执行 PHP 脚本的时候,该脚本都需要被编译成字节码,而 Opcache 可以对该字节码进行缓存,这样,下次请求同一个脚本的时候,该脚本就不需要重新编译,这极大节省了脚本的执行时间&#xff…

PHP的pm、pm.max_requests、memory_limit

1、php-fpm.conf中的pm pm是来控制php-fpm的工作进程数到底是一次性产生固定不变(static)还是在运行过程中随着需要动态变化(dynamic)。众所周知,工作 进程数与服务器性能息息相关,太少则不能及时处理请求&…

结构体数组排序

要求&#xff1a;结构体变量中有两个数据&#xff0c;一个是index&#xff0c;另一个是max 按照index的从小到大的顺序排序。 struct student { int index; double max; }seq[length]; void _seq() {int i,j,k,tmp;double tmp_2;for(i0;i<length;i){ki;for(ji1;j<length;…

9553下载站java,java se development kit11最新版 64位

java se development kit11&#xff0c;简称java11&#xff0c;是一款专门进行java开发的编程软件&#xff0c;这款软件还拥有applet和组件的开发环境等操作&#xff0c;是程序员们进行java开发的飞铲不错软件&#xff0c;如果你喜欢这款软件&#xff0c;那就来下载基本介绍自从…

python源码编译 mingw_在windows上用gcc(mingw32)从命令行编译Cython扩展

我正在尝试在win32上测试一个小的cython模块&#xff0c;但是我在构建它时遇到了困难。在文件名为linalg_赛顿.pyx包括以下内容&#xff1a;from __future__ import absolute_import, division, print_functionimport numpy as npcimport numpy as npimport cython#cython.boun…

php ldap支付,php – 实现LDAP合规性

我正在专门研究一个包含联系人和其他数据的php Web应用程序.我想知道使用LDAP协议将这些数据提供给外部程序有多难.那里有专门的工具吗&#xff1f;我真的找不到任何东西,但我无法想象我是第一个想到这一点的人.编辑1&#xff1a;我正在寻找的是让应用程序(如邮件客户端)能够使…

java sleep方法_一文搞懂 Java 线程中断!

在之前的一文《如何”优雅”地终止一个线程》详细说明了 stop 终止线程的坏处及如何优雅地终止线程&#xff0c;那么还有别的可以终止线程的方法吗&#xff1f;答案是肯定的&#xff0c;它就是我们今天要分享的——线程中断。下面的这断代码大家应该再熟悉不过了&#xff0c;线…

java 观察者模式_图解Java设计模式之观察者模式

图解Java设计模式之观察者模式天气预报项目需求天气预报设计方案 1 - 普通方案观察者模式&#xff08;Observer&#xff09;原理观察者模式解决天气预报需求观察者模式在JDK应用的源码分析天气预报项目需求1&#xff09;气象站可以将每天测量到的湿度、温度、气压等等以公告的形…

matlab中mapshow,函数式编程 - MATLAB中的Map函数?

函数式编程 - MATLAB中的Map函数&#xff1f;我对MATLAB没有地图功能感到有些惊讶&#xff0c;所以我自己一起攻击了一个&#xff0c;因为它是我无法生存的东西。 那里有更好的版本吗&#xff1f; 有没有一个有点标准的MATLAB函数式编程库我缺少&#xff1f;function results …

linux 定时java程序,Linux操作系统上定时运行Java程序的方法

运行crontab -e编辑一个job。例如0 30 * * * /home/your_login/bin/java_PRogram | | | | | | | | | | | | | | —day of the week (0-6 with 0Sunday). | | | —— month of the year (1-12), | | |_____day of the month (1-31), | | | |____hour (0-23), | minute (0-59),更…