上次說到了驅動表,這裏給出利用驅動表進行預測分析的算法實現(原書僞碼見p144)
syn_unit end(0);//結束符
syn_unit start(mode, mesh_table[mode]->src.lex, 0, syn_unit::NONTERMINATOR);//mode爲開始符號的參數
stack<syn_unit> stk;
stk.push(end);
stk.push(start);
int pos = 0;
auto lx_unit = lex->getNextToken(code, pos);//讀入第一個詞法單元
while (stk.top() != end && pos < code.length()){
auto&cur_sig = stk.top();
switch (cur_sig.type){//符號類型
case syn_unit::LEX:
if (lx_unit->compare(cur_sig.token)){//匹配
output(lx_unit->token);//處理匹配結果
stk.pop();
}
else{//失配 嘗試別的?
report("不匹配的類型:"+lx_unit->token);
}
lx_unit = lex->getNextToken(code, pos);//匹配後才後移
break;
case syn_unit::NONTERMINATOR:
auto&prod = mesh_table[cur_sig.token];//獲取產生式組
if (prod->drivetable.find(lx_unit) != prod->drivetable.end()){//該單詞在驅動表中
stk.pop();
auto&dst = prod->dst[prod->drivetable[lx_unit]];//選擇產生式
for (auto&var = dst.rbegin(); var != dst.rend(); var++)
stk.push(*var);//展開並逆序壓入棧
}
break;
}
}
驅動表是是一個二維數組,其行和列分別用產生式頭(非終結符)和當前詞法單元(終結符)爲索引,構造這個表需要每個產生式的FIRST集合以及FOLLOW集合,每個產生式組(各個產生式以‘|’分割開來)的FIRST集合是互不相交的(LL(1)文法的要求),因此根據FIRST集合中的終結符可以確定產生式,但這不是唯一確定,因爲FIRST集合中可能有空符ε的存在,如果ε存在,則需要查看其FOLLOW集合,將FOLLOW集合中含有該詞法單元的產生式添加到表中。
上次的結構中沒有FOLLOW集合,大致說一下FOLLOW集合的構成。舉個例子:A->ABc,其中A B爲非終結符,c爲終結符,A的FOLOW集合在這個產生式中就是FIRST(B)的內容,如果FIRST(B)含有ε,那麼還需要添加c。
至此預測分析器的內容大致結束,由於代碼太長不適合貼出,只留下運行結果。
可以看出跟詞法分析的結果類似,但不同的是每個數字都輸出爲詞法單元標識,而不是具體值。每個詞法單元所含的具體值是其一種屬性,需要在制導翻譯的過程中獲得,並通過產生式的語義動作進行運算,得到翻譯結果。