c++前提:给定预测分析表,见教材 P76 表 4.1(对应文法为文法 4.2) 要求:构造出相关预测分析程序,并返回一个符号串的分析结果,如果是一个合法的符号串输出正确标志并返回 True,否则输出错误标志并返回 False。 参考:教材 P76-78 4.5 预测分析程序。
时间: 2023-12-10 14:38:33 浏览: 92
这是一个典型的 LL(1) 文法的预测分析程序,可以按照以下步骤实现:
1. 定义文法符号和预测分析表
我们可以按照文法 4.2 的定义,定义终结符号和非终结符号:
```c++
enum Symbol {
S, A, B, C, D, PLUS, MINUS, TIMES, DIVIDE, LPAREN, RPAREN, ID, NUM,
END
};
```
其中,S 是文法的起始符号,PLUS、MINUS、TIMES、DIVIDE、LPAREN、RPAREN、ID、NUM、END 是终结符号,A、B、C、D 是非终结符号。
接下来,我们需要构造预测分析表。表格中每一行对应一个非终结符号,每一列对应一个终结符号或者 $ \$$ (表示输入串已经结束),表格中的每个单元格中存储了一个产生式的编号,或者是一个错误标记。
我们可以使用一个二维数组来存储预测分析表:
```c++
const int kTableRows = 5;
const int kTableCols = 10;
int prediction_table[kTableRows][kTableCols] = {
// + - * / ( ) i n $ E
{ 0, 0, 0, 0, 1, 0, 1, 1, 0, 0 }, // S
{ 2, 3, 0, 0, 0, 4, 5, 5, -1, 0 }, // A
{ 0, 0, 6, 7, 0, 0, 8, 8, -1, 0 }, // B
{ 0, 0, 9, 10, 0, 0, 11, 11, -1, 0 }, // C
{ 0, 0, 0, 0, 0, 0, 12, 13, -1, 0 }, // D
};
```
在数组中,-1 表示错误标记,0 表示该单元格为空(无产生式),其他正整数表示对应的产生式的编号。
2. 定义产生式
按照文法 4.2 的定义,我们可以定义以下产生式:
```c++
const int kNumProductions = 13;
struct Production {
Symbol lhs;
std::vector<Symbol> rhs;
};
Production productions[kNumProductions] = {
{ S, { E } },
{ E, { A } },
{ A, { B, PLUS, A } },
{ A, { B, MINUS, A } },
{ A, { B } },
{ B, { C, TIMES, B } },
{ B, { C, DIVIDE, B } },
{ B, { C } },
{ C, { LPAREN, A, RPAREN } },
{ C, { ID } },
{ C, { NUM } },
{ D, { PLUS, C } },
{ D, { MINUS, C } },
};
```
其中,lhs 表示产生式左部的符号,rhs 表示产生式右部的符号序列。
3. 实现预测分析程序
我们可以按照教材 P76-78 的算法,实现一个 LL(1) 预测分析程序:
```c++
bool Predict(std::vector<Symbol>& input) {
std::stack<Symbol> symbols;
symbols.push(END);
symbols.push(S);
auto it = input.begin();
while (!symbols.empty()) {
Symbol top = symbols.top();
symbols.pop();
if (top == END) {
if (it == input.end()) {
// 输入串已经结束,分析成功
return true;
} else {
// 输入串还未结束,分析失败
return false;
}
}
if (top == *it) {
// 栈顶和输入符号匹配,继续读入下一个输入符号
++it;
} else if (IsTerminal(top) || prediction_table[GetIndex(top)][GetIndex(*it)] == -1) {
// 栈顶是一个终结符号,或者预测分析表中没有对应的产生式,分析失败
return false;
} else {
// 栈顶是一个非终结符号,根据预测分析表选择产生式
int prod_index = prediction_table[GetIndex(top)][GetIndex(*it)];
const auto& prod = productions[prod_index];
for (auto it = prod.rhs.rbegin(); it != prod.rhs.rend(); ++it) {
symbols.push(*it);
}
}
}
return false;
}
```
其中,IsTerminal 函数用于判断一个符号是不是终结符号:
```c++
bool IsTerminal(Symbol s) {
return s <= END;
}
```
GetIndex 函数用于获取一个符号在预测分析表中的索引:
```c++
int GetIndex(Symbol s) {
switch (s) {
case PLUS:
return 0;
case MINUS:
return 1;
case TIMES:
return 2;
case DIVIDE:
return 3;
case LPAREN:
return 4;
case RPAREN:
return 5;
case ID:
return 6;
case NUM:
return 7;
case END:
return 8;
case S:
case A:
case B:
case C:
case D:
return 9;
default:
return -1;
}
}
```
4. 测试预测分析程序
我们可以使用以下代码测试预测分析程序:
```c++
int main() {
std::vector<Symbol> input = {
ID, PLUS, NUM, TIMES, LPAREN, NUM, MINUS, ID, RPAREN, END
};
bool result = Predict(input);
if (result) {
std::cout << "Input is a valid string!" << std::endl;
} else {
std::cout << "Input is an invalid string!" << std::endl;
}
return 0;
}
```
输出结果应该是:
```
Input is a valid string!
```
这说明输入的符号串是一个合法的字符串。
阅读全文