第五章作业10
S → a S→∧ S→ (T) T→ ST’ T’→ ,ST’ T’→ ε
2计算FIRST集
3计算FOLLOW集
FIRST S a∧(
T a∧ ( T’ ε ,
FOLLOW S #, ) T) T’ )
由S→ (T) 得Follow(T)={)} 由T→ ST’ 得 由于T’能推出ε 所以Follow(S)= (First(T’)-{ε}) Follow(T)={ , } { ) } 由T→ ST’ 得 Follow(T’)= Follow(T)={ ) }
T’;
end
else if TOKEN ≠‘)’ then ERROR;
end;
可以不写,但写成else ERROR;是错误的 也可以写成: else if TOKEN =‘)’ then return
else ERROR; 但是不能写成 else if TOKEN =‘)’ then GetNext(Token)
1 文法G[S]
S→ a |∧ |(T)
T→ T,S | S
(2)给出(a,(a,a))和 (((a,a), ∧,(a)),a)的最左推导
S(T) (T,S) (S,S) (a,S) (a,(T)) (a,(T,S)) (a,(S,S)) (a,(a,S)) (a,(a,a))
S (T) (T,S) (S,S) ((T),S) ((T,S),S) ((T,S,S),S) ((S,S,S),S) (((T),S,S),S) (((T,S),S,S),S) (((S,S),S,S),S) (((a,S),S,S),S) (((a,a),S,S),S) (((a,a), ∧,S),S) (((a,a), ∧,(T)),S) (((a,a), ∧,(S)),S) (((a,a), ∧,(a)),S)
SELECT(T→ ST’ ) ={ a, ∧,( }
SELECT(T ’→ ,ST’ ) ={ , }
SELECT(T ’→ ε) ={ ) }
是LL(1)文法,构造预测分析表如下:
a
∧
(
S S→a S→ ∧ S→(T)
T T→ST’ T→ST’ T→ST’
T’
) T’→ ε
,
#
T’→ ,ST’
(4)给出输入串(a,a)#的分析过程,并说明该串是否为G的句子。
select(S→a) 和select(S→ ∧) 和select(S→(T))两两不相交 Select(T ’→ ,ST’ ) ∩ select(T ’→ ε) = Φ 因为具有相同左部的产生式的SELECT集两两交集为空,所以此 文法是LL(1)文法。
c) 对每个非终结符写出不带回溯的递归子程序
begin
If TOKEN=‘a’ then GETNEXT(TOKEN)
else if TOKEN=‘∧’ then GETNEXT(TOKEN) else if TOKENI)=f ‘T(没o’ k有en被≠读’)’掉th,en变E量RTRoOkRen;(=‘)错’,误S)后续的
then begin过程GE处T理NE的X第T(一TO个K字EN为);‘)’,导致出错
a
∧
S S→a S→ ∧
T T→ST’ T→ST’
T’
( S→(T) T→ST’
) T’→ ε
,
#
T’→ ,ST’
步骤 分析栈 1 #S 2 #)T( 3 #)T 4 #)T’S 5 #T’a 6 #)T’ 7 #)T’S,
剩余输入串 (a,a)# (a,a)# a,a)# a,a)# a,a)# ,a)# ,a)#
用到的一些子过程: ➢过程GETNEXT负责读入下一个TOKEN字 ➢过程ERROR负责报告语法错误
约定: ➢全局变量TOKEN存放已读入的TOKEN字 ➢过程进入时变量TOKEN存放了一个待匹配的TOKEN 字 ➢退出过程时,变量TOKEN中仍存放着一个待匹配的 TOKEN字。
递归子程序的写法:
所用产生式 S→(T) ( 匹配 T→ST’ S→a a 匹配 T’→,ST’ , 匹配
a
∧
S S→a S→ ∧
T T→ST’ T→ST’
T’
( S→(T) T→ST’
) T’→ ε
,
#
T’→ ,ST’
8 #)T’S
a)#
9 #)T’a
a)#
10 #)T’
)#
11 #)
)#
12 #
#
S→a a 匹配 T’→ ε ) 匹配 接受
else ERROR;
procedure T ; begin S;
T’ end;
/* T→ ST’ 对应的程序*/
(3)经改写后的文法是否是LL(1)的?给出它的预测分 析表。
已求得产生式的SELECT集
SELECT(S → a ) ={ a }
SELECT(S→∧) ={ ∧ }
SELECT(S→ (T)) ={ ( }
4计算SELECT集
SELECT(S → a ) ={ a } SELECT(S→∧) ={ ∧ } SELECT(S→ (T)) ={ ( } SELECT(T→ ST’ ) =First(ST’)={ a, ∧,( } SELECT(T ’→ ,ST’ ) ={ , } SELECT(T ’→ ε) =Follow(T’)={ ) }
T;
if TOKEN=‘)’ then GETNEXT(TOKEN)
else ERROR;
end
else ERROR;
end;
procedure T’ ;
/*T’→ ,ST’|’ then begin GETNEXT(TOKEN); (容易出错)
S;
(((a,a), ∧,(a)),a)
(2)对文法G进行改写,然后对每个非终结符写出不 带回溯的递归子程序。
文法中含有左递归,一定不是LL(1)文法,不能应用 递归子程序法,所以 a) 消除左递归,改写后的文法是:
S → a | ∧ | (T) T→ ST’ T’→ ,ST’ | ε
b) 判断文法是否为LL(1)文法 S → a S→∧ S→ (T) T→ ST’ T’→ ,ST’ T’→ ε LL(1)文法的充分必要条件是:对每个非终结符A的任 意两个产生式,A→α ,A→β,满足 select(A→ α) ∩select(A→β)=Φ , LL(1)文法的判别: 1 求出能推出ε非终结符 { T’ }
➢若关于一个非终结符的产生式只有一条,直接按产生式右部 写程序,右部是终结符就进行匹配,是非终结符就调用相应的 子程序,如T→ ST’
➢若关于一个非终结符的产生式不只一条,按select集合写成if 条件语句,如: S → a, S→∧, S→ (T)
SELECT(S → a ) ={ a } SELECT(S→∧) ={ ∧ }
SELECT(S→ (T)) ={ ( }
➢若产生式右部为空串
可以不生成任何语句,或者按select集合,生成一条判断语句 如:SELECT(T ’→ ε) ={ ) }
生成:if Token ≠‘)’ then Error;
procedure S;
/* S → a | ∧| (T)对应的程序 */