里抽象语法树_NLP之上下文无关语法及分析

参考链接:第09章 上下文无关语法及分析 - 自己动手写编译器

词法分析后,源文件的字符流被分割为 token 流了,接下来就开始进行语法分析,分析出源程序的语法结构,将线性的 token 流转化为树状结构,为后续的语义分析和代码生成做准备。本章介绍什么是语法,如何用语法来描述语言,以及语法分析的任务、基本方法和思路。

上下文无关语法
在程序编译场景下,一个程序就是一个句子(字符串),语言就是一个句子集合。那么如何准确的表示这个集合?用枚举法?显然不行,这个集合可能包含了无限多个元素。用特性法?那应该如何精确的描述这个集合的特性?
编译的第一个任务就是判断给定的句子是否属于这个集合,因此必须提供一个精确的、可操作的描述来表示这集合。如 ” C 语言就是所有能编译成功的源程序的集合” 这样的描述是无法操作的,对任意的源程序显然无法用这个描述来判断其是否属于 C 语言这个句子集合。
在第 7 章中介绍了正则语言和正则表达式,一个正则表达式可以用来表示一个句子集合(正则语言),且每个正则表达式都可以构造出有限状态自动机来判断任意的句子是否属于这个句子集合。因此,用正则表达式来表示正则语言是精确的、可操作的。
那么,可以用正则表达式来表示程序语言(比如 C 语言)所代表的句子集合吗?
很遗憾,答案是否定的。正则表达式毕竟太简单了,无法来表示程序语言这样复杂级别的句子集合。
为了表示程序语言的句子集合,需要采用表达能力更强大的工具 —— 上下文无关语法(context-free grammar)
下面以一个简单的例子来说明什么是上下文无关语法,假设有一种非常非常原始的语言,我们把它成为 X 语言,它的句子只有: 主语 谓语 宾语 这样一种结构, 主语 中只有 我、 你、 他 三个词, 谓语 中只有 一个词, 宾语 中只有 饭、菜 两个词。我们把它的语法写出下面这样的形式:
语句 -> 主语 谓语 宾语 主语 -> 我 主语 -> 你 主语 -> 他 谓语 -> 吃 宾语 -> 饭 宾语 -> 菜
可以看出, X 语言总共只有 6 个句子: { 我吃饭, 我吃菜, ..., 他吃菜 }。也就是说,我们可以用上面这个语法来表示 X 语言这个集合,我们可以从第一行的 “语句 -> 主语 谓语 宾语” 开始,分别将主、谓、宾替换成可用的词,从而将所有满足语法的句子都推导出来。对于任意一个句子,我们也可以将句子和此语法来对比,判断它是否属于满足 X 语言。
上面这个语法中的每一行形如 “语句 -> 主语 谓语 宾语” 的式子称为 产生式(production)
产生式左侧的符号(语句、主语、谓语和宾语)称为 非终结符(nonterminal) ,代表可以继续扩展或产生的符号,也就是说,当在某条产生式的右边遇到了此非终结符的时候,总是可以用本产生式的右边来替换这个非终结符。
而 “我、你、他、吃、饭、菜” 这些符号是 X 语言中的词,无法再产生新的符号了,称为 终结符(terminal) 。终结符只能出现在产生式的右边,非终结符则左边和右边都可以出现。
上述产生式中有一个特别的非终结符: “语句” , X 语言中的所有句子都以它为起点产生,这个符号被称为 起始符号(start symbol)
通常把同一个非终结符的产生式写在一起,用 “|” 隔开,如下:
语句 -> 主语 谓语 宾语 主语 -> 我 | 你 | 他 谓语 -> 吃 宾语 -> 饭 | 菜
注意,上面的第二行中有 3 个产生式,第四行中有 2 个产生式。
一个上下文无关语法 G 就是由一个终结符集合 T ,一个非终结符集合 N ( N 和 T 不相交),一个产生式集合 P

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值