《编译原理》实验二:自上而下语法分析(预测分析法)
本实验采用预测分析法,对PL/0语言的算术运算进行语法分析。
本程序由我个人独立完成,代码为C++98,因此可能较丑陋(尤其是预测分析表部分),且不能保证完全正确,还请见谅 ┗( T﹏T )┛
一. 设计思想
1. 文法
(1)EBNF
<表达式> ::= [+|-]<项>{<加法运算符> <项>}
<项> ::= <因子>{<乘法运算符> <因子>}
<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
<加法运算符> ::= +|-
<乘法运算符> ::= *|/
(2)对EBNF中的各对象简称
E:表达式
X:项
Y:因子
A:加法运算符
C:乘法运算符
b:标识符
z:无符号整数
(3)将文法改写成常规的产生式形式
E -> AX|X|EAX
X -> Y|XCY
Y -> b|z|(E)
A -> +|-
C -> *|/
(4)消除左递归后的文法
E -> AXE'|XE'
E' -> AXE'|ε
X -> YX'
X' -> CYX'|ε
Y -> b|z|(E)
A -> +|-
C -> *|/
注意:以上文法为了文章美观在"->"前后添加了空格,实际输入时不要输入空格,否则结果将错误。
2. First集和Follow集
First(E) = {+,-,b,z,(} | Follow(E) = {#,)} |
First(E') = {+,-,ε} | Follow(E') = {#,)} |
First(X) = {b,z,(} | Follow(X) = {+,-,#,)} |
First(X') = {*,/,ε} | Follow(X') = {+,-,#,)} |
First(Y) = {b,z,(} | Follow(Y) = {+,-,#,)} |
First(A) = {+,-} | Follow(A) = {b,z,(} |
First(C) = {*,/} | Follow(C) = {b,z,(} |
满足LL(1)文法的条件,是LL(1)文法。
3. 预测分析表
+ | - | * | / | # | ( | ) | b | z | |
E | E -> AXE' | E -> AXE' | E -> XE' | E -> XE' | E -> XE' | ||||
E' | E -> AXE' | E -> AXE' | E' -> ε | E' -> ε | |||||
X | X -> YX' | X -> YX' | X -> YX' | ||||||
X' | X' -> ε | X' -> ε | X' -> CYX' | X' -> CYX' | X' -> ε | X' -> ε | |||
Y | Y -> (E) | Y -> b | Y -> z | ||||||
A | A -> + | A -> - | |||||||
C | C -> * | C -> / |
二. 算法流程
三. 源程序

1 #include <iostream>
2 #include <string>
3 #include <vector>
4 #include <map>
5 #include <stack>
6 using namespace std;
7
8 vector<vector<string> > input; // 输入(逗号两边)
9 const int nt_num=10; // 非终结符数目
10 const int t_num=10; // 终结符数目
11 vector<string> nonterminal,terminal; // 非终结符数组 终结符数组
12 map<string,int> ntchar2idx; // 非终结符转下标
13 map<string,int> tchar2idx; // 终结符转下标
14 vector<vector<vector<string> > > table(t_num,vector<vector<string> >(nt_num,vector<string>(4,""))); // 预测分析表
15 stack<string> s;
16
17 void getNonterminal() // 非终结符数组
18 {
19 // TODO
20 nonterminal.push_back("E");
21 nonterminal.push_back("E'");
22 nonterminal.push_back("X");
23 nonterminal.push_back("X'");
24 nonterminal.push_back("Y");
25 nonterminal.push_back("A");
26 nonterminal.push_back("C");
27 }
28
29 void getTerminal() // 终结符数组
30 {
31 // TODO
32 terminal.push_back("+");
33 terminal.push_back("-");
34 terminal.push_back("*");
35 terminal.push_back("/");
36 terminal.push_back("#");
37 terminal.push_back("(");
38 terminal.push_back(")");
39 terminal.push_back("b");
40 terminal.push_back("z");
41 }
42
43 bool isTerminal(const string& str) // 判断是否为终结符
44 {
45 for (int i=0;i<(int)terminal.size();++i)
46 {
47 if (str==terminal[i])
48 {
49 return true;
50 }
51 }
52 return false;
53 }
54
55 void char2idx() // (非)终结符转下标
56 {
57 string str;
58 for (int i=0;i<(int)nonterminal.size();++i)
59 {
60 str=nonterminal[i];
61 ntchar2idx[str]=i+1;
62 }
63 for (int i=0;i<(int)terminal.size();++i)
64 {
65 str=terminal[i];
66 tchar2idx[str]=i+1;
67 }
68 }
69
70 void createTable() // 创建预测分析表
71 {
72 // TODO,C++98的写法太丑了。。。
73 string str1[3]={"A","X","E'"};
74 table[1][1].insert(table[1][1].begin(),str1,str1+3);
75 table[1][1].resize(3);
76 string str2[3]={"A","X","E'"};
77 table[1][2].insert(table[1][2].begin(),str2,str2+3);
78 table[1][2].resize(3);
79 string str3[2]={"X","E'"};
80 table[1][6].insert(table[1][6].begin(),str3,str3+2);
81 table[1][6].resize(2);
82 string str4[2]={"X","E'"};
83 table[1][8].insert(table[1][8].begin(),str4,str4+2);
84 table[1][8].resize(2);
85 string str5[2]={"X","E'"};
86 table[1][9].insert(table[1][9].begin(),str5,str5+2);
87 table[1][9].resize(2);
88 string str6[3]={"A","X","E'"};
89 table[2][1].insert(table[2][1].begin(),str6,str6+3);
90 table[2][1].resize(3);
91 string str7[3]={"A","X","E'"};
92 table[2][2].insert(table[2][2].begin(),str7,str7+3);
93 table[2][2].resize(3);
94 string str8[1]={" "};
95 table[2][5].insert(table[2][5].begin(),str8,str8+1);
96 table[2][5].resize(1);
97 string str9[1]={" "};
98 table[2][7].insert(table[2][7].begin(),str9,str9+1);
99 table[2][7].resize(1);
100 string str10[2]={"Y","X'"};
101 table[3][6].insert(table[3][6].begin(),str10,str10+2);
102 table[3][6].resize(2);
103 string str11[2]={"Y","X'"};
104 table[3][8].insert(table[3][8].begin(),str11,str11+2);
105 table[3][8].resize(2);
106 string str12[2]={"Y","X'"};
107 table[3][9].insert(table[3][9].begin(),str12,str12+2);
108 table[3][9].resize(2);
109 string str13[1]={" "};
110 table[4][1].insert(table[4][1].begin(),str13,str13+1);
111 table[4][1].resize(1);
112 string str14[1]={" "};
113 table[4][2].insert(table[4][2].begin(),str14,str14+1);
114 table[4][2].resize(1);
115 string str15[3]={"C","Y","X'"};
116 table[4][3].insert(table[4][3].begin(),str15,str15+3);
117 table[4][3].resize(3);
118 string str16[3]={"C","Y","X'"};
119 table[4][4].insert(table[4][4].begin(),str16,str16+3);
120 table[4][4].resize(3);
121 string str17[1]={" "};
122 table[4][5].insert(table[4][5].begin(),str17,str17+1);
123 table[4][5].resize(1);
124 string str18[1]={" "};
125 table[4][7].insert(table[4][7].begin(),str18,str18+1);
126 table[4][7].resize(1);
127 string str19[3]={"(","E",")"};
128 table[5][6].insert(table[5][6].begin(),str19,str19+3);
129 table[5][6].resize(3);
130 string str20[1]={"b"};
131 table[5][8].insert(table[5][8].begin(),str20,str20+1);
132 table[5][8].resize(1);
133 string str21[1]={"z"};
134 table[5][9].insert(table[5][9].begin(),str21,str21+1);
135 table[5][9].resize(1);
136 string str22[1]={"+"};
137 table[6][1].insert(table[6][1].begin(),str22,str22+1);
138 table[6][1].resize(1);
139 string str23[1]={"-"};
140 table[6][2].insert(table[6][2].begin(),str23,str23+1);
141 table[6][2].resize(1);
142 string str24[1]={"*"};
143 table[7][3].insert(table[7][3].begin(),str24,str24+1);
144 table[7][3].resize(1);
145 string str25[1]={"/"};
146 table[7][4].insert(table[7][4].begin(),str25,str25+1);
147 table[7][4].resize(1);
148 return;
149 }
150
151 inline bool ERROR(int pos)
152 {
153 //cout<<"wrong_pos = "<<pos<<endl;
154 return false;
155 }
156
157 bool predictAnalyse() // 预测分析程序
158 {
159 s.push("#");
160 s.push("E"); //TODO
161 int i=0;
162 string nt,t0,t1;
163 vector<string> vec;
164 while (!s.empty() && i<(int)input.size())
165 { //cout<<"s.size="<<s.size()<<" "<<"i="<<i<<endl;
166 if (isTerminal(s.top())) // 栈顶元素是终结符
167 {
168 t0=input[i][0];
169 if (t0=="ident")
170 {
171 t1="b";
172 }
173 else if (t0=="number")
174 {
175 t1="z";
176 }
177 else
178 {
179 t1=input[i][1];
180 }
181 if (s.top()==t1)
182 {
183 s.pop();
184 ++i;
185 }
186 else
187 {
188 return ERROR(1);
189 }
190 }
191 else // 栈顶元素是非终结符
192 {
193 nt=s.top();
194 s.pop();
195 t0=input[i][0];
196 if (t0=="ident")
197 {
198 t1="b";
199 }
200 else if (t0=="number")
201 {
202 t1="z";
203 }
204 else
205 {
206 t1=input[i][1];
207 }
208 vec.clear();
209 //cout<<ntchar2idx[nt]<<","<<tchar2idx[t1]<<endl;
210 vec.assign(table[ntchar2idx[nt]][tchar2idx[t1]].begin(),table[ntchar2idx[nt]][tchar2idx[t1]].end());
211 if (vec.size())
212 {
213 if (vec[0]==" ")
214 {
215 continue;
216 }
217 else if (vec[0]!="")
218 {
219 for (int i=vec.size()-1;i>=0;--i)
220 {
221 s.push(vec[i]);
222 }
223 }
224 else
225 {
226 return ERROR(2);
227 }
228 }
229 else
230 {
231 return ERROR(3);
232 }
233 }
234 }
235 if (!s.empty() || i<(int)input.size())
236 {
237 return ERROR(4);
238 }
239 return true;
240 }
241
242 int main()
243 {
244 getNonterminal();
245 getTerminal();
246 char2idx();
247 createTable();
248 string str;
249 vector<string> vec;
250 while (cin>>str)
251 {
252 int pos=str.find(',');
253 vec.clear();
254 vec.push_back(str.substr(1,pos-1));
255 vec.push_back(str.substr(pos+1,str.size()-pos-2));
256 // for (auto i:vec)
257 // {
258 // cout<<i<<",";
259 // }cout<<endl;
260 input.push_back(vec);
261 }
262 vec.clear();
263 vec.push_back("#");vec.push_back("#");
264 input.push_back(vec);
265
266 if (predictAnalyse())
267 {
268 cout<<"Yes,it is correct."<<endl;
269 }
270 else
271 {
272 cout<<"No,it is wrong."<<endl;
273 }
274
275 return 0;
276 }
注释为TODO的代码由两个预期程序进行替换:
1.实验1的词法分析程序
2.自构建预测分析表程序(从输入文法到去掉左递归到First、Follow集再到预测分析表),感觉较难
四. 调试数据
1.样例输入:
1 (lparen,()
2 (ident,a)
3 (plus,+)
4 (number,15)
5 (rparen,))
6 (times,*)
7 (ident,b)
样例输出:
Yes,it is correct.
图片展示:
2.样例输入:
1 (number,0)
2 (plus,+)
3 (number,10)
4 (times,*)
5 (ident,b)
6 (minus,-)
7 (lparen,()
8 (ident,z)
9 (slash,/)
10 (number,3)
11 (rparen,))
样例输出:
Yes,it is correct.
图片展示:
3.样例输入:
1 (lparen,()
2 (lparen,()
3 (ident,a)
4 (plus,+)
5 (number,3)
6 (rparen,))
7 (times,*)
8 (lparen,()
9 (number,0)
10 (minus,-)
11 (ident,b)
12 (rparen,))
13 (minus,-)
14 (ident,c)
15 (slash,/)
16 (number,0)
17 (plus,+)
18 (lparen,()
19 (ident,a)
20 (times,*)
21 (ident,d)
22 (slash,/)
23 (ident,e)
24 (plus,+)
25 (ident,f)
26 (rparen,))
27 (rparen,))
样例输出:
Yes,it is correct.
图片展示:
4.样例输入:
1 (lparen,()
2 (ident,a)
3 (plus,+)
4 (number,15)
5 (rparen,))
6 (times,*)
样例输出:
No,it is wrong.
图片展示:
5.样例输入:
1 (ident,a)
2 (plus,+)
3 (number,15)
4 (rparen,))
5 (times,*)
6 (ident,b)
样例输出:
No,it is wrong.
图片展示:
6.样例输入:
1 (number,0)
2 (plus,+)
3 (number,10)
4 (times,*)
5 (ident,b)
6 (lparen,()
7 (ident,z)
8 (slash,/)
9 (number,3)
10 (rparen,))
样例输出:
No,it is wrong.
图片展示:
注:文法只包含简单的+、-、*、/运算等,而像实验1中的const和:=等符号均未引入。
五. 实验调试情况及体会
略
六. thinking & upgrade
1.将实验1的词法分析写入本实验:

1 #include <iostream>
2 #include <string>
3 #include <vector>
4 #include <map>
5 #include <stack>
6 using namespace std;
7
8 vector<vector<string> > input; // 输入(逗号两边)
9 const int nt_num=10; // 非终结符数目
10 const int t_num=10; // 终结符数目
11 vector<string> nonterminal,terminal; // 非终结符数组 终结符数组
12 map<string,int> ntchar2idx; // 非终结符转下标
13 map<string,int> tchar2idx; // 终结符转下标
14 vector<vector<vector<string> > > table(t_num,vector<vector<string> >(nt_num,vector<string>(4,""))); // 预测分析表
15 stack<string> s;
16
17 void getNonterminal() // 非终结符数组
18 {
19 // TODO
20 nonterminal.push_back("E");
21 nonterminal.push_back("E'");
22 nonterminal.push_back("X");
23 nonterminal.push_back("X'");
24 nonterminal.push_back("Y");
25 nonterminal.push_back("A");
26 nonterminal.push_back("C");
27 }
28
29 void getTerminal() // 终结符数组
30 {
31 // TODO
32 terminal.push_back("+");
33 terminal.push_back("-");
34 terminal.push_back("*");
35 terminal.push_back("/");
36 terminal.push_back("#");
37 terminal.push_back("(");
38 terminal.push_back(")");
39 terminal.push_back("b");
40 terminal.push_back("z");
41 }
42
43 bool isTerminal(const string& str) // 判断是否为终结符
44 {
45 for (int i=0;i<(int)terminal.size();++i)
46 {
47 if (str==terminal[i])
48 {
49 return true;
50 }
51 }
52 return false;
53 }
54
55 void char2idx() // (非)终结符转下标
56 {
57 string str;
58 for (int i=0;i<(int)nonterminal.size();++i)
59 {
60 str=nonterminal[i];
61 ntchar2idx[str]=i+1;
62 }
63 for (int i=0;i<(int)terminal.size();++i)
64 {
65 str=terminal[i];
66 tchar2idx[str]=i+1;
67 }
68 }
69
70 void createTable() // 创建预测分析表
71 {
72 // TODO,C++98的写法太丑了。。。
73 string str1[3]={"A","X","E'"};
74 table[1][1].insert(table[1][1].begin(),str1,str1+3);
75 table[1][1].resize(3);
76 string str2[3]={"A","X","E'"};
77 table[1][2].insert(table[1][2].begin(),str2,str2+3);
78 table[1][2].resize(3);
79 string str3[2]={"X","E'"};
80 table[1][6].insert(table[1][6].begin(),str3,str3+2);
81 table[1][6].resize(2);
82 string str4[2]={"X","E'"};
83 table[1][8].insert(table[1][8].begin(),str4,str4+2);
84 table[1][8].resize(2);
85 string str5[2]={"X","E'"};
86 table[1][9].insert(table[1][9].begin(),str5,str5+2);
87 table[1][9].resize(2);
88 string str6[3]={"A","X","E'"};
89 table[2][1].insert(table[2][1].begin(),str6,str6+3);
90 table[2][1].resize(3);
91 string str7[3]={"A","X","E'"};
92 table[2][2].insert(table[2][2].begin(),str7,str7+3);
93 table[2][2].resize(3);
94 string str8[1]={" "};
95 table[2][5].insert(table[2][5].begin(),str8,str8+1);
96 table[2][5].resize(1);
97 string str9[1]={" "};
98 table[2][7].insert(table[2][7].begin(),str9,str9+1);
99 table[2][7].resize(1);
100 string str10[2]={"Y","X'"};
101 table[3][6].insert(table[3][6].begin(),str10,str10+2);
102 table[3][6].resize(2);
103 string str11[2]={"Y","X'"};
104 table[3][8].insert(table[3][8].begin(),str11,str11+2);
105 table[3][8].resize(2);
106 string str12[2]={"Y","X'"};
107 table[3][9].insert(table[3][9].begin(),str12,str12+2);
108 table[3][9].resize(2);
109 string str13[1]={" "};
110 table[4][1].insert(table[4][1].begin(),str13,str13+1);
111 table[4][1].resize(1);
112 string str14[1]={" "};
113 table[4][2].insert(table[4][2].begin(),str14,str14+1);
114 table[4][2].resize(1);
115 string str15[3]={"C","Y","X'"};
116 table[4][3].insert(table[4][3].begin(),str15,str15+3);
117 table[4][3].resize(3);
118 string str16[3]={"C","Y","X'"};
119 table[4][4].insert(table[4][4].begin(),str16,str16+3);
120 table[4][4].resize(3);
121 string str17[1]={" "};
122 table[4][5].insert(table[4][5].begin(),str17,str17+1);
123 table[4][5].resize(1);
124 string str18[1]={" "};
125 table[4][7].insert(table[4][7].begin(),str18,str18+1);
126 table[4][7].resize(1);
127 string str19[3]={"(","E",")"};
128 table[5][6].insert(table[5][6].begin(),str19,str19+3);
129 table[5][6].resize(3);
130 string str20[1]={"b"};
131 table[5][8].insert(table[5][8].begin(),str20,str20+1);
132 table[5][8].resize(1);
133 string str21[1]={"z"};
134 table[5][9].insert(table[5][9].begin(),str21,str21+1);
135 table[5][9].resize(1);
136 string str22[1]={"+"};
137 table[6][1].insert(table[6][1].begin(),str22,str22+1);
138 table[6][1].resize(1);
139 string str23[1]={"-"};
140 table[6][2].insert(table[6][2].begin(),str23,str23+1);
141 table[6][2].resize(1);
142 string str24[1]={"*"};
143 table[7][3].insert(table[7][3].begin(),str24,str24+1);
144 table[7][3].resize(1);
145 string str25[1]={"/"};
146 table[7][4].insert(table[7][4].begin(),str25,str25+1);
147 table[7][4].resize(1);
148 return;
149 }
150
151 inline bool ERROR(int pos)
152 {
153 //cout<<"wrong_pos = "<<pos<<endl;
154 return false;
155 }
156
157 bool predictAnalyse() // 预测分析程序
158 {
159 s.push("#");
160 s.push("E"); //TODO
161 int i=0;
162 string nt,t0,t1;
163 vector<string> vec;
164 while (!s.empty() && i<(int)input.size())
165 {
166 if (isTerminal(s.top())) // 栈顶元素是终结符
167 {
168 t0=input[i][0];
169 if (t0=="ident")
170 {
171 t1="b";
172 }
173 else if (t0=="number")
174 {
175 t1="z";
176 }
177 else
178 {
179 t1=input[i][1];
180 }
181 if (s.top()==t1)
182 {
183 s.pop();
184 ++i;
185 }
186 else
187 {
188 return ERROR(1);
189 }
190 }
191 else // 栈顶元素是非终结符
192 {
193 nt=s.top();
194 s.pop();
195 t0=input[i][0];
196 if (t0=="ident")
197 {
198 t1="b";
199 }
200 else if (t0=="number")
201 {
202 t1="z";
203 }
204 else
205 {
206 t1=input[i][1];
207 }
208 vec.clear();
209 vec.assign(table[ntchar2idx[nt]][tchar2idx[t1]].begin(),table[ntchar2idx[nt]][tchar2idx[t1]].end());
210 if (vec.size())
211 {
212 if (vec[0]==" ")
213 {
214 continue;
215 }
216 else if (vec[0]!="")
217 {
218 for (int i=vec.size()-1;i>=0;--i)
219 {
220 s.push(vec[i]);
221 }
222 }
223 else
224 {
225 return ERROR(2);
226 }
227 }
228 else
229 {
230 return ERROR(3);
231 }
232 }
233 }
234 if (!s.empty() || i<(int)input.size())
235 {
236 return ERROR(4);
237 }
238 return true;
239 }
240
241 /* 词法分析start */
242 void getChar(const string s,int& idx,char& ch) // 取下个字符
243 {
244 ch=s[idx++];
245 return;
246 }
247
248 void getBC(const string s,int& idx,char& ch) // 跳过空格
249 {
250 while (ch==' ')
251 {
252 getChar(s,idx,ch);
253 }
254 return;
255 }
256
257 void concat(string& strToken,const char ch) // 字符拼接
258 {
259 strToken+=ch;
260 return;
261 }
262
263 void retract(int& idx,char& ch) // 退一格
264 {
265 --idx;
266 ch=' ';
267 return;
268 }
269 // 基本字数组
270 string basicWord[13]={"begin","call","const","do","end",
271 "if","odd","procedure","read",
272 "then","var","while","write"};
273 // 处理基本字
274 string basic(const string strToken)
275 {
276 bool isbasic=false;
277 for (int i=0;i<13;++i)
278 {
279 if (strToken==basicWord[i])
280 {
281 isbasic=true;
282 break;
283 }
284 }
285 if (isbasic) // 如果是基本字
286 {
287 return strToken;
288 }
289 else // 否则是标识符
290 {
291 return "ident";
292 }
293 }
294 /* 词法分析end */
295
296 void getInput()
297 {
298 string s="";
299 string str;
300 while (cin>>str) // 循环读入
301 {
302 s=s+' '+str;
303 }
304
305 int idx=0;
306 while (idx<(int)s.length()) // 处理每个字符
307 {
308 char ch=' ';
309 string strToken="";
310 getChar(s,idx,ch);
311 getBC(s,idx,ch);
312 if (isalpha(ch)) // 如果是字母
313 {
314 while (isalnum(ch)) // 读字母或数字
315 {
316 concat(strToken,ch);
317 getChar(s,idx,ch);
318 }
319 retract(idx,ch);
320 string ret=basic(strToken);
321 if (ret=="ident")
322 {
323 input.push_back({"ident",strToken});
324 }
325 else
326 {
327 input.push_back({string(ret+"sym"),strToken});
328 }
329 }
330 else if (isdigit(ch)) // 如果是数字
331 {
332 while (isdigit(ch)) // 持续获取数字
333 {
334 concat(strToken,ch); // 将所有数字拼起来
335 getChar(s,idx,ch); // 下一个字符
336 }
337 retract(idx,ch);
338 input.push_back({"number",strToken});
339 }
340 else if (ch=='+')
341 {
342 input.push_back({"plus","+"});
343 }
344 else if (ch=='-')
345 {
346 input.push_back({"minus","-"});
347 }
348 else if (ch=='*')
349 {
350 input.push_back({"times","*"});
351 }
352 else if (ch=='/')
353 {
354 input.push_back({"slash","/"});
355 }
356 else if (ch=='=')
357 {
358 input.push_back({"eql","="});
359 }
360 else if (ch=='<') // '<'后有 <>、<= 两种可能
361 {
362 getChar(s,idx,ch);
363 if (ch=='>')
364 {
365 input.push_back({"neq","<>"});
366 }
367 else if (ch=='=')
368 {
369 input.push_back({"leq","<="});
370 }
371 else
372 {
373 retract(idx,ch);
374 input.push_back({"les","<"});
375 }
376 }
377 else if (ch=='>') // '>'后有 >= 的可能
378 {
379 getChar(s,idx,ch);
380 if (ch=='=')
381 {
382 input.push_back({"geq",">="});
383 }
384 else
385 {
386 retract(idx,ch);
387 input.push_back({"gtr",">"});
388 }
389 }
390 else if (ch==':')
391 {
392 getChar(s,idx,ch);
393 if (ch=='=')
394 {
395 input.push_back({"becomes",":="});
396 }
397 }
398 else if (ch=='(')
399 {
400 input.push_back({"lparen","("});
401 }
402 else if (ch==')')
403 {
404 input.push_back({"rparen",")"});
405 }
406 else if (ch==',')
407 {
408 input.push_back({"comma",","});
409 }
410 else if (ch==';')
411 {
412 input.push_back({"semicolon",";"});
413 }
414 else if (ch=='.')
415 {
416 input.push_back({"period","."});
417 }
418 else
419 {
420 str=ch;
421 input.push_back({"OTHER",str});
422 }
423 }
424 // for (int i=0;i<(int)input.size();++i) // 输出
425 // {
426 // cout<<input[i][0]<<" "<<input[i][1]<<endl;
427 // }
428 return;
429 }
430
431 int main()
432 {
433 getNonterminal();
434 getTerminal();
435 char2idx();
436 createTable();
437 string str;
438 vector<string> vec;
439 getInput();
440 vec.clear();
441 vec.push_back("#");vec.push_back("#");
442 input.push_back(vec);
443
444 if (predictAnalyse())
445 {
446 cout<<"Yes,it is correct."<<endl;
447 }
448 else
449 {
450 cout<<"No,it is wrong."<<endl;
451 }
452
453 return 0;
454 }
2.将自构建预测分析表写入本实验:
时间紧张就不写了。。。
参考博客:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库