原文链接:https://ruslanspivak.com/lsbasi-part4/
在前面的文章中你学会了怎样识别和解释包含任意数量的加减操作的算术表达式,例如“7 - 3 + 2 - 1”。还学会了句法图以及它们如何被用来表示一门编程语言的语法。
今天你将会学习解析(parse)和解释(interpret)包含任意乘除操作的算术表达式,例如“7 * 4 / 2 * 3”。在这篇文章中使用的是整数除法,所以对于表达式“9 / 4”来说,结果是一个 整数:2。
我今天会讲很多另一个表示编程语言句法的广泛使用的表示法,叫 上下文无关语法 (context-free grammars, 简记为 grammars)或 BNF (Backus-Naur Form)。为了这篇文章的目的,我不会使用纯 BNF 记法,而更像是一个修改过的 EBNF 记法。
文法(语法):描述语言的语法结构的形式规则。
上下文无关语法就是说这个文法中所有的产生式左边只有一个非终结符,比如:
S -> aSb
S -> ab
这个文法有两个产生式,每个产生式左边只有一个非终结符S,这就是上下文无关文法,因为你只要找到符合产生式右边的串,就可以把它归约为对应的非终结符。比如:
aSb -> aaSbb
S -> ab
这就是上下文相关文法,因为它的第一个产生式左边有不止一个符号,所以你在匹配这个产生式中的S的时候必需确保这个S有正确的“上下文”,也就是左边的a和右边的b,所以叫上下文相关文法。作者:徐辰
链接:https://www.zhihu.com/question/21833944/answer/40689967
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
以下是一些使用语法的原因:
- 语法使用了一种简明的方式来描述一门编程语言的句法。不像语法图,语法非常紧凑。 在以后的文章中,你会看到我越来越多地使用语法。
- 语法可以做为文档保存。
- 即使对从头开始写解析器(parser)来说,语法也是一个好的入手点。很多时候通过遵循 一套简单的规则你就可以把语法转化成代码。
- 有一套工具,叫解析器生成器(parser generator),可以把语法做为输入并自动根据它为你生成一个解析器。我会以后在这个系列中谈到这些工具。
语法机制
下面的语法描述了算术表达式,像“7 * 4 / 2 * 3”这样的(这只是该语法可以生成的许多表达式之一):
语法是由一系列规则组成的,也被称为产生式(production)。我们的语法中有两条规则(产生式):
第一条规则左边的非终结符被叫做 开始符号(start symbol). 在我们的语法中,开始符号是 expr:
你可以这么理解 expr
这条规则:“expr 是一个 factor 后面可选地跟一个乘或除运算符再跟 另一个 factor,后面也相应可选地跟一个乘或除运算符再跟另一个 factor,如此重复”。
factor 是什么?对于本文来说 factor 就是一个整数。
语法中的符号
将语法变成代码
下面是一些我们在把语法转化成源代码时会用到的==四个准则==。按照这些准则,你真的就可以把语法翻译成一个可工作的 parser:
- 对于语法中定义的每个规则 R,将它做成一个有相同名字的方法,对该规则的引用就变成了一个方法调用:R()。该方法的方法体遵循该规则的步骤,过程中使用相同的准则。
- 多选一
(a1|a2|aN)
变成 if-elif-else 语句 - 可选组
(...)*
变成一个可以执行 0 或多次的 while 循环(can loop over zero or more times) - 每个 Token 记为 T 变成一个
eat
方法调用:eat(T)
.eat
方法的工作是 当它匹配到当前的向前看
(lookahead) token 就消耗掉它,然后从 lexer 中得到一个新 token 并将它赋值给内部变量current_token
.
|
|
|
|
原作者将本文的代码放在了文件 parser.py
中,它包含了 lexer 和 parser 但没有interpreter。你可以直接从 GitHub下载并尝试一下。它包含有一个 interpreter 提示符,你可以输入表达式来查看它是否合法,即查看根据语法建立的 parser 是否可以识别出表达式。
下面是在我笔记本上的一次尝试:
|
|
这里再次提起语法图。这是相同的 expr
规则(也叫,产生式(production))对应的句法图:
下面是原作者的关于本文的源码。下面是可以处理包含任意数量整数 乘除(整数除法)操作的合法的算术表达式的计算器代码。这里把词法分析器重构 到了一个单独的类 Lexer
中,并让 Interpreter
类使用 Lexer
实例做为参数:
|
|
将以上代码保存到名为 calc4.py
中,或者直接从 GitHub 上下载。和以往一样,自己尝 试一下,确认它能工作。