LR(0)语法分析器
- 实验目的:
根据LR(0)语法分析的原理,编写、调试一个语法分析代码程序,对输入的句子进行分析。
- 实验工具:
使用了Java语言进行编写 ,使用Java开发工具IntelliJ IDEA 。
- 实验过程分析:
3.1、进行对LR(0)语法分析过程的深入了解。首先我们需要在文件data. txt中保存我们想要分析的文法。(这里展示的是课本例题6.1)
3.2、利用Java文件读取类进行读取文件data. txt(如下伪代码)
BufferedReader bf = new BufferedReader(new FileReader(“这里输入文件地址”));
然后使用bf.readLine()就可以按行读取出文件中的句子。
String p = "";
while((p = bf.readLine()) != null){…要进行的操作…}
3.3、读取之后,使用数据结构数组保存非总结符和总结符。
结果输出:
3.4、同时利用链表left 和 right 保存文法的左右两部分,比如S’->S
Left链表就保存 S’,right链表就保存S。
3.5、之后,我们需要输出所有的加黑点的文法,这一步比较简单,直接遍历left和right ,然后根据right的长度进行移动黑点,再输出即可。
3.6、在这之后,我们需要构造出所有的状态来,来构造DFA,为此,我专门自定义了一个类,叫做DFA ,具体属性如图所示,可以完美表示单个状态,然后我们使用List<DFA>ok 用来保存整个状态连接图!
3.7、在对于状态图的构建上,我们的思路是,先把文法拓展一下,放入 S’->S 进入第1个状态,也就是T0,然后根据黑点的右部首个字符,如果他属于非终结符,意味着我们要拓展这个状态!这里拓展状态的算法是使用了递归回溯算法。
最终在不懈的努力下,完成了各个状态的保存,以及状态的转移:
3.8、接下来我们便需要构建LR(0)分析表了,我们知道LR(0)分析表包含了Action 表 和 Goto表,这里保存他们需要选择好的数据结构来保存。思来想去,最后还是选择了HashMap内置HashMap来保存数据。
我们根据所有的状态来进行遍历,同时在内部遍历一下终结符和非终结符的状态转移,也就是每个DFA对象的next中的数据,就可以将其保存。然后再输出时候,使用System.out.printf(“%-ns”); 来进行n位缩进,这样子输出来更好看。
3.9、最后,我们使用了while()循环输入一段句子,在句子最后判断有无#,加上它,然后进行语法分析。如果再分析过程,我们的HashMap中对应的值为空了,说明分析不对。具体情况如下:
如果输入的句子分析正确,我们就开始输出啦,对于数据的保存,我们又自定义了一个类,然后再对这个类进行对象数组的构建,用来保存一整个表:
4、实验结论:
此次实验,其实原理并不困难,难的是,将原理用代码展示出来,我们需要选择合适的数据结构还有算法才可以进行,这也应证了那句“程序 = 数据结构 + 算法“,总之,通过此次实验,我们学到了很多语法分析的知识,对于其分析过程有了很深入的了解。
5、最终效果:
6、最终代码:
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.*;
import java.util.logging.Level;
public class Main {
public static List<String> left;
public static List<String> right;
//产生式 比如 :A -> a
//构造dfa
public static List<DFA> ok; //已经搞好的dfa
public static Map<Integer,Map<Character,String>>Action;
public static Map<Integer,Map<Character,Integer>>Goto;
public static Map<String,Integer> R; //第几条产生式规约
public static boolean is[];
public static char ZhongJie[]; //保存终结符
public static char FeiZhongJie[]; //保存非终结符
public static int ZhongJieNum = 0;
public static int FeiZhongJieNum = 0;
public static class DFA{
Integer id;
List<String> DFAleft;
List<String> DFAright;
Map<Character,Integer> next;
public DFA(){
}
public DFA(Integer id, List<String> DFAleft, List<String> DFAright, Map<Character, Integer> next) {
this.id = id;
this.DFAleft = DFAleft;
this.DFAright = DFAright;
this.next = next;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<String> getDFAleft() {
return DFAleft;
}
public void setDFAleft(List<String> DFAleft) {
this.DFAleft = DFAleft;
}
public List<String> getDFAright() {
return DFAright;
}
public void setDFAright(List<String> DFAright) {
this.DFAright = DFAright;
}
public Map<Character, Integer> getNext() {
return next;
}
public void setNext(Map<Character, Integer> next) {
this.next = next;
}
}
//打开文件,将所有的产生式存进List数据结构
public static void OpenFile() throws Exception{
left.add("S'");
right.add("S");
String property = System.getProperty("user.dir");
BufferedReader bf = new BufferedReader(new FileReader(property+"\\data.txt"));
String p = "";
while((p = bf.readLine()) != null){
for(int k = 0;k<p.length();k++){
char ch = p.charAt(k);
if(is[ch]){
continue;
}
if(ch >= 'A' && ch <= 'Z'){ //非终结符
FeiZhongJie[FeiZhongJieNum++] = ch;
}
else { //终结符
if(ch != '-' && ch != '>')
ZhongJie[ZhongJieNum++] = ch;
}
is[ch] = true;
}
String a[] = p.split("->");
String b[] = a[1].split("\\|");
for(int i = 0;i<b.length;i++){
left.add(a[0]);
right.add(b[i]);
}
}
bf.close();
}
//在头部加点
public static String addFirstPoint(String str){
return "."+str;
}
public static int getPointPosition(String str){
return str.indexOf(".");
}
//往右边移动点
public static String movePoint(String str){
if(getPointPosition(str) != str.length()-1){
String[] a = str.split("\\.");
String newStr = a[0]+a[1].charAt(0)+"."+a[1].substring(1);
return newStr;
}
return str;
}
//
public static void OutWenFa() throws Exception{
R = new HashMap<>();
OpenFile();
for(int i = 0;i<left.size();i++){
String s = left.get(i) + "->" + right.get(i);
R.put(s,i);
System.out.println(s);
}
System.out.println("----------------------------------------------------------------");
}
public static void OutJiaDianWenFa(){
for(int i = 0;i<left.size();i++){
String a1 = left.get(i);
String a2 = addFirstPoint(right.get(i));
while(getPointPosition(a2) != a2.length()-1){
System.out.println(a1+"->" + a2);
a2 = movePoint(a2);
}
System.out.println(a1+"->" + a2);
}
System.out.println("----------------------------------------------------------------");
}
//扩展非终结符X的项目
public static boolean isok[] = new boolean[1001];
public static void soloveTuoZhanDFA(List<String> le , List<String>ri ,String X){
int size = left.size();
for(int i = 0;i<size;i++){
if(X.equals(left.get(i))){ // 如果
le.add(left.get(i)); // 添加左边的
ri.add(addFirstPoint(right.get(i)));//添加右边的
if(right.get(i).charAt(0) >= 'A' && right.get(i).charAt(0) <= 'Z' && !isok[right.get(i).charAt(0)]){
String nextStr = ""+right.get(i).charAt(0);
isok[right.get(i).charAt(0)] = true;
soloveTuoZhanDFA(le,ri,nextStr);
}
}
}
}
public static void TuozhanDFA(DFA dfa){ //拓展dfa
List<String> dfAright = dfa.getDFAright();
int lenth = dfAright.size();
List<String> dfaLeft = new LinkedList<>();
List<String> dfaRight = new LinkedList<>();
for(int l = 0;l<lenth;l++){
String rg = dfAright.get(l);
int len = rg.length();
int pos = getPointPosition(rg);
if(pos < len-1 && rg.charAt(pos+1) >= 'A' && rg.charAt(pos+1) <= 'Z'){
String Arg = ""+rg.charAt(pos+1);
Arrays.fill(isok,false);
isok[Arg.charAt(0)] = true;
soloveTuoZhanDFA(dfaLeft,dfaRight,Arg);
int sz = dfaLeft.size();
for(int i = 0;i<sz;i++){
dfa.getDFAleft().add(dfaLeft.get(i));
dfa.getDFAright().add(dfaRight.get(i));
}
}
}
}
// 状态
public static void OutZhuangTai(){
//先新建一个S'->S吧。。。、
List<String> firstLeft = new LinkedList<>();
List<String> firstRight = new LinkedList<>();
firstLeft.add("S'");
firstRight.add(addFirstPoint("S"));
DFA dfa = new DFA();
dfa.setDFAleft(firstLeft);
dfa.setDFAright(firstRight);
ok.add(dfa);
TuozhanDFA(dfa);
}
public static int QuChuChongFu(){ //去除重复
int sz = ok.size();
for(int i =0;i<sz-1;i++){
if(ok.get(i).getDFAleft().get(0).equals(ok.get(sz-1).getDFAleft().get(0)) &&
ok.get(i).getDFAright().get(0).equals(ok.get(sz-1).getDFAright().get(0))){
ok.remove(sz-1);
return i;
}
}
return -1;
}
public static void createNewDFA(String le,String ri){ //创建新的状态
DFA dfa = new DFA();
ri = movePoint(ri);
dfa.setId(ok.size());
List<String> LEFT = dfa.getDFAleft() == null ? new LinkedList<>() : dfa.getDFAleft();
List<String> RIGHT = dfa.getDFAright() == null ? new LinkedList<>() : dfa.getDFAright();
LEFT.add(le);
RIGHT.add(ri);
dfa.setDFAleft(LEFT);
dfa.setDFAright(RIGHT);
ok.add(dfa);
}
public static boolean Exist[] = new boolean[1001];
public static void AddNewZhuangTai(){
for(int i = 0;i<ok.size();i++){
Arrays.fill(Exist,false);
for(int j = 0;j<ok.get(i).getDFAleft().size();j++){
String riStr = ok.get(i).getDFAright().get(j);
if(riStr.indexOf(".") == riStr.length()-1){
break;//不可以移动黑点
}
int pointPosition = getPointPosition(riStr);
char c = riStr.charAt(pointPosition+1);
if(Exist[c]){
continue;
}
createNewDFA(ok.get(i).getDFAleft().get(j),ok.get(i).getDFAright().get(j));
Exist[c] = true;
for(int k = j+1;k<ok.get(i).getDFAleft().size();k++){
String s = ok.get(i).getDFAright().get(k);
if(s.indexOf(".") == s.length()-1){
continue;
}
int pointPosition1 = getPointPosition(s);
if(s.charAt(pointPosition1+1) == c){
String s1 = ok.get(i).getDFAleft().get(k);
String s2 = ok.get(i).getDFAright().get(k);
s2 = movePoint(s2);
ok.get(ok.size()-1).getDFAleft().add(s1);
ok.get(ok.size()-1).getDFAright().add(s2);
System.out.println(s1+"===>"+s2);
}
}
int chong = QuChuChongFu();
if(chong == -1){
TuozhanDFA(ok.get(ok.size()-1));///用第一行拓展
int dotpos = getPointPosition(riStr);
Map<Character,Integer> map = ok.get(i).getNext() == null ? new HashMap<>() : ok.get(i).getNext();
map.put(riStr.charAt(dotpos+1) , ok.size()-1);
ok.get(i).setNext(map);
}
else{
int dotpos = getPointPosition(riStr);
Map<Character,Integer> map = ok.get(i).getNext() == null ? new HashMap<>() : ok.get(i).getNext();
map.put(riStr.charAt(dotpos+1) , chong);
ok.get(i).setNext(map);
}
}
}
}
public static void PrintZhuangTai(){
System.out.println("--------所有的状态--------");
int size = ok.size();
for(int i = 0;i<size;i++){
System.out.println("I"+i+":");
for(int j = 0;j<ok.get(i).getDFAleft().size();j++){
System.out.println(ok.get(i).getDFAleft().get(j) + " -> " + ok.get(i).getDFAright().get(j));
}
System.out.println("-------------------");
}
}
public static void OutBiaoLine(){ //输出表的行线
System.out.print("-------");
for(int i = 0;i<FeiZhongJieNum+ZhongJieNum;i++){
System.out.print("-------");
}
System.out.println("-");
}
public static void PrintShu(){
System.out.print("|");
}
public static void PrintBiao(){
OutBiaoLine();//输出表的行线
PrintShu();
System.out.printf("%-5s"," 状态");
for(int i = 0;i<ZhongJieNum;i++){
PrintShu();
System.out.printf("%-6s"," "+ZhongJie[i]);
}
for(int i = 0;i<FeiZhongJieNum;i++){
PrintShu();
System.out.printf("%-6s"," "+FeiZhongJie[i]);
}
System.out.println("|");
// for(int i = 0;i<ok.size();i++){ // 测试输出Action
// Map<Character, String> characterStringMap = Action.get(i);
// for(int j = 0;j<ZhongJieNum;j++){
// char ch = ZhongJie[j];
// String s = characterStringMap.get(ch);
// System.out.print(s+" ");
// }
// System.out.println();
// }
// System.out.println("Goto");
// for(int i = 0;i<ok.size();i++){ //测试输出Goto
// Map<Character, Integer> characterStringMap = Goto.get(i);
// for(int j = 0;j<FeiZhongJieNum;j++){
// char ch = FeiZhongJie[j];
// int s = characterStringMap.get(ch);
// System.out.print(s+" ");
// }
// System.out.println();
// }
for(int i = 0;i<ok.size();i++){
OutBiaoLine();
PrintShu();
System.out.printf("%-6s"," "+i);
for(int j = 0;j<ZhongJieNum;j++){
char ch = ZhongJie[j];
if(Action.get(i).get(ch).equals("-1")){
PrintShu();
System.out.print(" ");
}
else{
PrintShu();
System.out.printf("%-6s"," "+Action.get(i).get(ch));
}
}
for(int j = 0;j<FeiZhongJieNum;j++){
char ch = FeiZhongJie[j];
if(Goto.get(i).get(ch) != -1){
PrintShu();
System.out.printf("%-6s"," "+Goto.get(i).get(ch));
}
else{
PrintShu();
System.out.print(" ");
}
}
System.out.println("|");
}
OutBiaoLine();
}
public static void GouJianACTION(){ //构造ACTION表
Action = new HashMap<>();
for(int i = 0;i<ok.size();i++){
Map<Character,String> ac = new HashMap<>();
for(int j = 0;j<ZhongJieNum;j++){
char ch = ZhongJie[j];
if(i == 1){
if(ch == '#'){
ac.put(ch,"acc");
}
else{
ac.put(ch,"-1");
}
continue;
}
if(ok.get(i).getNext() == null){
String s = ""+ok.get(i).getDFAleft().get(0)+"->"+ok.get(i).getDFAright().get(0);
s = s.substring(0,s.length()-1);
ac.put(ch,"r"+R.get(s));
continue;
}
if(ok.get(i).getNext().containsKey(ch)){
ac.put(ch,"s"+ok.get(i).getNext().get(ch));
}
else{
ac.put(ch,"-1");
}
}
Action.put(i,ac);
}
}
public static void GouJianGoto(){//构建Goto表
Goto = new HashMap<>(); // Map<Integer,Map<Character,Integer>>Goto;
for(int i = 0;i<ok.size();i++){
Map<Character,Integer> ac = new HashMap<>();
for(int j = 0;j<FeiZhongJieNum;j++){
char ch = FeiZhongJie[j];
if(ok.get(i).getNext() == null || ok.get(i).getNext().get(ch) == null){
ac.put(ch,-1);
continue;
}
Integer integer = ok.get(i).getNext().get(ch);
ac.put(ch,integer);
}
Goto.put(i,ac);
}
}
public static void OutZhong(){ //输出终结符和非终结符....
System.out.print("非终结符:");
for(int i = 0;i<FeiZhongJieNum;i++){
System.out.print(FeiZhongJie[i]+" ");
}
System.out.println();
System.out.print("终结符:");
ZhongJie[ZhongJieNum++] = '#';
for(int i = 0;i<ZhongJieNum;i++){
System.out.print(ZhongJie[i]+" ");
}
System.out.println();
}
public static void PrintZhuangTaiZhuanYi(){
for(int i = 0;i<ok.size();i++){
Map<Character, Integer> next = ok.get(i).getNext();
if(next != null){
for(Character key : next.keySet()){
Integer to = next.get(key);
System.out.println("状态T"+i+"----"+key+"------>状态T"+to);
}
}
}
}
public static class GuoCheng{
String ZhuanTai;
String FuHao;
String ShuRuChuan;
String Action;
Integer goTo;
public GuoCheng() {
}
public String getZhuanTai() {
return ZhuanTai;
}
public void setZhuanTai(String zhuanTai) {
ZhuanTai = zhuanTai;
}
public String getFuHao() {
return FuHao;
}
public void setFuHao(String fuHao) {
FuHao = fuHao;
}
public String getShuRuChuan() {
return ShuRuChuan;
}
public void setShuRuChuan(String shuRuChuan) {
ShuRuChuan = shuRuChuan;
}
public String getAction() {
return Action;
}
public void setAction(String action) {
Action = action;
}
public Integer getGoTo() {
return goTo;
}
public void setGoTo(Integer goTo) {
this.goTo = goTo;
}
}
public static String StackToString(Stack st){
String s = st.toString();
String[] split = s.substring(1, s.length() - 1).split(", ");
String ans = "";
for(int i = split.length-1;i>=0;i--){
ans+=split[i];
}
return ans;
}
public static void find(String str){ //对输入串的分析
Stack<Character> Shuruchuan = new Stack<>();//这是输入串的栈 abb#
GuoCheng mp[] = new GuoCheng[1001]; //穿它个1000个
int num = 0;
Stack<Integer> ZhuangTai = new Stack<>(); //这是状态 0345....
Stack<Character> Fuhao = new Stack<>();//这是符号的栈
for(int i = str.length()-1;i>=0;i--){
Shuruchuan.add(str.charAt(i)); //加进去
}
ZhuangTai.add(0);
Fuhao.add('#');
while(true){
mp[num] = new GuoCheng();
StringBuffer sf = new StringBuffer(StackToString(ZhuangTai));
mp[num].setZhuanTai(sf.reverse().toString());//状态放进入输出
sf = new StringBuffer(StackToString(Fuhao));
mp[num].setFuHao(sf.reverse().toString());//符号放进入输出
mp[num].setShuRuChuan(StackToString(Shuruchuan));//符号放进入输出
char ch = Shuruchuan.peek(); //取出首个字符
int pi = ZhuangTai.peek(); //取出栈顶的状态
Map<Character, String> map = Action.get(pi);
String s = map.get(ch);
if(s.equals("-1")){
System.out.println("输入串不符合LR(0)的规则,请重新输入...");
return ;
}
mp[num].setAction(s);
if(s.charAt(0) == 's'){
int Jin = s.charAt(1)-'0';
Shuruchuan.pop();
ZhuangTai.add(Jin);
Fuhao.add(ch);
}
else if(s.charAt(0) == 'r'){
int Jin = s.charAt(1) - '0';
String s1 = left.get(Jin);
String s2 = right.get(Jin);
for(int k = 0;k<s2.length();k++){
ZhuangTai.pop();
Fuhao.pop();
}
ch = s1.charAt(0);
Jin = ZhuangTai.peek();
Map<Character, Integer> map1 = Goto.get(Jin);
Jin = map1.get(ch);
ZhuangTai.add(Jin);
Fuhao.add(ch);
mp[num].setGoTo(Jin);
}
num++;
if(mp[num-1].getAction() .equals("acc")){
break;
}
}
System.out.println("---------字符串"+str+"的分析过程:---------");
PrintLine();
System.out.printf("%-14s","| 步骤");
System.out.printf("%-13s","| 状态栈");
System.out.printf("%-13s","| 符号栈");
System.out.printf("%-13s","| 输入串");
System.out.printf("%-16s","| ACTION");
System.out.printf("%-16s","| GOTO");
System.out.println("|");
PrintLine();
for(int i = 0;i<num;i++){
String kk = "| ";
System.out.printf("%-16s",kk+i);
System.out.printf("%-16s",kk+mp[i].getZhuanTai());
System.out.printf("%-16s",kk+mp[i].getFuHao());
System.out.printf("%-16s",kk+mp[i].getShuRuChuan());
System.out.printf("%-16s",kk+mp[i].getAction());
System.out.printf("%-16s",kk+mp[i].getGoTo());
System.out.println("|");
PrintLine();
}
}
public static void PrintLine(){
for(int i = 0;i< 6;i++){
System.out.print("----------------");
}
System.out.println();
}
public static String add(String str){
if(str.charAt(str.length()-1) != '#'){
str+="#";
}
return str;
}
public static String str;
public static void In(){
Scanner cin = new Scanner(System.in);
while(true){
System.out.print("请输入待分析的字符串:");
str = cin.next();
if(str.equals("stop")){
break;
}
str = add(str);
find(str);
}
}
public static void main(String[] args) throws Exception {
System.out.println("--------------制作人----------------");
System.out.println("| 姓名 | 学号 | 班级 |");
System.out.println("| 吴锦坤 | 2020611107 | 20计算机 |");
System.out.println("| 温金宝 | 2020611106 | 20计算机 |");
System.out.println("| 谢宇琛 | 2020611109 | 20计算机 |");
System.out.println("| 王文杰 | 2020611105 | 20计算机 |");
System.out.println("| 张展航 | 2020611117 | 20计算机 |");
System.out.println("-----------------------------------");
System.out.println("本实验以例题6.1作报告。当然,只需要改变data.txt中的文法就可以实现任何LR(0)语法分析!");
left = new LinkedList<>();
right = new LinkedList<>();
ok = new LinkedList<>();
is = new boolean[1001];
ZhongJie = new char[1001];
FeiZhongJie = new char[1001];
// System.out.println("Hello world!");
System.out.println("拓广文法为:");
OutWenFa();
System.out.println("终结符与非终结符:");
OutZhong();
System.out.println("加点的文法:");
OutJiaDianWenFa();
//解决状态
OutZhuangTai();
// 添加新的状态
AddNewZhuangTai();
//输出所有的状态
PrintZhuangTai();
System.out.println("--------------状态转移-----------------");
PrintZhuangTaiZhuanYi();
//累寄了,终于可以开始建表了.......
System.out.println(" LR(0)分析表:");
GouJianACTION();//构建action表
GouJianGoto(); //构建Goto表
//输出分析表
PrintBiao();
//解决分析过程!!完结撒花,嘿嘿嘿
In();
}
}