1. 基本思路
1. 从外部文件读入文法规则;
2. 分析是否存在左递归,如果存在则消除之;
3. 求取每个候选式的FIRST集;
4. 求各非终结符的FOLLOW集;
5. 根据LL(1)文法的3个判定条件判断其是否是LL(1)文法;
6. 如果是LL(1)文法就构造分析表,并判断输入的句子是否是该文法的句子。
2. 类设计
依照基本思路,每一项都用一个类来实现,再都多一个共用的存储文法规则的类。一共7个类,主要功能如下:
2.1 LL1类
入口类,一个main函数和一个无实参构造函数。构造函数实现读入文法规则的功能,并将每一行文法规则送Language类存储,最后调用LL1Help类对象,将控制权转给LL1Help类对象。
2.1.1 属性
private BufferedReader buffer;
private Language language;
private LL1Help ll1Help;
2.1.2 方法
public LL1()
public static void main(String[] args)
2.2 LL1Help类
辅助类,通过displayMessage方法控制程序的输入和输出。
2.2.1 属性
private Language language;
private LeftRecursive leftRecursive;
private FirstCollection firstCollection;
private FollowCollectionfollowCollection;
private AnalysisTable analysisTable;
2.2.2 方法
public LL1Help(Languagelanguage)
public void displayMessage() //控制程序的输入和输出
public boolean isLL_1() //判断输入的文法是否是LL(1)文法
privateSet<String> getMixed(List<Set<String>> sets)
// 得到多个集合的交集,用于判断LL(1)文法
private StringdisplaySet(Set<String> elementSet)
// 辅助集合的输出,如{a, b, c, d}
2.3 Language类
存储文法规则。由于它存储了文法,其他类都会用到Language类对象,Language类也定义了很多用于处理文法、语句的方法,供其他类调用。其中,很多方法都是基于可扩展的考虑。由于用例都是单个英文字母表示,没有用真实语言中的单词、语句这些来表示,所以为了今后的可扩展,预留了这些方法。
2.3.1 属性
public static String EmptyCharactor= "?"; //"?"表示“空” private String startCharactor; // 开始字符 private boolean startSwitch= true; // 辅助记录开始字符 privateLinkedHashMap<String, List<String>> grammar; // 存储文法规则的LinkedHashMap,键--非终结字符,值--候选式(列表) privateHashSet<String> terminalSet; // 终端字符集
2.3.2 方法
public Language() public boolean addProduction(String sentence) // 给定一条语句添加文法 public void changeProduction(String nonTerminal, List<String>rightParts) // 按产生式的左右两部分修改文法规则 public void removeProduction(String nonTerminal) // 删除非终端字符参数所在的产生式 publicSet<String> getNonTerminalSet() // 返回非终端字符集 publicSet<String> getTerminalSet() // 返回终端字符集 publicList<String> getRightPartsOfProduction(String nonTerminal) // 返回产生式的右部,即各候选式 public boolean isTerminal(String charactor) // 判断是否是终端字符 public void displayLanguage() // 输出文法规则 public StringgetStartCharactor() // 返回开始字符 public StringgetFirstWord(String sentence) // 返回候选式的首字符 public StringgetLastWord(String sentence) // 返回候选式的末字符 publicList<String> getEachWord(String sentence)// 返回候选式的每个字符
2.4 LeftRecursive类
处理左递归。没有单独的去判断文法是否存在左递归,而是在消除左递归的过程中间接判断是否存在左递归。
2.4.1 属性
private Language language; public boolean doneRemove; // 标记是否存在左递归
2.4.2 方法
publicLeftRecursive(Language language) private void removeLeftRecursive() // 消除文法中的左递归 private boolean removeDirectLeftRecursive(String nonTerminal, List<String> newRightParts, Map<String,String> mapping) // 消除直接左递归 private StringgetNewNonTerminal() // 得到一个新的非终结字符 private void removeUnnecessary() // 清除多余的产生式
2.5 FirstCollection类
处理FIRST集。主要是一个计算每个非终端字符FIRST集的setFirst方法和一个返回查询字符串的FIRST集的getFirst方法。
2.5.1 属性
private Language language; private final Map<String, Set<String>> firstCollection; // 存储各非终端字符的FIRST集,键--非终端字符,值--其FIRST集的字符集合
2.5.2 方法
publicFirstCollection(Language language) private void initFirstCollection() /* 初始化FIRST集,就是给每个非终端字符调用setFirst方法,并将返回的集合保存到实例变量firstCollection */ privateSet<String> setFirst(String word) // 求非终端字符的FIRST集 publicSet<String> getFirst(String sentence) // 返回查询字符串的FIRST集
2.6 FollowCollection类
处理FOLLOW集。其结构和FirstCollection类相同。
2.6.1 属性
private Language language; private FirstCollection firstCollection; private final Map<String, Set<String>> followCollection; // 存储各非终端字符的FOLLOW集,键--非终端字符,值--其FOLLOW集的字符集合
2.6.2 方法
publicFollowCollection(Language language, FirstCollectionfirstCollection) private void initFollowCollection() privateSet<String> setFollow(String nonTerminal, String from) // 注意这里有个from参数,是为了防止无限的递归调用 publicSet<String> getFollow(String nonTerminal)
2.7 AnalysisTable类
存储LL(1)文法分析表,由此实现LL(1)分析器。
2.7.1 属性
private Language language; private FirstCollection firstCollection; private FollowCollectionfollowCollection; private Map<String,Map<String, String>> table; // LL(1)文法分析表,键--非终端字符,值--终端字符以及对应的候选式 publicSet<String> columnSet; // LL(1)文法分析表的终端字符和句子终结符“#” privateStack<String> workStack = new Stack<String>(); // LL(1)分析器的分析栈 privateStack<String> inputStack = new Stack<String>(); // 对读入的句子,也存在一个栈中
2.7.2 方法
publicAnalysisTable(Language language, FirstCollection firstCollection, FollowCollection followCollection) private void initAnalysisTable() // 得到LL(1)文法分析表 public void displayAnalysisTable() // 输出LL(1)文法分析表 public boolean analyseSentence(String sentence) // 根据分析表分析输入的句子是否是该文法的句子,是的话返回true private void displayStack(String option, Stringoutput) // 输出栈内容
源码+报告:DBank