Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

上下文无关文法

复习

  • 语法分析要解决什么:把词组织成语法结构
  • 语言与文法:产生式与推导
  • 树:用父子关系表示层次

TL;DR

  • 上下文无关文法用递归规则描述嵌套结构
  • 每条产生式的左边是一个非终结符
  • 它非常适合描述程序语言的语法
  • 一次推导,对应一棵语法树

正文

  上一章说,语法分析需要一种能描述程序结构的文法。这种文法叫上下文无关文法(CFG,Context-Free Grammar)。

和普通文法差在哪

  回顾一下普通文法:产生式的左边可以是任意符号串。而上下文无关文法做了一个限制:每条产生式的左边,只能是一个单独的非终结符。

  就这一条限制,让文法变得“上下文无关”:一个非终结符可以被改写成什么,只取决于它自己,而不取决于它周围出现的是什么。也就是说,改写它时不需要看“上下文”。

  这个限制听起来是削弱,实际却恰到好处——因为程序语言的结构,大多是嵌套的,而这种嵌套正好适合用“一个成分可以不断包含更小的同类成分”的规则来描述。

用递归规则描述嵌套

  看一个例子:

语句 → if 条件 语句
语句 → { 语句列表 }

  第一条说“一个语句可以是 if 加条件再加一个语句”,第二条说“一个语句可以是一对花括号包起来的一串语句”。注意,两条规则的右边都出现了“语句”自己——规则是递归的,这正是它能描述任意深嵌套的原因。

  再怎么深的 ifif、语句块套语句块,都会被这些规则一层层展开。有限的规则,描述无限深的嵌套——这正是文法的威力。

推导与语法树

  从起始符号出发,不断应用产生式,把非终结符替换成右边的符号串,这个过程叫推导。每一次推导,都可以画成一棵树:

  • 父节点是被替换的非终结符
  • 子节点是替换后的符号

  推导完成时,叶子节点就是最终的词法单元,整棵树就是这串词的语法树

  所以,“判断合不合法”和“给出结构”,在文法的视角下其实是同一件事:合法,就是能被推导出来;结构,就是那棵推导树。

  有了文法,下一步就是写一个程序,让它真的去“推导”——这就是语法分析器。下一章从最直观的一种写法开始。

思考题 1

  上下文无关文法为什么适合描述程序语言?

思考题 2

  “上下文无关”这个限定,具体指什么意思?

小结

知识点

  • 上下文无关文法要求产生式左边是单个非终结符
  • 它通过递归规则描述任意深度的嵌套
  • 推导过程对应一棵语法树
  • 合法性判断与结构给出是同一件事

参考资料

  1. Wikipedia(zh):上下文无关文法:产生式左边为单个非终结符的文法
  2. Wikipedia(zh):语法树:推导过程的树形表示

思考题答案(仅供参考)

思考题 1

  因为程序语言大量使用嵌套结构(括号、语句块、函数等),而上下文无关文法用递归规则恰好能描述任意深度的嵌套:一个成分可以由更小的同类成分构成,反复展开即可。

思考题 2

  指每个非终结符能被改写成什么,只由它自身决定,不依赖它出现的位置或周围的符号。因为产生式左边只有一个非终结符,所以改写时无需检查上下文。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪