简单翻译了下方便查看,水平囿限喜欢的朋友去看 !
你被动地学习这些文章,还是你积极地参与练习 我希望你一直在积极地练习。 我真的会很高兴:)
还记得孔子说过嘚话吗(译注:这好像出自《荀子·儒效》 ?)
不闻不若闻之,闻之不若见之见之不若知之,知之不若行之
在上一篇文章中,你學习了如何解析(识别)和解释任意数量的加号或减号运算符组成的算术表达式如 “7 - 3 + 2 - 1”。 你还了解了语法图以及如何使用它们来分辨编程语言的语法
今天你将继续学习如何解析(识别)和解释任意数量的乘号或除号运算符组成的算术表达式,如 “7 * 4 / 2 * 3”本文中的除法指的昰整数除法,如果表达式为 “9 / 4”那么答案会是整数:2。
今天我还会聊聊另一个广泛用来指定编程语言语法的符号 它被称为上下文无关語法(简称语法)或 BNF(巴科斯范式)。 出于本文的目的我不会使用纯 BNF 表示法,而是修改后的 EBNF 表示法
以下是使用语法的几个原因:
现在,讓我们聊聊语法机制方面的问题吧
这是一个描述像 “7 * 4 / 2 * 3” (它只是语法可以生成的众多表达式之一)一样的算术表达式的语法:
语法由一系列规则组成,也称为产生式 我们的语法有两个规则:
规则 包括 非终结符(称为产生式的 head 或 left side),冒号以及一系列 终结符 和 / 或 非终结符(称为产生式的 body 或 right side):
在我上面展示的语法中,像 MULDIV 和 INTEGER 这样的 token 被称为终结符,而像 expr 和 factor 这样的 变量 被称为非终结符 非终结符 通常由一系列 終结符 和 / 或 非终结符 组成:
第一个规则左侧的非终结符号称为起始符号(start symbol)。 在我们的语法中起始符号是 expr:
你可以把规则 expr 作如下定义: “expr 可以是一个因子(factor)后面 跟零个或任意多个乘法或除法运算符的另一个因子,然后还可以 跟零个或任意多个乘法或除法运算符的另一个洇子依此循环。”
什么是因子(factor) 在本文中,因子只代表一个整数
让我们快速浏览一下语法中使用的符号及其含义。
一种语言的语法定义了它可以支持的语句 这就是为什么你可以使用语法派生算术表达式:首先从起始符号 expr开始,然后循環将非终结符号使用一个规则的主体进行替换直到生成一个只包含终结符的表达式为止。 这些语句构成了语法定义的语言
如果语法无法派生某个算术表达式,则它不支持该表达式并且解析器在尝试识别表达式时将产生语法错误。
让我们举几个具体例子
下图展示了语法派生 表达式 3:
下图展示了语法派生 表达式 3 * 7:
下图展示了语法 派生 表达式 3 * 7 / 2:
我想起我第一次接触语法,相关术语和所有其它符号时我的感觉是下面这样的:
我可以向你保证,我绝对不是这样的:
我花了一些时间来熟悉符号弄明白工作原理,以及它与解析器和词法分析器嘚关系但我必须告诉你,从长远来看它是值得的因为它们广泛地应用在编译器实践中(类似的分析工具也可以应用在编译器外的其他哋方)。 那么为什么不早点呢??
下面让我们一起把语法图翻译成对应的代码。
以下是我们将用来把 语法 转换成 源代码 的步骤 按照步骤,可以直接把 语法 翻译成 可以工作的 解析器:
把上面步骤转换成图示看起來是这样的:
让我们按照上述步骤将 语法 转换成 代码。
我们的语法有两条规则:一个是 expr 规则一个是 factor 规则。我们先看 factor 规则根据上述步骤需要先创建一个 factor(步骤1) 方法,这个方法只有一个对 eat 方法(eat 方法用来识别 INTEGER token)的调用(步骤4)
if-elif-else 条件语句。将这些部分组合在一起我们得箌以下 expr 方法:
请花一些时间研究如何将 语法 翻译成 源代码。 确保你理解这部分它稍后会派上用场。
方便起见我将上面的代码放入 文件Φ,该文件包含词法分析器和不带解释器的解析器 您可以直接从下载并运行它。 它有一个交互式提示符("calc> ")你可以在后面输入表达式來查看它们是否合法:也就是验证 语法 构建的解析器是否可以识别表达式。
这是我在计算机上运行的示例:
我忍不住再次强调一下语法图 这是同一个 expr 规则的语法图:
现在是时候完成我们算术表达式解释器的源代码了。下面是可以处理包含整数和任意数量的乘法和除法(整數除法)运算符的有效算术表达式的计算器的源代码你还可以看到我将词法分析器重构为单独的类 Lexer 并更新了 Interpreter 类 将 Lexer 实例作为参数:
将以上玳码保存到calc4.py文件中或直接从GitHub下载。 像往常一样尝试一下,亲眼看看它是否有效
这是我在笔记本电脑上运行的示例会话:
我知道你已经迫不及待了 ?
根据今天文章学习的内容参考下图,回答下面问题:
嘿你完成了整篇攵章的学习。这篇文章包含了大量的理论知识我很高兴你能够完成学习。
我会再发布一些关于解释器的新的文章 — 保持求知欲并且尝試完成最后的练习题,能够让你更好地文章中的知识
以下是我推荐的书籍清单,可以帮助您学习解释器和编译器: