编译原理-学习记录11

ch4.(2)自下而上语法分析(续)

  上回,为了解决移进-规约时的几个问题,引入了几个定义:

  短语

  设有文法G[Z],w=xuy是它的一个句型,如果有: Z ⇒ ∗ x U y Z\mathop\Rightarrow\limits^* xUy Z⇒∗xUy并且 U ⇒ + u U\mathop\Rightarrow\limits^+u U⇒+u,则称句型xuy中子串u为句型xuy(相对于非终结符号U)的短语

  特别地,如果是 Z ⇒ ∗ x U y Z\mathop\Rightarrow\limits^* xUy Z⇒∗xUy并且 U ⇒ u U\mathop\Rightarrow u U⇒u,则称u为句型xuy的直接(简单)短语

  句柄

  句型的最左直接短语称为句柄

  根据定义,短语、直接短语和句柄,都和语法树有关系:

  1、语法树子树的末端结点符号串即是语法树所描述句型(相对于子树的根)的短语
  2、简单子树(只有父子两代)的末端结点符号串即是直接短语
  3、最左简单子树的末端结点符号串即是句柄

  光从文字来看,这样的定义还是太抽象了。这个定义应该对后面的自下而上分析方法很重要,所以不得不看懂。然而这三行看了很久都没看懂,看书也看不懂,最后看了https://icode.blog.csdn.net/article/details/93236597这篇文章才勉强搞懂。现进行举例:

  对于文法G[S]:

S → A B A → A a ∣ b B B → a ∣ S b \begin{aligned}S&\rightarrow AB\\ A&\rightarrow Aa|bB\\ B&\rightarrow a|Sb\end{aligned} SAB​→AB→Aa∣bB→a∣Sb​

  现打算要求句型baSb的短语、直接短语和句柄。首先使用最左推导的方法,构造出语法树:

编译原理-学习记录11

  除叶结点单独形成的子树之外,这棵语法树共有4个子树:
  1、B(a)
  2、B(S, b)
  3、A(b, B(a))
  4、S(A(b, B(a)), B(S, b))

  因此,短语共有四个:a、Sb、ba、baSb

  而因为前两棵子树只有父子两代,所以直接短语有两个:a、Sb

  句柄是最左直接短语(位于最左端的简单子树),而两棵子树中,B(a)在B(S, b)的左边,所以句柄应该为a

  在理解定义之后,就开始看LR方法的思想了

LR分析法和LR分析程序

  此类分析法命名为LR,是用于表达“从左至右”的含义

  现在,自上而下语法分析面临的问题,主要就在于这两点:
  1、如何找出当前句型中的句柄
  2、应该将句柄归约到哪一个非终结符号

  在进行详细讨论之前,首先大致浏览程序的总体结构,以展现出LR分析法相对于LL(1)分析法的简洁之处

LR分析程序的逻辑结构

  LR分析程序主要有总控程序和分析表这两个部分

  相比于LL(1),LR多出了一个状态栈,用于存储符号栈中各个符号所对应的状态,而新进栈的符号的状态则是根据栈顶的状态和输入的符号进行查表(分析表)而决定

编译原理-学习记录11

  分析表主要包含:动作部分(ACTION)和状态转换部分(GOTO)。表中使用S表示移进、r表示规约、acc(accept)表示接受、(ACTION部分的)空白表示错处理(而GOTO部分的空白则不是出错处理)

编译原理-学习记录11

分析表

  尽管LR分析器有好几种类型(常见的有LR(0)、SLR、LR(1)、LALR),但所有LR分析器的总控程序一致,只是分析表不同而已。由此可知,LR分析法的程序是可以通用的,这再次体现出了LR分析法的一个优越之处

LR分析过程简要描述

  LR分析过程主要包括移进、规约、接受和出错四种操作。对过程的简要描述如下:
  1、总控程序在分析的每一步,按照状态栈顶状态q和当前输入符号a,查阅LR分析表,并执行其中ACTION[q,a]和GOTO部分规定的操作。

编译原理-学习记录11

初始状态

  2、若ACTION [ q i q_i qi​, a k a_k ak​]= S j S_j Sj​,则:

编译原理-学习记录11

  3、若ACTION [ q i q_i qi​, a k a_k ak​]=rj,且第j条产生式为U → \rightarrow →x,|x|=m,LR分析表中有GOTO[ q i − m q_{i-m} qi−m​,U]= q t q_t qt​,则:

编译原理-学习记录11

  4、若ACTION[ q i q_i qi​, a k a_k ak​]=acc,表示接受,不发生变化,分析成功:

编译原理-学习记录11

  5、若ACTION[ q i q_i qi​, a k a_k ak​]=ERROR,表示出错,中止变化

  LR分析过程非常地简单,没有左递归、提取公因子的问题,因此关键在于:如何构造分析表

LR(0)分析表的构造

LR分析法的基本原理

  对于由n个符号构成的句柄,如果每识别一个句柄的符号就对应着一个状态,则加上开始状态后,共有n+1个状态

  可以利用打点的方式记录状态,例如,现在有句柄XYZ,则.XYZ表示即将开始得到X,X.YZ表示已经得到X,即将得到YZ,XY.Z表示已经得到XY,即将得到Z,XYZ.表示已经得到XYZ,即将归约

  用LR(0)项目来表示一个句柄的所有识别状态:
  移进项目: U → x . a y U\rightarrow x.ay U→x.ay。点后为终结符号,需要移入栈中
  待约项目: U → x . V y U\rightarrow x.Vy U→x.Vy。点后为非终结符号
  规约项目: U → x . U\rightarrow x. U→x.。点已经到句柄的最后了,已完整地完成
  接受项目: S ′ → S . S'\rightarrow S. S′→S.。其中,S为开始符号。这里使用了拓广文法,引入了一个新的开始符号S’,和产生式 S ′ → S S'\rightarrow S S′→S

  即便是在得到完整的产生式右部时,也无法知道能不能规约(信息还是不够),说明不能离开句型谈句柄,即需要句型中的信息,利用历史来帮助判断

  由此引入活前缀:包含了句柄识别到当前时刻的历史,并逐步向后传递,最长活的前缀(可归约前缀)包含了句柄完全被识别的整个历史。这样一来,符号栈中存放的就是活前缀,而符号串和输入串连起来就是句型:

编译原理-学习记录11

  对句柄的识别过程就是对规范句型的活前缀的识别过程,对于这样的识别,可以用确定的有穷自动机来进行

构造识别规范句型活前缀的DFA

  在此处,使用拓广文法:引入一个新的开始符号S’,及对应的产生式 S ′ → S S'\rightarrow S S′→S

  将所有的产生式的所有状态全部列出,然后根据状态间的转换关系进行相应的连线:

编译原理-学习记录11

  上述方式构造出的是NFA,如果要转换为DFA,则需要进行状态的合并

  首先对空弧的闭包进行状态合并:

编译原理-学习记录11

  合并后,被并入的状态所对应的产生式称作派生项目,反之称为核心项目。例如,在上图的开始状态集中, S ′ → . S S'\rightarrow .S S′→.S为核心项目,而 S → . a A c B e S\rightarrow .aAcBe S→.aAcBe则为派生项目

  随后,再对相同输入所到达的多个状态进行合并:

编译原理-学习记录11

  这样便转换为了DFA

上一篇:意大利都灵古城旅拍人文LR预设


下一篇:pytorch(2):线性回归