实现一个SLR(1)语法分析器,近期忙于他事,项目集和语法分析表暂时采用手动输入,有空再填坑,后附源码。git
SLR是基于LR(0)实现的,故先进行LR(0)分析。github
Tips:
龙书给的4.36算法伪代码写得过于简略,容易形成误导,本文给出具体算法和分析过程。web
代码在https://github.com/monimm/LLandLR算法
SLR(1)分析流程闭包
先上结果截图
svg
对输入符号串自左向右进行扫描,并将输入符逐个移入一个先进后出栈中,边移进边分析,一旦栈顶符号串造成某个句型的可归约串时,就用相应产生式的左部非终结符代替此可归约串。重复这一过程,直到归约到栈中只剩下文法的开始符号时分析成功。函数
移进-归约冲突this
即便知道了栈的全部内容以及接下来的k个输入符号,仍然没法判断应该进行移进仍是归约操做spa
归约-归约冲突code
没法在可能的多个归约方法中选择正确的归约动做。
增广文法
若是G是一个以S开始符号的文法,那么G的增广文法G’就是在G中加上新开始符号S’和产生式S’ → S而获得的文法。
目的是告诉分析器什么时候中止语法分析
LR(0)自动机
项目
文法G中的LR(0)项目由产生式和 · 组成
如产生式A→XYZ,产生四个项目
A→·XYZ A→X·YZ A→XY·Z A→XYZ·
产生式A→ε 生成一个项: A→·
项目集
项目集I的闭包:内核项集的闭包
通俗的理解是至关于一次等价替换
项集族
goto 函数
1.对产生式进行编号
2.构造规范的 LR(0)项目集族
3.构造LR(0)语法分析表
Action[i, a]结果
Goto[i, X]结果
4.执行语法分析程序
s为状态栈顶状态,a为待处理符号,将状态0入状态栈
执行循环{
若是查表为移进状态t,即st,
若是查表为归约A→ β,即rt,t为状态
}
源码:
public void analyzeLR() {
action = "";
index = 0;
stackState.push("0");
char a = strInput.charAt(index);
System.out.println("****************LR分析过程**********");
System.out.println(" State Symbol Input Action");
this.displayLR();
while (true) {
String s = stackState.peek();
// 查表为移进
if (Action(s, a).charAt(0) == 's') {
stackState.push(Action(s, a).substring(1));
stackSymbol.push(a);
a = strInput.charAt(++index);
action = "shift ";
displayLR();
}
// 查表为归约
else if (Action(s, a).charAt(0) == 'r') {
// 获取文法串
String str = LRGS[Integer.parseInt(Action(s, a).substring(1)) - 1];
int len = str.substring(3).length();
// 弹出右部长度的符号和状态
for (int i = 0; i < len; i++) {
stackSymbol.pop();
stackState.pop();
}
// goto的值进栈
String t = stackState.peek();
stackState.push(Action(t, str.charAt(0)));
stackSymbol.push(str.charAt(0));
action = "reduce:" + str;
displayLR();
} else if (Action(s, a) == "acc")
break;
else
return;
}
System.out.println("analyze LR successfully");
System.out.println("****************LR分析过程**********");
}
1.构造SLR分析表
2.同LR(0)
SLR描述能力有限