您的位置:首页 > 其它

LL(1)文法first集

2017-04-08 11:56 671 查看
LL(1) 文法 first集

 思路:  利用递归(但普通递归的方法不能处理非终极符直接递归和间接递归的情况) 考虑到这种情况,见下方利用bfs遍历first集关系图的方法

第一步先计算可导空的非终极符集合

  令first(X)=空

  若 X->a... 则将a加入first(X) 

  若 X->ABC.. ,则计算first(A) ,first(B) ,first(C)..直到遇到第一个不导空的非终结符或者终极符,则将他们都加入first(X) 并除去^(空串)的情况

  若 右部可以导空,将右部所有的非终结符的first集加入first(X),并加上空串的情况

package first_collection;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* first集
* 第一步先计算可导空的非终极符集合
* 令first(X)=空
* 若 X->a... 则将a加入first(X)
* 若 X->ABC.. ,则计算first(A) ,first(B) ,first(C)..直到遇到第一个不导空的非终结符或者终极符,则将他们都加入first(X) 并除去^(空串)的情况
* 若 右部可以导空,将右部所有的非终结符的first集加入first(X),并加上空串的情况
*
* @author parting_soul
*
*/
public class FirstCollection {
private Set<Character> emptyNonTerminal;
private List<Rule> ruleLists;
private Set<Character> terminalC;
private Set<Character> nonterminalC;
private Map<String, Set<Character>> first;

public FirstCollection() {
ruleLists = new ArrayList<>();
terminalC = new HashSet<>();
nonterminalC = new HashSet<>();
init();
}

/**
* 输入产生式,求出可导空的非终结符
*/
private void init() {
inputRuleLists();
// 计算可导空的非终结符集合
EmptyNonterminalSet nonterminalSet = new EmptyNonterminalSet(ruleLists);
nonterminalSet.solve();
emptyNonTerminal = nonterminalSet.getR();
first = new HashMap<String, Set<Character>>();
initRuleVisit();
}

private void initRuleVisit() {
for (Rule r : ruleLists) {
r.isVisit = false;
}
}

public void getTerminalFirst(char noTernimalLeft) {
Rule r = null;
Set<Character> terminalFirstSet = null;
// 判断之前是否存在该非终结符的first集
if ((terminalFirstSet = first.get(noTernimalLeft + "")) == null) {
// 没有计算过,新建一个集合用来保存该非终结符的first集
terminalFirstSet = new HashSet<>();
first.put(noTernimalLeft + "", terminalFirstSet);
// System.out.println(noTernimalLeft + " create ");
}
for (int i = 0; i < ruleLists.size(); i++) {
// 遍历所有的产生式,计算每一个左边为该非终结符产生式的first集
r = ruleLists.get(i);
// 如果该产生式别计算过,直接选择下一个产生式
if (r.isVisit)
continue;
if (r.left.equals(noTernimalLeft + "")) {
// System.out.println(r);
// 找到左部为该非终极符的产生式,标记为访问过
r.isVisit = true;
String right = r.right;
for (int j = 0; j < right.length(); j++) {
// 右部从左到右扫描每一个字符
char c = right.charAt(j);
if (!isNonTerminal(c)) {
// 如果是非终结符,直接加入到first集,然后停止计算
terminalFirstSet.add(c);
// System.out.println(r.left + " -> " + r.right + " " +
// c);
break;
} else {
// 如果当前为非终结符,递归计算该非终结符的first集
getTerminalFirst(c);
// System.out.println(r.left + " -> " + r.right + " " +
// c + " nonterminal " + first.get(c + ""));
// 将该非终结符的first集加入当前待求的first集中
terminalFirstSet.addAll(first.get(c + ""));
// 除去空串
terminalFirstSet.remove('^');
if (!emptyNonTerminal.contains(c)) {
// 如果当前非终结符不可导空,不用继续计算,跳出循环
break;
}
}
}
// 判断当前产生式最后一个字符是否可导空
char last = right.charAt(right.length() - 1);
if (emptyNonTerminal.contains(last)) {
// 可导空则加入空串
terminalFirstSet.add('^');
}
}
}
}

public Map<String, Set<Character>> getFirstCollection() {
for (Character c : nonterminalC) {
// System.out.println(" current " + c);
// 遍历每一个非终结符,求出该非终结符的first集
getTerminalFirst(c);
}
return first;
}

public static void main(String[] args) {
FirstCollection collection = new FirstCollection();
collection.printTerAndNon();
Map<String, Set<Character>> first = collection.getFirstCollection();
System.out.println(first);
}

/**
* 输入产生式
*/
private void inputRuleLists() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("rule.txt"))));
String str = null;
while ((str = reader.readLine()) != null) {
// System.out.println(str);
saveRule(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
reader = null;
}
}
}
}

/**
* 分析产生式
*
* @param str
*/
private void saveRule(String str) {
String[] strs = str.split("->");
// System.out.println(strs.length);
if (strs.length == 2) {
Rule r = new Rule();
r.left = strs[0];
r.right = strs[1];
if (isNonTerminal(r.left.charAt(0))) {
nonterminalC.add(r.left.charAt(0));
for (int i = 0; i < r.right.length(); i++) {
char c = r.right.charAt(i);
if (!isNonTerminal(c)) {
terminalC.add(c);
} else {
nonterminalC.add(c);
}
}
ruleLists.add(r);
}
}
}

void printTerAndNon() {
System.out.println("终结符:");
for (Character c : terminalC) {
System.out.print(c + " ");
}
System.out.println();
System.out.println("非终结符:");
for (Character c : nonterminalC) {
System.out.print(c + " ");
}
System.out.println();
System.out.println("产生式");
for (Rule r : ruleLists) {
System.out.println(r.left + "->" + r.right);
}
System.out.println("可导空非终极符");
System.out.println(emptyNonTerminal);
}

/**
* 是否为终极符
*
* @param c
* @return
*/
private boolean isNonTerminal(char c) {
if (c >= 'A' && c <= 'Z') {
return true;
}
return false;
}

}

/**
* 求出可导空的非终极符集合类
*
* @author parting_soul
*
*/
class EmptyNonterminalSet {
private List<Rule> L;

private Set<Character> R = new HashSet<>();

public EmptyNonterminalSet(List<Rule> L) {
this.L = L;
}

public Set<Character> getR() {
return R;
}

public void solve() {
// 先扫描一遍所有的产生式,将右端为空的且左端为终结符的产生式左端加入集合R中(这里^号表示空)
for (int i = 0; i < L.size(); i++) {
Rule r = L.get(i);
if (r.right.equals("^") && !isTerminator(r.left.charAt(0))) {
R.add(r.left.charAt(0));
r.isVisit = true;
}
}

int rLength = 0;
while (rLength != R.size()) {
rLength = R.size();
for (int i = 0; i < L.size(); i++) {
Rule r = L.get(i);
if (!r.isVisit && isBelongToR(r.right)) {
R.add(r.left.charAt(0));
r.isVisit = true;
}
}
}
}

/**
* 判断产生式右端的所有字符是否属于R
*
* @return
*/
private boolean isBelongToR(String right) {
for (int i = 0; i < right.length(); i++) {
if (!R.contains(right.charAt(i))) {
// System.out.println(right.charAt(i));
return false;
}
}
return true;
}

// 判断是否是终结符
public boolean isTerminator(Character c) {
return Character.isLowerCase(c);
}

public void print() {
for (Rule r : L) {
System.out.println(r);
}
}

public void printR() {
for (Character c : R) {
System.out.print(c + " ");
}
System.out.println();
}

}

class Rule {
String left;
String right;
boolean isVisit;

@Override
public String toString() {
return "Rule [left=" + left + ", right=" + right + ", isVisit=" + isVisit + "]";
}

}

利用bfs的方法

first集 思想: 利用图的广度遍历

对文法先进行预处理,求出每一个非终结符的出度

然后将待求的非终结符加入到队列,并标记为访问过,然后开始广度优先遍历,

队列为空,则停止遍历,若出队的是终极符,则加入到该非终结符的first集中

若出队的是非终结符,则将该非终结符中没有被访问过的出度加入到队列中

package first_collection_bfs;

import java.io.*;
import java.util.*;

/**
* first集 思想: 利用图的广度遍历
* 对文法先进行预处理,求出每一个非终结符的出度
* 然后将待求的非终结符加入到队列,并标记为访问过,然后开始广度优先遍历,
* 队列为空,则停止遍历,若出队的是终极符,则加入到该非终结符的first集中
* 若出队的是非终结符,则将该非终结符中没有被访问过的出度加入到队列中
*
* @author parting_soul
*/
public class FirstCollection {
private Set<Character> emptyNonTerminal;
private List<Rule> ruleLists;
private Set<Character> terminalC;
private Set<Character> nonterminalC;
private Map<String, Set<Character>> first;
private Map<Character, Set<Character>> map;
private Queue<Character> queue;

private Map<Character, Boolean> isVisistMap;

public FirstCollection() {
ruleLists = new ArrayList<>();
terminalC = new HashSet<>();
nonterminalC = new HashSet<>();
map = new HashMap<>();
queue = new LinkedList<>();
isVisistMap = new HashMap<>();
init();
}

/**
* 输入产生式,求出可导空的非终结符
*/
private void init() {
inputRuleLists();
// 计算可导空的非终结符集合
EmptyNonterminalSet nonterminalSet = new EmptyNonterminalSet(ruleLists);
nonterminalSet.solve();
emptyNonTerminal = nonterminalSet.getR();
getMap();
first = new HashMap<>();
}

/**
* 预处理,得到每一个非终结符的出度
*/
private void getMap() {
for (char c : nonterminalC) {
for (int j = 0; j < ruleLists.size(); j++) {
Rule rule = ruleLists.get(j);
if (rule.left.equals(c + "")) {
Set<Character> characters = map.get(c);
if (characters == null) {
characters = new HashSet<>();
}
for (int k = 0; k < rule.right.length(); k++) {
char currentC = rule.right.charAt(k);
if ("^".equals(currentC + "")) break;
characters.add(currentC);
if (!isNonTerminal(currentC) || !emptyNonTerminal.contains(currentC)) {
break;
}
}
map.put(c, characters);
}

}
}
}

/**
* bfs求非终结符first
*
* @param noTernimalLeft
*/
public void getNonTerminalFirstByBFS(char noTernimalLeft) {
queue.clear();
//将待求的非终结符加入队列
queue.offer(noTernimalLeft);
//标记为访问过
isVisistMap.put(noTernimalLeft, true);
Set<Character> sets = new HashSet<>();
first.put(noTernimalLeft + "", sets);
while (queue.size() != 0) {
//队首出队
char currentC = queue.poll();
if (!isNonTerminal(currentC)) {
//如果是终结符加入到该非终结符的first中
sets.add(currentC);
continue;
}
//如果是非终结符,就遍历该非终结符的出度
Set<Character> characters = map.get(currentC);
for (char c : characters) {
if (!isNonTerminal(c)) {
//如果是终结符,直接加入队列
queue.offer(c);
continue;
}
//如果是非终结符就先判断是否访问过,没有访问过就入队,并标记为访问过
boolean isVisist = isVisistMap.get(c);
if (isVisist) continue;
isVisistMap.put(c, true);
queue.offer(c);
}
}

}

public Map<String, Set<Character>> getFirstCollection() {
for (Character c : nonterminalC) {
// System.out.println(" current " + c);
// 遍历每一个非终结符,求出该非终结符的first集
getNonTerminalFirstByBFS(c);
//重置非终结符为未访问
initNonTernimalVisit();
//若该非终结符可导空,加入^
if (emptyNonTerminal.contains(c)) {
first.get(c.charValue() + "").add('^');
}
}
return first;
}

private void initNonTernimalVisit() {
for (char c : nonterminalC) {
isVisistMap.put(c, false);
}
}

public static void main(String[] args) {
FirstCollection collection = new FirstCollection();
collection.printTerAndNon();
Map<String, Set<Character>> first = collection.getFirstCollection();
System.out.println(first);
}

/**
* 输入产生式
*/
private void inputRuleLists() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("rule1.txt"))));
String str = null;
while ((str = reader.readLine()) != null) {
// System.out.println(str);
saveRule(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
reader = null;
}
}
}
}

/**
* 分析产生式
*
* @param str
*/
private void saveRule(String str) {
String[] strs = str.split("->");
// System.out.println(strs.length);
if (strs.length == 2) {
Rule r = new Rule();
r.left = strs[0];
r.right = strs[1];
if (isNonTerminal(r.left.charAt(0))) {
nonterminalC.add(r.left.charAt(0));
isVisistMap.put(r.left.charAt(0), false);
for (int i = 0; i < r.right.length(); i++) {
char c = r.right.charAt(i);
if (!isNonTerminal(c)) {
terminalC.add(c);
} else {
nonterminalC.add(c);
}
}
ruleLists.add(r);
}
}
}

void printTerAndNon() {
System.out.println("终结符:");
for (Character c : terminalC) {
System.out.print(c + " ");
}
System.out.println();
System.out.println("非终结符:");
for (Character c : nonterminalC) {
System.out.print(c + " ");
}
System.out.println();
System.out.println("产生式");
for (Rule r : ruleLists) {
System.out.println(r.left + "->" + r.right);
}
System.out.println("可导空非终极符");
System.out.println(emptyNonTerminal);
}

/**
* 是否为非终极符
*
* @param c
* @return
*/
private boolean isNonTerminal(char c) {
if (c >= 'A' && c <= 'Z') {
return true;
}
return false;
}

}

/**
* 求出可导空的非终极符集合类
*
* @author parting_soul
*/
class EmptyNonterminalSet {
private List<Rule> L;

private Set<Character> R = new HashSet<>();

public EmptyNonterminalSet(List<Rule> L) {
this.L = L;
}

public Set<Character> getR() {
return R;
}

public void solve() {
// 先扫描一遍所有的产生式,将右端为空的且左端为终结符的产生式左端加入集合R中(这里#号表示空)
for (int i = 0; i < L.size(); i++) {
Rule r = L.get(i);
if (r.right.equals("^") && !isTerminator(r.left.charAt(0))) {
R.add(r.left.charAt(0));
r.isVisit = true;
}
}

int rLength = 0;
while (rLength != R.size()) {
rLength = R.size();
for (int i = 0; i < L.size(); i++) {
Rule r = L.get(i);
if (!r.isVisit && isBelongToR(r.right)) {
R.add(r.left.charAt(0));
r.isVisit = true;
}
}
}
}

/**
* 判断产生式右端的所有字符是否属于R
*
* @return
*/
private boolean isBelongToR(String right) {
for (int i = 0; i < right.length(); i++) {
if (!R.contains(right.charAt(i))) {
// System.out.println(right.charAt(i));
return false;
}
}
return true;
}

// 判断是否是终结符
public boolean isTerminator(Character c) {
return Character.isLowerCase(c);
}

public void print() {
for (Rule r : L) {
System.out.println(r);
}
}

public void printR() {
for (Character c : R) {
System.out.print(c + " ");
}
System.out.println();
}

}

class Rule {
String left;
String right;
boolean isVisit;

@Override
public String toString() {
return "Rule [left=" + left + ", right=" + right + ", isVisit=" + isVisit + "]";
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  编译原理 first集