编译原理之LL1文法
原理讲解
- LL(1)是自上而下的分析方法,第一个
L
表示从左向右扫描输入串,第二个L
表示分析过程中将使用最左推导,最后一个1
表示只需要向右看一个符号就可以决定用哪个产生式进行推导 - 步骤
- 求出First集,FoLLow集
- 根据First集与Follow集求出Select集
- 根据Select集构造预测分析表
- 具体参见我的上一个博客.
实例
E->E+T|T
T->T*F|F
F->i|(E)
代码实现
以下为主要的
代码部分
package LL1;
import java.util.*;
public class LL1 {
// 预测分析表
private Map<String,Map<String,String>> analysisTable = new TreeMap<>();
// 分析栈
private Stack<String> analysisStack = new Stack<>();
// 输入符号栈
private Stack<String> inputStack = new Stack<>();
// 输入串
private String inputString ;
private Map<String , Set<String>> select;
private G g;
public LL1(Map<String, Set<String>> select, G g, String inputString) {
this.select = select;
this.g = g;
this.inputString = inputString;
}
public void startLL1() {
// 初始化
initLL1();
// 开始分析
startAnalysis();
}
// 开始分析
private void startAnalysis() {
String start = g.getpList().get(0).getKey(); // 默认第一个为 文法开始符号
// 将开始符号压入栈中
analysisStack.push(start);
// 输出
System.out.println("分析栈" + " " + "剩余输入串" + " " + "所用的产生式或匹配");
while (!(analysisStack.peek().equals("#")&&inputStack.peek().equals("#"))) {
String inputSymbol = inputStack.peek(); // 获取 输入栈的栈顶符号
String anlysisSymbol = analysisStack.peek(); // 获取分析栈的栈顶符号
if (isVNorVT(anlysisSymbol, g.getVT())) { // 如果分析栈顶是终结符
if (inputSymbol.equals(anlysisSymbol)) { // 两栈符号相同
System.out.println(analysisStack.toString() + " " + inputStack.toString() + " " + anlysisSymbol+ "匹配");
inputStack.pop();
analysisStack.pop();
} else { // 两栈符号不同
try {
throw new Exception("终结符不匹配,可能非LL1文法");
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}else {
String needAddanaly = analysisTable.get(anlysisSymbol).get(inputSymbol);
if (needAddanaly==null||needAddanaly.equals("")) { // 如果不存在,报错
try {
throw new Exception("非终结符的产生式获取的为空,可能非LL1文法");
} catch (Exception e) {
e.printStackTrace();
}
break;
} else if (needAddanaly.equals("ε")){ // 如果推导的为ε,需要弹出
System.out.println(analysisStack.toString() + " " + inputStack.toString() + " " + anlysisSymbol + "->" +needAddanaly);
analysisStack.pop();
} else { //有其他的话 需要压入栈中
System.out.println(analysisStack.toString() + " " + inputStack.toString() + " " + anlysisSymbol + "->" +needAddanaly);
addToStack(analysisStack, needAddanaly);
}
}
}
}
// 将符号压入 分析栈中
private void addToStack(Stack<String> analysisStack, String symbols) {
analysisStack.pop();
for (int i= symbols.length()-1; i>=0; i--) {
String symbol = symbols.charAt(i)+ "";
if (i>=1&&symbols.charAt(i)=='\'') {
symbol = symbols.charAt(i-1)+symbol;
--i;
}
analysisStack.push(symbol);
}
}
// 判断是终结符还是非终结符
private boolean isVNorVT(String charac , String[] value) {
boolean bool = false;
for (String val:value) {
if (charac.equals(val)) {
bool = true;
}
}
return bool;
}
// 初始化 LL1文法
private void initLL1(){
// 根据Select集构建预测分析表
setAnalysisTable();
// 构造 输入符号栈
setInputStack();
// 初始化 分析栈
setAnalysisStack();
}
// 构造分析表
private void setAnalysisTable() {
for (Map.Entry<String,Set<String>> set : select.entrySet()) { // 遍历 select
String key = set.getKey().split("->")[0];
String value = set.getKey().split("->")[1];
// 获取需要的终结符
String[] VTsymbols = new String[g.getVT().length+1];
VTsymbols[g.getVT().length] = "#";
System.arraycopy(g.getVT(), 0, VTsymbols, 0, g.getVT().length);
// 存储
Map<String, String> nowSymbol = new TreeMap<>();
for (String symbols: VTsymbols) {
if (set.getValue().contains(symbols)) {
nowSymbol.put(symbols,value);
} else { // 如果没有 , 则为空
nowSymbol.put(symbols, "");
}
}
if (analysisTable.get(key)== null) {
analysisTable.put(key,nowSymbol);
} else {
Map<String,String> lastSymbol = analysisTable.get(key); //之前存储过此类数据,需要合并
for (Map.Entry<String,String> entry:lastSymbol.entrySet()) {
if (!entry.getValue().equals("")&&nowSymbol.get(entry.getKey()).equals("")){
nowSymbol.put(entry.getKey(),entry.getValue());
}
}
analysisTable.get(key).putAll(nowSymbol);
}
}
System.out.println("预测分析表:");
System.out.println(analysisTable.toString());
}
// 构造输入符号栈
private void setInputStack() {
inputStack.push("#");
for (int i = inputString.length() -1; i>=0;i--) {
String symbol = inputString.charAt(i)+"";
inputStack.push(symbol);
}
System.out.println("输入符号栈:");
System.out.println(inputStack.toString());
}
// 构造分析栈
private void setAnalysisStack() {
analysisStack.push("#");
}
}
效果图