大连理工大学 编译原理第四次上机——语法分析

题目要求:

1. 使用的文法如下:

       E ->TE '

       E ' -> + TE ' | #

       T -> FT '

       T '-> * FT '| #

       F ->(E) | id

2. 对于任意给定的输入串(词法记号流)进行语法分析,使用非递归预测分析方法

3. 要有一定的错误处理功能。即对错误能提示,并且能在一定程度上忽略尽量少的记号来进行接下来的分析。可以参考书上介绍的同步记号集合来处理。

可能的出错情况:idid*id,  id**id,  (id+id, +id*+id ……

网上的前辈们已有完整的思路以及代码,详情可参考:

大连理工大学编译原理第4次上机—语法分析2_偷熊的小糖的博客-CSDN博客_例如. 使用的文法如下: e te ¢ e ¢ + te ¢ | e t f

但是这个代码有个小的bug,他在实现分析后,错把“)”也当成终结符。这样,导致的问题就是你的语法分析,在移进右括号后,程序判断已分析结束,然后程序就会自己停止,剩下的部分程序就会自动将其忽略。

以下是修改前的运行结果:

可以发现此时,在分析到第一个括号后,程序停止。栈中并没有移进第一个右括号后的内容。

修改思路呢,就是在Ee()和Te()中判断终结符后,添加新的判断ahead==")",且此时input[0]后为运算符号"+"或"*",进行新的分析。

这是修改后的代码:

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
static string input;
static string ahead;
void E();
void Ee();
void T();
void Te();
void F();
bool whether_in(string target,vector<string> v){
	for(int i=0;i<v.size();i++)
		if(target==v[i])
			return true;
return false;
}
void nextToken(){
	ahead.clear();
	if(input[0]=='*'||input[0]=='+'||input[0]=='('||input[0]==')'||input[0]=='$'){
		ahead += input[0];
		input = input.substr(1);         
	}
	else if(input[0]=='i'){   
		ahead = "id";
		input = input.substr(2);
	}
	else if(input[0]==' '){     //如果开头是空格的话就跳过 
		nextToken();
	}
}
 
void E(){
	vector<string> synch;
	synch.push_back(")");
	synch.push_back("$");
	if(ahead == "id"||ahead == "("){
		cout << "E->TE'" << endl;
		T();
		Ee();
	}	
	else if(whether_in(ahead,synch)){
		cout << "弹栈,弹出非终结符E,用户少输入了一个id"<<endl;
		
	}
	else{
		cout << "输入串跳过记号" << ahead << ",用户多输入了一个" << ahead << endl;
		nextToken(); 
		E();
	}
}
 
void Ee(){
	if(ahead=="+"){
		cout << "E'->+TE'" << endl;
		nextToken();
		T();
		Ee();
	}
	else if(ahead=="$"||ahead==")"){
		cout << "E'->#" << endl;
		if(ahead==")"){
			if(input[0]=='+')
			{
				nextToken();
				Ee();
			}
			else if(input[0]=='*'){
				nextToken();
				Te();
			}
			
		}
		//return ;
	}
	else{
		cout << "输入串跳过记号" << ahead << ",用户多输入了一个" << ahead << endl;
		nextToken(); 
		Ee();
	}	
	
}
 
void T(){
	vector<string> synch;
	synch.push_back("+");
	synch.push_back(")");
	synch.push_back("$");
	if(ahead == "("||ahead=="id"){
		cout << "T->FT'" << endl;
		F();
		Te();
	}
	else if(whether_in(ahead,synch)){
		cout << "弹栈,弹出非终结符T,用户少输入了一个id"<<endl;
	} 
	else{
		cout << "输入串跳过记号" << ahead << ",用户多输入了一个" << ahead << endl;
		nextToken(); 
		T();
	}
}
 
void Te(){
	if(ahead == "*"){
		cout << "T'->*FT'" << endl;
		nextToken();
		F();
		Te();
	}
	else if(ahead=="$"||ahead=="+"||ahead==")"){
		cout << "T'->#" << endl;
		if(ahead==")"){
			if(input[0]=='+')
			{
				nextToken();
				Ee();
			}
			else if(input[0]=='*'){
				nextToken();
				Te();
			}
		
		}
		//return ;
	}
	else{
		cout << "输入串跳过记号" << ahead << ",用户多输入了一个" << ahead << endl;
		nextToken();
		Te(); 
	}
}
 
void F(){
	vector<string> synch;
	synch.push_back("+");
	synch.push_back("*");
	synch.push_back(")");
	synch.push_back("$");
	if(ahead=="id"){
		cout << "F->id" << endl;
		nextToken();
	}
	else if(ahead=="("){
		cout << "F->(E)" << endl;
		nextToken();
		E();
		if(ahead!=")"&&ahead!="$")                       
			cout << "弹栈,弹出终结符),用户少输入了一个)" << endl;
	}
	else if(whether_in(ahead,synch)){
		cout << "弹栈,弹出非终结符F,用户少输入了一个id"<< endl;		
	}
	else{
		cout << "输入串跳过记号" << ahead << ",用户多输入了一个" << ahead << endl;
		nextToken();
		F(); 
	}
	
}
 
int main(){
	char in[100];
	cin.getline(in,100);
	input = in;
	input+="$"; 
	cout<<"输出:"<<endl;
	nextToken();
	E();
return 0;
}

以下是运行截图:

这是就出现了两个F->(E)的分析过程,结果正确。 经过测试,应该运行上没有bug了,可以放心使用。

 

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
大连工大软件编译技术课程——词法分析上机实验 实验目的:对循环语句和条件判断语句编写词法分析编译程序,只能通过一遍扫描完成。(用c++实现) 实验要求: (1) 关键字: for if then else while do 所有关键字都是小写。 (2)运算符和分隔符: : = + - * / <= >= ; ( ) # (3)其他标识符(ID)和整型常数(NUM),通过以下正规式定义: ID=letter(letter | digit)* NUM=digit digit* (4)空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM、运算符、分隔符和关键字,词法分析阶段通常被忽略。 各种词法单元对应的词法记号如下: 词法单元 词法记号 词法单元 词法记号 for 1 : 17 if 2 := 18 then 3 < 20 else 4 21 while 5 23 letter(letter+digit)* 10 >= 24 digit digit* 11 = 25 + 13 ; 26 - 14 ( 27 * 15 ) 28 / 16 # 0 词法分析程序的功能 输入:源程序 输出:二元组(词法记号,属性值/其在符号表中的位置)构成的序列。 例如:对源程序 x:=5; if (x>0) then x:=2*x+1/3; else x:=2/x; # 经词法分析后输出如下序列: (10,’x’)(18, :=) (11,5) (26, ;) (2, if ) (27,( )…… 1.几点说明: (1)关键字表的初值。 关键字作为特殊标识符处,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符,查关键字表。如能查到匹配的单词,则该单词的关键字,否则为一般标识符。关键表为一个字符串数组,其描述如下: char *keyword[6]={”for”, ”if”, ”then” ,”else”,”while”, ”do” }; (2) 程序中需要用到的主要变量为 token , id和num. 1)id用来存放构成词法单元的字符串; 2)num用来存放整数(可以扩展到浮点数和科计数法表示); 3)token用来存放词法单元的词法记号。 可以参考下面的代码: do{ lexical(); //将词法单元对应的记号保存到token中,属性值保存到num或者id中 switch(token) { case 11: printf ("(token, %d\n) ", num); break; case -1: printf("error!\n");break; default: printf("(%d,%s)\n", token, id); } }while (token!=0);

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值