RL分析器

import java.util.ArrayList;
//lsh
import java.util.Scanner;

/**
 *题目:LR1分析过程模拟
 *说明:
 * 首先要说句,这程序没有花大量的时间写,稍微写了下吧,能运行,兼容中间插入空格
 * 无特殊功能,就只能判断一个语句是否符合给定文法和显示LR(1)分析过程
 *要求:
 * 本程序按照如下文法设计:
 * E->E+T|T
 * T->T*F|F
 * F->(E)|i
 */
public class RL1Analysis {
 String[][] sentence = new String[][]{//文法,也是内定了,当然要用到其他文法也可以,就只要这些参数改一下就可以了,但为了简单起见,字符不能使用带一撇的字符
   {"E","E+T"},//E->E+T
   {"E","T"},//E->T
   {"T","T*F"},//T->T*F
   {"T","F"},//T->F
   {"F","(E)"},//F->(E)
   {"F","i"}//F->i
 };
 String[][] table = new String[][]{//为了简单,LR分析表就手工输入了,那样输入也挺麻烦的,其实老师还忘了一个个东西给我们,给了我们分析表,就必须得给对应的文法才可以,还好,看出来那文法了
   {"","i","+","*","(",")","#","E","T","F"},
   {"S0","S5","","","S4","","","1","2","3"},
   {"S1","","S6","","","","acc","","",""},
   {"S2","","r2","S7","","r2","r2","","",""},
   {"S3","","r4","r4","","r4","r4","","",""},
   {"S4","S5","","","S4","","","8","2","3"},
   {"S5","","r6","r6","","r6","r6","","",""},
   {"S6","S5","","","S4 ","","r1","","9","3"},
   {"S7","S5","","","S4","","","","","10"},
   {"S8","","S6","","","S11","","","",""},
   {"S9","","r1","S7","","r1","r1","","",""},
   {"S10","","r3","r3","","r3","r3","","",""},
   {"S11","","r5","r5","","r5","r5","","",""}
 };
 String in=null;
 public RL1Analysis(){
  this.printSentence();//打印文法
  Scanner sc = new Scanner(System.in);
  System.out.println("/n请输入一个句子:");
  in = sc.nextLine().toString();
  in = removeBlank(in);
  int index=0;//记录输入串的索引位置
  StringBuffer stateTrack = new StringBuffer("S0");//状态栈,初始时如S0
  StringBuffer analysisTrack = new StringBuffer("#");//分析栈,初始放#
  ArrayList<String> list = new ArrayList<String>();
  String operator = "";//记录分析表中对应的值
  String staTrack="";
  int x,y;//记录在分析表中的位置
  boolean isOver=false;
  System.out.println("/n语句分析过程如下:");
  System.out.println("状态栈"+getBlank(26)+"符号栈"+getBlank(20)+"输入串/tACTION/tGOTO");
  while(!isOver){
   x=0;y=0;
   String inS = in.charAt(index)+"";//输入串如今读到的位置
   for(int i= 1;i<table[0].length;i++)//查表得到Y坐标
    if(table[0][i].equals(inS))
    {
     y = i;
     break;
    }
   staTrack = stateTrack.substring(stateTrack.lastIndexOf("S"),stateTrack.length());//读取状态栈最上面一个状态
   for(int i=1;i<table.length;i++)//得到X坐标
    if(staTrack.equals(table[i][0])){
     x = i;
     break;
    }
   operator = table[x][y];//分析表中对应位置的动作
   if(operator.length()>0){
    System.out.print(stateTrack+getBlank(16-stateTrack.length())+analysisTrack+getBlank(18-analysisTrack.length()-in.length()+index)+in.substring(index,in.length())+"/t"+operator);
    if(operator.startsWith("S")){//移进
     stateTrack.append(operator);
     analysisTrack.append(inS);
     index++;//输入串指针下移一位
    }else if(operator.startsWith("r")){//规约
     int m = Integer.parseInt(operator.substring(1,operator.length()))-1;//截取后面的数字,用于查产生式,还有一点,这是从1开始的
     String liutemp = sentence[m][1];
     list.add(sentence[m][1]+"=>"+sentence[m][0]);//规约步骤
     if(analysisTrack.toString().endsWith(liutemp))
      analysisTrack.delete(analysisTrack.length()-liutemp.length(),analysisTrack.length());//在分析栈除去产生式右部的字符串
     else{
      System.out.println("/n规约时出错!");
      System.exit(0);
     }
     analysisTrack.append(sentence[m][0]);//加上产生式左部,就相当于规约了
     int stindex=stateTrack.lastIndexOf("S");
     for(int i=0;i<liutemp.length();i++){//为了程序不节外生枝,就简单化了,这个地方的求liutemp的长度才确定有效字符个数还是不准确的,假如产生式中字母后跟了一撇的,就不对了,如E->T'+F
      stateTrack.delete(stindex,stateTrack.length());//一次去掉去掉一个状态
      stindex=stateTrack.lastIndexOf("S");
     }
     x = 0;y = 0;
     staTrack = stateTrack.substring(stateTrack.lastIndexOf("S"),stateTrack.length());
     for(int i=1;i<table.length;i++){//得到待规约X坐标
      if(staTrack.equals(table[i][0])){
       x = i;
       break;
      }
     }
     for(int i=1;i<table[0].length;i++){
      if(table[0][i].equals(sentence[m][0])){
       y = i;
       break;
      }
     }
     operator = table[x][y];//得到GOTO值
     System.out.print("/t"+operator);
     if(operator.matches("//d+"))
      stateTrack.append("S"+operator);
     else{
      System.out.println("/n待规约项出错!");
      System.exit(0);
     }
    }else if(operator.equals("acc")){
     System.out.println("/n该语句符合该合法!");
     isOver=true;
    }
    System.out.println();
   }else {
    System.out.println("输入的语句不符合给定文法!");
    System.exit(0);
   }
  }
  System.out.println("该句子语法树自底向上生成过程:");
  for(int i=0;i<list.size();i++)
   System.out.println(list.get(i));
 }
 public void printSentence(){
  System.out.println("假定文法如下:");
  for(int i=0;i<sentence.length;i++)
   System.out.println(sentence[i][0]+"->"+sentence[i][1]);
 }
 public String getBlank(int n){//打印n个连续空格
  String blank="";
  for(int i=0;i<n;i++)
   blank+=" ";
  return blank;
 }
 public String removeBlank(String s){//消除多余的空格,最后追加#
  StringBuffer res = new StringBuffer(s);
  int kong=res.indexOf(" ");
  while(kong>=0){
      res.delete(kong,kong+1);
      kong=res.indexOf(" ");
  }
  if(s.indexOf("#")==-1)//如果没有#号
   res.append("#");
  return res.toString();
 }
 public static void main(String[] args){
  new RL1Analysis();
 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值