你如何处理和了解像创建解释器或编译器这样复杂的事情?在开始时,一切看上去都像是一团乱七八糟的纱线,你需要解开缠结才能得到完美的球。

到达那里的方法是将它解开一个线,一次解开一个结。不过有时候,你可能会觉得自己听不懂某些内容,但必须继续前进,我向你保证,如果你足够坚持,它最终将“咔嗒”一声被解开。

在理解如何创建解释器和编译器的过程中,最好的建议之一是阅读文章中的解释,阅读代码,然后自己编写代码,甚至在一段时间里编写相同的代码,使你能完全了解材料和代码,然后继续学习新主题。不要着急,只要放慢脚步,花点时间深刻理解基本概念,这种方法虽然看似很慢,但会在未来获得回报。相信我。

最后,最终将获得完美的毛线球,即使不是那么完美,它也比什么也不做或者快速浏览后的几天内忘掉好多了。

请记住:一步步理解这些知识点,并通过编写代码练习所学的知识:

今天,你将使用前几篇文章中获得的知识,学习如何解析和解释具有任意数量的加,减,乘和除运算的算术表达式,你将编写一个解释器,该解释器将能够对"14 + 2 * 3 - 6 / 2"之类的表达式求值。

在深入学习并编写一些代码之前,我们先讨论一下运算符的结合性(associativity)和优先级(associativity)。

按照惯例7 + 3 + 1与(7 + 3)+ 1相同,而7 - 3 - 1相当于(7 - 3)- 1。 我们都了解这些。如果我们将7 - 3 - 1视为7 -(3 - 1),则结果将会意外的变成5,而不是我们预期的3。

在普通算术和大多数编程语言中,加,减,乘和除是左结合(left-associative)的:

7 + 3 + 1 is equivalent to (7 + 3) + 1

- 3 - 1 is equivalent to (7 - 3) - 1

* 4 * 2 is equivalent to (8 * 4) * 2

/ 4 / 2 is equivalent to (8 / 4) / 2

什么是运算符号的左结合性呢?

当表达式7 + 3 + 1中的3之类的操作数在两侧都带有加号时,我们需要约定来确定哪个运算符适用于3,是左边的加号还是右边的加号?我们说运算符加号左结合,是因为在存在两侧都带有加号的操作数时,此时左边的加号适用于此操作数,因此我们说运算符加号是左结合的(The operator + associates to the left because an operand that has plus signs on both sides belongs to the operator to its left and so we say that the operator + is left-associative.),所以按照结合性惯例,7 + 3 + 1等于(7 + 3)+ 1。

我们再来看7 + 5 * 2这个表达式,在操作数5的两边都有不同类型的运算符,该表达式等于7 +(5 * 2)还是(7 + 5)* 2呢?我们如何解决这种歧义?

在这种情况下,结合性约定对我们没有帮助,因为它仅适用于加减法(+,-)或乘除法(*,/)这种同一类型的运算符。当我们在同一表达式中具有不同种类的运算符时,我们需要另一种约定来解决歧义。我们需要一个定义运算符相对优先级的约定。

我们说如果运算符乘号在加号之前执行其操作数,则乘号具有更高的优先级(higher precedence)。在我们所使用的运算中,乘法和除法的优先级高于加法和减法,所以表达式7 + 5 * 2等效于7 +(5 * 2),表达式7 - 8 / 4等效于7-(8 / 4)。

在含有优先级相同的运算符的表达式中,我们仅使用结合性约定并从左到右执行运算符:

7 + 3 - 1 is equivalent to (7 + 3) - 1

/ 4 * 2 is equivalent to (8 / 4) * 2

希望你不要因为这些运算符的结合性和优先级而感到无聊,我们可以利用这些约定来构造算术表达式的语法,以显示算术运算符的结合性和优先级,然后,我们可以按照我在第4部分中概述的准则将语法转换为代码,我们的解释器将能够处理运算符的优先级和结合性约定。

这是我们的优先级表(precedence table):

从表中可以看出,运算符加号和减号具有相同的优先级,并且它们都是左结合的,还可以看到,运算符乘号和除号也是左结合的,它们之间也具有相同的优先级,但是比加减运算符具有更高的优先级。

以下是有关如何根据优先级表构造语法的规则:

1、为每一类优先级定义一个非终结符。非终极符的产生式主体应包含该类优先级的算术运算符和下一类更高优先级的非终结符。( The body of a production for the non-terminal should contain arithmetic operators from that level and non-terminals for the next higher level of precedence.)

2、为基本的表达单位(在本文下为整数)创建一个附加的非终结符factor。一般规则是,如果具有N类优先级,则总共将需要N + 1个非终结符:每类级别一个非终结符(N个)再加上一个运算基本单位的非终结符factor(1个)。(Create an additional non-terminal factor for basic units of expression, in our case, integers. The general rule is that if you have N levels of precedence, you will need N + 1 non-terminals in total: one non-terminal for each level plus one non-terminal for basic units of expression.)

继续!

让我们遵循规则并构建语法。

根据规则1,我们将定义两个非终结符:一个用于级别2的称为expr的非终结符和一个用于级别1的称为term的非终结符,通过规则2,我们将为算术的基本单位定义一个非终结符factor来表达整数。

新语法的起始符号将为expr,expr的产生式将包含一个表示使用级别2的运算符主体,在本例中为加号和减号,并将包含更高级别优先级的非终结符term。

级别2:

term产生式将包含一个使用级别1运算符的主题,即运算符乘号和除号,并且它也包含基本表达式单位(整数)的非终结符factor:

非终结符factor的产生式为:

你已经在之前的文章看见过以上产生式的语法和语法图,在这里,考虑到结合性和优先级,我们将它们组合成一个语法:

这是与上面的语法相对应的语法图:

图中的每个矩形框都是对另一个图的“函数调用(method call)”。 如果你采用表达式7 + 5 * 2并从顶部expr开始,然后一直走到最底部的factor,那么应该能够看到较高优先级的运算符乘号和除号在较低的图中,运算符加号和减号在较

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[实现一个简单的解释器(5)]http://www.zyiz.net/tech/detail-113299.html

java开发简单解释器,实现一个简单的解释器(5)相关推荐

  1. 将Java程序变成可执行文件的一个简单方法

    将Java程序变成可执行文件的一个简单方法 运行Java程序(SWING或SWT的桌面程序)可以直接执行.class文件或将所有的.class文件及相关的其他文件压缩成.jar文件,然后使用javaw ...

  2. java 语言 写字板_一个简单的java语言写字板.docx

    一个简单的java语言写字板.docx 一个简单的JAVA语言写字板一.需求分析1.需求分析:现在网络上各种文档编辑器数不胜数.功能也是应有尽有,有能改变字体的,有可以改变字体颜色的,但是,这些软件有 ...

  3. 程序基于MATLAB yalmip 开发,做了一个简单的微网优化调度模型,模型中含有蓄电池储能、风电、光伏等发电单元,程序运行结果良好

    微网 优化调度 机组组合 YALMIP cplex 编程语言:MATLAB平台 主题:基于YALMIP 的微网优化调度模型 内容简介:程序基于MATLAB yalmip 开发,做了一个简单的微网优化调 ...

  4. java widget_自己的AppWidget一个简单教程 - 开发 - Android - JavaEye群组

    Android开发的应用除了程序应用,还有是Widget应用.好多人会开发程序应用而不会开发Widget应用.本帖子就是帮助大家学习如何开发Widget应用的.可要多谢您捧场. 呀. 先简单说说Wid ...

  5. JNI开发笔记(四)--实现一个简单的JNI工程并生成so库

    实现一个简单的JNI工程并生成so库 引 前言 1. 编写C/h文件并添加到工程 2. 修改CmakeLists.txt文件 3. 编写native-lib.cpp文件 4. 在MainActivit ...

  6. java 缓存方法_Java实现一个简单的缓存方法

    Java实现一个简单的缓存方法 发布时间:2020-09-07 21:39:55 来源:脚本之家 阅读:99 作者:BrightLoong 缓存是在web开发中经常用到的,将程序经常使用到或调用到的对 ...

  7. java实现编译器_实现一个简单的编译器

    简单的说 编译器 就是语言翻译器,它一般将高级语言翻译成更低级的语言,如 GCC 可将 C/C++ 语言翻译成可执行机器语言,Java 编译器可以将 Java 源代码翻译成 Java 虚拟机可以执行的 ...

  8. java 围棋_Java.awt实现一个简单的围棋

    目录 0.前言 我小时候学过一段时间的围棋,可惜脑子不好使,是个臭棋篓子,到现在也有十多年的时间没有下过棋了,但是近几年围棋AI的出现,又让我重新关注了围棋 围棋真的很有意思,千变万化,有人简明的围空 ...

  9. iWatch 开发 2:创建一个简单的Apple watch应用

    在上篇文章中,我系统的介绍了一下 iWatch 的功能,相信大家对iWatch开发 也有了一个系统的认识. 今天这篇文章来跟大家说下如何创建一个简单的 iWatch app. 使用 Xcode 创建 ...

最新文章

  1. 这位挺身而出的研究生,被直接录用!
  2. java线程池拒绝策略_Java核心知识 多线程并发 线程池原理(二十三)
  3. arcengine遍历属性表_记录一次Hive表清理过程
  4. 进阶指南:如何编写可重用程序
  5. spreedrest
  6. CNN理解比较好的文章
  7. ASP.Net请求处理机制初步探索之旅 - Part 3 管道
  8. python运行命令_Python中执行外部命令
  9. Linux 进程管理控制
  10. 新手入门学Python一定要知道的编程开发工具
  11. IT给生活带来了什么?
  12. Java项目:在线bbs论坛系统(java+SSM+JSP+bootstrap+jQuery+mysql)
  13. word转pdf组合的图片出现灰线,如何处理
  14. 我是一名自由职业白帽黑客
  15. SpringBoot框架的基本结构
  16. hadoop2.x学习01
  17. [计算机网络笔记14] IPv4地址—定长子网掩码和变长子网掩码
  18. 隐藏excel分组框中的边框
  19. html5限制拖拽区域怎么实现,html5怎么实现拖拽
  20. 拓嘉辰丰:把握拼多多改价技巧,降低降权风险

热门文章

  1. back_inserter的使用
  2. RK3399平台开发系列讲解(其他篇)1.11、CPU如何定频
  3. 当定频神器爱上多线程|ROS2定频话题发布Demo
  4. html文标题党,标题党:如何写出一个SEO与新媒体传播都吸引人的标题! - 蝙蝠侠IT...
  5. 贴片电阻电容的封装形式及尺寸
  6. 历史上的今天:PHP公开发布;iPhone 4 问世;万维网之父诞生
  7. SpringBoot+Redis 实现一个微博热搜!
  8. Shell脚本中的流程控制,如if判断,case语句,for循环,while循环
  9. [蓝桥杯]圆周率(Python)
  10. 登录网站空间无法连接服务器,网站空间打不开的处理办法