python输入两个数字的成语_一起来写个简单的解释器(2)
上一篇文章中,我们一起实现了计算器的加法功能。
并且,在文末给大家留下了一些练习:
让解释器支持减法运算;
让解释器支持多位整数的运算,例如:12+36;
添加一个方法,让解释器能够处理用户所输入表达式中的空格。
我建议大家先独自尝试完成这些练习,再继续本篇文章的学习。
当然,如果你如果已经尽力,但是没能够完成练习,那么,这篇文章将会给你带来很大的收获。
在开始这篇文章的主体内容之前,我先引用原文中的一个小故事。
这个故事它所包含的哲理适用于各行各业。
《高效思考的5个要素》的作者 Burger 和 Starbird 在书中分享了一个关于他们观看国际知名小号演奏家 Tony Plog 为多才多艺的小号演奏者举办大师课的故事。学生们首先演奏了复杂的音乐章节,他们表演的都很棒。但是,随后他们被要求表演非常基础、简单的音符。当他们演奏那些音符时,比起之前演奏的复杂乐章显得有些稚嫩。当他们完成演奏之后,大师也演奏了相同的音符。但大师演奏这些音符时听起来并不稚嫩,差异非常明显。Tony 解释道:掌握简单音符的演奏,让演奏者可以更完美地掌握复杂的乐章。
这个故事的结论:要想成为真正的艺术家,你必须集中精力掌握简单、基础的概念。
再精密的仪器也都是由简单的一个一个零件巧妙的组合而成。
在任何一个领域,你必须先掌握这些简单基础的概念,再通过灵活的运用才能够成为这个领域的高手。
接下来,我们再继续依靠我们所学过的Python3基础知识,来为我们的计算器或者说算术表达式的解释器添加更多的功能。
根据之前的练习要求,我们逐步来完成这些任务。
一、增加保存当前字符的变量
因为我们是逐个获取字符进行验证,一个多位数字需要多次获取才能够组成完整的数字生成记号,那么在记号生成之前,我们需要先使用一个变量保存字符,进行验证。
示例代码:(class Interpreter)
def __init__(self, text):
...省略其它代码...
self.current_char = self.text[self.position] # 设置当前字符为指定位置的字符
二、增加获取下一个字符的方法
因为新增加的功能中表达式中字符的数量不再是3个,而是无法固定的数量。
数字部分可能是多位数字,并且表达式中可能包含任意数量的空格。
这样的话,我们需要对字符进行循环验证,会经常用到获取下一个字符的方法。
那么,经常用到的重复的方法,我们把它抽象成一个独立的方法。
示例代码:
def advance(self): # 定义获取下一个字符的方法
self.position += 1 # 获取字符的位置自增
if self.position >= len(self.text): # 如果位置到达字符串的末尾
self.current_char = None # 设置当前字符为None值
else: # 否则
self.current_char = self.text[self.position] # 设置当前字符为指定位置的字符
三、增加跳过空格的方法
如果遇到空格,无论是单个还是连续多个,我们都应该将其跳过。
示例代码:
def skip_whitespace(self): # 定义跳过空格的方法
while self.current_char is not None and self.current_char.isspace(): # 如果当前字符不是None值并且当前字符是空格
self.advance() # 获取下一个字符
四、增加获取多位数字的方法
如果获取到的字符是数字,无论是单个还是连续多个,我们都将它们连接起来,转为整数类型后返回。
示例代码:
def long_integer(self): # 获取多位数字
result = ''
while self.current_char is not None and self.current_char.isdigit(): # 如果当前字符不是None值并且当前字符是数字
result += self.current_char # 连接数字
self.advance() # 获取下一个字符
return int(result) # 返回数字
五、修改词法分析器的代码
在新版本的词法分析器中,我们只需要根据当前字符的类型进行不同的处理。
示例代码:
def get_next_token(self):
while self.current_char is not None: # 如果当前字符不是None值
if self.current_char.isspace(): # 如果当前字符是空格
self.skip_whitespace() # 跳过所有空格
continue
if self.current_char.isdigit(): # 如果当前字符是整数
return Token(INTEGER, self.long_integer()) # 获取完整的数字创建记号对象并返回
if self.current_char == '+': # 如果当前字符是加号
self.advance() # 跳到下一字符
return Token(PLUS, self.current_char) # 创建记号对象并返回
if self.current_char == '-': # 如果当前字符是减号
self.advance() # 跳到下一字符
return Token(MINUS, self.current_char) # 创建记号对象并返回
self.error() # 如果以上都不是,则抛出异常。
return Token(EOF, None) # 遍历结束返回结束标识创建的记号对象
这一次,词法分析器的代码更加清晰。
六、修改表达式计算方法
这里我们添加减法的支持。
def expr(self):
self.current_token = self.get_next_token()
left = self.current_token
self.eat(INTEGER)
operator = self.current_token
if operator.value_type == PLUS: # 如果运算符的类型是加法
self.eat(PLUS) # 验证加法运算符
else: # 否则
self.eat(MINUS) # 验证减法运算符
right = self.current_token
self.eat(INTEGER)
if operator.value_type == PLUS: # 如果运算符的类型是加法
result = left.value + right.value # 进行加法运算
else: # 否则
result = left.value - right.value # 进行减法运算
return result
上方代码中,添加注释的部分是更新的内容。
到这里,我们就完成了所有目标功能。
最后,我们仍然需要掌握一些概念。
在上一篇文章中,我们了解了在两个重要的概念: Token(记号) 和 Lexical Analyzer(词法分析器)。
这一篇文章中,我们来简单了解一下 lexeme(词位)、parsing(语法分析)和 parser(语法分析器)。
1、 lexeme(词位)
词位的中文解释是语言词汇的基本单位。
在这里,lexeme就是组成 token 的字符序列。
以当前的案例来说,词位就是数字、加号和减号:
记号
词位
INTEGER
1,12,666,69,8,0,3568
PLUS
+
MINUS
–
2、parsing(语法分析)和 parser(语法分析器)。
我们所编写的代码中,“ expr()”方法是真正的对一个算术表达式进行解释的地方。
但是,在对一个算术表达式进行解释之前,我们需要先识别短语的类型,比如是加法表达式还是减法表达式。
“ expr()”方法本质上就是:先从“ get_next_token()” 方法获取token流,找到token流中的特定的结构,或者说识别出特定的短语,然后,解释识别出的短语,生成算术表达式的结果。
找到token流中特定结构的过程,或者说,识别token 流中特定短语的过程称之为Parsing(语法分析)。
解释器或编译器中完成语法分析的部分,叫做Parser(语法分析器)。
现在我们知道“ expr()”方法是解释器中既做了 Parsing(语法分析),又做了Interpreting(解释)的部分。
“ expr()”方法首先尝试识别(Parsing)token流中的[INTEGER>>PLUS>>INTEGER]结构或者[INTEGER>>MINUS>>INTEGER] 结构的短语,成功识别其中一种短语后,对短语进行解释,并将两整数相加或相减的结果返回。
以上就是《一起来写一个简单的解释器》系列文章的第二篇内容。
在这篇内容的基础上,大家可以尝试进行以下功能的扩展:
让解释器支持乘法运算;
让解释器支持除法运算;
让解释器支持任意多加法和减法运算,例如:3+7-4-2+8。
而且,当学习完这篇文章,请大家自我检查一下,是否了解了以下内容:
什么是 Lexeme(词位)?
找出Token流中特定结构的过程叫什么?或者说,从 Token流中识别出特定短语的过程叫什么?
解释器或编译器中做 parsing(语法分析)部分的叫什么?
项目源代码下载:【点此下载】
python输入两个数字的成语_一起来写个简单的解释器(2)相关推荐
- python输入两个数字的成语_请用 Python 语言编写一个简易的猜数字游戏程序。
import random answer = random.randint(1,10) print('猜数游戏 ') num=input('请输入你猜测的数字 n') guess=int(num) n ...
- python输入两个数字、输出和差积商_C语言程序设计:输入两个整数,计算并输出它们的和、积、差、商和余数各是多少?...
展开全部 #include void main(){ int a,b; printf("请输入两个数字"); scanf("%d",&a); scanf ...
- python读取文本两个数字的成语_【十分钟Python知识点】让文本数据更加生动——词云工具推荐...
stylecloud 是一个 Python 包,它基于流行的 word_cloud 包,并添加了一些有用的功能,从而创建出独特的词云.stylecloud 具备以下特点:为词云提供(任意大小)的图标形 ...
- python读取文本两个数字的成语_只要2步!将搜狗词库(scel)转为Python可读的文本...
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 将搜狗词库(scel)转化为python可读的文本(text)的方法方法 1. 利用R语言(方法简单) ① 载入词库(R语言) library(Rword ...
- python输入10个数字排序案例_介绍十个Python小案例,新手入门就在这里
今天给大家分享十个Python入门级别的小案例. 案例一:排列组合 要求: 将4个数字可能组成的所有互不相同且无重复数字的排列组合列出. 分析: 排列就好了 代码: 案例二:阶梯求和 要求: 企业实行 ...
- python输入两个坐标求距离_计算python中*多组*地理坐标之间的距离
编辑: here's a simple notebook example 一般方法,假设您有一个包含点的DataFrame列,并且您想要计算所有这些列之间的距离(例如,如果您有单独的列,则首先将它们组 ...
- python 使用input函数输入两个数字,比较两个数字的大小,并输出较大的数
# python 使用input函数输入两个数字,比较两个数字的大小,并输出较大的数 """ 任务 1.定义变量x和y,用于存放输入的两个数值 2.判断x与y是否相等,相 ...
- Python如何计算两个数字之和是多少?
python是一门非常受欢迎的编程语言,具有多种优势,简单易学.用途广泛.免费开源.易读易维护.可移植,且具有丰富的库,在诸多领域都得到了广泛的应用.而在python中,求两个数的和是非常常见的需求, ...
- Python---编写一个函数,提示输入两个数字a,b,并进行a与b的除法运算。
题目: 编写一个函数,提示输入两个数字 a,b ,并进行 a 与 b 的除法运算,把运算结果打印出来.要求对输入和程序进行检测,可以排除所有的错误. 源代码: def devision():try:a ...
最新文章
- k-d tree树 近邻算法
- 求链式线性表的倒数第K项(堆栈解法)
- 3种骚操作,教你查看 Java 字节码!
- 从“不务正业”到“回归本行”,“中年”雅戈尔的偶然与必然
- [译]多线程网络服务模型
- MySQL之命令mysql -- MySQL服务器的客户端工具
- C++程序设计基础(7)位运算
- border做三角形
- 手贱拆笔记本清灰记录
- C++--第24课 - 专题四经典问题解析
- C++数据库编程 ODBC连接SQL Server数据库
- Linux如何安装iperf软件,【iperf】iperfforLinux-最笨下载
- Nginx-负载均衡部署
- C#开发工控上位机编程 csdn_5种将死的编程语言
- c语言json使用,cJSON使用(二)
- android iccid获取不完整,Android调用getSimSerialNumber获取iccid不完整
- CSS中id选择器和类选择器的区别
- 一些前端入门者可能需要的网站
- H5常见问题 微信踩过得坑
- 分位数Quantiles
热门文章
- 三相电压型整流器的设计与仿真
- repo:.repo/manifest/default.xml详解
- 用OpenCV的SVM实现简单的手势识别(切水果)[附源码]
- 【python】准点跑路人必备小程序~ 不信你用不到
- kaggle住房预测项目——第1部分
- Sovit3D钢铁厂三维可视化 智慧钢铁厂的转型升级
- 门窗软件测试自学,Revit 系列讲座第一季-路文虎
- c++版MC(我的世界)
- 如何在移动端app中应用字体图标icon fonts
- 视觉里程计--视觉slam7.1/相机运动估计视觉算法