编译原理2-语法分析

语法分析是指,根据词法分析后生成的单词,根据语法规则,检查是否存在语法错误

实验步骤:

(1)用正则表达式描述词法规则

(2)改造文法,消除左递归,提取左公因子

(3)求各非终结符的first集和follow集

(4)判断文法是否满足LL(1)文法

(4)特殊处理不满足LL(1)文法的文法

(5)根据first集和follow集构造分析表

(6)根据分析表构造程序

test语言语法规则:

1)  <program> → {<declaration_list><statement_list>} 
2)  <declaration_list> → <declaration_list><declaration_stat> | ε 
3)  <declaration_stat> → int ID; 
4)  <statement_list> → <statement_list><statement>| ε 
5)  <statement> → <if_stat>|<while_stat>|<for_stat>|<read_stat>|<write_stat>|
<compound_stat> |<assignment_stat>|;
6)  <if_stat> → if (<bool_expression >) <statement > 
| if (<bool_expression>) <statement >else < statement > 
7)  <while_stat> → while (<bool_expression>) < statement > 
8)  <for_stat> → for (<assignment_expression>; <bool_expression>; <assignment_ expression
 >)<statement> 
9)  <write_stat> → write < arithmetic_expression >; 
10) <read_stat> → read ID; 
11) <compound_stat> → {<statement_list>}
12) <assignment_expression> → ID=<arithmetic_expression> 
13) <assignment_stat> →<assignment_expression>; 
14) <bool_expression>→<arithmetic_expression> >  <arithmetic_expression> |
<arithmetic_expression> <  <arithmetic_expression> |
<arithmetic_expression> >= <arithmetic_expression> |
<arithmetic_expression> <= <arithmetic_expression> |
<arithmetic_expression> == <arithmetic_expression> |
<arithmetic_expression> != <arithmetic_expression> 
15) <arithmetic_expression> → <arithmetic_expression>+<term> |
< arithmetic_expression>-<term> |
< term >  
16) < term > → < term >*<factor>|< term >/<factor>|< factor > 
17) < factor > → (<arithmetic_expression>)|ID|NUM

实验目的:

1、会判别一个文法是否是 LL(1)文法;

2、会对上下文无关文法进行改造,使之满足确定的自顶向下分析要求。

3、掌握LL(1)分析程序的编写方法。

4、会采用超前读单词方法对不能改造的产生式进行特殊处理。 

 

 

 

(1)替换语法规则中的非终结符

<program>   S
<declaration_list>  A
<statement_list>  B
<declaration_stat>  C
<statement>  D
<if_stat>  E
<while_stat>  F
<for_stat> G
<read_stat>  H
<write_stat>  I
<compound_stat>  J
<assignment_stat>  K
<bool_expression >  L
<assignment_expression>  M
< arithmetic_expression >  N
<term>   O
< factor >   P

 

 

  1. 替换后的语法规则
1)S → {AB}
2)A → AC | ε
3)C → int ID;
4)B → BD| ε
5)D → E|F|G|H|I|J |K|;
6)E → if (L) D | if (L) D else D
7)F → while (L) D
8)G → for (M; L; M) D
9)I → write N;
10)H→ read ID;
11)J → {B}
12)M → ID=N 
13)K →M;
14)L→N > N | N <N | N >= N |N <= N | N == N | N != N 
15)N → N+O | N-O | O
16)O → O*P | O/P | P
17) P → (N)|ID|NUM

 

(3)分析上述语法规则

分析上述语法规则发现:

语法2,4,15,16产生式存在左递归,需要进行语法改造

语法6,14需要消除左递归。

  1. 进行文法改造
1)将文法A → AC | ε消除左递归为: A→CA | ε
2)将文法B → BD| ε 消除左递归为:B→DB | ε
3)将文法N → N+O | N-O | O消除左递归为: N→On
		n →-On | +On | ε
4)将文法O → O*P | O/P | P消除左递归为: O→Po
		o → *Po| /Po | ε
5)将文法E → if (L) D | if (L) D else D消除左递归为: E → if ( L ) D e
	 e → ε | else D
6)将文法L→N > N | N <N | N >= N |N <= N | N == N |N != N
消除左递归为: L → NL1,L1 → >N | < N | == N | != N|>=N | <= N

 

根据修改后的文法得出FOLLOW集:

检查是不是 LL(1) 文法 

1)文法不含左递归。

2)文法的任何一个非终结符 A 的各个产生式的右部符号串的 FIRST 集两两不

相交

3)对于 E → if ( L ) D e, e → ε | else D 其中 FIRST (e)∩ FOLLOW (e) =else需要进行特殊处理。

4)对于E1进行特殊处理,当程序读入else时,继续读入一个单词,并判断下一个单词是否是 } ,当是 } 时,就用E1 → ε产生式。

LL(1)分析表:

 

 语法分析程序:

 

#include<iostream>
#include<string>
#include<sstream>
#include<fstream>
#include<stack>
#include<vector>
#include<Windows.h>
using namespace std;
// 分析表
string M[21][27] =
{
	{ "" ,"" ,"" ,"" ,"" ,"" ,"{ A B }" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "C A" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","ε" },
{ "" ,"D B" ,"D B" ,"D B" ,"D B" ,"D B" ,"D B" ,"ε" ,"D B" ,"D B" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","ε" },
{ "int ID ;" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"E" ,"G" ,"F" ,"H" ,"I" ,"J" ,"" ,"K" ,";" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"if ( L ) D e" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"else D | ε" ,"" ,"" ,"","","","ε" },
{ "" ,"" ,"" ,"while ( L ) D" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"for ( M ; L ; M ) D" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"" ,"" ,"read ID ;" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"" ,"" ,"" ,"write N ;" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"{ B }" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"M ;" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"N l" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"N l" ,"" ,"N l","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"> N" ,"< N" ,">= N" ,"<= N" ,"== N" ,"!= N" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"ID = N" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"O n" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"O n" ,"" ,"O n","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"ε" ,"+ O n" ,"- O n" ,"" ,"" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"" ,"" ,"ε" ,"","","","ε" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"P o" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"P o" ,"" ,"P o","","","" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"ε" ,"ε" ,"ε" ,"* P o" ,"/ P o" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"ε" ,"" ,"" ,"ε" ,"","","","ε" },
{ "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"ID" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"( N )" ,"" ,"NUM","","","" }
};

// 非终态集合
string VN[] = { "S","A","B","C","D","E","e","F","G","H","I","J","K","L","l","M","N","n","O","o","P" };
// 终态集合
string VT[] = { "int","if","for","while","read","write","{","}","ID",";","+","-","*","/",">","<",">=","<=","==","!=","else","(",")","NUM","=",",","#" };

// 判断是否属于终态集合
bool IsBelongToVT(string str)
{
	for (int i = 0; i < sizeof(VT) / sizeof(string) - 1; ++i)
		if (str == VT[i])
			return true;
	return false;
}
// 错误
void Error(string lineOfWord,string errInfo)
{
	cout << "Error in line " << lineOfWord<<", errInfo: "<<errInfo << endl;
}
// 通过产生式左部和输入符号得到产生式右部
string GetFormulaRight(string formulaLeft, string inputSymbol)
{
	int row = 0, col = 0;
	for (int i = 0; i < sizeof(VN) / sizeof(string); ++i)
	{
		if (formulaLeft == VN[i])
		{
			row = i;
			break;
		}
	}
	for (int i = 0; i < sizeof(VT) / sizeof(string); ++i)
	{
		if (inputSymbol == VT[i])
		{
			col = i;
			break;
		}
	}
	return M[row][col];
}
// 得到下一个单词
string GetNextSymbol(vector<string> words, int i)
{
	if (i >= words.size())
		return "";
	return words[i];
}
// 语法分析代码
void Test(vector<string>& wordsType,vector<string>& words,vector<string>& lineOfWord, int& symbolIndex, stack<string>& istack, string& word, bool& flag)
{
	string top = istack.top();
	istack.pop();
	if (IsBelongToVT(top))
		if (top == word)
			word = GetNextSymbol(wordsType, ++symbolIndex);
		else
		{
			Error(lineOfWord[symbolIndex],words[symbolIndex]);
			flag = false;
		}
	else if (top == "#")
		if (top == word)
		{
			cout << "成功" << endl;
			flag = false;
		}
		else
		{
			Error(lineOfWord[symbolIndex], words[symbolIndex]);
			flag = false;
		}
	else if (GetFormulaRight(top, word) != "")
	{
		string formulaRight = GetFormulaRight(top, word);
		if (formulaRight != "ε"&&formulaRight.find("ε") != -1)
		{
			formulaRight = GetNextSymbol(wordsType, symbolIndex+1) == "}" ? "ε" :
				formulaRight.substr(0,formulaRight.find("|"));
		}
		if (formulaRight != "ε")
		{
			istringstream tempStream(formulaRight);
			vector<string> words;
			string tempStr = "";
			while (tempStream >> tempStr)
			{
				words.push_back(tempStr);
			}
			for (int i = words.size() - 1; i >= 0; --i)
			{
				istack.push(words[i]); 
			} 
		}
	}
	else
	{
		Error(lineOfWord[symbolIndex], words[symbolIndex]);
		flag = false;
	}

}
// 得到词法分析之后的所有单词的信息
void GetAllWords(ifstream& ifile, vector<string>& wordsType,vector<string>& lineOfWord,vector<string>& words)
{
	string temp = "";
	while (true)
	{
		ifile >> temp;
		if (!ifile)
			break;
		wordsType.push_back(temp);
		ifile >> temp;
		lineOfWord.push_back(temp);
		ifile >> temp;
		ifile >> temp;
		words.push_back(temp);
		
	}
	wordsType.push_back("#");
	lineOfWord.push_back("last line");
	words.push_back("miss something");
}
// 调用词法分析程序,并生成lex.txt文件,文件中包含单词的类别,所在行号,单词本身
void WordAnalysis()
{
	SHELLEXECUTEINFO shellInfo;
	memset(&shellInfo, 0, sizeof(shellInfo));
	shellInfo.cbSize = sizeof(shellInfo);
	shellInfo.hwnd = NULL;
	shellInfo.lpVerb = "open";
	shellInfo.lpFile = "F:\\vs2017\\编译原理\\test1\\Debug\\test1.exe";
	shellInfo.lpParameters = "F:\\vs2017\\编译原理\\test2\\test2\\test.txt F:\\vs2017\\编译原理\\test2\\test2\\lex.txt";
	shellInfo.nShow = SW_SHOWNORMAL;
	shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
	bool bResult = ShellExecuteEx(&shellInfo);
}
int main()
{
	WordAnalysis();
	stack<string> istack; // 分析栈
	ifstream ifile("lex.txt", ios::in);
	istack.push("#");
	istack.push("S");
	vector<string> wordsType;  // 单词类别
	vector<string> words;  // 单词本身
	vector<string> lineOfWord;  // 单词所在行号
	GetAllWords(ifile, wordsType,lineOfWord,words);
	string word = wordsType[0];
	bool flag = true;  // 用来表示分析是否成功,false表示成功
	int symbolIndex = 0;	// 用来标识读到了第几个单词
	while (flag)
	{
		Test(wordsType,words,lineOfWord, symbolIndex, istack, word, flag);
	}
	return 0;
}

语法分析程序显示的程序错误结果 

  • 9
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值