文章目录
本文概述实验要求实验内容(一)实验原理(二)程序结构及功能介绍(三)完整代码(四)代码的不足
本文概述
本文讲述了LL(1)文法的原理及如何用C语言实现。并在给出的代码中实现了消除文法的左递归,First集,Follow集,select集的输出,构造预测分析表并输出,和对任意输入字符串的分析。
实验要求
根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。显示文法的First集,Follow集,可选集,构造预测分析表。
实验内容
(一)实验原理
LL(1)分析法,第一个‘L’:从左到右扫描源程序,第二个“L”:最左推导,“1”:向前看1个符号,即查看输入符的当前符号。
文法要求
无左递归:文法中不能有直接或间接的左递归。无冲突:对于任意的非终结符 A 和输入符号 a,最多只有一个产生式可以用于 A 的推导,且这个产生式的第一个符号必须与 a 匹配(即同一非终结符的所有产生式的select集相交为空)。First集
FIRST(A):集合包含所有可以从非终结符 A 导出的字符串的第一个符号。如果 A 可以导出空串 ε,则 ε 也属于 FIRST(A)。构造方法:Follow集
FOLLOW(A):集合包含所有可能出现在非终结符 A 后面的输入符号。初始时,文法起始符号的 FOLLOW 集包含输入结束符 #。构造方法:预测分析表
LL(1) 分析表是一个二维表,其中行对应文法中的非终结符,列对应输入符号。表的每个单元格存储一个产生式或错误标记。
对于每个产生式 A → α:
分析过程
LL(1) 分析器的工作过程如下:
初始化栈:分析栈中最初包含文法的起始符号和输入结束符 #。读取输入:读取输入字符串的第一个符号。匹配和替换: 如果栈顶符号是一个终结符,且与当前输入符号相同,则将两者都移除。如果栈顶符号是一个非终结符 A,且当前输入符号为 a,则查找分析表中的 (A, a) 单元格,找到对应的产生式 A → α,并将 α 的符号序列逆序压入栈中。如果栈顶符号是一个非终结符 A,但在分析表中找不到对应的产生式,则报告语法错误。 结束条件: 如果栈为空且输入字符串也已完全读取,则分析成功。(二)程序结构及功能介绍
程序总流程为:从文件读取文法 -> 输出文法信息 -> 消除左因子和左递归并输出消除后的文法 -> 计算First集并输出 -> 计算Follow集并输出 ->计算select集并输出 -> 判断是否是LL(1)文法 -> 构造预测分析表并输出 ->手动输入要分析的字符串 -> 输出分析过程和结果
读取文件
本程序的文法是从文件中读取的,事先要准备一个规则.txt文件,如下:
非终结符要求必须是大写字母,一行只能有一条规则,可用‘|’表示或,空用$表示
程序读取后输出如下:
//产生式的读取,非终结符必须为大写字母,$表示空void read_rule(char* rulefile, noterminal* h_noter, terminal* h_ter); //产生式输出void print_rule(noterminal* h_noter, terminal* h_ter);
消除相同左因子
程序会先消除显式的相同左因子,如下例子
对文法
进行消除左递归:
int eliminate_unionl(noterminal* h_noter); //消除左公因子
消除左递归
程序会对文法进行直接和间接左递归的消除,然后判段文法是否进行了消除左递归的操作,如果没有表示此文法没有左递归,反之输出消除后的文法。如下:
//消除左递归int eliminate_lr(noterminal* h_noter);
First,Follow,select集的计算输出
然后程序会对最终的文法进行三个集合的计算,为构造预测分析表做准备工作:
void find_first(noterminal* h_noter); //生成FIRST集void find_follow(noterminal* h_noter); //生成FOLLOW集void find_select(noterminal* h_noter); //生成select集
判断是否为LL(1)文法
通过判断同一非终结符的所有产生式的select集相交是否为空来断定,如果不是LL(1)文法,程序会输出判断结果然后退出:
bool judge_ll(noterminal* h_noter); //判断是否是LL(1)文法
构造预测分析表
程序会根据各产生式的select集构造预测分析表:
void make_Pat(noterminal* h_noter, terminal* h_ter); //构造预测分析表
输入与分析
最后,手动输入字符串,程序会进行分析并输出:
int LL1_analyse(noterminal* h_noter, terminal* h_ter, char* st); //LL(1)分析
(三)完整代码
#include<stdio.h>#include <string.h>#include <stdlib.h>//非终结符typedef struct noterminal{char ch;char* First; //对应first集char* Follow; //对应follow集char* guize[10]; //对应产生式int size = 0; //产生式个数char* select[10]; //每个产生式对应的可选集struct noterminal* next; }noterminal;//终结符typedef struct terminal{char ch;struct terminal* next;}terminal;//头指针noterminal* h_noter;terminal* h_ter;noterminal* check_noterminal(char ch, noterminal* h_noter); //检查非终结符是否已拥有terminal* check_terminal(char ch, terminal* h_ter); //检查终结符是否已拥有bool in_char(char* string, char ch); //检查字符串string中是否有字符chint combin(char* ch, char* bech); //连接字符串ch和bech于chvoid read_rule(char* rulefile, noterminal* h_noter, terminal* h_ter); //产生式的读取,非终结符必须为大写字母,$表示空noterminal* copy_noter(noterminal* h_noter); //复制非终结符链表void free_list(noterminal* h_noter, terminal* h_ter); //释放链表空间void print_rule(noterminal* h_noter, terminal* h_ter); //产生式输出int eliminate_unionl(noterminal* h_noter); //消除左公因子int eliminate_lr(noterminal* h_noter); //消除左递归int first_add(noterminal* noter, int site, int r_site, int len); //FIRST集加入元素void find_first(noterminal* h_noter); //生成FIRST集void find_follow(noterminal* h_noter); //生成FOLLOW集void find_select(noterminal* h_noter); //生成select集bool judge_ll(noterminal* h_noter); //判断是否是LL(1)文法void make_Pat(noterminal* h_noter, terminal* h_ter); //构造预测分析表int LL1_analyse(noterminal* h_noter, terminal* h_ter, char* st); //LL(1)分析int main() {char rulefile[100] = "D:\\新建文件夹\\Desktop\\编译原理\\实验二\\规则3.txt";//初始化h_noter = (noterminal*)malloc(sizeof(noterminal));h_noter->next = NULL;h_noter->First = NULL;h_noter->Follow = NULL;h_noter->size = 0;h_ter = (terminal*)malloc(sizeof(terminal));h_ter->next = NULL;//读取文法read_rule(rulefile, h_noter, h_ter);//输出文法print_rule(h_noter, h_ter);//消除左因子int sign2 = eliminate_unionl(h_noter);//消除左递归sign2 += eliminate_lr(h_noter);if (sign2) {printf("\t--消除左递归和左因子--\n\n\n");print_rule(h_noter,h_ter);}else {printf("\t--此文法无左递归和左因子--\n\n\n");}//计算first集find_first(h_noter);//计算follow集find_follow(h_noter);//计算select集find_select(h_noter);//LL(1)文法判断if (judge_ll(h_noter)) {printf("\t------------------此文法不是LL(1)文法------------------\n\n\n");free_list(h_noter, h_ter);return 0;}//构造预测分析表make_Pat(h_noter, h_ter);//对输入符号串进行分析char st[100];int h = 1;while (h) {printf("\n\n\t请输入要分析的字符串:");scanf_s("%s", st, 99);int sign = LL1_analyse(h_noter, h_ter, st);if (sign == 0) printf("\t非法输入!\n\n");else printf("\t合法输入!\n\n");printf("\t是否继续输入(0退出,1继续):");scanf_s("%d",&h);}free_list(h_noter, h_ter);return 0;}noterminal* check_noterminal(char ch, noterminal* h_noter) {int sign = 0;noterminal* h_n = h_noter;while (h_n->next != NULL){h_n = h_n->next;if (h_n->ch == ch) {sign = 1;break;}};if (sign == 0) return NULL;else return h_n;}terminal* check_terminal(char ch, terminal* h_ter) {int sign = 0;terminal* h_n = h_ter;while (h_n->next != NULL){h_n = h_n->next;if (h_n->ch == ch) {sign = 1;break;}};if (sign == 0) return NULL;else return h_n;}bool in_char(char* string, char ch) {int coutn = strlen(string);int i = 0;for (; i < coutn; i++) {if (string[i] == ch) break;}return coutn == i ? false : true;}int combin(char* ch, char* bech) {int cont = strlen(ch);int sign = 0;for (int i = 0; bech[i] != 0; i++) {if (bech[i] != '$' && !in_char(ch, bech[i])) {ch[cont++] = bech[i];sign = 1;}}return sign;}void read_rule(char* rulefile, noterminal* h_noter, terminal* h_ter) {FILE* yuan = NULL;noterminal* noter, * r_noter = h_noter;terminal* ter, * r_ter = h_ter;//非终结符加入'#'ter = (terminal*)malloc(sizeof(terminal));ter->ch = '#';ter->next = NULL;r_ter->next = ter;r_ter = ter;char ch;if (fopen_s(&yuan, rulefile, "r") != 0) {printf("规则 文件打开失败!");exit(1);}while ((ch = fgetc(yuan)) != -1) {if (64 < ch && ch < 91) {noterminal* h_n = check_noterminal(ch, h_noter);//增加非终结符结点if (h_n == NULL) {noter = (noterminal*)malloc(sizeof(noterminal));noter->ch = ch;noter->next = NULL;noter->First = NULL;noter->Follow = NULL;noter->size = 0;r_noter->next = noter;r_noter = noter;}else {noter = h_n;}//读取产生式char chsh[10];for (int i = 0; i < 2; i++) ch = fgetc(yuan);int quit = 0;while ((ch = fgetc(yuan))) {if (ch == '|' || ch == '\n' || ch == -1) {//存储产生式chsh[quit] = '\0';quit = 0;noter->guize[noter->size++] = (char*)malloc(sizeof(char[10]));int s = 0;do {noter->guize[noter->size - 1][s] = chsh[s];} while (chsh[s++] != '\0');if (ch == '\n' || ch == -1) {break;}}else {chsh[quit++] = ch;//增加终结符if (ch < 65 || ch>90) {terminal* h_t = check_terminal(ch, h_ter);if (h_t == NULL) {ter = (terminal*)malloc(sizeof(terminal));ter->ch = ch;ter->next = NULL;r_ter->next = ter;r_ter = ter;}}}}}else {printf("产生式错误");}}fclose(yuan);}noterminal* copy_noter(noterminal* h_noter) {//初始化noterminal* copy_h_noter = (noterminal*)malloc(sizeof(noterminal));copy_h_noter->next = NULL;copy_h_noter->First = NULL;copy_h_noter->Follow = NULL;copy_h_noter->size = 0;noterminal* copy_noter, * noter = h_noter, * r_noter = copy_h_noter;while (noter->next != NULL) {noter = noter->next;copy_noter = (noterminal*)malloc(sizeof(noterminal));copy_noter->next = NULL;copy_noter->First = NULL;copy_noter->Follow = NULL;copy_noter->size = noter->size;//复制非终结符和产生式copy_noter->ch = noter->ch;for (int i = 0; i < noter->size; i++) {copy_noter->guize[i] = (char*)malloc(sizeof(char[10]));for (int j = 0; j <= strlen(noter->guize[i]); j++) {copy_noter->guize[i][j] = noter->guize[i][j];}}r_noter->next = copy_noter;r_noter = copy_noter;}return copy_h_noter;}void free_list(noterminal* h_noter, terminal* h_ter) {noterminal* noter = h_noter;terminal* ter = h_ter;while (h_noter != NULL) {h_noter = h_noter->next;free(noter);noter = h_noter;}while (h_ter != NULL) {h_ter = h_ter->next;free(ter);ter = h_ter;}}void print_rule(noterminal* h_noter, terminal* h_ter) {printf("\t产生式:\n");noterminal* noter = h_noter;int i = 0;while (noter->next != NULL) {noter = noter->next;for (int j = 0; j < noter->size; j++) {printf("\t%-10d %-10c %-10s\n", ++i, noter->ch, noter->guize[j]);}}printf("\n\t非终结符:\n\t");noter = h_noter;while (noter->next != NULL) {noter = noter->next;printf("%-10c", noter->ch);}printf("\n\n\t终结符:\n\t");terminal* ter = h_ter;while (ter->next != NULL) {ter = ter->next;printf("%-10c", ter->ch);}printf("\n\n\n");}int eliminate_unionl(noterminal* h_noter) {int sign = 0; //记录是否有左因子noterminal* noter = h_noter;while (noter->next != NULL) {noter = noter->next;char* tg[20]; //记录同左因子规则int st; //记录同左因子个数char ch1;for (int i = 0; i < noter->size; i++) {ch1 = noter->guize[i][0];st = 0;//找同左因子规则for (int j = i; j < noter->size; j++) {if (noter->guize[j][0] == ch1) {tg[st++] = noter->guize[j];if (st > 1) {//消除同左因子规则for (int z = j; z < noter->size - 1; z++) {noter->guize[z] = noter->guize[z + 1];}noter->size--;j--;}}}if (st > 1) {//计算相同字符个数int unch = 1;while (true) {int r = 0;char kk = tg[r][unch];for (; r < st; r++) {if (tg[r][unch] != kk) break;}if (r != st) break;unch++;}//新节点初始化char ch = 'A';noterminal* newnoter;for (int i = 1; i < 24; i++) {if ((newnoter = check_noterminal(ch, h_noter)) != NULL) ch++;else break;}newnoter = (noterminal*)malloc(sizeof(noterminal));newnoter->next = NULL;newnoter->First = NULL;newnoter->Follow = NULL;newnoter->ch = ch;newnoter->size = st;//原节点产生式处理noter->guize[i] = (char*)malloc(sizeof(char[10]));for (int t = 0; t < unch; t++) noter->guize[i][t] = tg[1][t];noter->guize[i][unch] = ch;noter->guize[i][unch+1] = 0;//规则处理for (int q = 0; q < st; q++) {int lon = strlen(tg[q]);if (lon - unch == 0) {newnoter->guize[q] = (char*)malloc(sizeof(char[10]));newnoter->guize[q][0] = '$';newnoter->guize[q][1] = 0;}else {for (int w = 0; w < lon - unch; w++) {tg[q][w] = tg[q][w + unch];}tg[q][lon - unch] = 0;newnoter->guize[q] = tg[q];}}//插入新节点noterminal* r = h_noter;while (r->next != NULL) {r = r->next;}r->next = newnoter;sign++;}}}return sign;}int eliminate_lr(noterminal* h_noter) {//复制一个文法int sign = 0; //记录是否有左递归noterminal* copy_h_noter = copy_noter(h_noter);noterminal* noter = copy_h_noter;noterminal* r_ter;while (noter->next != NULL) {noter = noter->next;r_ter = copy_h_noter;while (r_ter->next != noter) {r_ter = r_ter->next;for (int j = 0; j < noter->size; j++) {//间接变直接if (noter->guize[j][0] == r_ter->ch) {char ch1[20] = { 0 }; //后for (int f = 1; f < strlen(noter->guize[j]); f++) {ch1[f - 1] = noter->guize[j][f];}//guize数值更新int d;for (d = j; d < noter->size - 1; d++) {noter->guize[d] = noter->guize[d + 1];}noter->size--;//加入新的产生式for (int g = 0; g < r_ter->size; g++) {char ch2[20] = { 0 }; //前for (int f = 0; f < strlen(r_ter->guize[g]); f++) {if (r_ter->guize[g][f] == '$') break;ch2[f] = r_ter->guize[g][f];}combin(ch2, ch1);noter->guize[d++] = (char*)malloc(sizeof(char[20]));for (int e = 0; e <= strlen(ch2); e++) {noter->guize[d - 1][e] = ch2[e];}noter->size++;}break;}}}//消除直接左递归for (int j = 0; j < noter->size; j++) {if (noter->guize[j][0] == noter->ch) {//1int size1 = j;int size2 = 0;char* ch1[10];ch1[size2++] = noter->guize[j];for (int i = j + 1; i < noter->size; i++) {if (noter->guize[i][0] == noter->ch) {ch1[size2++] = noter->guize[i];}else {noter->guize[size1++] = noter->guize[i];}}noter->size = size1;//2//新节点初始化char ch = 'A';noterminal* newnoter;for (int i = 1; i < 24; i++) {if ((newnoter = check_noterminal(ch, copy_h_noter)) != NULL) ch++;else break;}newnoter = (noterminal*)malloc(sizeof(noterminal));newnoter->next = NULL;newnoter->First = NULL;newnoter->Follow = NULL;newnoter->ch = ch;//产生式处理for (int i = 0; i < size2; i++) {int s = 0;for (; s < strlen(ch1[i]) - 1; s++) {ch1[i][s] = ch1[i][s + 1];}ch1[i][s] = ch;}ch1[size2++] = (char*)malloc(sizeof(char[10]));ch1[size2 - 1][0] = '$';ch1[size2 - 1][1] = 0;for (int i = 0; i < 10; i++) {newnoter->guize[i] = ch1[i];}newnoter->size = size2;for (int i = 0; i < noter->size; i++) {noter->guize[i][strlen(noter->guize[i]) + 1] = 0;noter->guize[i][strlen(noter->guize[i])] = ch;}//插入新节点noterminal* r = copy_h_noter;while (r->next != NULL) {r = r->next;}r->next = newnoter;sign = 1;break;}}}if (sign) {noterminal* r = h_noter->next;h_noter->next = copy_h_noter->next;copy_h_noter->next = r;}free_list(copy_h_noter, NULL);return sign;}int first_add(noterminal* noter, int site, int r_site, int len) {char ch = noter->guize[r_site][site];int sign = 0;if (64 < ch && ch < 91) {noterminal* h_n = check_noterminal(ch, h_noter);if (h_n->First != NULL) {if (noter->First == NULL) {noter->First = (char*)malloc(sizeof(char[20]));for (int j = 0; j < 20; j++) noter->First[j] = 0;}sign = combin(noter->First, h_n->First);if (in_char(h_n->First, '$')) {if (site == len - 1) {//防治反复判空if (!in_char(noter->First, '$')) {noter->First[strlen(noter->First)] = '$';sign = 1;}}else {sign += first_add(noter, site + 1, r_site, len);}}}}//首字符为终结符else {//first集为空if (noter->First == NULL) {noter->First = (char*)malloc(sizeof(char[20]));for (int j = 0; j < 20; j++) noter->First[j] = 0;noter->First[0] = ch;sign = 1;}else {if (!in_char(noter->First, ch)) {noter->First[strlen(noter->First)] = ch;sign = 1;}}}return sign;}void find_first(noterminal* h_noter) {int sign;do{sign = 0;noterminal* noter = h_noter;//对每个非终结符进行一轮分析while (noter->next != NULL){noter = noter->next;//对一个非终结符进行一轮分析for (int i = 0; i < noter->size; i++) {//防治sign值被覆盖sign += first_add(noter, 0, i, strlen(noter->guize[i]));}}} while (sign);//输出first集noterminal* noter = h_noter;printf("\tFIRST集:\n\n");while (noter->next != NULL) {noter = noter->next;printf("\t%-10c", noter->ch);printf("first=%-10s\n", noter->First);}printf("\n\n");}void find_follow(noterminal* h_noter) {int sign;//置#于开始符follow集中h_noter->next->Follow = (char*)malloc(sizeof(char[20]));for (int j = 0; j < 20; j++) h_noter->next->Follow[j] = 0;h_noter->next->Follow[0] = '#';do{sign = 0;noterminal* noter = h_noter;//对每个非终结符进行一轮分析while (noter->next != NULL){noter = noter->next;//对一个非终结符的所有产生式进行一轮分析for (int i = 0; i < noter->size; i++) {char* guize = noter->guize[i];int size = strlen(guize);//对一条产生式进行分析for (int z = 0; z < size; z++) {char ch = guize[z];int s = z + 1;//本身为终结符if (ch < 65 || ch>90) continue;noterminal* h_n = check_noterminal(ch, h_noter);//follow初始化if (h_n->Follow == NULL) {h_n->Follow = (char*)malloc(sizeof(char[20]));for (int j = 0; j < 20; j++) h_n->Follow[j] = 0;}//位于最后if (z == size - 1) {if (noter->Follow != NULL) {sign += combin(h_n->Follow, noter->Follow);}continue;}//下一个为终结符if (guize[s] < 65 || guize[s] > 90) {if (!in_char(h_n->Follow, guize[s])) {h_n->Follow[strlen(h_n->Follow)] = guize[s];sign = 1;}}//下一个为非终结符else {noterminal* r_n = check_noterminal(guize[s], h_noter);sign += combin(h_n->Follow, r_n->First);while (in_char(r_n->First, '$')) {//后都有空if (s == size - 1) {if (noter->Follow != NULL) {sign += combin(h_n->Follow, noter->Follow);}break;}char a = guize[++s];//为非终结符if (a > 64 && a < 91) {r_n = check_noterminal(a, h_noter);sign += combin(h_n->Follow, r_n->First);}//为终结符else {if (!in_char(h_n->Follow, a)) {h_n->Follow[strlen(h_n->Follow)] = a;sign = 1;}break;}}}}}}} while (sign);//输出follow集noterminal* noter = h_noter;printf("\tFOLLOW集:\n\n");while (noter->next != NULL) {noter = noter->next;printf("\t%-10c", noter->ch);printf("follow=%-10s\n", noter->Follow);}printf("\n\n");}void find_select(noterminal* h_noter) {noterminal* noter = h_noter;while (noter->next != NULL) {noter = noter->next;//对一个非终结符的所有产生式依次进行分析for (int i = 0; i < noter->size; i++) {char* guize = noter->guize[i];int size = strlen(guize); //规则长度int z = 0;//初始化noter->select[i] = (char*)malloc(sizeof(char[20]));for (int j = 0; j < 20; j++) noter->select[i][j] = 0;//为终结符if (guize[z] < 65 || guize[z]>90) {//为空if (guize[z] == '$') {combin(noter->select[i], noter->Follow);}else { noter->select[i][0] = guize[z]; }continue;}//为非终结符else {noterminal* h_n = check_noterminal(guize[z], h_noter);combin(noter->select[i], h_n->First);while (in_char(h_n->First, '$')){//后都有空if (z == size - 1) {combin(noter->select[i], noter->Follow);break;}char a = guize[++z];//为非终结符if (a > 64 && a < 91) {h_n = check_noterminal(a, h_noter);combin(noter->select[i], h_n->First);}//为终结符else {if (!in_char(noter->select[i], a)) {noter->select[i][strlen(noter->select[i])] = a;}break;}}}}}//输出select集noter = h_noter;printf("\tselect集:\n\n");while (noter->next != NULL){noter = noter->next;for (int j = 0; j < noter->size; j++) {printf("\t%c->%-10s select=%-10s\n", noter->ch, noter->guize[j], noter->select[j]);}}printf("\n\n");}bool judge_ll(noterminal* h_noter) {noterminal* noter = h_noter;while (noter->next != NULL) {noter = noter->next;for (int i = 0; i < noter->size; i++) {for (int f = 0; f < strlen(noter->select[i]); f++) {for (int j = i + 1; j < noter->size; j++) {for (int s = 0; s < strlen(noter->select[j]); s++) {if (noter->select[i][f] == noter->select[j][s]) {return true;}}}}}}return false;}void make_Pat(noterminal* h_noter, terminal* h_ter) {printf("\t预测分析表:\n\n\t");terminal* ter = h_ter;printf("%-10c", ' ');while (ter->next != NULL) {ter = ter->next;printf("%-10c", ter->ch);}noterminal* noter = h_noter;while (noter->next != NULL) {noter = noter->next;printf("\n\n\t%-10c", noter->ch);ter = h_ter;while (ter->next != NULL) {ter = ter->next;int j = 0;for (; j < noter->size; j++) {if (in_char(noter->select[j], ter->ch)) {printf("%-10s", noter->guize[j]);break;}}if (j == noter->size) {printf("%-10c", ' ');}}}printf("\n");}int LL1_analyse(noterminal* h_noter, terminal* h_ter, char* st){char anal[20] = { 0 }; //分析栈anal[0] = '#';int a_top = 0; //分析栈顶int s_top = 0; //字符串栈顶st[strlen(st) + 1] = 0;st[strlen(st)] = '#';printf("\t分析过程如下:\n");printf("\t分析栈 剩余输入串 推导所用产生式或匹配\n");noterminal* noter = h_noter->next;anal[++a_top] = noter->ch;while (1) {//输出两栈元素printf("\t%-15s %-15s", anal, st);//两栈顶都为‘#’if (anal[a_top] == '#' && st[s_top] == '#') {printf("接受\n");return 1;}//分析栈顶为非终结符if (64 < anal[a_top] && anal[a_top] < 91) {noter = check_noterminal(anal[a_top], h_noter);int j = 0;for (; j < noter->size; j++) {//字符位于select集中if (in_char(noter->select[j], st[s_top])) {//产生式为空if (in_char(noter->guize[j], '$')) {anal[a_top--] = 0;printf("%c->%s\n", noter->ch, noter->guize[j]);}else {//产生式入栈int z = strlen(noter->guize[j]) - 1;for (; z >= 0; z--) {anal[a_top++] = noter->guize[j][z];}a_top--;printf("%c->%s\n", noter->ch, noter->guize[j]);}break;}}//select集中无if (j == noter->size) {printf("无匹配产生式!\n");return 0;}}//分析栈顶为终结符else {if (anal[a_top] == st[s_top]) {printf("\"%c\"匹配\n", anal[a_top]);anal[a_top--] = 0;st[s_top++] = ' ';}else {printf("\n");return 0;}}}}
(四)代码的不足
消除左因子的功能是后续加上去的,如果有bug请在评论区指出。
输入的字符串最好不要超过15个字符,不然输出的分析过程的排版不会对齐。
如果代码还有其他不足之处,欢迎在评论区指出。