编译原理实验(2)——递归下降语法分析器

编译实验——递归下降语法分析器

实验内容:

根据课堂讲授的形式化算法,编制程序实现递归下降分析器,能对常见的语句进行分析。
要求实现以下语法的递归下降分析:
在这里插入图片描述

算法分析:

1. 算法设计:

  • 递归下降的语法分析首先应该消除左递归提取左公因子,从逻辑上检测避免死循环和低效处理,得到产生式如下:

    program -> block
    block -> {stmts}
    stmts -> stmt stmts|null
    stmt -> id=expr;|if(bool)stmt stmt1|while(bool)stmt|do stmt while(bool)|break|block
    stmt1 -> null|else stmt
    bool -> expr bool1
    bool1 -> <expr|<=expr|>expr|>=expr|null
    epxr -> term expr1
    expr1 -> +term expr1|-term expr1|null
    term -> factor term1
    term1 -> *factor term1|/factor term1|null
    factor -> (expr)|id|num

  • 将实验一词法分析器的输出文件token.txt作为输入,逐个读入单词,采用每个产生式的左边的文法符号对应一个函数的形式,实现递归下降分析器。

  • 将最左推导的过程逐步完整输出,具体实现方式是将上一行的输出存储在一个字符串变量Ans中,每次用产生式的右部替换字符串最左非终结符再输出。
    这一步利用到了C++ stl中string头文件中定义的函数erase(),insert(),find()
    以推导步骤stmts --> stmt stmts为例 :
    在这里插入图片描述
    2. 输出展示:
    在这里插入图片描述

源代码

#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<algorithm>
using namespace std;
int sym[10000];
string token[10000];
string Ans;
int Pos;
int p = 0;//p指向当前正在处理的单词
int flag = 0;
void error();
void program();
void block();
void stmts();
void stmt();
void stmt1();
void booL();
void booL1();
void expr();
void expr1();
void term();
void term1();
void factor();
/*
根据上一实验词法分析器规定:

保留字,一符一类,种类码0~21:
"if","else","while","do","break","main","int","float","double","return","const","void","continue","char","unsigned","enum","long","switch","case","unsigned","auto","static"

特殊符号,一符一类,种类码22~38,种类码39~44为==,!=,&&,||,>=,<=:
"+","-",",","/","=","<",">","{","}",";","(",")","&","!","#","[","]"

ID,种类码101

数字,种类码98~100(十进制,八进制,十六进制)
*/
int main()
{
	ifstream file("token.txt", ios::in);
	if (!file)
	{
		cerr << "文件打开失败!" << endl;
		exit(1);
	}
	char ch;
	string source="";
	file.get(ch);
	do {
		source += ch;
		file.get(ch);
	} while (!file.eof());
	stringstream ss(source);
	int i = 0;
	while (ss>>sym[i])
	{
		ss >> token[i];
		//cout << sym[i] << " " << token[i] << endl;
		i++;
	}
	program();
	if (flag == 0)
		cout << "\n语法分析成功!" << endl;
	return 0;
}
void error()
{
	cout << "语法分析出错!" << endl;
}
void program()
{
	cout << "program";
	Ans = "--> block\n       ";
	cout << Ans;
	block();
}
void block()
{
	if (token[p++] == "{")
	{
		//cout << "block --> { stmts }" << endl;
		Pos = Ans.find("block");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "{stmts}");
		cout << Ans;
		stmts();
		if (flag == 1)
		{
			error();
			return;
		}
		if (token[p++] != "}")
			error();
	}
	else
		error();
}
void stmts()
{
	if (sym[p] == 101 || token[p] == "if" || token[p] == "while" || token[p] == "do" || token[p] == "break" || token[p] == "{")
	{
		//cout << "stmts --> stmt stmts" << endl;
		Pos = Ans.find("stmts");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "stmtstmts");
		cout << Ans;
		stmt();
		if (flag == 1) return;
		stmts();
		if (flag == 1) return;
	}
	else
	{
		//cout << "stmts --> null" << endl;
		Pos = Ans.find("stmts");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "");
		cout << Ans;
		return;
	}	
}
void stmt()
{
	if (sym[p] == 101)
	{
		//cout << "stmt --> id = expr ;" << endl;
		Pos = Ans.find("stmt");
		Ans.erase(Pos, 4);
		Ans.insert(Pos, "id=expr;");
		cout << Ans;
		p++;
		if (token[p++] == "=")
		{
			expr();
			if (flag == 1) return;
			if (token[p++] != ";")
				flag = 1;
		}
		else
			flag = 1;
	}
	else if (token[p] == "while")
	{
		//cout << "stmt --> while (bool) stmt" << endl;
		Pos = Ans.find("stmt");
		Ans.erase(Pos, 4);
		Ans.insert(Pos, "while(bool)stmt");
		cout << Ans;
		p++;
		if (token[p++] == "(")
		{
			booL();
			if (token[p++] == ")")
			{
				stmt();
				if (flag == 1) return;
			}
			else
				flag = 1;
		}
		else
			flag = 1;
	}
	else if (token[p] == "do")
	{
		//cout << "stmt --> do stmt while (bool)" << endl;
		Pos = Ans.find("stmt");
		Ans.erase(Pos, 4);
		Ans.insert(Pos, "dostmtwhile(bool)"); 
		cout << Ans;
		p++;
		stmt();
		if (flag == 1) return;
		if (token[p++] == "while" && token[p++] == "(")
		{
			booL();
			if (flag == 1) return;
			if (token[p++] != ")")
				flag = 1;
		}
		else
			flag = 1;
	}
	else if (token[p] == "break")
	{
		//cout << "stmt --> break" << endl;
		Pos = Ans.find("stmt");
		Ans.erase(Pos, 4);
		Ans.insert(Pos, "break");
		cout << Ans;
		p++;
	}
	else if (token[p] == "{")
	{
		//cout << "stmt --> block" << endl;
		Pos = Ans.find("stmt");
		Ans.erase(Pos, 4);
		Ans.insert(Pos, "block");
		cout << Ans;
		block();
	}
	else if (token[p++] == "if" && token[p++] == "(")
	{
		//cout << "stmt --> if (bool) stmt stmt1" << endl;
		Pos = Ans.find("stmt");
		Ans.erase(Pos, 4);
		Ans.insert(Pos, "if(bool)stmt stmt1");
		cout << Ans;
		stmt();
		if (flag == 1) return;
		stmt1();
		if (flag == 1) return;
	}
	else
		flag = 1;
}
void stmt1()
{
	if (token[p++] == "else")
	{
		//cout << "stmt1 --> else stmt" << endl;
		Pos = Ans.find("stmt1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "else stmt");
		cout << Ans;
		stmt();
		if (flag == 1) return;
	}
	else
		return;
}
void booL()
{
	//cout << "bool --> expr bool1" << endl;
	Pos = Ans.find("bool");
	Ans.erase(Pos, 4);
	Ans.insert(Pos, "exprbool1");
	cout << Ans;
	expr();
	if (flag == 1) return;
	booL1();
	if (flag == 1) return;
}
void booL1()
{
	if (token[p] == "<" || token[p] == "<=" || token[p] == ">" || token[p] == ">=")
	{
		//cout << "bool1 --> " << token[p] << " expr" << endl;
		Pos = Ans.find("bool1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, token[p]+"expr");
		cout << Ans;
		p++;
		expr();
		if (flag == 1) return;
	}
}
void expr()
{
	//cout << "expr --> term expr1" << endl;
	Pos = Ans.find("expr");
	Ans.erase(Pos, 4);
	Ans.insert(Pos, "termexpr1");
	cout << Ans;
	term();
	if (flag == 1) return;
	expr1();
	if (flag == 1) return;
}
void expr1()
{
	if (token[p] == "+")
	{
		//cout << "expr1 --> + term" << endl;
		Pos = Ans.find("expr1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "+term");
		cout << Ans;
		p++;
		term();
		if(flag == 1) return;
	}
	else if (token[p] == "-")
	{
		//cout << "expr1 --> - term" << endl;
		Pos = Ans.find("expr1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "-term");
		cout << Ans;
		p++;
		term();
		if (flag == 1) return;
	}
	else
	{
		//cout << "expr1 --> null" << endl;
		Pos = Ans.find("expr1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "");
		cout << Ans;
		return;
	}
}
void term()
{
	//cout << "term --> factor term1" << endl;
	Pos = Ans.find("term");
	Ans.erase(Pos, 4);
	Ans.insert(Pos, "factorterm1");
	cout << Ans;
	factor();
	if (flag == 1) return;
	term1();
	if (flag == 1) return;
}
void term1()
{
	if (token[p] == "*")
	{
		//cout << "term1 --> * factor" << endl;
		Pos = Ans.find("term1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "*factor");
		cout << Ans;
		p++;
		factor();
		if (flag == 1) return;
	}
	else if (token[p] == "/")
	{
		//cout << "term1 --> / factor" << endl;
		Pos = Ans.find("term1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "/factor");
		cout << Ans;
		p++;
		factor();
		if (flag == 1) return;
	}
	else
	{
		//cout << "term1 --> null" << endl;
		Pos = Ans.find("term1");
		Ans.erase(Pos, 5);
		Ans.insert(Pos, "");
		cout << Ans;
		return;
	}
}
void factor()
{
	if (token[p] == "(")
	{
		//cout << "factor --> (expr)" << endl;
		Pos = Ans.find("factor");
		Ans.erase(Pos, 6);
		Ans.insert(Pos, "(expr)");
		cout << Ans;
		p++;
		expr();
		if (flag == 1) return;
		if (token[p++] != ")")
			flag = 1;
	}
	else if (sym[p] == 101)
	{
		//cout << "factor --> id" << endl;
		Pos = Ans.find("factor");
		Ans.erase(Pos, 6);
		Ans.insert(Pos, "id");
		cout << Ans;
		p++;
	}
	else if (sym[p] >= 98 && sym[p] <= 100)
	{
		//cout << "factor --> num" << endl;
		Pos = Ans.find("factor");
		Ans.erase(Pos, 6);
		Ans.insert(Pos, "num");
		cout << Ans;
		p++;
	}
	else
		flag = 1;
}
  • 5
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
语法分析是编译原理中的重要部分,它的作用是将词法分析阶段得到的词法单元序列转换成抽象语法树(AST)或语法分析树(Parse Tree),以便于后续的语义分析、中间代码生成和目标代码生成等环节的进行。在本次实验中,我们将使用Java语言实现一个简单的语法分析器实验要求: 1. 实现自顶向下的递归下降分析器。 2. 支持的文法如下: ``` <program> ::= <stmts_list> <stmts_list> ::= <stmt> | <stmts_list> <stmt> <stmt> ::= <if_stmt> | <while_stmt> | <assign_stmt> <if_stmt> ::= if <condition> then <stmts_list> end <while_stmt> ::= while <condition> do <stmts_list> end <assign_stmt> ::= <id> = <expr> <condition> ::= <expr> <relop> <expr> <expr> ::= <term> | <expr> <addop> <term> <term> ::= <factor> | <term> <mulop> <factor> <factor> ::= <id> | <number> | '(' <expr> ')' <relop> ::= '<' | '>' | '=' | '<=' | '>=' | '<>' <addop> ::= '+' | '-' <mulop> ::= '*' | '/' <id> ::= <letter> | <id> <letter> | <id> <digit> <number> ::= <digit> | <number> <digit> <letter> ::= A | B | ... | Z | a | b | ... | z <digit> ::= 0 | 1 | ... | 9 ``` 注意:文法中的关键字 if、then、end、while、do、and 等均为保留字。 3. 实现的语法分析器应具备以下功能: - 能够识别出语法正确的程序,并输出相应的语法分析树或抽象语法树。 - 能够识别出语法错误的程序,并给出相应的错误提示信息。 - 能够处理注释和空格等无意义的字符。 4. 实验提交要求: - 实验报告,包括程序设计和实验结果分析。 - 程序源代码。 实验设计思路: 1. 根据给定的文法,设计语法分析器的语法规则和对应的产生式。 2. 编写相应的Java代码,将文法转换为递归下降分析器所需要的形式。 3. 实现从输入的源代码中读取词法单元序列的功能。 4. 实现递归下降分析器的核心算法,对输入的词法单元序列进行语法分析,并构建相应的语法分析树或抽象语法树。 5. 在语法分析过程中,需要处理注释和空格等无意义的字符,以便于正确识别语法错误。 6. 在语法分析过程中,需要对输入的源代码进行错误检查,并给出相应的错误提示信息。 7. 输出语法分析树或抽象语法树,以便于后续的语义分析、中间代码生成和目标代码生成等环节的进行。 实验结果分析: 经过实验测试,我们的语法分析器能够正确地识别出合法的程序,并输出相应的语法分析树或抽象语法树。同时,它也能够正确地识别出语法错误的程序,并给出相应的错误提示信息。总的来说,本次实验取得了较好的实验效果。 实验源代码: 见下方代码框:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值