语法分析器-LL(1)语法分析

一丶实验名称

语法分析器

二丶实验目的及要求

通过设计、编制、调试-个典型的语法分析程序(任选有代表性的语法分析方法,如LL(1)、递归下降分析法、LR、 算符优先分析法)等,作为编制语法分析程序的依据,对词法分析器所提供的单词序列进行语法检测和结构分析,实现并进- -步掌握常用的语法分析方法。

三、实验内容

选择对各种常见高级程序设计语言都较为通用的语法结构作为分析对象(例如表达式、if、 while、for 等等),给出其文法规则描述(注意,文法规则的描述要符合所选分析方法的要求,比如用LL(1)分析法,文法必须是LL(1)文法),设计并实现一一个完整的语法分析程序。

输入:源程序以文件的形式输入。

输出:对于输入的源程序,如果输入源程序是给定文法定义的合法程序,则输出“success",如果不是,即输入源程序有错误,则输出“Error”,并且尽可能指出出错位置和原因。

四、实验算法描述

文法规则:

 E→TZ

 Z→+TZ|ε

 T→FY

 Y→*FY|ε

 F→(E)|i

程序描述(LL(1)文法)

本程序是基于以构建好的某一语法的预测分析表来对用户的输入字符串进行分析,判断输入的字符串是否属于该文法的句子。

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

1.First集和Follow集

FIRST(E)={(,i} FOLLOW(E)={),#}

FIRST(Z)={+,ε} FOLLOW(Z)={),#}

FIRST(T)={(,i} FOLLOW(T)={+,),#}

FIRST(Y)={*,ε} FOLLOW(Y)={+,),#}

FIRST(F)={(,i} FOLLOW(F)={*,+,),#}

2.构建好的预测分析表

 

i

+

*

(

)

#

E

→TZ

 

 

→TZ

synch

synch

Z

 

→+TZ

 

 

→ε

→ε

T

→FY

synch

 

→FY

synch

synch

Y

 

→ε

→*FY

 

→ε

→ε

F

→i

synch

synch

→(E)

synch

synch

                                      LL(1)预测分析表

3.运行结果

输入正确的源程序截图:

输出结果截图

 

输入错误的源程序截图:

输出结果截图

 

五、设计技巧和心得体会

这次实验编写了一个语法分析方法的程序。但是在LL (1)分析器的编写中我只达到了最低要求,就是自己手动输入的文法规则然后通过程序将预测分析表构造出来,然后自已编写总控程序根据分析表进行分析。

通过本次试验,我能够设计一个简单的语法分析程序,实现对文法规则进行语法检查和结构分析,进一步掌握常用的语法分析方法。

六、源程序清单(电子版)

import java.util.Stack;

public class GramerAnasys {
	
	//加入同步符号的LL(1)分析表
	private  String [][] analysisTable = new String[][]{
			{"TZ","","","TZ","synch","synch"},
			{"","+TZ","","","ε","ε"},
			{"FY","synch","","FY","synch","synch"},
			{"","ε","*FY","","ε","ε"},
			{"i","synch","synch","(E)","synch","synch"}
	};
	
	//存储终结符
	private String [] VT = new String[]{"i","+","*","(",")","#"};
	
	//存储终结符
	private String [] VN = new String[]{"E","Z","T","Y","F"};
	//输入串
	
	private StringBuilder strToken = new StringBuilder("i*i)+i");
	
	//分析栈
	private Stack<String> stack = new Stack<String>();
	
	//a保存从输入串中读取的一个输入符号,当前符号
	private String a = null;
	
	//X中保存stack栈顶符号
	private String X = null;
	
	//flag标志预测分析是否成功
	private boolean flag = true;
	
	//记录输入串中当前字符的位置
	private int cur = 0;
	
	//记录步数
	private int count = 0;
	
	//输出语法规则
	protected void print(){
		System.out.printf("E→TZ \n"+"Z→+TZ|ε \n"+"T→FY \n"+"Y→*FY|ε \n"+"F→(E)|i \n");
		
	}
	//初始化
	protected void init(){
		strToken.append("#");
		stack.push("#");
		System.out.printf("%-9s %-38s %6s %-20s\n","步骤 ","符号栈 ","        输入串 ","    所用产生式 ");
		stack.push("E");
		curCharacter();
		System.out.printf("%-6d %-20s %6s \n",count,stack.toString(),strToken.substring(cur, strToken.length()));
	}
	
	//读取当前栈顶符号
	protected String stackPeek(){
		X = stack.peek();
		return X;
	}
	
	//返回输入串中当前位置的字母
	private String curCharacter(){
			a = String.valueOf(strToken.charAt(cur));
		return a;
	}
	
	//判断X是否是终结符
	protected boolean XisVT(){
		for(int i = 0 ; i < (VT.length - 1); i++){
			if(VT[i].equals(X)){
				return true;
			}
		}
		return false;
	}
	
	//查找X在非终结符中分析表中的横坐标
	protected 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(a)){
				Tj = j;
			}
		}
		return analysisTable[Ni][Tj];
	}
	
	//判断M[A,a]={X->X1X2...Xk}
	//把X1X2...Xk推进栈
	//X1X2...Xk=ε,不推什么进栈
	protected boolean productionType(){
		if(VNTI() != ""){
			return true;
		}
		return false;
	}
	
	//推进stack栈
	protected void pushStack(){
		stack.pop();
		String M = VNTI();
		String ch;
		for(int i = (M.length() -1) ; i >= 0 ; i--){
			ch = String.valueOf(M.charAt(i));
			stack.push(ch);
		}
		System.out.printf("%-6d %-20s %6s %-1s->%-12s\n",(++count),stack.toString(),strToken.substring(cur, strToken.length()),X,M);
	}
	
	//总控程序
	protected void totalControlProgram(){
		while(flag == true){
			stackPeek();
			if(XisVT() == true){
				if(X.equals(a)){
					cur++;
					a = curCharacter();
					stack.pop();
					System.out.printf("%-6d %-20s %6s \n",(++count),stack.toString(),strToken.substring(cur, strToken.length()));
				}else{
					ERROR();
				}
			}else if(X.equals("#")){
				if(X.equals(a)){
					flag = false;
				}else{
					ERROR();
				}
			}else if(productionType() == true){
				if(VNTI().equals("synch")){
					ERROR();
				}else if(VNTI().equals("ε")){
					stack.pop();
					System.out.printf("%-6d %-20s %6s %-1s->%-12s\n",(++count),stack.toString(),strToken.substring(cur, strToken.length()),X,VNTI());
				}else{
					pushStack();
				}
			}else{
				ERROR();
			}
		}
	}
	
	//出现错误
	protected void ERROR(){
		System.out.println("Error.输入串出现错误,无法进行分析");
		System.exit(0);
	}
	
	//打印存储分析表
	protected void printf(){
		if(flag == false){
			System.out.println("********success");
		}else {
			System.out.println("********Error");
		}
		
	}
	
	public static void main(String[] args) {
		
		GramerAnasys gramerAnasys= new GramerAnasys();
		gramerAnasys.print();
		gramerAnasys.init();
		gramerAnasys.totalControlProgram();
		gramerAnasys.printf();
	}
	
}

 

  • 16
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个里面的都是测试数据,总共得分5分。从控制台输入,不能从文件中读取。实现了基本功能,加分项目都没有去实现,没有函数数组这些的实现。这是用C++语言写的,新建parser类别要选C++,其他对于VS的配置和C语言一样。for语句用的是枚举所有情况,你可以自行修改。 对预备工作中自然语言描述的简化C编译器的语言特性的语法,设计上下文无关文法进行描述 借助Yacc工具实现语法分析器 考虑语法树的构造: 1.语法树数据结构的设计:节点类型的设定,不同类型节点应保存哪些信息,多叉树的实现方式 2.实现辅助函数,完成节点创建、树创建等功能 3.利用辅助函数,修改上下文无关文法,设计翻译模式 4.修改Yacc程序,实现能构造语法树的分析器 考虑符号表处理的扩充 1.完成语法分析后,符号表项应增加哪些标识符的属性,保存语法分析的结果 2.如何扩充符号表数据结构,Yacc程序如何与Lex程序交互,正确填写符号表项 以一个简单的C源程序验证你的语法分析器,可以文本方式输出语法树结构,以节点编号输出父子关系,来验证分析器的正确性,如下例: main() { int a, b; if (a == 0) a = b + 1; } 可能的输出为: 0 : Type Specifier, integer, Children: 1 : ID Declaration, symbol: a Children: 2 : ID Declaration, symbol: b Children: 3 : Var Declaration, Children: 0 1 2 4 : ID Declaration, symbol: a Children: 5 : Const Declaration, value:0, Children: 6 : Expr, op: ==, Children: 4 5 7 : ID Declaration, symbol: a Children: 8 : ID Declaration, symbol: b Children: 9 : Const Declaration, value:1, Children: 10: Expr, op: +, Children: 8 9 11: Expr, op: =, Children: 7 10 12: if statement, Children: 6 11 13: compound statement, Children: 3 12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值