本文概述
本文讲述了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 → α:
- 如果 a ∈ FIRST(α),则在表的 (A, a) 单元格中填入 A → α。
- 如果 ε ∈ FIRST(α),则对于每个 b ∈ FOLLOW(A),在表的 (A, b) 单元格中填入 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中是否有字符ch
int combin(char* ch, char* bech); //连接字符串ch和bech于ch
void 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) {
//1
int 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个字符,不然输出的分析过程的排版不会对齐。
-
如果代码还有其他不足之处,欢迎在评论区指出。