编译原理--LL1分析实验

实验要求

根据给出的简单语言的语法构成规则(见下面),编制LL(1)语法分析器,要在词法分析输出的单词基础上进行语法分析,输出相应的语法分析结果和错误信息。
E->E+T|E-T|T
T->T*F|T/F|F
F->(E)|i
上式中, i 为整数或标识符,对于整数和标识符的识别可以借助实验1。
关于错误信息:不要求错误种类,只需给出出错位置。

代码中的函数
open_inputf():打开input.txt
● void inf_nextc(): 读入文件的内容-若是空,返回0
int is_number(char number):判断是否为整常量,是的话返回1
int is_oper(char letter): //暂时猜测:判断是不是±/()这几个符号,是的话返回1
//cq猜测:判断当前列有无对应的文法,如果有则返回当前第几列
int is_endc()://是不是±
/() i 这几个符号–终结符,是的话返回1

● int str_put_stack() :入栈(字符栈),如果是整常量,i入栈。同时把我们输入的2+33转为i+i3(即转为一般化)
char get_str_stack_top():获取栈顶元素
char out_str_stack():出栈(字符栈)
char out_analy_stack() :出栈(分析栈)
void put_analy_stack(char letter):入栈(分析栈)

● get_product_form(): 有横纵坐标,返回预测表对应的产生式
open_LL1analyf():将input.txt内容读入分析器

● LL1_analy():预测分析过程,先把#E压入栈中,导序入栈—如果抽到我们的话,我觉得主要回报的就是栈的弹出和进入

  1.  如果分析栈-字符栈一样的话,这可以是字符栈输出,
    
  2. 分析栈-字符栈都为#作为栈顶—>分析正确

  3.  如果得到的分析栈顶不是终结符的话,则查二维表(横坐标是自己,纵坐标是字符栈顶),strcmp(相等才是0),只有二者(product_form与“1”即无产生式)相等时候才会提示分析储出错。当既不是1也不是0时,将其逆序压入分析栈。
    

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define analy_stack_cap 30
#define str_stack_cap 30
#define row_num 5
#define col_num 8
char ch;
char analy_stack_top;
const char* product_form;
int str_stack_content_num, str_stack_current_num;
char str_stack[str_stack_cap];
int analy_stack_current_num=2;
char analy_stack[analy_stack_cap]={'#', 'E'};
const char fat_row[]={'E', 'A', 'T', 'B', 'F'};
const char fat_col[]={'i', '+', '-', '*', '/', '(', ')', '#'};
const char* const forecast_analy_table[row_num][col_num]={
	{"TA", "1", "1", "1", "1", "TA", "1", "1"},
	{"1", "+TA", "-TA", "1", "1", "1", "0", "0"},
	{"FB", "1", "1", "1", "1", "FB", "1", "1"},
	{"1", "0", "0", "*FB", "/FB", "1", "0", "0"},
	{"i", "1", "1", "1", "1", "(E)", "1", "1"}
};
int error_location=1;
FILE *inputf, *LL1f;

void open_inputf(){
	if((inputf=fopen("input.txt", "r"))==NULL){
		printf("打开input失败\n");
		exit(0);
	}
}

void inf_nextc(){
	if((ch=fgetc(inputf))==EOF){
		ch=0;
	}
}

int is_number(char number){
	if(ch>=48 && ch<=57)
		return 1;
	return 0;
}

int is_oper(char letter){
	int col=0;
	for(int i=1; i<col_num-1; i++){
		if(fat_col[i]==letter){
			col=1;
			break;
		}
	}
	return col;
}

int is_endc(char letter){
	int endc_mark=0;
	for(int i=0; i<col_num-1; i++){
		if(fat_col[i]==letter){
			endc_mark=1;
			break;
		}
	}
	return endc_mark;
}
int str_put_stack(){
	int i=0, result=0;
	inf_nextc();
began:
	if(ch==' '){
		inf_nextc();
		goto began;
	}else if(is_number(ch)){
		if(ch!='0'){
			do{
				inf_nextc();
			}while(is_number(ch));
		}else{
			inf_nextc();
			if(is_number(ch)){
				printf("扫描至 %d 行\n", error_location);
				return result;
			}
		}
		if(ch=='.'){
			inf_nextc();
			if(is_number(ch))
				do{
					inf_nextc();
				}while(is_number(ch));
			else{
				printf("扫描至 %d 行\n", error_location);
				return result;
			}
		}
		str_stack[i++]='i';
		goto began;
	}else if(is_oper(ch) ){
		str_stack[i++]=ch;
		inf_nextc();
		goto began;
	}else if(ch=='#'){
		str_stack[i++]=ch;
		do{
			inf_nextc();
		}while(ch==' ');
		if(ch=='\n'){
			error_location++;
		}
		str_stack_current_num=str_stack_content_num=i;
		printf("第 %d 行扫描完成\n", error_location-1);
		result=1;
	}else{
		printf("全文扫描至 %d 行\n", error_location);
	}
	return result;
}

char get_str_stack_top(){
	return str_stack[str_stack_content_num-str_stack_current_num];
}

char out_str_stack(){
	char letter=str_stack[str_stack_content_num-str_stack_current_num--];
	str_stack[str_stack_content_num-str_stack_current_num-1]=' ';
	return letter;
}

char out_analy_stack(){
	char letter=analy_stack[--analy_stack_current_num];
	analy_stack[analy_stack_current_num]=0;
	return letter;
}

void put_analy_stack(char letter){
	analy_stack[analy_stack_current_num++]=letter;
}

const char* get_product_form(char rowc, char colc){
	int row=0, col=0;
	for(; row<row_num; row++)
		if(fat_row[row]==rowc)
			break;
	for(; col<col_num;col++)
		if(fat_col[col]==colc)
			break;
	return forecast_analy_table[row][col];
}

void open_LL1analyf(){
	if((LL1f=fopen("LL1.txt", "w"))==NULL){
		printf("打开LL1.txt失败");
		exit(0);
	}
}

int LL1_analy(){
	int i=1;
	fprintf(LL1f, " %4s %14s %15s %13s\n", "步骤", "分析栈", "剩余输入串", "所用产生式");
began:
	ch=get_str_stack_top();
abegan:
	analy_stack_top=out_analy_stack();
	if(is_endc(analy_stack_top)){
		if(analy_stack_top==ch){
			fprintf(LL1f, " %-4d %13s%c %15s    %c %-5s\n", i, analy_stack, analy_stack_top, str_stack, ch, "匹配");
			out_str_stack();
			i++;
			goto began;
		}else{
			fprintf(LL1f, " %-4d %13s%c %15s    %s\n", i, analy_stack, analy_stack_top, str_stack, "出错,终止");
			printf("语法错误,程序终止\n");
		}
	}else{
		if(analy_stack_top=='#'){
			if(analy_stack_top==ch){
				fprintf(LL1f, " %-4d %13s%c %15s    %s\n", i, analy_stack, analy_stack_top, str_stack, "接受");
				analy_stack[0]='#';
				analy_stack[1]='E';
				analy_stack_current_num=2;
				memset(str_stack, 0, sizeof(str_stack));
				printf("语法正确\n");
				return 1;
			}else{
				fprintf(LL1f, " %-4d %13s%c %15s    %s\n", i, analy_stack, analy_stack_top, str_stack, "出错,终止");
				printf("语法错误,程序终止\n");
			}
		}else{
			product_form=get_product_form(analy_stack_top, ch);
			if(strcmp(product_form, "1")){
				fprintf(LL1f, " %-4d %13s%c %15s    %c%s%s\n", i, analy_stack, analy_stack_top, str_stack, analy_stack_top, "->", product_form);
				i++;
				if(strcmp(product_form, "0")){
					int num=strlen(product_form);
					while(num--){
						put_analy_stack(product_form[num]);
					}
				}
				goto abegan;
			}else{
				fprintf(LL1f, " %-4d %13s%c %15s    %s\n", i, analy_stack, analy_stack_top, str_stack, "出错,终止");
				printf("语法错误,程序终止\n");
			}
		}
	}
	return 0;
}

int main(){
	open_inputf();
	open_LL1analyf();
	while(str_put_stack()){
		if(LL1_analy()){
		}else{
			getchar();
			break;
		}
	}
	fclose(LL1f);
	fclose(inputf);
	return 1;
}
修改下路径即可

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个里面的都是测试数据,总共得分5分。从控制台输入,不能从文件中读取。实现了基本功能,加分项目都没有去实现,没有函数数组这些的实现。这是用C++语言写的,新建parser类别要选C++,其他对于VS的配置和C语言一样。for语句用的是枚举所有情况,你可以自行修改。 对预备工作中自然语言描述的简化C编译器的语言特性的语法,设计上下文无关文法进行描述 借助Yacc工具实现语法分析器 考虑语法树的构造: 1.语法树数据结构的设计:节点类型的设定,不同类型节点应保存哪些信息,多叉树的实现方式 2.实现辅助函数,完成节点创建、树创建等功能 3.利用辅助函数,修改上下文无关文法,设计翻译模式 4.修改Yacc程序,实现能构造语法树的分析器 考虑符号表处理的扩充 1.完成语法分析后,符号表项应增加哪些标识符的属性,保存语法分析的结果 2.如何扩充符号表数据结构,Yacc程序如何与Lex程序交互,正确填写符号表项 以一个简单的C源程序验证你的语法分析器,可以文本方式输出语法树结构,以节点编号输出父子关系,来验证分析器的正确性,如下例: main() { int a, b; if (a == 0) a = b + 1; } 可能的输出为: 0 : Type Specifier, integer, Children: 1 : ID Declaration, symbol: a Children: 2 : ID Declaration, symbol: b Children: 3 : Var Declaration, Children: 0 1 2 4 : ID Declaration, symbol: a Children: 5 : Const Declaration, value:0, Children: 6 : Expr, op: ==, Children: 4 5 7 : ID Declaration, symbol: a Children: 8 : ID Declaration, symbol: b Children: 9 : Const Declaration, value:1, Children: 10: Expr, op: +, Children: 8 9 11: Expr, op: =, Children: 7 10 12: if statement, Children: 6 11 13: compound statement, Children: 3 12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值