【学习笔记】编译原理 第四章 语法分析(基础篇)

以下为参考课件与《编译技术》(张莉等著)的个人整理,若有错误欢迎指出

第四章 语法分析(基础篇)

一、概述

1、语法分析功能:从单词符号串中识别出语法成分,并进行语法检查

2、两大类方法

自顶向下分析法自底向上分析法
思路从识别符号开始推出句子从句子规约到识别符号
主要问题左递归(无法处理)、回溯问题(带预测的)句柄的识别问题
主要方法递归子程序法、LL分析法算符优先分析法、LR分析法

本文基础篇 仅介绍自顶向下分析法的递归子程序法

二、自顶向下分析

1、特点

带预测、需要回溯因此效率低

自顶向下分析方法面临着无法处理左递归(不断调用自身、死循环)和回溯的问题,因此下面讨论解决方法

2、消除直接左递归的方法

(1)方法一:使用扩充的BNF改写文法,如 E : : = E + T ∣ T ⟹ E : : = T { T } E::=E+T|T\quad \Longrightarrow E::=T\{T\} E::=E+TTE::=T{T}

规则

  • 提取因子

    注意:最长匹配规则 E : : = x ∣ x y ⟹ 改 E : : = x ( y ∣ ε ) , 不 要 ( ε ∣ y ) E::=x|xy\quad \overset改\Longrightarrow E::=x(y|\varepsilon) ,不要(\varepsilon|y) E::=xxyE::=x(yε),(εy)

  • U ∷ = x ∣ y ∣ … … ∣ z ∣ U v ⟹ 改 U : : = ( x ∣ y ∣ … … ) { v } U∷ =x|y|……|z|Uv \quad \stackrel改 \Longrightarrow U::=(x|y|……)\{v\} U::=xyzUvU::=(xy){v}

    个别情况不太推荐 { } \{\} {}的写法(原因同下文“回溯”中提到的空语句的情况),更推荐此处使用方法二

(2)方法二:左递归改成右递归

P ∷ = P α ∣ β P∷ =Pα| β P::=Pαβ,则可改写为 P ∷ = β P ’ , P ’ ∷ = α P ’ ∣ ε P ∷ = β P’,P’ ∷ = αP’| \varepsilon P::=βPP::=αPε

(3)小结:消除一般左递归的算法

步骤:

  1. 把文法的非终结符整理成一种顺序,使后面的规则中仅包含前面规则左部的非终结符,如:
    A 1 : : = δ 1 ∣ δ 2 ∣ … … δ k A 2 : : = A 1 r … … A 3 : : = A 2 u ∣ A 1 v … . . \begin{aligned} A1 &::= δ 1|δ 2|……δ k\\ A2 &::= A1 r……\\ A3 &::= A2u | A1v…..\\ \end{aligned} A1A2A3::=δ1δ2δk::=A1r::=A2uA1v..

  2. 从上往下,依次用上面的规则消去当前规则中的非终结符。这个过程中既可以压缩文法,也可以检查出直接/间接的左递归(用上面提到的方法删除)。

3、回溯

(1)对于规则 U : = α 1 ∣ α 2 ∣ . . . , U ∈ V n U:=\alpha_1|\alpha_2|...,U \in V_n U:=α1α2...,UVn,定义(每个选择所推出的终结符号串的)首符号集: F I R S T ( α i ) = { a ∣ α i ⟹ ∗ a . . . , a ∈ V t } FIRST(\alpha_i)=\{a|\alpha_i \stackrel*\Longrightarrow a..., a\in V_t\} FIRST(αi)={aαia...,aVt}

(2)不带回溯文法的充分必要条件

对于每一个非终结符A的任意两条规则 A : : = α ∣ β A::=\alpha|\beta A::=αβ,下列条件成立:

  • 非左递归

  • F I R S T ( α i ) ∩ F I R S T ( α j ) = Φ , i ≠ j FIRST(\alpha_i)\cap FIRST(\alpha_j) =\Phi, i \neq j FIRST(αi)FIRST(αj)=Φ,i=j

    也就是每条支路推导出来的字符串无交集,这样就不用试探

  • β ⟹ ε \beta \Longrightarrow\varepsilon βε, 则 F I R S T ( α ) ∩ F O L L O W ( A ) = Φ FIRST(\alpha) ∩ FOLLOW(A) = \Phi FIRST(α)FOLLOW(A)=Φ

    A的后继符号集合 F O L L O W ( A ) = { a ∣ Z ⟹ ∗ . . . A a . . . , a ∈ V t } FOLLOW(A)=\{a|Z\stackrel*\Longrightarrow...Aa...,a\in V_t\} FOLLOW(A)={aZ...Aa...,aVt}(特别地,若 Z ⟹ ∗ . . . A Z\stackrel*\Longrightarrow...A Z...A,则 ε ∈ F O L L O W ( A ) \varepsilon \in FOLLOW(A) εFOLLOW(A)

    这里强调的是推出空语句的影响。如果能推出空语句,那还要求这条之后能推出的所有符号不能与首符号集相交,不然就无法确定到底是这里取到这个符号,还是后续推导得到的。

    举一个具体例子:

    U : : = T a , T : : = a ∣ ε U::=Ta,T::=a|\varepsilon U::=Ta,T::=aε,如果要对句子 a a a进行自顶向下的检查,根据递归子程序法(最左),就不知道 T T T这里到底取哪一个了,因此也会带来回溯。

(3)消除回溯的方法

  • 改写文法:反复提取左因子(这样就能实现首字符集的交为空)

  • 超前扫描(其实就是多看几个符号,但不处理,所以也有一点回溯)

三、递归子程序法

对应最左推导

具体做法:针对每一个非终极符都编写一个分析程序,每个分析程序根据规则的右部去匹配输入串

约定:在调用子程序前先读好下一个词并把其类别码(这个由词法分析程序得到,详细可看上一篇文章)存放在sym,程序结束前也要先读好

《编译技术》P88-90有具体例子,基本步骤就是先对文法进行处理(消除左递归和回溯),然后对每一个非终结符编写子程序即可(取词,按照规则右部,是非终结符就调用子程序,是终结符就判断类别码)。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值