JAVA实现LR分析器

目的:熟练掌握自下而上的语法分析方法,并能用程序实现。

要求

1. 使用如下文法:

E -> E+T | T

      T-> T*F | F

      F -> (E) | id

2. 对于任意给定的输入串(词法记号流)进行语法分析,要求采用LR分析器来完成。手工构造LR分析表,利用移进-归约分析算法(P71 图3.12)输出(P72 表3.8)对应的动作部分。如:

输入:id*+id/(id+id)#

输出:移进

按 F->id归约

      移进

      error

      ……

3. 要有一定的错误处理功能。即对错误能提示,并且能在一定程度上忽略尽量少的记号来进行接下来的分析。

例如:

从状态0开始的记号流为:bm

将b移进之后,栈里的情况应该为: 0 b 2

此时查表发现 action[2,m]=error

输出打印:error

把A和状态1相继压入栈,用户指针后移到FOLLOW(A)对应的元素继续分析。

扩展:

1.利用P94页的表3.13的方式将错误进行分类提示,即给出具体的出错信息。

2. 在已有文法的基础上再加上减法“-”和除法“/”对应的产生式构成最终的文法。从而使得记号流可以处理带括号的加、减、乘、除四则运算。

这个题就是要利用LR的动作转移表实现LR 分析器~代码在下面~

import java.util.Scanner;
import java.util.Stack;

public class Test {
	private static String Str = null; // 输入串
	private static String Sub = null; //输入串的待处理部分
	private static boolean acc = false;// 是否已处理完输入串
	private static boolean bResult = false;// 是否出错

	// Goto表,即每个状态遇见非终结符时的动作
	private static int[][] Goto = new int[][] { { 1, 2, 3 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 2, 3 },
			{ 0, 0, 0 }, { 0, 9, 3 }, { 0, 0, 10 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; 
			

	private static Stack<String> stack = new Stack<String>();// 状态栈,栈中元素都是String类型

	/**
	 * 
	 * @param state 状态
	 * @param fzjf 遇见的非终结符
	 * fzjf == 'E'代表是Goto表的第一列
	 * fzjf == 'T'代表是Goto表的第二列
	 * fzjf == 'F'代表是Goto表的第三列
	 */
	public static void Gto(int state, char fzjf) {
		int i = -1;
		if (fzjf == 'E')
			i = 0;
		if (fzjf == 'T')
			i = 1;
		if (fzjf == 'F')
			i = 2;

		stack.push(fzjf + ""); //将非终结符压入栈中,字符+空串转化为字符串
		stack.push(Goto[state][i] + "");//将Goto表中对应的状态压入栈中

	}

	/**
	 * e1代表缺少运算对象 将“id”压入栈中,随即将相应的状态压入栈中
	 * 
	 */
	public static void e1() {
		System.out.println("缺少运算对象");
		stack.push("id");
		stack.push(String.valueOf(3));
//		bResult = true;
//若该行不注释掉,程序遇到输入错误就会立即停止	;若注释掉,程序不会立即停止,而是会恢复错误	
	}

	public static void e3() {
		System.out.println("缺少算符");
		stack.push("+");
		stack.push("" + 6);
//		bResult = true;
	}

	public static void e3_() {
		System.out.println("缺少算符");
		stack.push("*");
		stack.push("" + 7);
//		bResult = true;
	}

	public static void e2() {
		System.out.println("不匹配的右括号");
		Sub = Sub.substring(1, Sub.length());
//		bResult = true;
	}

	public static void e4() {
		System.out.println("缺少右括号");
		stack.push("");
		stack.push(11 + "");
//		bResult = true;
	}

	public static void e5() {
		System.out.println("算符错误");
		stack.push("+");
		stack.push(6 + "");
		Sub = Sub.substring(1, Sub.length());
//		bResult = true;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("请输入串:");
		Scanner in = new Scanner(System.in);
		Str = in.nextLine();
		Sub = Str;   //初始时Sub = Str
		in.close();

		int y;
		boolean flag = false;

		// 0状态先进栈
		stack.push(String.valueOf(0));
		while (!bResult && acc == false) {
			switch (stack.peek().charAt(0)) {
			case '0':
				if (Sub.substring(0, 2).equals("id")) {
					stack.push("id");
					stack.push("" + 5);
					Sub = Sub.substring(2, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals("(")) {
					stack.push("(");
					stack.push("" + 4);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else {
					e1();
				}
				break;
			case '1':
				if ("1".equals(stack.peek())) {
					if (Sub.substring(0, 1).equals("+")) {
						stack.push("id");
						stack.push("" + 6);
						Sub = Sub.substring(1, Sub.length());
						System.out.println("移进");
					} else if (Sub.substring(0, 1).equals("#")) {
						acc = true;
						System.out.println("接受");
					} else {
						e3();
					}
					break;
				} else if (stack.peek().charAt(1) == '0') {
					if (Sub.substring(0, 1).equals("+")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
						System.out.println("按T->T*F归约");
					} else if (Sub.substring(0, 1).equals(")")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
						System.out.println("按T->T*F归约");
					} else if (Sub.substring(0, 1).equals("#")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
						System.out.println("按T->T*F归约");
					} else if (Sub.substring(0, 1).equals("*")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
						System.out.println("按T->T*F归约");
					} else {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
						System.out.println("按T->T*F归约");
					}
					break;
				} else {
					if (Sub.substring(0, 1).equals("+")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
						System.out.println("按F->(E)归约");
					} else if (Sub.substring(0, 1).equals(")")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
						System.out.println("按F->(E)归约");
					} else if (Sub.substring(0, 1).equals("#")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
						System.out.println("按F->(E)归约");
					} else if (Sub.substring(0, 1).equals("*")) {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
						System.out.println("按F->(E)归约");
					} else {
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						stack.pop();
						Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
						System.out.println("按F->(E)归约");
					}
					break;
				}
			case '2':
				if (Sub.substring(0, 1).equals("*")) {
					stack.push("*");
					stack.push("" + 7);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals("+")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'E');
					System.out.println("按E->T归约");
				} else if (Sub.substring(0, 1).equals(")")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'E');
					System.out.println("按E->T归约");
				} else if (Sub.substring(0, 1).equals("#")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'E');
					System.out.println("按E->T归约");
				} else {
					e3_();
				}
				break;
			case '3':
				if (Sub.substring(0, 1).equals("+")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
					System.out.println("按T->F归约");
				} else if (Sub.substring(0, 1).equals(")")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
					System.out.println("按T->F归约");
				} else if (Sub.substring(0, 1).equals("#")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
					System.out.println("按T->F归约");
				} else if (Sub.substring(0, 1).equals("*")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
					System.out.println("按T->F归约");
				} else {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'T');
					System.out.println("按T->F归约");
				}
				break;
			case '4':
				if (Sub.substring(0, 2).equals("id")) {
					stack.push("id");
					stack.push("" + 5);
					Sub = Sub.substring(2, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals("(")) {
					stack.push("(");
					stack.push("" + 4);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals(")")) {
					e2();
				} else
					e1();
				break;
			case '5':
				if (Sub.substring(0, 1).equals("+")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
					System.out.println("按F->id归约");
				} else if (Sub.substring(0, 1).equals(")")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
					System.out.println("按F->id归约");
				} else if (Sub.substring(0, 1).equals("#")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
					System.out.println("按F->id归约");
				} else if (Sub.substring(0, 1).equals("*")) {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
					System.out.println("按F->id归约");
				} else {
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'F');
					System.out.println("按F->id归约");
				}
				break;
			case '6':
				if (Sub.length() > 1) {
					if (Sub.substring(0, 1).equals("(")) {
						stack.push("(");
						stack.push("" + 4);
						Sub = Sub.substring(1, Sub.length());
						System.out.println("移进");
					} else if (Sub.substring(0, 2).equals("id")) {
						stack.push("id");
						stack.push("" + 5);
						Sub = Sub.substring(2, Sub.length());
						System.out.println("移进");
					} else if (Sub.substring(0, 1).equals(")")) {
						e2();
					}
				} else
					e1();
				break;
			case '7':
				if (Sub.substring(0, 2).equals("id")) {
					stack.push("id");
					stack.push("" + 5);
					Sub = Sub.substring(2, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals("(")) {
					stack.push("(");
					stack.push("" + 4);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals("(")) {
					stack.push("(");
					stack.push("" + 4);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals(")")) {
					e2();
				} else
					e1();
				break;
			case '8':
				if (Sub.substring(0, 1).equals("+")) {
					stack.push("+");
					stack.push("" + 6);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals(")")) {
					stack.push(")");
					stack.push("" + 11);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals("#")) {
					e4();
				} else if (Sub.substring(0, 1).equals("*")) {
					e5();
				} else
					e3();
				break;
			case '9':
				if (Sub.substring(0, 1).equals("*")) {
					stack.push("*");
					stack.push("" + 7);
					Sub = Sub.substring(1, Sub.length());
					System.out.println("移进");
				} else if (Sub.substring(0, 1).equals("+")) {
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'E');
					System.out.println("按E->E+T归约");
				} else if (Sub.substring(0, 1).equals(")")) {
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'E');
					System.out.println("按E->E+T归约");
				} else if (Sub.substring(0, 1).equals("#")) {
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'E');
					System.out.println("按E->E+T归约");
				} else {
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					stack.pop();
					Gto((int) stack.peek().charAt(0) - (int) '0', 'E');
					System.out.println("按E->E+T归约");
				}
				break;

			}

		}
		if (acc)

		{
			System.out.println("匹配成功");
		}

	}
}

我使用了短语级的错误恢复策略,此时LR分析表已经改为 

程序运行效果:

1、正常输入的情况:

2、输入有错误:

 

可以看出提示了缺少算符,并且恢复了错误,使得语法分析能够正常执行结束

 

缺少右括号

缺少运算对象~

按理说还可以用粗略的恢复错误方法,不过我没有实现,欢迎大家补充~

  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值