在上一次词法分析的基础之上,我完成了我的C语言的语法分析器。这次选择的是用Java来实现,采用了自顶向下的分析方法,其思想是根据输入token串的最左推导,试图根据现在的输入字符来判断用哪个产生式来进行推导。
使用LL(1)分析法的问题就是对文法的要求较高,要求消除回溯了左递归,以致于后来在写文法的时候遇到各种麻烦,做了各种消除(本来想偷个懒,不通过程序直接手动解决这个问题的,结果还是耗费了不少体力)。
预测分析法的关键在于预测分析表的构造。这就要求求出每个变量的FIRST集和FOLLOW集,并且根据这来求出每个产生式的SELECT集。所以只要在顺利的理解了求解非终结符的FIRST集和FOLLOW集的算法之后,语法分析的实现其实已经胜利在望了。
图1.求FIRST集的算法
/**
* 初始化First集
*
* @param expList
* @param mFirst
*/
public static List<String> initFirst(List<Grammar> expList,
List<String> mFirst) {
List<String> right = null;
for (int i = 0; i < expList.size(); i++) { // 初始化FIRST集
right = expList.get(i).getRightPart();
if (right.size() > 0) {
if (terminalSymbolMap.containsKey(right.get(0))) { // 若右部表达式的第一位为终结符则加入nts的FIRST集
mFirst.add(right.get(0));
}
}
}
return mFirst;
}
/**
* 求非终结符的FIRST集
*
* @param nts
* 非终结符
* @return FIRST集
*/
public static List<String> FIRST(NonTerminalSymbol nts) {
List<Grammar> expList = getMyExp(nts.getValue());
List<String> mFirst = new ArrayList<String>();
List<String> right = null;
mFirst = initFirst(expList, mFirst);// 初始化工作
for (int i = 0; i < expList.size(); i++) {
right = expList.get(i).getRightPart();
if (right.size() > 0) {
if (nonTerminalSymbolMap.containsKey(right.get(0))) {// 若右部表达式的第一位为非终结符则递归
combineList(mFirst,
FIRST(new NonTerminalSymbol(right.get(0))));
int j = 0;
while (j < right.size() - 1 && isEmptyExp(right.get(j))) { // 若X→Y1…Yn∈P,且Y1...Yi-1⇒*ε,
combineList(mFirst,
FIRST(new NonTerminalSymbol(right.get(j + 1))));
j++;
}
}
}
}
if (mFirst.contains("$"))
mFirst.remove("$");
combineList(nts.getFirst(), mFirst);
return mF