博客 > 硬件&操作系统&网络&DevOps > 编译原理
# 语法分析-自顶向下 对给定的某编程语言的目标语句,由一个已知的文法G,从初始符号S开始不断对目标语句从左至右进行推导,最终将目标语句恰好匹配为一个符合文法规则的句子,则完成一次成功的自顶向下语法分析,若不能匹配,则视为出现语法错误。过程中可能因为产生式的多选性而产生回溯。 ## 提取左前缀 ![cb3b9f07d26dd7aad1feb055ff0a5592.png](/resources/bee4d3e2126444bebbfcd44d6cc83cc4) ## 消除左递归 - 对直接左递归:枚举原产生式的候选前缀(非左递归的分支,如bd|ε)成为原产生式的右部,每个枚举另外跟随一个 - 新定义的非终结符(如bdA'|A'),其循环生成原产生式的候选后缀(如cA'|adA'|ε) - 对间接左递归:带入相关子产生式,然后消除子产生式的左递归(如将S→Aa|b带入Sd产生Aad|bd) ![db15294ac06f4baa4f16fcd0a6616a2c.png](/resources/a753a70886a84d3eb1d49c2b158f75cc) ## 非终结符的后继终结符集 FOLLOW(X) 即X后可以直接跟什么终结符(或ε) - 若初始符号S可直接或间接推出以X结尾的串,则`$`$\in$FOLLOW(X) - 对所有包含X但不以X结尾的产生式中X后续的整个符号串$\beta$,有(FIRST($\beta$) - {ε})$\subset$FOLLOW(X) - 对所有直接以X结尾的产生式的左部A,有FOLLOW(A)$\subset$FOLLOW(X)。 - 对所有可能以X结尾的产生式(X之后可能全部推出ε)的左部A,有FOLLOW(A)$\subset$FOLLOW(X)。 - 对所有必然以X结尾的产生式(无法直接或间接推出不以X结尾的串)的左部A,有FOLLOW(A)=FOLLOW(X)。 在实际按照产生式的顺序依次进行推导的过程中,推导过程可能执行多次无放回的重复(因为规则中有环路)。 ## 文法符号串的首终结符集 FIRST(X) 即该文法符号串(可以有终结符和非终结符)可推出的首个终结符的集合。 - 对X是单个文法符号的情况: - 若X是终结符,则FIRST(X)={X} - 若X是非终结符且有$X\rightarrow Y_1\cdots Y_n$,则第一个包含终结符的FIRST($Y_i$) $\subset$ FIRST(X),$i=1,\cdots,n$ - 在无满足条件的FIRST($Y_i$)时,有ε$\in$FIRST($X$) - 若X是非终结符且有X→ε,则ε$\in$FIRST($A_i$) - 对X是文法符号串的情况,构造$X'\rightarrow X$,有FIRST($X'$)=FIRST($X$) ## 产生式的可选集 SELECT(X→α) 即可用该产生式推出的首个终结符的集合 - SELECT(X→α) = FIRST(α) - {ε} - SELECT(X→ε) = FOLLOW(X) ## LL(1)文法 ![bef625830f2b009bbaeffb98bde98035.png](/resources/861d0241948c46e6ab2840f6e699abde) ![1c53d2f62b0519e8d913e500d6014e4d.png](/resources/e672df4250a4462da74d1371b5b71e59) ## 预测分析 对LL(1)文法,可以构建预测分析表,其中列为输入字典的枚举,行为非终结符的枚举,单元格值代表目标推导过程的产生式 ![976f4733a1d06cc927c9bd7e10092e4e.png](/resources/f9574805956744e7be557517acab4990) 基于预测分析表和带有无穷栈的下推自动机,可以实现一个基于状态转移的预测分析:(如果不使用,则需手动实现基于规则的递归分析) ![93b97f74018080a71c1955bc14a10e8b.png](/resources/a164554151e94d1e8c8f441ca80bd4c9) 如下是使用一个栈和一个队列(即一个下推自动机)实现的预测分析/自动推导过程: ![a15a5d0186050059bcbd1ad01d20fbc0.png](/resources/51ab82e1482d457297315e14a9529b5a) ## 预测分析的错误处理 - 恐慌模式:忽略不能匹配的输入符号,直接匹配下一个输入符号(并报错) - 同步符号集:在推导某个非终结符时,若当前输入符号恰好是该非终结符对应的同步符号集中的元素,则强行终止此非终结符的推导,直接进入下一个文法符号的推导(并报错)。常取FOLLOW集中的元素作为一个非终结符的同步符号集 - 如果终结符在栈顶不能匹配,常用方法直接将其出栈(并报错) 综合上述方式,对LL(1)文法的预测分析可做如下错误处理方案: ![dee807bbd3c9e1a1ed9073c70ce6ffb5.png](/resources/551b1945fbe2411c98457171b929e738) ![24f4483d6c6949370ea376be001908ee.png](/resources/7ea0deafd9a64695b0a9d7e33a0b8ef7)