1.语法分析程序的主要任务是什么?简述自顶向下语法分析的思想。
-
语法分析程序(也称为解析器)的主要任务是将词法分析器生成的词法单元(tokens)序列,根据所定义的语言语法规则,构建出语法树或抽象语法树,并验证输入程序的语法是否正确。具体来说,语法分析程序需要完成以下几个关键任务:
- 语法正确性检查:确保输入的程序符合语言的语法规则,识别并报告语法错误。
- 结构分析:根据语法规则,将词法单元组织成具有层次结构的语法树,反映程序的语法结构。
- 语法树构建:生成详细的语法树或抽象语法树,为后续的语义分析、优化和代码生成提供基础。
-
自顶向下语法分析的思想 自顶向下语法分析是一种从语法规则的开始符号(根节点)出发,逐步推导并匹配输入符号串的解析方法。其基本思想包括以下几个方面:
-
开始于根节点:解析过程从语法树的根节点,即文法的开始符号 递归展开:通过应用文法的产生式规则,将非终结符逐步替换为其右侧的符号(终结符或非终结符),以匹配输入的词法单元序列。
-
预测选择:在有多个产生式可供选择时,利用预测分析(如预测表或先行符)来决定使用哪一条产生式,从而避免回溯,提高解析效率。
-
递归下降:常见的自顶向下解析方法之一,通过为每个非终结符编写一个递归函数,实现对输入的逐步匹配和解析。
-
错误检测与恢复:在解析过程中,当发现输入符号与预期不符时,能够及时检测到语法错误,并尝试进行适当的错误恢复,以继续解析后续部分。
-
- 对文法G[S] S → a | & | (T) T → T,S | S 给出(a, (a, a))和(((a,a), &, (a)),a)的最左推导。
- S ⇒(T) ⇒(T,S) ⇒(a,S) ⇒(a,(T)) ⇒(a,(T,S)) ⇒(a,(a,S)) ⇒(a,(a,a))
- S ⇒(T) ⇒(T,S) ⇒((T),S) ⇒((T,S),S) ⇒(((T),S),S) ⇒(((T,S),S),S) ⇒(((a,S),S),S) ⇒(((a,ϵ),S),S) ⇒(((a,ϵ),(T)),S) ⇒(((a,ϵ),(a)),S) ⇒(((a,ϵ),(a)),a) ⇒(((a,&),(a)),a)
- 判断下面文法是否为LL(1)文法,并说明理由。 (1) S → A B | P Q x A → x y B → b c P → d P | ε Q → a Q | ε
(2) S → T P T → + P T | ε P → ( S ) | a
要判断给定的文法是否为 LL(1) 文法,需要检查以下条件:
- 消除左递归:文法中不应存在直接或间接的左递归。
- 左因子化:对于每个非终结符,其不同产生式的 FIRST 集合应当互不相交。
- 处理 ε 产生式:如果某个非终结符可以推导出 ε(空串),则其 FIRST 集合与 FOLLOW 集合应当互不相交。
我们将逐一分析提供的两个文法是否满足上述条件。
[ \begin{aligned} S &\rightarrow A B \mid P Q \ x \ A &\rightarrow x \ y \ B &\rightarrow b \ c \ P &\rightarrow d \ P \mid \epsilon \ Q &\rightarrow a \ Q \mid \epsilon \end{aligned} ]
步骤 1:检查左递归
- 文法中不存在直接或间接的左递归。
步骤 2:计算 FIRST 集合
-
FIRST(A B):
- ( A \rightarrow x \ y ),因此 FIRST(A) = { x }。
- 因此,FIRST(A B) = { x }。
-
FIRST(P Q x):
- ( P \rightarrow d \ P \mid \epsilon ),因此 FIRST(P) = { d, ε }。
- ( Q \rightarrow a \ Q \mid \epsilon ),因此 FIRST(Q) = { a, ε }。
- FIRST(P Q x) 需要考虑 ( P ) 和 ( Q ) 的所有可能组合:
- 如果 ( P \rightarrow d \ P ),则 FIRST(P Q x) 包含 d。
- 如果 ( P \rightarrow \epsilon ) 且 ( Q \rightarrow a \ Q ),则包含 a。
- 如果 ( P \rightarrow \epsilon ) 且 ( Q \rightarrow \epsilon ),则包含 x。
- 因此,FIRST(P Q x) = { d, a, x }。
步骤 3:检查冲突
- 对于非终结符 S,有两个产生式:
- ( S \rightarrow A B ) 的 FIRST 集合为 { x }。
- ( S \rightarrow P Q x ) 的 FIRST 集合为 { d, a, x }。
- 这两个 FIRST 集合存在交集 { x }。
结论:
由于 S 的两个产生式在 FIRST 集合上有重叠(都包含 x),在遇到输入符号 x 时,解析器无法确定选择哪一个产生式。因此,文法 (1) 不是 LL(1) 文法。
[ \begin{aligned} S &\rightarrow T \ P \ T &\rightarrow + \ P \ T \mid \epsilon \ P &\rightarrow ( \ S \ ) \mid a \end{aligned} ]
步骤 1:检查左递归
- 文法中不存在直接或间接的左递归。
步骤 2:计算 FIRST 和 FOLLOW 集合
-
FIRST 集合:
- FIRST(S):由 ( S \rightarrow T \ P ) 推导,依赖于 FIRST(T)。
- FIRST(T):
- ( T \rightarrow + \ P \ T ),因此包含 +。
- ( T \rightarrow \epsilon ),因此也包含 ε。
- FIRST(T) = { +, ε }。
- FIRST(T P):
- 如果 ( T \rightarrow + \ P \ T ),则 FIRST(T P) 包含 +。
- 如果 ( T \rightarrow \epsilon ),则 FIRST(T P) = FIRST(P)。
- FIRST(P):
- ( P \rightarrow ( \ S \ ) ),因此包含 (。
- ( P \rightarrow a ),因此包含 a。
- FIRST(P) = { (, a }。
- 因此,FIRST(S) = { +, (, a }。
-
FOLLOW 集合:
- FOLLOW(S):由 ( P \rightarrow ( \ S \ ) ) 推导,FOLLOW(S) 包含 )。
- FOLLOW(T):
- 由 ( S \rightarrow T \ P ),FOLLOW(T) = FIRST(P) = { (, a }。
- FOLLOW(P):
- 由 ( S \rightarrow T \ P ),FOLLOW(P) = FOLLOW(S) = { ) }。
步骤 3:检查冲突
-
对于非终结符 T,有两个产生式:
- ( T \rightarrow + \ P \ T ) 的 FIRST 集合为 { + }。
- ( T \rightarrow \epsilon ),因此需要确保 FIRST(+ P T) 与 FOLLOW(T) 没有交集。
- FIRST(+ P T) = { + },FOLLOW(T) = { (, a }。
- 交集为空集,满足 LL(1) 条件。
-
对于非终结符 P,有两个产生式:
- ( P \rightarrow ( \ S \ ) ) 的 FIRST 集合为 { ( }。
- ( P \rightarrow a ) 的 FIRST 集合为 { a }。
- 这两个 FIRST 集合互不相交,满足 LL(1) 条件。
结论:
所有非终结符的产生式在 FIRST 和 FOLLOW 集合上均满足 LL(1) 文法的要求。因此,文法 (2) 是 LL(1) 文法。
- 文法 (1) 不是 LL(1) 文法,因为非终结符 S 的两个产生式在 FIRST 集合上存在交集,导致解析时存在二义性。
- 文法 (2) 是 LL(1) 文法,因为所有非终结符的产生式在 FIRST 和 FOLLOW 集合上均满足 LL(1) 的要求,没有产生任何冲突。