i+i*i#
是否符合给定文法,加深对FIRST集、FOLLOW集、SELECT集计算方法的理解。实验规定对下列文法,用LL(1)分析法对任意输入的符号串进行分析:
(1)E::=TG
(2)G::=+TG
(3)G::=ε
(4)T::=FS
(5)S::=*FS
(6)S::=ε
(7)F::=(E)
(8)F::=i
若输入串为i+i*i# ,则输出为:
步骤 | 分析栈 | 剩余输入 | 动作 |
---|---|---|---|
1 | #E | i+i*i# | E→TG,栈变为#GT |
2 | #GT | i+i*i# | T→FS,栈变为#GSF |
3 | #GSF | i+i*i# | F→i,匹配i,栈变为#GS |
4 | #GS | +i*i# | S→ε,弹出,栈变为#G |
5 | #G | +i*i# | G→+TG,栈变为#GT+ |
6 | #GT+ | i*i# | 匹配+,栈变为#GT |
7 | #GT | i*i# | T→FS,栈变为#GSF |
8 | #GSF | i*i# | F→i,匹配i,栈变为#GS |
9 | #GS | *i# | S→FS,栈变为#GSF |
10 | #GSF* | i# | 匹配*,栈变为#GSF |
11 | #GSF | i# | F→i,匹配i,栈变为#GS |
12 | #GS | # | S→ε,弹出,栈变为#G |
13 | #G | # | G→ε,弹出,栈变为# |
14 | # | # | 分析成功 |
FIRST(α)
(若α不能推导出ε)或FIRST(α) ∪ FOLLOW(A)
(若α可推导出ε)。非终结符 | 输入符号 | 产生式 |
---|---|---|
A | a | 若a ∈ SELECT(A→α),填入A→α |
符号 | FIRST集 |
---|---|
E | { i, ( } |
G | { +, ε } |
T | { i, ( } |
S | { *, ε } |
F | { i, ( } |
符号 | FOLLOW集 |
---|---|
E | { ), # } |
G | { ), # } |
T | { +, ), # } |
S | { +, ), # } |
F | { *, +, ), # } |
产生式 | SELECT集 |
---|---|
E → T G | { i, ( } |
G → + T G | { + } |
G → ε | { ), # } |
T → F S | { i, ( } |
S → * F S | { * } |
S → ε | { +, ), # } |
F → ( E ) | { ( } |
F → i | { i } |
验证:同一非终结符的候选式SELECT集无交集,满足LL(1)条件。
非终结符 | i | + | * | ( | ) | # |
---|---|---|---|---|---|---|
E | E→TG | E→TG | ||||
G | G→+TG | G→ε | G→ε | |||
T | T→FS | T→FS | ||||
S | S→ε | S→*FS | S→ε | S→ε | ||
F | F→i | F→(E) |
#include
#include
#include
char A[20]; // 分析栈
char B[20]; // 输入串
char v1[] = "i+*()#"; // 终结符集合
char v2[] = "EGTSF"; // 非终结符集合
typedef struct {
char origin; // 产生式左部
char array[5]; // 产生式右部
int length; // 右部长度
} Production;
Production C[5][6]; // 预测分析表 [非终结符][终结符]
// 初始化预测分析表
void initTable() {
// 行索引:E(0),G(1),T(2),S(3),F(4)
// 列索引:i(0),+(1),*(2),(3),)(4),#(5)
// E行
C[0][0] = (Production){'E', "TG", 2}; // i
C[0][3] = (Production){'E', "TG", 2}; // (
// G行
C[1][1] = (Production){'G', "+TG", 3}; // +
C[1][4] = (Production){'G', "^", 1}; // )
C[1][5] = (Production){'G', "^", 1}; // #
// T行
C[2][0] = (Production){'T', "FS", 2}; // i
C[2][3] = (Production){'T', "FS", 2}; // (
// S行
C[3][1] = (Production){'S', "^", 1}; // +
C[3][2] = (Production){'S', "*FS", 3}; // *
C[3][4] = (Production){'S', "^", 1}; // )
C[3][5] = (Production){'S', "^", 1}; // #
// F行
C[4][0] = (Production){'F', "i", 1}; // i
C[4][3] = (Production){'F', "(E)", 3}; // (
}
void printStack() { // 输出分析栈
printf("#");
for(int i = strlen(A)-1; i >= 0; i--) {
if(A[i] != '#') printf("%c", A[i]);
}
printf("\t\t");
}
void printInput() { // 输出剩余输入串
printf("%s", B);
printf("\t\t");
}
int main() {
char ch;
int j = 0, b = 0, top = 0, step = 1;
int finish = 0, flag = 0, l;
initTable(); // 初始化预测分析表
// 输入处理
printf("请输入待分析的字符串(以#结尾):");
do {
scanf("%c", &ch);
if(strchr(v1, ch) == NULL && ch != '#') {
printf("输入包含非法字符'%c'\n", ch);
exit(1);
}
B[j++] = ch;
} while(ch != '#');
l = j;
B[j] = '\0';
// 初始化分析栈
A[top] = '#';
A[++top] = 'E';
ch = B[0];
printf("\n步骤\t分析栈\t\t剩余输入\t\t动作\n");
printf("-----------------------------------------------------------\n");
do {
printf("%-4d\t", step++);
printStack(); // 输出分析栈
printInput(); // 输出剩余输入
char x = A[top--]; // 弹出栈顶符号
flag = 0;
// 判断是否为终结符
for(int i = 0; i < strlen(v1); i++) {
if(x == v1[i]) {
flag = 1;
break;
}
}
if(flag) { // 终结符处理
if(x == '#') {
printf("接受\n");
finish = 1;
break;
}
if(x == ch) {
printf("匹配 %c\n", ch);
// 移除已匹配字符
memmove(B, B+1, strlen(B));
ch = B[0];
} else {
printf("错误:栈顶为%c,输入为%c\n", x, ch);
exit(1);
}
} else { // 非终结符处理
int m = -1, n = -1;
// 查找非终结符行坐标
for(int i = 0; i < strlen(v2); i++) {
if(v2[i] == x) {
m = i;
break;
}
}
// 查找终结符列坐标
for(int i = 0; i < strlen(v1); i++) {
if(v1[i] == ch) {
n = i;
break;
}
}
if(m == -1 || n == -1 || C[m][n].origin == '\0') {
printf("错误:无可用产生式(%c遇到%c)\n", x, ch);
exit(1);
}
Production prod = C[m][n];
printf("用 %c→%s 推导\n", prod.origin, prod.array);
// 压栈处理
if(prod.array[0] != '^') { // 非空产生式
for(int i = prod.length-1; i >= 0; i--) {
A[++top] = prod.array[i];
}
}
}
} while(!finish && top >= 0);
return 0;
}
代码说明:
数据结构优化:
A
和输入串B
使用字符数组实现Production
结构体存储产生式信息C
按非终结符和终结符顺序存储产生式核心功能实现:
initTable()
初始化符合文法的预测分析表错误处理:
界面优化:
#include
#include
#include
char A[20]; // 分析栈
char B[20]; // 输入串
char v1[] = "i+*()#"; // 终结符集合
char v2[] = "EGTSF"; // 非终结符集合
typedef struct { // 产生式结构体
char origin; // 左部符号
char array[5]; // 右部符号
int length; // 右部长度
} Production;
Production C[5][6]; // 预测分析表 [非终结符][终结符]
// 初始化预测分析表
void initTable() {
// 初始化所有表项为空
for(int m=0; m<5; m++) {
for(int n=0; n<6; n++) {
C[m][n].origin = 'N'; // 'N'表示空项
}
}
// E行
C[0][0] = (Production){'E', "TG", 2}; // i
C[0][3] = (Production){'E', "TG", 2}; // (
// G行
C[1][1] = (Production){'G', "+TG", 3}; // +
C[1][4] = (Production){'G', "^", 1}; // )
C[1][5] = (Production){'G', "^", 1}; // #
// T行
C[2][0] = (Production){'T', "FS", 2}; // i
C[2][3] = (Production){'T', "FS", 2}; // (
// S行
C[3][1] = (Production){'S', "^", 1}; // +
C[3][2] = (Production){'S', "*FS", 3};// *
C[3][4] = (Production){'S', "^", 1}; // )
C[3][5] = (Production){'S', "^", 1}; // #
// F行
C[4][0] = (Production){'F', "i", 1}; // i
C[4][3] = (Production){'F', "(E)", 3};// (
}
// 输出分析栈
void printStack(int top) {
for(int a = top; a >= 0; a--) {
printf("%c", A[a]);
}
printf("\t\t");
}
// 输出剩余输入串
void printInput(int b, int l) {
for(int j = b; j < l; j++) {
printf("%c", B[j]);
}
printf("\t\t");
}
int main() {
char ch;
int j = 0, b = 0, top = 0, step = 1;
int finish = 0, l;
initTable(); // 初始化预测分析表
// 输入处理
printf("请输入待分析的字符串(以#结尾):");
do {
scanf("%c", &ch);
if(strchr(v1, ch) == NULL) {
printf("输入包含非法字符'%c'\n", ch);
exit(1);
}
B[j++] = ch;
} while(ch != '#');
l = j;
// 初始化分析栈
A[top] = '#';
A[++top] = 'E'; // 初始符号入栈
printf("\n步骤\t分析栈\t\t剩余输入\t\t动作\n");
printf("-----------------------------------------------------------\n");
do {
printf("%-4d\t", step++);
printStack(top); // 输出分析栈
printInput(b, l); // 输出剩余输入
char x = A[top--]; // 弹出栈顶符号
// 判断是否为终结符
int isTerminal = 0;
for(int i = 0; i < strlen(v1); i++) {
if(x == v1[i]) {
isTerminal = 1;
break;
}
}
if(isTerminal) { // 终结符处理
if(x == '#') {
printf("接受\n");
finish = 1;
break;
}
if(x == B[b]) {
printf("匹配 %c\n", x);
b++; // 移动到下一个输入符号
} else {
printf("错误:栈顶为%c,输入为%c\n", x, B[b]);
exit(1);
}
} else { // 非终结符处理
int m = -1, n = -1;
// 查找非终结符行号
for(int i = 0; i < strlen(v2); i++) {
if(v2[i] == x) {
m = i;
break;
}
}
// 查找终结符列号
for(int i = 0; i < strlen(v1); i++) {
if(v1[i] == B[b]) {
n = i;
break;
}
}
if(m == -1 || n == -1 || C[m][n].origin == 'N') {
printf("错误:无可用产生式(%c遇到%c)\n", x, B[b]);
exit(1);
}
Production prod = C[m][n];
printf("%c→%s\n", prod.origin, prod.array);
// 逆序压栈(空产生式不压栈)
if(prod.array[0] != '^') {
for(int i = prod.length-1; i >= 0; i--) {
A[++top] = prod.array[i];
}
}
}
} while(!finish);
return 0;
}
数据结构优化
C[5][6]
存储预测分析表origin
字段验证表项有效性核心逻辑增强
l
b
和top
分别跟踪输入位置和栈顶错误处理完善
界面优化
%-4d
保持表格整齐