语法分析是指,根据词法分析后生成的单词,根据语法规则,检查是否存在语法错误
实验步骤:
(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)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)将文法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;
}
语法分析程序显示的程序错误结果