编译原理实验二:LL(1)分析法(附C/C++完整代码)

本文概述

本文讲述了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) 分析器的工作过程如下:

  1. 初始化栈:分析栈中最初包含文法的起始符号和输入结束符 #。
  2. 读取输入:读取输入字符串的第一个符号。
  3. 匹配和替换:
    • 如果栈顶符号是一个终结符,且与当前输入符号相同,则将两者都移除。
    • 如果栈顶符号是一个非终结符 A,且当前输入符号为 a,则查找分析表中的 (A, a) 单元格,找到对应的产生式 A → α,并将 α 的符号序列逆序压入栈中。
    • 如果栈顶符号是一个非终结符 A,但在分析表中找不到对应的产生式,则报告语法错误。
  4. 结束条件:
    • 如果栈为空且输入字符串也已完全读取,则分析成功。

(二)程序结构及功能介绍

程序总流程为:从文件读取文法 -> 输出文法信息 -> 消除左因子和左递归并输出消除后的文法 -> 计算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;
			}
		}
	}
}

(四)代码的不足

  1. 消除左因子的功能是后续加上去的,如果有bug请在评论区指出。

  2. 输入的字符串最好不要超过15个字符,不然输出的分析过程的排版不会对齐。
    在这里插入图片描述

  3. 如果代码还有其他不足之处,欢迎在评论区指出。

### 回答1LL(1)文法分析器可以通过递归下降法实现。下面是一个简单的C语言LL(1)文法分析器的示例代码: ```c #include <stdio.h> #include <ctype.h> #define MAX_LENGTH 100 char lookahead; char input[MAX_LENGTH]; int index = 0; int error = 0; void match(char c) { if (lookahead == c) { lookahead = input[index++]; } else { error = 1; } } void program(); void statement(); void expression(); void term(); void factor(); void program() { statement(); if (!error && lookahead == '\0') { printf("Parsing successful!\n"); } else { printf("Parsing failed.\n"); } } void statement() { if (lookahead == 'i') { match('i'); match('d'); match('='); expression(); } else { error = 1; } } void expression() { term(); while (!error && (lookahead == '+' || lookahead == '-')) { match(lookahead); term(); } } void term() { factor(); while (!error && (lookahead == '*' || lookahead == '/')) { match(lookahead); factor(); } } void factor() { if (isdigit(lookahead)) { match(lookahead); } else if (lookahead == '(') { match('('); expression(); match(')'); } else { error = 1; } } int main() { printf("Enter an arithmetic expression: "); fgets(input, MAX_LENGTH, stdin); lookahead = input[index++]; program(); return 0; } ``` 该程序可以识别类似于下面的算术表达式: ``` id = 3 + (4 * 5) / 6 ``` 如果输入的表达式符合LL(1)文法规则,程序将输出"Parsing successful!",否则将输出"Parsing failed."。 ### 回答2: LL1文法分析器是一种逐步分析和解析输入的字符串的工具,它是根据LL1文法规则来构建的。在C语言中,我们可以使用LL1文法分析器来验证C代码的语法正确性。 首先,编写一个词法分析器来将输入的C代码转换成一个个的Token,每个Token代表了代码中的一个原子元素,比如:关键字、标识符、常量等。然后,根据C语言LL1文法规则,构建一个语法分析表。 语法分析表是一个维数组,其中的每一个格子都代表了分析器在某个状态下对某个输入Symbol(Token)的处理。通过预测分析法(Predictive Parsing Algorithm)和LL1文法规则,可以构建语法分析表。 接下来,我们可以使用LL1文法分析器对输入的Token串进行语法分析。从开始符号(比如程序(Program))开始,依次读取Token串中的每一个Token,并根据语法分析表中的指导进行相应的操作,比如推导规则(Production Rule)的选择、符号的匹配等。 如果在分析的过程中发现了不符合LL1文法规则的错误,那么分析器将会报错,并指示发现错误的位置和类型。这种方式能够帮助开发者及早发现和修正代码中的语法错误,在程序编译或解析阶段就可以减少后续的错误和调试难度。 总结来说,LL1文法分析器是一种用于检验C语言代码语法正确性的工具。通过将C代码转换为Token串、构建语法分析表和使用预测分析法,我们可以逐步解析并验证代码的语法,减少错误和调试难度。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值