编译原理实验3 递归下降法的语法分析器

实验3 递归下降法的语法分析器
一、实验目的
学习用递归下降法构造语法分析器的原理,掌握递归下降法的编程方法。

二、实验内容
用递归下降法编写一个语法分析程序,使之与词法分析器结合,能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子。
这里只要求实现部分产生式,文法的开始符号为program。
program → block
block → { stmts }
stmts →stmt stmts | 
stmt → id = expr ;
| if ( bool ) stmt
| if ( bool) stmt else stmt
| while (bool) stmt
| do stmt while (bool ) ;
| break ;
| block
bool → expr < expr
| expr <= expr
| expr > expr
| expr >= expr
| expr
expr → expr + term
| expr - term
| term
term → term * factor
| term / factor
| factor
factor → ( expr ) | id | num

三、实验要求
1.个人完成,提交实验报告。
2.实验报告中给出采用测试源代码片断,及其对应的最左推导过程(形式可以自行考虑)。
测试程序片断:
{
i = 2;
while (i <=100)
{
sum = sum + i;
i = i + 2;
}
}
对应的推导过程为:
program  block
 { stmts }
 { stmt stmts }
 { id = expr ; stmts }
 { id = num; stmts }
 { id = num; stmt stmts }
 { id = num; while (bool) stmt stmts }
 { id = num; while (expr<= expr) stmt stmts }
 { id = num; while (id <= expr) stmt stmts }
 { id = num; while (id <= num) stmt stmts }
 { id = num; while (id <= num) block stmts }
 { id = num; while (id <= num) { stmts }stmts }
 .......

四、实验思路
词法分析器,能够将语句中的每一个词素都识别出来,因此,在此基础上,定义一个二维字符串数组finaltable[100][20],用于存放由词法分析器提取出来的每个词素,比如,i=2,则finaltable[0]=”id”,finaltable[1]=”=”,finaltable[2]=”num”。并且,为了以后能够方便使用switch() case 语句,另外再定义一个一维整型数组finaltableint[100],用于存放一个数字和finaltable[100][20]中的字符串对应。这里,我们定义if=100,for=200,else=300,while=400,do=500,float=600,int=700,break=800,< = 17,<= = 16,> = 15,>= = 14,+ = 13,&&=12,||=11,}=10,{=9,;=8;)=7,(=6,= = 5,== = 4,!= =3,/=2,id =1,keyword=0,num=99,*=18,- = 19.相比词法分析器,词法分析的时候,是以单个字符为一个单位,而语法分析,我们以字符串为单位,这些字符串即finaltable[100][20]中的字符串。编写的过程中涉及几个问题
,1、如何把每一步的迭代都显示出来?对于这个问题,可以在每个非终结符函数的开头输出对应的迭代即可。
2、在应用文法的时候,应该首先消除左递归,这是至关重要的,该实验我们只要消除expr()和term()的左递归即可。
3、if语句二义性处理。对于这个问题,我们只要再往后看一个字符串,看其是否是else,如果是,则匹配if ( bool) stmt else stmt,否则匹配if ( bool ) stmt。
4、对于空选择,如何处理?一开始的时候,我选择暂时忽略。

五、实验代码

#include<stdio.h>
#include<string.h>
#include <ctype.h>
/* 
if=100,for=200,else=300,while=400,do=500,float=600,int=700,break=800,< = 17,<= = 16,> = 15,>= = 14,+ = 13,&&=12,||=11,}=10,{=9,;=8;)=7,(=6,= = 5,== = 4,!= =3,/=2,id =1,keyword=0,num=99,*=18,- = 19
*/
char *keyword[8]={"if","for","else","while","do","float","int","break"};
char keywordtable[20][20],re_keywordtable[20][20];
char digittable[20][20],re_digittable[20][20];
char otherchartable[20][20],re_otherchartable[20][20];
char idtable[20][20],re_idtable[20][20];
char notetable[20][20];
char finaltable[100][20];
int  finaltableint[100];
char word[20];
void initialize();
void alpha();
void digit();
void error();
void otherchar();
void note();
void print();
void prin();
void check();
void program();
void block();
void stmts();
void stmt();
void Bool();
void expr();
void expr1();
void term();
void term1();
void factor();
void match(char *t);

int digit_num=0,keyword_num=0,otherchar_num=0,id_num=0,note_num=0; 
int redigit_num=1,rekeyword_num=1,reotherchar_num=1,reid_num=1; 
int final_num=0,finalnum=0;
int flag_error=0;
int flagerror=0;
char lookahead;

void main()
{
	printf("请输入要分析的语句:\n");
	initialize();
	lookahead=getchar();
	while(1)
	{
		if(isalpha(lookahead))
		{
			alpha();
			initialize();
		}
		else if(isdigit(lookahead))
		{
			digit();
			initialize();
		}
		else if(lookahead=='\t'||lookahead==' ')
		{
			;
		}
		else if(lookahead=='\n')
			break;
		else if(lookahead=='/')
		{
			lookahead=getchar();
			if(lookahead=='*')
			{
				note();
				initialize();
			}
			else
			{
				ungetc(lookahead,stdin);
				strcpy(finaltable[final_num],"/");
				strcpy(otherchartable[otherchar_num++],"/");
				finaltableint[final_num++]=2;
				initialize();
			}
		}
		else
		{
			otherchar();
			initialize();
		}
		lookahead=getchar();
	}
	check();
	if(flag_error==0)
	{
		printf("词法分析结果如下:\n");
		print();
		prin();
		program();
		if(finalnum==final_num)
			printf("语法分析完成!\n");
	}
}

void alpha()
{
	int i=1,flag;
	char ch;
	ch=lookahead;
	word[0]=ch;
	ch=getchar();
	while(isalpha(ch)||isdigit(ch))
	{
		word[i++]=ch;
		ch=getchar();
	}
	ungetc(ch,stdin);
	flag=0;
	for(i=0;i<8;i++)
	{
		if(strcmp(word,keyword[i])==0)
			flag=1;	
	}
	if(flag==1)
	{
		strcpy(keywordtable[keyword_num++],word);
		strcpy(finaltable[final_num],word);
		if(strcmp(word,"if")==0)
			finaltableint[final_num++]=100;
		if(strcmp(word,"for")==0)
			finaltableint[final_num++]=200;
		if(strcmp(word,"else")==0)
			finaltableint[final_num++]=300;
		if(strcmp(word,"while")==0)
			finaltableint[final_num++]=400;
		if(strcmp(word,"do")==0)
			finaltableint[final_num++]=500;
		if(strcmp(word,"float")==0)
			finaltableint[final_num++]=600;
		if(strcmp(word,"int")==0)
			finaltableint[final_num++]=700;
		if(strcmp(word,"break")==0)
			finaltableint[final_num++]=800;
	}
	else
	{
		strcpy(idtable[id_num++],word);
		strcpy(finaltable[final_num],"id");
		finaltableint[final_num++]=1;
	}
}

void digit()
{
	int i=1,flag;
	char ch;
	ch=lookahead;
	word[0]=ch;
	ch=getchar();
	while(isalpha(ch)||isdigit(ch))
	{
		word[i++]=ch;
		ch=getchar();
	}
	ungetc(ch,stdin);
	flag=0;
	for(i=0;word[i]!='\0';i++)
	{
		if(word[i]<'0'||word[i]>'9')
			flag=1;
	}
	if(flag==1)
	{
		strcpy(idtable[id_num++],word);
		strcpy(finaltable[final_num],"id");
		finaltableint[final_num++]=1;
	}
	else
	{
		strcpy(digittable[digit_num++],word);
		strcpy(finaltable[final_num],"num");
		finaltableint[final_num++]=99;
	}
}

void otherchar()
{
	char ch;
	ch=lookahead;
	switch(ch){
	case '!':
		{
			ch=getchar();
			if(ch=='=')
			{
				strcpy(otherchartable[otherchar_num++],"!=");
				strcpy(finaltable[final_num],"!=");
				finaltableint[final_num++]=3;
			}
			else
			{
				ungetc(ch,stdin);
				error();
			}
		}
		break;
	case '=':
		{
			ch=getchar();
			if(ch=='=')
			{
				strcpy(otherchartable[otherchar_num++],"==");
				strcpy(finaltable[final_num],"==");
				finaltableint[final_num++]=4;
			}
			else
			{
				strcpy(otherchartable[otherchar_num++],"=");
				strcpy(finaltable[final_num],"=");
				finaltableint[final_num++]=5;
				ungetc(ch,stdin);
			}
		}
		break;
	case '(':
		strcpy(otherchartable[otherchar_num++],"(");
		strcpy(finaltable[final_num],"(");
		finaltableint[final_num++]=6;                      // ( 6
		break;
	case ')':
		strcpy(otherchartable[otherchar_num++],")");
		strcpy(finaltable[final_num],")");
		finaltableint[final_num++]=7;                      // ) 7
		break;
	case ';':
		strcpy(otherchartable[otherchar_num++],";");
		strcpy(finaltable[final_num],";");
		finaltableint[final_num++]=8;						// ; 8
		break;
	case '{':
		strcpy(otherchartable[otherchar_num++],"{");
		strcpy(finaltable[final_num],"{");
		finaltableint[final_num++]=9;						// { 9
		break;
	case '}':
		strcpy(otherchartable[otherchar_num++],"}");
		strcpy(finaltable[final_num],"}");
		finaltableint[final_num++]=10;						// } 10
		break;
	case '||':
		strcpy(otherchartable[otherchar_num++],"||");
		strcpy(finaltable[final_num],"||");
		finaltableint[final_num++]=11;						// || 11
		break;
	case '&&':
		strcpy(otherchartable[otherchar_num++],"&&");
		strcpy(finaltable[final_num],"&&");
		finaltableint[final_num++]=12;						//&& 12
		break;
	case '+':
		strcpy(otherchartable[otherchar_num++],"+");
		strcpy(finaltable[final_num],"+");
		finaltableint[final_num++]=13;						// + 13
		break;
	case '-':
		strcpy(otherchartable[otherchar_num++],"-");
		strcpy(finaltable[final_num],"-");
		finaltableint[final_num++]=19;						// - 19
		break;
	case '>':
		{
			ch=getchar();
			if(ch=='=')
			{
				strcpy(otherchartable[otherchar_num++],">=");
				strcpy(finaltable[final_num],">=");
				finaltableint[final_num++]=14;
			}												// >= 14
			else
			{
				strcpy(otherchartable[otherchar_num++],">");
				strcpy(finaltable[final_num],">");
				finaltableint[final_num++]=15;				// > 15
				ungetc(ch,stdin);
			}
		}
		break;
	case '<':
		{
			ch=getchar();
			if(ch=='=')
			{
				strcpy(otherchartable[otherchar_num++],"<=");
				strcpy(finaltable[final_num],"<=");
				finaltableint[final_num++]=16;
			}												// <= 16
			else
			{
				strcpy(otherchartable[otherchar_num++],"<");
				strcpy(finaltable[final_num++],"<");
				finaltableint[final_num++]=17;				//< 17
				ungetc(ch,stdin);
			}
		}
		break;
	case '*':
		strcpy(finaltable[final_num],"*");
		finaltableint[final_num++]=18;						// * 18
		break;
	default:
		error();break;
	}
}

void error()
{
	flag_error=1;
	printf("出现错误,中止分析!\n");
}

		
void initialize()
{
	int i;
	for(i=0;i<20;i++)
	{
		word[i]='\0';
	}
}

void check()
{
	int i,j,flag;
	strcpy(re_keywordtable[0],keywordtable[0]);
	for(i=1;i<keyword_num;i++)
	{
		flag=0;
		for(j=0;j<rekeyword_num;j++)
		{
			if(strcmp(keywordtable[i],re_keywordtable[j])==0)
			{
				flag=1;
				break;
			}
		}
		if(flag==0)
			strcpy(re_keywordtable[rekeyword_num++],keywordtable[i]);
	}

	strcpy(re_digittable[0],digittable[0]);
	for(i=1;i<digit_num;i++)
	{
		flag=0;
		for(j=0;j<redigit_num;j++)
		{
			if(strcmp(digittable[i],re_digittable[j])==0)
			{
				flag=1;
				break;
			}
		}
		if(flag==0)
			strcpy(re_digittable[redigit_num++],digittable[i]);
	}

	strcpy(re_otherchartable[0],otherchartable[0]);
	for(i=1;i<otherchar_num;i++)
	{
		flag=0;
		for(j=0;j<reotherchar_num;j++)
		{
			if(strcmp(otherchartable[i],re_otherchartable[j])==0)
			{
				flag=1;
				break;
			}
		}
		if(flag==0)
			strcpy(re_otherchartable[reotherchar_num++],otherchartable[i]);
	}

	strcpy(re_idtable[0],idtable[0]);
	for(i=1;i<id_num;i++)
	{
		flag=0;
		for(j=0;j<reid_num;j++)
		{
			if(strcmp(idtable[i],re_idtable[j])==0)
			{
				flag=1;
				break;
			}
		}
		if(flag==0)
			strcpy(re_idtable[reid_num++],idtable[i]);
	}
}

void note()
{
	char ch;
	int i=0;
	ch=getchar();
	while(1)
	{
		if(ch=='*')
		{
			ch=getchar();
			if(ch=='/')
				break;
			else
			{
				ungetc(ch,stdin);
				word[i++]=ch;
			}
		}
		else
		{
			word[i++]=ch;
		}
		ch=getchar();
	}
	strcpy(notetable[note_num++],word);
}

void print()
{
	int i;
	//printf("Keywords:\n");
	if(keyword_num!=0)
	for(i=0;i<rekeyword_num;i++)
		printf("< %s, >\n",re_keywordtable[i]);
	//printf("\nDigits:\n");
	if(digit_num!=0)
	for(i=0;i<redigit_num;i++)
		printf("< number,%s >\n",re_digittable[i]);
	//printf("\nOtherchars:\n");
	if(otherchar_num!=0)
	for(i=0;i<reotherchar_num;i++)
		printf("< comparison,%s >\n",re_otherchartable[i]);
	//printf("\nId:\n");
	if(id_num!=0)
	for(i=0;i<reid_num;i++)
		printf("< id,%s >\n",re_idtable[i]);
	if(note_num!=0)
	{
		printf("注释:\n");
		for(i=0;i<note_num;i++)
			printf("%s\n",notetable[i]);
	}
	printf("词法分析完成!\n");
}

void prin()
{
	int i;
    finaltableint[final_num]='\0';
	printf("语法分析结果如下:\n");
	for(i=0;i<final_num;i++)
		printf("%s",finaltable[i]);
	printf("\n语法分析过程如下:\n");
}

void program()
{
	printf("program-->block\n");
	block();
	if(flagerror==1)
	{
		error();
		return;
	}
}

void block()
{
	if(flagerror==1)
	{
		return;
	}
	printf("block-->{stmts}\n");
	match("{");
	stmts();
	match("}");
}

void stmts()
{
	if(flagerror==1)
	{
		return;
	}
	if(finaltableint[finalnum]==10)
	{
		printf("stmts-->null\n");
		return;
	}
	printf("stmts-->{stmt stmts}\n");
	stmt();
	stmts();
}

void stmt()
{
	if(flagerror==1)
	{
		return;
	}
	switch(finaltableint[finalnum]){
	case 1:
		printf("stmt-->id=expr\n");
		match("id");
		match("=");
		expr();
		match(";");
		break;
	case 100:
		match("if");
		match("(");
		Bool();
		match(")");
		stmt();
		if(strcmp(finaltable[finalnum],"else")==0)
		{
			printf("stmt-->if(bool) stmt else stmt\n");
			match("else");
			stmt();
			break;
		}
		else
		{
			printf("stmt-->{if(bool) stmt\n");
			break;
		}
	case 400:
		printf("stmt-->while(bool) stmt\n");
		match("while");
		match("(");
		Bool();
		match(")");
		stmt();
		break;
	case 500:
		printf("stmt-->do stmt while(bool)\n");
		match("do");
		stmt();
		match("while");
		match("(");
		Bool();
		match(")");
		match(";");
		break;
	case 800:
		printf("stmt-->break;\n");
		match("break");
		match(";");
		break;
	default:
		printf("stmt-->block\n");
		block();
		break;
	}
}

void Bool()
{
	if(flagerror==1)
	{
		return;
	}
	expr();
	switch(finaltableint[finalnum]){
	case 17:
		printf("bool-->expr<expr\n");
		match("<");
		expr();
		break;
	case 16:
		printf("bool-->expr<=expr\n");
		match("<=");
		expr();
		break;
	case 15:
		printf("bool-->expr>expr\n");
		match(">");
		expr();
		break;
	case 14:
		printf("bool-->expr>=expr\n");
		match(">=");
		expr();
		break;
	default:
		printf("bool-->expr\n");
		expr();
		break;
	}
}

void expr()
{
	if(flagerror==1)
	{
		return;
	}
	printf("expr-->term expr1\n");
	term();
	expr1();
}

void expr1()
{
	if(flagerror==1)
	{
		return;
	}
	switch(finaltableint[finalnum]){
	case 13:
		printf("expr1-->+term expr1\n");
		match("+");
		term();
		expr1();
		break;
	case 19:
		printf("expr1-->-term expr1\n");
		match("-");
		term();
		expr1();
		break;
	default:
		printf("expr1-->null\n");
		return;
	}
}

void term()
{
	if(flagerror==1)
	{
		return;
	}
	printf("term-->factor term1\n");
	factor();
	term1();
}

void term1()
{
	if(flagerror==1)
	{
		return;
	}
	switch(finaltableint[finalnum]){
	case 18:
		printf("term1-->*factor term1\n");
		match("*");
		factor();
		term1();
		break;
	case 2:
		printf("term1-->/factor term1\n");
		match("/");
		factor();
		term1();
		break;
	default:
		printf("term1-->null\n");
		return;
	}
}

void factor()
{
	if(flagerror==1)
	{
		return;
	}
	switch(finaltableint[finalnum]){
	case 6:
		printf("fatcor-->(expr)\n");
		match("(");
		expr();
		match(")");
		break;
	case 1:
		printf("factor-->id\n");
		match("id");
		break;
	case 99:
		printf("factor-->num\n");
		match("num");
		break;
	default:
		flagerror=1;
		break;
	}
}

void match(char *t)
{
	if(strcmp(finaltable[finalnum],t)==0)
		;
	else
	{
		flagerror=1;
		return;
	}
	finalnum++;
} 


六、实验结果
正确的语法
{i=6;sum=i+sum}
在这里插入图片描述
对于不正确的语句
{i=4;while(i<=30){sum=sum+i;i=i+1}}/少了一个;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 编译原理语法分析是编译器的关键步骤之一,用于检查源码是否符合文规则,判断义是否正确,生成中间代码等等。其中递归下降分析是常用的语法分析之一。具体说,递归下降分析的开始符号开始,通过递归调用函数来实现对规则的分析。在解析过程中,程序使用递归下降按照的层次进行分解,将复杂的问题分解为简单的子问题,每个子问题对应一个程序,依次调用子程序就可以完成对整个文语法分析。 在Java编译器的实现中,javac采用了递归下降分析。Java规则十分复杂,包括各种句、表达式、变量类型等等,因此编写一个符合Java递归下降分析程序也非常复杂。总的来说,javac的语法分析程序包括以下几个部分:词法分析器语法分析器、符号表等。 词法分析器用于将源程序转化为词单元(Token),然后传给语法分析器进行分析。语法分析器则根据Java规则,利用递归下降分析来对Token序列进行分析,采用自顶向下的分析方,逐步分析规则,直到最终将整个程序解析完成。在语法分析过程中,还需要使用符号表来确定变量类型,计算表达式的值等等,完成义分析的任务。 总的来说,递归下降分析是一种常用的语法分析,适用于多种编程的编译器实现,可以通过编译原理的学习和练习,更好地掌握这一方,并开发出高质量的编译器。 ### 回答2: 编译原理语法分析是指将源程序转换为一种内部表示形式的过程,在此过程中,需要对源程序进行语法分析,也就是检查源程序是否符合规则。递归下降分析是一种常用的语法分析,它是基于自顶向下的推导方实现的。 在进行递归下降分析时,我们需要将源程序按照相应的规则进行分解,然后递归分析每个生成式对应的子串,最终得到源程序树。递归下降分析的一个优点是它能够直接产生树,因此更容易进行义分析和代码生成等后续处理。 在Java编译器的实现中,javac使用了递归下降分析方对源代码进行语法分析。在分析过程中,它将Java源代码分解为若干个符号,然后按照Java规则进行递归下降分析,最终得到树。与其他编译器相比,javac的递归下降分析方具有较高的可读性和可维护性,因为它的代码与Java规则紧密相关。 同时,在语法分析的过程中,javac还涉及到词分析、错误处理、符号表管理等方面的问题,这些都是编译原理的基础知识点,对于Java编译器的实现非常重要。 ### 回答3: 编译原理语法分析是编译器的一个重要组成部分,其作用是对程序源代码进行语法分析,将其转换为可以执行的目标代码。其中,递归下降分析是一种常用的语法分析。 在递归下降分析中,编译器会根据规则对源代码进行递归分析,以确定其正确性,并生成对应的树。该方的基本思路是把一个复合规则拆分成多个较简单的子规则,然后通过递归调用不同的子规则来完成分析过程。这种方可以较为高效地进行语法分析,但需要编写大量的递归函数来完成分析工作。 对于Java编译器而语法分析是其中一个非常重要的部分,因为Java中有严格的规则需要遵循。在语法分析中,Java编译器可以使用递归下降分析进行处理,通过遍历源代码来分析其中的结构,生成对应的树,最终将其转化为可执行的目标代码。同时,在使用递归下降分析时,Java编译器需要对不同的规则进行拆分和分析,并通过栈的方式来完成函数递归调用,以实现整个语法分析过程。 总之,递归下降分析编译原理语法分析中的一个重要方,可以用于解析各种编程中的结构。在Java编译器中,递归下降分析也是其中一个重要的语法分析,在语法分析过程中起着关键性的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值