编译原理-语法分析器的java实现

语法分析器

实验步骤

1.2.1 1. 文法

  • E->TE’
  • E’->+TE’|ε
  • T->FT’
  • T’->*FT’|ε
  • F->(E)|i

1.2.2 2. 程序描述(LL(1)文法)

本程序是基于已构建好的某一个语法的预测分析表来对用户的输入字符串进行分析,判断输入的字符串是否属于该文法的句子。  
基本实现思想:接收用户输入的字符串(字符串以“#”表示结束)后,对用做分析栈的一维数组和存放分析表的二维数组进行初始化。然后取出分析栈的栈顶字符,判断是否为终结符,若为终结符则判断是否为“#”且与当前输入符号一样,若是则语法分析结束,输入的字符串为文法的一个句子,否则出错若不为“#”且与当前输入符号一样则将栈顶符号出栈,当前输入符号从输入字符串中除去,进入下一个字符的分析。若不为“#”且不与当前输入符号一样,则出错。

1.2.3 3.判断是否LL(1)文法

要判断是否为LL(1)文法,需要输入的文法G有如下要求:

  1. 具有相同左部的规则的SELECT集两两不相交,即: SELECT(A→?)∩ SELECT(A→?)= ?
  2. 如果输入的文法都符合以上的要求,则该文法可以用LL(1)方法分析。
  3. 算法描述如下:
    把第一条产生式的SELECT(0)集放到一个临时数组temp[]中,for(i=1;i<=产生式总数-1;i++)
    求temp的长度length    
    if
    i指向的当前产生式的左部等于上一条产生式的左部
    then     
    把SELECT(i)并入到temp数组中,

If (temp的长度小于length加上SELECT (i)的长度)
返回0       
else   
把temp清空   
把SELECT (i)存放到temp中   
结果返回1;

预测分析表

在这里插入图片描述

实验内容

流程图

在这里插入图片描述

程序代码
public class LL1_Deque {    
	//预测分析表 
	private String[][] analysisTable = new String[][]{ 
		{"TE'","","","TE'","",""}, 
		{"","+TE'","","","ε","ε"}, 
		{"FT'","","","FT'","",""},
		{"","ε","*FT'","","ε","ε"},
		{"i","","","(E)","",""}
	}; 
	//终结符 
	private String[] VT = new String[]{"i","+","*","(",")","#"};  
	//非终结符 
	private String[] VN = new String[]{"E","E'","T","T'","F"};  
	//输入串strToken 
	private static StringBuilder strToken = new StringBuilder("i*(i+()i)");  
	//分析栈stack 
	private Deque stack = new ArrayDeque<>();
	//shuru1保存从输入串中读取的一个输入符号,当前符号     
	private String shuru1 = null;  
	//X中保存stack栈顶符号     
	private String X = null;  
	//flag标志预测分析是否成功     
	private boolean flag = true;  
	//记录输入串中当前字符的位置 
	private int cur = 0;  
	//记录步数 
	private int count = 0;  
	public static void main(String[] args) {  
		System.out.println("所输入的表达式为:" + strToken );
		LL1_Deque ll1 = new LL1_Deque();         
		ll1.init(); 
		ll1.totalControlProgram();         
		ll1.printf();    
	}  
	//初始化 
	private void init() { 
		strToken.append("#");         
		stack.push("#"); 
		System.out.printf("%-20s %-80s %-40s %s\n", "步骤 ", "符号栈 ", "输入串 ", "所用产生式 ");         
		stack.push("E");         
		curCharacter(); 
		System.out.printf("%-10d %-30s %-20s\n", count, stack.toString(), strToken.substring(cur, strToken.length()));   
	}  
	//读取当前栈顶符号    
	private void stackPeek() {         
		X = (String) stack.peekFirst();     
	}  
	//返回输入串中当前位置的字母    
	private String curCharacter() { 
		shuru1 = String.valueOf(strToken.charAt(cur));        
		return shuru1;     
	}  
	//判断X是否是终结符     
	private boolean XisVT() { 
		for (int i = 0; i < (VT.length - 1); i++) {
			if (VT[i].equals(X)) {                 
				return true;             
			}         
		} 
		return false;     
	}  
	//查找X在非终结符中分析表中的横坐标     
	private String VNTI() {         
		int Ni = 0, Tj = 0; 
		for (int i = 0; i < VN.length; i++) {
			if (VN[i].equals(X)) {                 
				Ni = i;             
			}         
		} 
		for (int j = 0; j < VT.length; j++) {             
			if (VT[j].equals(shuru1)) {                 
				Tj = j;             
			}         
		} 
		return analysisTable[Ni][Tj];     
	}  
//	判断M[A,a]={X->X1X2...Xk}     
//	把X1X2...Xk推进栈 
//	X1X2...Xk=ε,不推什么进栈     
	private boolean productionType() {         
		return VNTI() != "";     
	}  
	//推进stack栈 
	private void pushStack() {         
		stack.pop(); 
		String M = VNTI();         
		String ch; 
		//处理TE' FT' *FT'特殊情况         
		switch (M) {             
			case "TE'": 
				stack.push("E'");                 
				stack.push("T");                 
				break;             
			case "FT'": 
				stack.push("T'"); 
				stack.push("F");                 
				break;             
			case "*FT'": 
				stack.push("T'");                 
				stack.push("F");                 
				stack.push("*");                 
				break;             
			case "+TE'": 
				stack.push("E'");                 
				stack.push("T");                 
				stack.push("+");                 
				break;             
			default: 
				for (int i = (M.length() - 1); i >= 0; i--) {                     
					ch = String.valueOf(M.charAt(i));                     
					stack.push(ch);                 
				}                 
				break;         
		} 
		System.out.printf("%-10d %-30s %-20s %s->%s\n", (++count), stack.toString(), strToken.substring(cur, strToken.length()), X, M);     
	}  
	//总控程序 
	private void totalControlProgram() {         
		while (flag) { 
			stackPeek();  
			//读取当前栈顶符号  令X=栈顶符号             
			if (XisVT()) { 
				if (X.equals(shuru1)) {                     
					cur++; 
					shuru1 = curCharacter();                     
					stack.pop(); 
					System.out.printf("%-10d %-30s %-20s \n", (++count), stack.toString(), strToken.substring(cur, strToken.length())); 
				} else { 
					ERROR();                 
				} 
			} else if (X.equals("#")) {                 
				if (X.equals(shuru1)) {                     
					flag = false;                 
				} else { 
					ERROR();                 
				} 
			} else if (productionType()) {  
				if (VNTI().equals("")) {                     
					ERROR(); 
				} else if (VNTI().equals("ε")) {                     
					stack.pop(); 
					System.out.printf("%-10d %-30s %-20s %s->%s\n", (++count), stack.toString(), strToken.substring(cur, strToken.length()), X, VNTI());                 } else { 
					pushStack();                 
				}             
			} else { 
				ERROR();            
			}         
		}     
	}  
	//出现错误 
	private void ERROR() { 
//		System.out.println("输入串出现错误,无法进行分析");  
		System.out.println( false );
		System.exit(0);     
	}  
	//打印存储分析表     
	private void printf() {         
		if (!flag) {  
			System.out.println( true );
//			System.out.println("****分析成功啦!****");         
		} else { 
//			System.out.println("****分析失败了****"); 
			System.out.println( false );
		}     
	} 
}

运行结果

在这里插入图片描述
在这里插入图片描述

实验总结

  1. 基于LL1算法构造语法树
  2. 对于输入的字符串进行语法分析,本实验只针对于加法、乘法、括号做了判断
  3. 返回:
    a) 分析正确,返回true
    b) 分析错误,返回false
    源代码下载:https://download.csdn.net/download/Simple__Code/12817517
  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值