正规式
和 有限自动机
描述和识别语言的 单词符号上下文无关文法
来描述语法规则语法分析的方法有两种:自上而下
以及 自下而上
:
自下而上(Bottom-up) | 自上而下(Top-down) |
---|---|
从输入串开始,逐步进行归约,直到文法的开始符号 | 从文法的开始符号出发, 反复使用各种产生式,寻 找"匹配"的推导 |
归约:根据文法的产生式规则,把串中出现的产生 式的右部替换成左部符号 | 推导:根据文法的产生式 规则,把串中出现的产生 式的左部符号替换成右部 |
从树叶节点开始,构造语法树 | 从树的根开始,构造语法树 |
算符优先分析法、LR分析法 | 递归下降分析法、预测分析程序 |
基本思想:
因为直接自上而下分析会有 回溯 和 左递归 问题,所以要先进行 消除文法的左递归性 以及 消除回溯 ,以 构造不带回溯的自上而下分析算法
(看图吧,md排版不怎么好。。。)
例如这样的一个文法的消除例子:
一个文法消除左递归的条件 :
这个过程就是不断的用下层的替换前面出现的,这样一直替换下去最后第一层就只有一个非终结符组成的文法了,最后有直接左递归的就用上一个方法去掉就行了。
对于上面的那个例子的消除结果就是:
{ S → a b c S ′ ∣ b c S ′ ∣ c S ′ S ′ → a b c S ′ ∣ ε \begin{cases} S → abcS'| bcS'| cS' \\ S'→ abcS'| ε \end{cases} {S→abcS′∣bcS′∣cS′S′→abcS′∣ε
为了消除回溯必须保证:对文法的任何非终结符,当要它去匹配输入串时, 能够根据它所面临的输入符号 准确地 指派它的一个候选去执行任务,并且此候选的工作结果应是确信无疑的(将多种可能的搜索变成单一的匹配)。
令G是一个不含左递归的文法,对G的所有 非终结符 的每个候选α定义它的终结首符集FIRST(α) 为:
F I R S T ( α ) = { a ∣ α ⇒ ∗ a . . . , a ∈ V T } 特 别 的 , 若 α ⇒ ∗ ε , 则 规 定 ε ∈ F I R S T ( α ) FIRST(\alpha)=\{a|\alpha⇒^*a..., a \in V_T\} \\ 特别的,若 \alpha ⇒^* ε,则规定 ε \in FIRST(\alpha) FIRST(α)={a∣α⇒∗a...,a∈VT}特别的,若α⇒∗ε,则规定ε∈FIRST(α)
就是某个非终结符 α \alpha α 其所有的可能推导出的句子的首字符组成的集合。
如果非终结符A的所有候选首符集两两不相交, 即A的任何两个不同候选 α i α_i αi 和 α j α_j αj : F I R S T ( α i ) ∩ F I R S T ( α j ) = φ FIRST(α_i)∩FIRST(α_j)=φ FIRST(αi)∩FIRST(αj)=φ , 当要求A匹配输入串时,A能根据它所面临的 第一个输入符号a,准确地指派某一个候选去执行任务。这个候选就是那个终结首符集含a的α。 (也就说,只要我们可以使得A下的产生式的First集合两两不相交,这样就可以唯一确定一个字符出现在那个First集合中,这样就可以从该产生式扩展下去,也就达到了消除回溯的目的:
而达到这一目的(两两不相交)的方法就是 提取公共左因子
在进行分析的过程中,对 T‘的推导中使用了 ε ε ε ,这里选用的原因之一就是 T’包含这样的一个句型,所以才使用 ε ε ε 来跳过:
假定S是文法G的开始符号,对于G的任何非终结符A,我们定义A的FOLLOW集合:
F O L L O W ( A ) = { a ∣ S ⇒ ∗ . . . A a . . . , a ∈ V T } 特 别 是 , 若 S ⇒ ∗ . . . A , 则 规 定 # ∈ F O L L O W ( A ) FOLLOW(A)=\{a|S ⇒^* ...Aa..., a \in V_T\} \\ 特别是,若 S ⇒^* ...A, 则规定 \# \in FOLLOW(A) FOLLOW(A)={a∣S⇒∗...Aa...,a∈VT}特别是,若S⇒∗...A,则规定#∈FOLLOW(A)
(也就是指FOLLOW(A) 为所有可能跟在非终结符A后的终结符的集合)
如果一个文法G满足以上条件,则称该文法G为LL(1)文法。 其中:
对于经过处理后的满足上述条件的LL(1)文法,可以对其输入串进行 有效的 无回溯的 自上而下分析:
F I R S T ( α ) = { a ∣ α ⇒ ∗ a . . . , a ∈ V T } FIRST(\alpha)=\{a|\alpha ⇒^* a..., a \in V_T\} FIRST(α)={a∣α⇒∗a...,a∈VT}
对于First集合的构造,可以由易到难进行考虑,首先考虑 α α α 为单个字符的情况,然后推广到任意长度的串:
{ α = X , X ∈ V T ∪ V N (单个文法符号) α = X 1 X 2 … X n , X i ∈ V T ∪ V N (任何符号串) \begin{cases} α= X,X∈V_T∪V_N & \text{(单个文法符号)}\\ α= X_1X_2…X_n,X_i∈V_T∪V_N & \text{(任何符号串)} \end{cases} {α=X,X∈VT∪VNα=X1X2…Xn,Xi∈VT∪VN(单个文法符号)(任何符号串)
这里的 F I R S T ( X i ) / { ε } FIRST(X_i) / \{ε\} FIRST(Xi)/{ε} 表示的是除去空字集合。
F O L L O W ( A ) = { a ∣ S ⇒ ∗ . . . A a . . . , a ∈ V T } FOLLOW(A)=\{a|S ⇒^* ...Aa..., a \in V_T\} FOLLOW(A)={a∣S⇒∗...Aa...,a∈VT}
对于上面的文法G(E):
E → T E ′ E ′ → + T E ′ ∣ ε T → F T ′ T ′ → ∗ F T ′ ∣ ε F → ( E ) ∣ i \begin{aligned} &E→TE' \\ &E'→+TE'| ε \\ &T→FT' \\ &T'→*FT'| ε \\ &F→(E) | i \\ \end{aligned} E→TE′E′→+TE′∣εT→FT′T′→∗FT′∣εF→(E)∣i
构造每个非终结符的FIRST和FOLLOW集合 :
根据前面构造FIRST集合的步骤:
FIRST | 第1步 | 第2步 | 第3步 | 第4步 |
---|---|---|---|---|
F I R S T ( E ) = FIRST(E)= FIRST(E)= | { ( , i \{(,i {(,i | { ( , i } \{(,i\} {(,i} | ||
F I R S T ( E ′ ) = FIRST(E')= FIRST(E′)= | { + , ε \{+, ε {+,ε | { + , ε \{+, ε {+,ε | { + , ε \{+, ε {+,ε | { + , ε } \{+, ε\} {+,ε} |
F I R S T ( T ) = FIRST(T)= FIRST(T)= | { ( , i \{(, i {(,i | { ( , i \{(, i {(,i | { ( , i } \{(, i\} {(,i} | |
F I R S T ( T ′ ) = FIRST(T')= FIRST(T′)= | { ∗ , ε \{*, ε {∗,ε | { ∗ , ε \{*, ε {∗,ε | { ∗ , ε \{*, ε {∗,ε | { ∗ , ε } \{*, ε\} {∗,ε} |
F I R S T ( F ) = FIRST(F)= FIRST(F)= | { ( , i \{(, i {(,i | { ( , i \{(, i {(,i | { ( , i \{(, i {(,i | { ( , i } \{(, i\} {(,i} |
有了FIRST集合,就可以构造FOLLOW集合(注意一个产生式可能有不同的匹配规则匹配):
FOLLOW | 第1步对E处理 | 第2步对E’处理 | 第3步对T处理 | 第4步对T’处理 | 第5步对F处理 | 第6步对E再处理 | 第7步对T再处理 | 之后继续几次直到发现各集合大小都不变 |
---|---|---|---|---|---|---|---|---|
F O L L O W ( E ) = FOLLOW(E)= FOLLOW(E)= | { # , \{\#, {#, | { # , \{\#, {#, | { # , \{\#, {#, | { # , \{\#, {#, | { # , ) , \{\#,), {#,), | { # , ) , \{\#,), {#,), | { # , ) , \{\#,), {#,), | { # , ) } \{\#,)\} {#,)} |
F O L L O W ( E ′ ) = FOLLOW(E')= FOLLOW(E′)= | { # , \{\#, {#, | { # , \{\#, {#, | { # , \{\#, {#, | { # , \{\#, {#, | { # , \{\#, {#, | { # , ) , \{\#,), {#,), | { # , ) , \{\#,), {#,), | { # , ) } \{\#,)\} {#,)} |
F O L L O W ( T ) = FOLLOW(T)= FOLLOW(T)= | { + , # , \{+, \#, {+,#, | { + , # , \{+, \#, {+,#, | { + , # , \{+, \#, {+,#, | { + , # , \{+, \#, {+,#, | { + , # , \{+, \#, {+,#, | { + , # , ) , \{+, \#,), {+,#,), | { + , # , ) , \{+, \#,), {+,#,), | { + , # , ) } \{+, \#,)\} {+,#,)} |
F O L L O W ( T ′ ) = FOLLOW(T')= FOLLOW(T′)= | { + , # , \{+, \#, {+,#, | { + , # , \{+, \#, {+,#, | { + , # , \{+, \#, {+,#, | { + , # , \{+, \#, {+,#, | { + , # , ) \{+, \#,) {+,#,) | { + , # , ) } \{+, \#,)\} {+,#,)} | ||
F O L L O W ( F ) = FOLLOW(F)= FOLLOW(F)= | { ∗ , + , # , \{*,+,\#, {∗,+,#, | { ∗ , + , # , \{*,+,\#, {∗,+,#, | { ∗ , + , # , \{*,+,\#, {∗,+,#, | { ∗ , + , # , \{*,+,\#, {∗,+,#, | { ∗ , + , # , ) , \{*,+,\#,), {∗,+,#,), | { ∗ , + , # , ) } \{*,+,\#,)\} {∗,+,#,)} |
ADVANCE
,把输入串指示器IP指向下一个输入符号, 即读入一个单词符号SYM
,IP当前所指的输入符号ERROR
,出错处理子程序每个非终结符有对应的子程序的定义,在分析 过程中,当需要从某个非终结符出发进行展开 (推导)时,就调用这个非终结符对应的子程序
框内的代码不简化可以写成这样:
ELSE IF SYM ∈ FOLLOW(A) THEN
BEGIN END
ELSE ERROR
在元符号“→”或“::=”和“|”的基础上,扩 充几个元语言符号:
例如,通常的“实数”可定义为:
D e c i m a l → [ S i g n ] I n t e g e r . { d i g i t } [ E x p o n e n t ] E x p o n e n t → E [ S i g n ] I n t e g e r I n t e g e r → d i g i t { d i g i t } S i g n → + ∣ − \begin{aligned} & Decimal→[Sign]Integer.\{digit\}[Exponent] \\ & Exponent→E[Sign]Integer \\ & Integer→digit\{digit\} \\ & Sign→ + |- \\ \end{aligned} Decimal→[Sign]Integer.{digit}[Exponent]Exponent→E[Sign]IntegerInteger→digit{digit}Sign→+∣−
用扩充的巴科斯范式来描述语法,直观易懂, 便于表示左递归消去和因子提取。
可以将最上面的文法转化为扩充巴科斯范式以及对应的语法图:
总控程序
,根据现行栈顶符号和当前输入符号, 执行动作分析表M[A, a]矩阵
, A ∈ V N , a ∈ V T A ∈V_N,a ∈V_T A∈VN,a∈VT 是终 结符或 ′ # ′ '\#' ′#′分析栈STACK
用于存放文法符号总控程序根据当前栈顶符号X和输入符号a,执行下列三动作之一:
对于上面的文法的一个预测分析的过程,其中分析表的构造看下一讲:
构造分析表前,首先要构造FIRST(α)和FOLLOW(A)
构造G的分析表 M [ A , a ] M[A,a] M[A,a] ,确定每个产生式 A → α A→α A→α 在表中的位置:
例如这样一个实现 ifelse 语句的文法就是二义性的,解决方法是人为的确定一个ifelse 语法,如就近匹配选择 S ′ → e S S'\to eS S′→eS
(end)
https://blog.csdn.net/pi31415926535x/article/details/105163345