编译原理实验二(LL1分析法)

Posted by nop on 2020-04-08
Words 1.1k In Total

说明

实验代码采用多文件的形式,即包含三部分:

  1. ll1.h : 结构体以及类(成员函数等)的声明
  2. lll1.cpp : 类的成员函数的实现
  3. main.cpp : 主调函数, 完成用户输入的大概判断以及类的的实例化

实验流程图

Alt

实验代码

  • ll1.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// ll1.h
#include <iostream>
using namespace std;

#ifndef LL1_H
#define LL1_H


#define LEN_VT 8
#define LEN_VN 5

struct stack
{
char ch;
stack *next;
stack *front;
};
// 双链表模拟栈

class LL1
{
public:
LL1(char input[], int len); // 构造函数
void stack_pop(char *ch); // 弹栈, 将栈顶元素弹出
void stack_push(char ch); // 压栈,将压到栈顶
bool isVn(char ch); // 判断非终结符
int getIndex(char ch, char table[], int len); // 查找数组下标

void Atable(); // 分析表处理
void show(int step, char *in, string CA, string action); // 输出分析结果
private:
stack *bp,*sp; //栈低、栈顶指针
char X, Y; // 临时存放从栈顶取出的字符和从输入缓冲中取出的字符
char Vt[8] = {'i', '(', ')', '*', '/', '+', '-', '#'}; // 终结符和‘#’
char Vn[5] = {'E', 'G', 'T', 'S', 'F'}; // 非终结符
char input[10]; // 输入缓冲区
/*
E->TG
G->+TG|-TG
G->~
T->FS
S->*FS|/FS
S->~
F->(E)
F->i
*/
/*
***************FIRST***********************
FIRST(E)={(,i}
FIRST(F)={(,i}
FIRST(G)={+,-,~}
FIRST(S)={*,/,~}
FIRST(T)={(,i}
****************FOLLOW**********************
FOLLOW(E)={#,)}
FOLLOW(F)={#,),*,+,-,/}
FOLLOW(G)={#,)}
FOLLOW(S)={#,),+,-}
FOLLOW(T)={#,),+,-}
*/
string vTable[5][8] = {
{"E->TG", "E->TG", "Error", "Error", "Error", "Error", "Error", "Error"},// E
{"Error", "Error", "G->~", "Error", "Error", "G->+TG", "G->-TG", "G->~"},// G
{"T->FS", "T->FS", "Error", "Error", "Error", "Error", "Error", "Error"},// T
{"Error", "Error", "S->~", "S->*FS", "S->/FS", "S->~", "S->~", "S->~"},// S
{"F->i", "(E)", "Error", "Error", "Error", "Error", "Error", "Error"} // F
}; //预测分析表
};

#endif
  • ll1.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//ll1.cpp
#include "ll1.h"
#include<cstring>
#include <algorithm>

void LL1::show(int i, char *in, string CA, string action)
{
string a_stack;
stack *p;
p = bp;
do{
a_stack += p->ch;
p = p->next;
}while(p != NULL);
cout<<i<<"\t\t"<<a_stack<<"\t\t"<<in<<"\t\t"<<CA<<"\t\t"<<action<<endl;
}

void LL1::Atable()
{
printf("Step\t\tStack\t\tInput\t\tC-A\t\tAction\n");
char *p = input;
int i=0; // 记录步数
char sp_value; // 临时记录弹出的栈顶符号
stack_push('E');
show(i++, p, "", "init");
X = sp->ch;
Y = *p;
while(X != '#' && Y != '#'){ // 分析结束条件
X = sp->ch;
Y = *p;
if(X == Y && X!= '#' && Y != '#'){
stack_pop(&sp_value); // 栈顶元素弹出
p++; // 指向下一个字符
show(i++, p, "","GETNEXT(I)");
}else if(isVn(X)){
string temp;
temp = vTable[getIndex(X,Vn,5)][getIndex(Y,Vt,8)];
if(temp != "Error"){
if(temp[3] == '~'){
stack_pop(&sp_value);
X = sp->ch;
show(i++, p, temp, "POP");
}else{
string t = temp;
temp = temp.substr(3,temp.length()-3); // 截取产生式右部
reverse(temp.begin(), temp.end());
stack_pop(&sp_value);
for(int j=0; j<temp.length(); j++)
stack_push(temp[j]);
X = sp->ch;
show(i++, p, t, "POP,PUSH("+t.substr(3,t.length()-3)+")");
}
}else{
// M[X,a]对应位置为Error的情况
cout<<"Error:Input string is invalid"<<endl;
break;
}

}else{
cout<<"Error:wrong input!"<<endl;
break;
}
}
}

int LL1::getIndex(char ch, char table[], int len)
{
int i=0;
for(i; i<len;i++)
if(ch == table[i])
return i;
else
continue;
return -1; //查找失败
}

bool LL1::isVn(char ch)
{
for(int i=0; i<LEN_VN; i++){
if(ch == Vn[i])
return true;
else
continue;
}
return false;
}

void LL1::stack_pop(char *ch)
{
stack *p;
p = sp;
*ch = p->ch;
sp = sp->front;
sp->next = NULL;
p->front = NULL;
delete p;
}

void LL1::stack_push(char ch)
{
/*
模拟压栈操作
*/
stack *q;
q = new stack;
q->ch = ch;
q->next = NULL;
q->front = sp;
sp->next = q;
sp = q;
}

LL1::LL1(char in[], int len)
{
// 初始化栈
sp = new stack;
sp->ch = '#';
sp->front = NULL;
sp->next = NULL;
bp = sp;

for(int i=0; i<=len ; i++) // 初始化缓冲半区
input[i] = in[i];
}
  • mian.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//main.cpp
#include "ll1.h"

int main()
{
cout<<"Only the following characters are supported:"<<endl;
cout<<"'i', '(', ')', '*', '/', '+', '-'\n"<<endl;
// 主调函数获取输入写入缓冲区
char input[10]="i+i*i#";
start:
cout<<"Enter a string ending in #: ";
cin>>input;
int i = 0;
char ch;
while((ch=input[i]) != '#'){
if(ch == 'i' || ch == '(' \
|| ch == ')' || ch == '*' \
|| ch == '/' || ch == '+' || ch == '-')
if(i<10){
input[i] = ch;
i++;
continue;
}
else{
cout<<"input too long"<<endl;
goto start;
}
else{
cout<<"wrong input!"<<endl;
goto start;
}
}
LL1 L(input, i);
L.Atable();
}

You are welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them.