语言与文法
复习
- 从字符串变为程序:编译器分阶段处理源码
- 字符串:字符的序列
- 集合:一组对象的整体
TL;DR
- 语言是合法字符串的集合
- 文法用规则描述哪些字符串属于语言
- 推导是从起始符号一步步生成句子的过程
- 编译器需要一种能描述程序嵌套结构的文法
正文
编译器要“读懂”源代码。可我们先得回答一个更基础的问题:怎样严谨地描述一门语言,说明哪些字符串是合法的?
语言就是一个集合
从数学上说,一门语言不过是一个字符串的集合:所有合法的句子,构成这个集合;不合法的,就不在里面。
比如“所有由 0 和 1 组成、且不包含连续两个 0 的字符串”,就是一个语言。
可问题是:语言可能包含无穷多个字符串,你没法把它们一个个列出来。于是需要一个更紧凑的描述方式——文法。
文法:用规则生成语言
文法由几部分组成:
- 终结符:最终出现在句子里的基本符号(比如
+、数字、字母) - 非终结符:代表某个语法成分的占位符(比如“表达式”)
- 产生式:形如“某个非终结符可以改写成什么”的规则
- 起始符号:从哪个非终结符开始生成
从起始符号出发,不断把非终结符按产生式改写成别的东西,直到得到一个只含终结符的字符串——这个过程叫推导,得到的字符串就是语言里的一句。
举个例子,一个描述加减表达式的文法:
表达式 → 数字
表达式 → 表达式 + 数字
表达式 → 表达式 - 数字
从“表达式”出发反复代入,就能推出 1 + 2 - 3 这样的句子。文法用有限的规则,描述了一个可能无限大的语言。
为什么这样描述有用
用规则而不是列举,好处是显而易见的:规则短小、有限,却能覆盖无穷多种情况。 而且,规则的结构往往和程序的结构对应。
编译器要处理的程序语言,含有大量嵌套(括号、语句块、函数……)。要描述这种嵌套,就需要一种特别合适的文法——这将是后面章节的重点。先记一句话:好的文法,能让“解析程序结构”这件事变得有章可循。
那么,文法描述的是“字符层面的句子”。在用它之前,我们得先把字符切成语法单位——这就是词法分析。
思考题 1
文法在“描述一门语言”时,扮演什么角色?
思考题 2
为什么用规则(推导)来描述语言,比直接列举所有合法句子更现实?
小结
知识点
- 语言是合法字符串的集合
- 文法由终结符、非终结符、产生式和起始符号组成
- 推导从起始符号生成合法句子
- 文法用有限规则描述可能无限的语言
参考资料
- Wikipedia(zh):形式文法:用规则描述形式语言的工具
- Wikipedia(zh):形式语言:由形式文法定义的字符串集合
思考题答案(仅供参考)
思考题 1
它提供了一种用有限规则描述语言的机制:通过产生式和推导,规定哪些字符串是合法的。文法既是语言的精确描述,也是编译器后续分析程序结构的依据。
思考题 2
因为语言通常包含无穷多个合法字符串,无法逐一列举。而文法用有限的规则,就能生成全部合法句子,既简洁又能覆盖无穷情况,还便于机器处理。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪