快要机测了,被逼无奈开始做题。。。
1. 思路概述:
言归正传,这道题有几个要注意的点:
- 没有使用到FIRST和FOLLOW集合,举个例子:
PROCEDURE A;
BEGIN
IF SYM in FIRST(TE’) THEN
BEGIN T;E' END
ELSE IF SYM in FIRST(BC) THEN
BEGIN B; C END
ELSE IF SYM in FOLLOW(A) THEN
BEGIN END
ELSE ERROR
END;
//这里找不到“属于”符号..先用“in”替代了
对于能推出空串的非结束符对应的子程序,可以通过判断该非结束符号的FOLLOW集合是否存在目标字符SYM来判断要不要采用空串推导;而这道题的测试点并没有体现这一点,不进行判断直接推导空串反而更符合本题的用例(或许是作者为了减少一些代码量。。。)。
-
进行语法分析前要先判断首字符是否为终结符,虽然我们的程序可以自己判断 输入串 是否是正确的文法,但是前面两步推导
E-->TG, T-->FS与 输入串 无关,因此无论 输入串 的首位是什么都会执行这两步,但是测试点可不允许,所以语法分析前我们要手动筛去首字符就不符合文法的情况。 -
对F的子程序要进行一些特殊处理,因为
F-->(E) | i中存在可以直接判断 输入串 不合规则的能力,像E,T完全由调用其他子程序组成,将问题抛给其他子程序;而G,S有空串推导,可以通过推导空串来将问题抛给上一个调用它的子程序(因为这道题无法通过FOLLOW集合来超前判断);而F有两种确定的判断 输入串 不合理的情况:1. 目标字符SYM不属于F的任意一个候选式的FIRST集合;2. 调用E后没有右括号闭合;此时直接打印error并使用exit(0)结束程序即可。
2. 代码结构:
- 使用一个
Buffer类来进行全局控制,相比全局变量结构更严谨;类设计如下:

buffer:存储输入串;
_border:输入串的边界;
_ptr:当前目标字符;
_count:当前行;
Advance():上一个字符匹配成功后,前进到下一个字符位置;
Push():读取输入串;
Count():更新当前行;
Now():读取当前目标字符;
End():判断程序结束后是否到达#
- 五个子程序:
void CallE(Buffer*);
void CallT(Buffer*);
void CallG(Buffer*);
void CallS(Buffer*);
void CallF(Buffer*);
3. 主体代码:
#include <iostream>
#include <string>
#include <set>
class Buffer {
private:
char buffer[100];
//最后一个元素的_borde-1
int _border = 0;
int _ptr = 0;
int _count = 0;
public:
void Advance() {
this->_ptr++;
}
void Push(char ch) {
buffer[_border++] = ch;
}
void Count() {
std::cout << this->_count<<" ";
this->_count++;
}
char Now() {
return buffer[_ptr];
}
bool End() {
return _ptr == (_border-1);
}
};
void CallE(Buffer*);
void CallT(Buffer*);
void CallG(Buffer*);
void CallS(Buffer*);
void CallF(Buffer*);
std::set<char> followE = { ')','#' };
std::set<char> followG = { ')','#' };
std::set<char> followT = { '+',')','#' };
std::set<char> followS = { '+',')','#' };
std::set<char> followF = { '*','+','#',')' };
std::set<char> firstE = { '(','i' };
std::set<char> firstG = { '+','&' };
std::set<char> firstT = { '(','i' };
std::set<char> firstS = { '*','&' };
std::set<char> firstF = { '(','i' };
std::set<char> Vn = { 'E','G','T','S','F' };
std::set<char> Vt = { 'i','+','(',')','*'};
void CallE(Buffer* buffer) {
buffer->Count();
std::cout << "E-->TG" << std::endl;
CallT(buffer);
CallG(buffer);
}
void CallT(Buffer* buffer) {
buffer->Count();
std::cout << "T-->FS" << std::endl;
CallF(buffer);
CallS(buffer);
}
void CallG(Buffer* buffer) {
if (buffer->Now() == '+'){
buffer->Count();
std::cout << "G-->+TG" << std::endl;
buffer->Advance();
CallT(buffer);
CallG(buffer);
}
else {
buffer->Count();
std::cout << "G-->&" << std::endl;
}
}
void CallS(Buffer* buffer) {
if (buffer->Now() == '*'){
buffer->Count();
std::cout << "S-->*FS" << std::endl;
buffer->Advance();
CallF(buffer);
CallS(buffer);
}
else {
buffer->Count();
std::cout << "S-->&" << std::endl;
}
}
void CallF(Buffer* buffer) {
if (buffer->Now() == '(') {
buffer->Count();
std::cout << "F-->(E)" << std::endl;
buffer->Advance();
CallE(buffer);
if (buffer->Now() == ')') {
buffer->Advance();
}
else {
std::cout << "error" << std::endl;
exit(0);
}
}
else if(buffer->Now() == 'i'){
buffer->Count();
std::cout << "F-->i" << std::endl;
buffer->Advance();
}
else {
std::cout << "error" << std::endl;
exit(0);
}
}
int main()
{
Buffer* buffer = new Buffer();
std::string s = "";
getline(std::cin, s);
for (char c : s) {
buffer->Push(c);
//std::cout << c;
}
if (Vt.count(s[0]) == 0) {
std::cout << "error";
return 0;
}
CallE(buffer);
if (buffer->End())
std::cout << "accept";
else
std::cout << "error";
}
3069

被折叠的 条评论
为什么被折叠?



