LL(1)语法分析实现
目录
- 一、 实验目的
- 二、 实验内容
- 三、 实验要求
- 四、 运行结果
- 1.解析文法
- 2.语法分析
一、 实验目的
设计一个LL(1)语法分析器,利用语法分析器对符号串的识别,加深对语法分析原理的理解。
二、 实验内容
设计并实现一个LL(1)语法分析器,实现对算术文法G[E]:E->E+T|T T->TF|F F->(E)|i所定义的符号串进行识别,例如符号串(string1.txt) abc+age+80为文法所定义的句子,符号串(string2.txt) (abc-80(s5)不是文法所定义的句子。
三、 实验要求
-
检测左递归,如果有则进行消除,实现remove_left_recursion()函数;消除直接左递归(已实现)。
-
求解FIRST集和FOLLOW集,分别实现getFirst()和getFollow()函数;
-
理解构建LL(1)分析表getTable()中的代码,实现格式打印分析表的功能(显示Table部分);
-
对于输入符号串,实现自顶向下的LL(1)分析,打印出分析过程:AnalyzePredict函数。
四、 运行结果
测试源文件:
E->T|E+T;
T->F|T*F;
F->i|(E);
1.解析文法
原文法 | 消除左递归后 | |
---|---|---|
规格显示 | ![]() |
![]() |
FIRST集 | ![]() |
![]() |
FOLLOW集 | ![]() |
![]() |
Table表 | ![]() |
![]() |
2.语法分析
1)对string1 (string1.txt)的tocken(out1.txt)进行语法分析
String1.txt | out1.txt |
---|---|
![]() |
![]() |
分析结果parse_result1.txt
2)对string2 (string2.txt)的tocken(out2.txt)进行语法分析
String2.txt | Out2.txt |
---|---|
![]() |
![]() |
分析结果parse_result2.txt
实验代码:
parse_my.cpp
#include
#include
#include
#include
#include
lex.cpp
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1e4;
const int maxlen = 1e4;
char operate[11][10] = { "+","-","*","/",">","<","=","(",")",";" ,"|"};
char keyword[5][10] = { "if","then","else","while","do" };
class lexical {
private:
static const int rowope = 11;//操作符个数
static const int rowkey = 5;//关键字个数
struct Twotuples {
char kind[10];
char proper[10];
}tuples[maxlen];
string filename;
public:
bool isCal(char *s, int &length) {
char sub[100];
for (int i = 0; i < rowope; i++) {
int len = strlen(operate[i]);
strncpy(sub, s, len);
sub[len] = '\0';
if (strcmp(sub, operate[i]) == 0) {
length = len;
return true;
}
}
return false;
}
bool isKey(char *s, int &length) {
char sub[100];
int num = 0;
while (isalpha(*(s + num))) {
num++;
}
length = num;
for (int i = 0; i < rowkey; i++) {
strncpy(sub, s, length);
sub[length] = '\0';
if (strcmp(sub, keyword[i]) == 0 && !isalpha(*(s + length))) {
return true;
}
}
return false;
}
bool isTen(char *s, int &length) {
if (s[0] == '0'&&!isdigit(s[1]) && s[1] != 'x') {
length = 1;
return true;
}
else
if (s[0] >= '1'&&s[0] <= '9') {
int num = 0;
while (isdigit(*(s + num))) {
num++;
}
length = num;
return true;
}
return false;
}
bool isEight(char *s, int &length) {
if (s[0] == '0' && (s[1] >= '1'&&s[1] <= '7')) {
int num = 0;
while (s[num] >= '0'&&s[num] <= '7') {
num++;
cout<<"1";
}
length = num;
return true;
}
return false;
}
bool isSixteen(char *s, int &length) {
if (s[0] == '0' && s[1] == 'x' && ((s[2] >= '0'&&s[2] <= '9') || (s[2] >= 'a'&&s[2] <= 'f'))) {
int num = 2;
while ((s[num] >= '0'&&s[num] <= '9') || (s[num] >= 'a'&&s[num] <= 'f')) {
num++;
cout<<"2";
}
length = num;
return true;
}
return false;
}
void scan(char *str, int &p1, int &p2) {
int len = 0;
char str_[] = "-";
char sub[100];
//运算符和界符
if (isCal(str + p1, len)) {
strncpy(sub, str + p1, len);
sub[len] = '\0';
strcpy(tuples[p2].kind, sub);
strcpy(tuples[p2].proper, str_);
p1 += len;
p2++;
}
//关键字
if (isKey(str + p1, len)) {
strncpy(sub, str + p1, len);
sub[len] = '\0';
strcpy(tuples[p2].kind, sub);
strcpy(tuples[p2].proper, str_);
p1 += len;
p2++;
}
//标识符
if (isalpha(*(str + p1))) {
int len = 0;
while (isalpha(*(str + p1 + len)) || isdigit(*(str + p1 + len))) {
len++;
cout<<"3";
}
strncpy(sub, str + p1, len);
sub[len] = '\0';
strcpy(tuples[p2].kind, "0");
strcpy(tuples[p2].proper, sub);
p1 += len;
p2++;
}
//十进制数字
if (isTen(str + p1, len)) {
strncpy(sub, str + p1, len);
sub[len] = '\0';
strcpy(tuples[p2].kind, "1");
strcpy(tuples[p2].proper, sub);
p1 += len;
p2++;
}
if (isEight(str + p1, len)) {
strncpy(sub, str + p1 + 1, len - 1);
sub[len - 1] = '\0';
strcpy(tuples[p2].kind, "2");
strcpy(tuples[p2].proper, sub);
p1 += len;
p2++;
}
if (isSixteen(str + p1, len)) {
strncpy(sub, str + p1 + 2, len - 2);
sub[len - 2] = '\0';
strcpy(tuples[p2].kind, "3");
strcpy(tuples[p2].proper, sub);
p1 += len;
p2++;
}
}
lexical(string inputfile , string outputfile) {
this->filename = inputfile;
char *buffer = new char[maxlen];
ifstream in(filename);
if (!in.is_open()) {
cout << "文件打开失败" << endl;
exit(1);
}
in.getline(buffer, maxlen, '#');
int len = strlen(buffer);
bool flagend = false;
for (int i = 0; i < strlen(buffer); i++) {
if (buffer[i] == '#') {
flagend = true;
break;
}
}
if (!flagend)buffer[len++] = '#';
buffer[len] = '\0';
cout << buffer << endl;
int buf_ptr = 0;
int tup_ptr = 0;
while (true) {
if (buffer[buf_ptr] == '#')break;
if (buffer[buf_ptr] == ' ' || buffer[buf_ptr] == '\n') {
buf_ptr++;
continue;
}
if (buffer[buf_ptr] == '\t') {
buf_ptr += 4;
continue;
}
scan(buffer, buf_ptr, tup_ptr);
}
cout.setf(std::ios::left);
ofstream out(outputfile);
for (int i = 0; i < tup_ptr; i++) {
out << "<" << setw(5) << tuples[i].kind << "," << setw(5) << tuples[i].proper << ">" << endl;
cout << "<" << setw(5) << tuples[i].kind << "," << setw(5) << tuples[i].proper << ">" << endl;
}
}
};
int main()
{
string pwd = "C:\\Users\\46855\\Desktop\\c\\grammaticalAnalysis\\";
// string filename1 = pwd + "parse_test1.txt";
// string filename1 = pwd + "string1.txt";
// string filename2= pwd + "Parsing\\out1.txt";
string filename1 = pwd + "string2.txt";
string filename2= pwd + "Parsing\\out2.txt";
lexical *text = new lexical(filename1,filename2);
system("pause");
return 0;
}