实验四.语法分析课程设计
一.语法分析的功能:语法分析是编译过程的核心部分,它的主要任务是按照和程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法分析成分,同时进行语法检查,为语义分析和代码生成作准备。
二.语法分析的目的:语法分析程序以词法分析输出的符号串作为输入,在分析过程中检查这个符号串是否为该程序语言的句子。
三.语法分析的规则:参照了课本上P69 的TEST规则(1)--(17)。
(1)<program>::={<declaration_list><statement_list>}
(2)<declaration_list>::=<declaration_list><delaration_stat>|e
(3)<declaration_stat>::=int ID;
(4)<statement_list>::=<statement_list><statement>|e
(5)<statement>::=<if_stat>|<while_stat>|<for_stat>|<read_stat>|<write_stat>|<do_stat>|<compound_stat>|<expression_stat>
(6)<if_stat>::=if(<expression>)<statement>[else<statement>]
(7)<while_stat>::=while(<expression>)<statement>
(8)<for_stat>::=for(<expression>,<expression>,<expression>)<statement>
(9)<write_stat>::=write<expression>
(10)<read_stat>::=read ID
(11)<do_stat>::=do<statement>while<expression>
(12)<compound_stat>::={<statement_list>}
(13)<expression_stat>::=<expression>;|;
(14)<expression>::=ID=<bool_expr>|<bool_expr>|<log_expr>|<log_expr>
(15)<bool_expr>::=<additive_expr>|<additive_expr>(>|<|>=|<=|==
!=)<additive_expr>
(16)<additive_expr>::=<term>{(+|-)|<term>}
(17) <term>::=<factor>{(*|/)<factor>}
(18)<factor>::=(<expression>)|ID|NUM
(19)<log_expr>::=<log_expr>(&&|||)<bool_expr>|!<log_expr>|<bool_expr>
该语法分析是自顶向下的语法分析。
四.实验过程:编译好语法分析程序后,将00.t文件保存到电脑D盘中,然后运行分析如下图:
00.T文件:
do{
if((month==4)||(month==6))
return (30);
else if((month==2)&&(month==1)&&(month!=9))
return (0);
}while(i>=0)
01.T文件:
do do
{ {
if if
( (
( (
ID month
== ==
NUM 4
) )
| |
| |
( (
ID month
== ==
NUM 6
) )
) )
ID return
( (
NUM 30
) )
; ;
else else
if if
( (
( (
ID month
== ==
NUM 2
) )
& &
& &
( (
ID month
== ==
NUM 1
) )
& &
& &
( (
ID month
!= !=
NUM 9
) )
) )
ID return
( (
NUM 0
) )
; ;
} }
while while
( (
ID i
>= >=
NUM 0
) )
02.T文件:
do do
{ {
if if
( (
( (
ID month
== ==
NUM 4
) )
| |
| |
( (
ID month
== ==
NUM 6
) )
) )
ID return
( (
NUM 30
) )
; ;
else else
if if
( (
( (
ID month
== ==
NUM 2
) )
& &
& &
( (
ID month
== ==
NUM 1
) )
& &
& &
( (
ID month
!= !=
NUM 9
) )
) )
ID return
( (
NUM 0
) )
; ;
} }
while while
( (
ID i
>= >=
NUM 0
) )
五.语法分析程序的源代码:
//TESTscan.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//下面定义保留,为简化程序,使用字符指针数组保存所有保留字。
//如果想增加保留字,可继续添加,并修改保留字数目
#define keywordSum 9
char *keyword[keywordSum]={"if","else","for","while","do","int","read","write","real"};
//下面定义纯单分界符,如需要可添加
char singleword[50]="+-*(){};,:&";
//下面定义双分界符的首字符
char doubleword[10]="><=!||";
extern char Scanin[300], Scanout[300]; //用于接收输入输出文件名,在TEST_main.c中定义
extern FILE *fin,*fout; //用于指向输入输出文件的指针,在TEST_main.c中定义
int TESTscan()//词法分析函数
{
char ch,token[40]; //ch为每次读入的字符,token用于保存识别出的单词
int es=0,j,n; //es错误代码,0表示没有错误。j,n为临时变量,控制组合单词时的下标等
printf("请输入源程序文件名(包括路径):");
scanf("%s",Scanin);
printf("请输入词法分析输出文件名(包括路径):");
scanf("%s",Scanout);
if((fin=fopen(Scanin,"r"))==NULL) //判断输入文件名是否正确
{
printf("/n打开词法分析输入文件出错!/n");
return(1);//输入文件出错返回错误代码1
}
if((fout=fopen(Scanout,"w"))==NULL) //判断输出文件名是否正确
{
printf("/n创建词法分析输出文件出错!/n");
return(2); //输出文件出错返回错误代码2
}
ch=getc(fin);
while(ch!=EOF)
{
while(ch==' '||ch=='/n'||ch=='/t')
ch=getc(fin);
if(isalpha(ch)) //如果是字母,则进行标识符处理
{
token[0]=ch;
j=1;
ch=getc(fin);
while(isalnum(ch)) //如果是字母数字则组合标识符;如果不是则标识符组合结束
{
token[j++]=ch; //组合的标识符保存在token中
ch=getc(fin); //读下一个字符
}
token[j]='/0'; //标识符组合结束
//查保留字
n=0;
while((n<keywordSum) && strcmp(token,keyword[n]))
n++;
if(n>=keywordSum) //不是保留字,输出标识符
fprintf(fout,"%s/t%s/n","ID",token); //输出标识符符号
else//是保留字,输出保留字
fprintf(fout,"%s/t%s/n",token,token); //输出保留字符号
}
else if(isdigit(ch))//数字处理
{
token[0]=ch;
j=1;
ch=getc(fin); //读下一个字符
while(isdigit(ch)) //如果是数字则组合整数;如果不是则整数组合结束
{
token[j++]=ch; //组合整数保存在token中
ch=getc(fin); //读下一个字符
}
token[j]='/0'; //整数组合结束
fprintf(fout,"%s/t%s/n","NUM",token); //输出整数符号
}
else if(strchr(singleword,ch)>0) //单分符处理
{
token[0]=ch;
token[1]='/0';
ch=getc(fin);//读下一个符号以便识别下一个单词
fprintf(fout,"%s/t%s/n",token,token); //输出单分界符符号
}
else if(strchr(doubleword,ch)>0) //双分界符处理
{
token[0]=ch;
ch=getc(fin); //读下一个字符判断是否为双分界符
if(ch=='=') //如果是=,组合双分界符
{
token[1]=ch;token[2]='/0'; //组合双分界符结束
ch=getc(fin); //读下一个符号以便识别下一个单词
}
else//不是=则为单分界符
token[1]='/0';
fprintf(fout,"%s/t%s/n",token,token); //输出单或双分界符符号
}
else if(ch=='/') //注释处理
{
ch=getc(fin); //读下一个字符
if(ch=='*') //如果是*,则开始处理注释
{ char ch1;
ch1=getc(fin); //读下一个字符
do
{ch=ch1;ch1=getc(fin);} //删除注释
while((ch!='*' || ch1!='/')&&ch1!=EOF); //直到遇到注释结束符*/或文件尾
ch=getc(fin);//读下一个符号以便识别下一个单词
}
else //不是*则处理单分界符/
{
token[0]='/'; token[1]='/0';
fprintf(fout,"%s/t%s/n",token,token); //输出单分界符/
}
}
else//错误处理
{
token[0]=ch;token[1]='/0';
ch=getc(fin); //读下一个符号以便识别下一个单词
es=3; //设置错误代码
fprintf(fout,"%s/t%s/n","ERROR",token); //输出错误符号
}
}
fclose(fin);//关闭输入输出文件
fclose(fout);
return(es); //返回主程序
}
//TESTparse.c
#include<stdio.h>
#include<ctype.h>
#include<conio.h>
#include<string.h>
int TESTparse();
int program();
int compound_stat();
int statement();
int expression_stat();
int expression();
int bool_expr();
int additive_expr();
int term();
int factor();
int if_stat();
int while_stat();
int for_stat();
int write_stat();
int read_stat();
int declaration_stat();
int declaration_list();
int statement_list();
int compound_stat();
char token[20],token1[40];
extern char Scanout[300];
FILE *fp;
int TESTparse()
{
int es=0;
if((fp=fopen(Scanout,"r"))==NULL)
{
printf("/n打开%s错误!/n",Scanout);
es=10;
}
if(es==0) es=program();
printf("=====语法分析结果!======/n");
switch(es)
{
case 0:printf("语法分析成功!/n");break;
case 10:printf("打开文件%S失败!/n",Scanout);break;
case 1:printf("缺少{!/n");break;
case 2:printf("缺少}!/n");break;
case 3:printf("缺少标识符!/n");break;
case 4:printf("少分号!/n");break;
case 5:printf("缺少(!/n");break;
case 6:printf("缺少)!/n");break;
case 7:printf("缺少操作数!/n");break;
}
fclose(fp);
return(es);
}
int program()
{
int es=0;
fscanf(fp,"%s%s/n",token,token1);
printf("%s%s/n",token,token1);
if(strcmp(token,"{"))
{es=1;
return(es);
}
fscanf(fp,"%s%s/n",&token,&token1);
printf("%s%s/n",token,token1);
es=declaration_list();
if(es>0)return(es);
es=statement_list();
if(es>0)return(es);
if(strcmp(token,"}"))
{
es=2;
return(es);
}
return(es);
}
int declaration_list()
{
int es=0;
while(strcmp(token,"int")==0)
{
es=declaration_stat();
if(es>0)return(es);
}
return(es);
}
int declaration_stat()
{
int es=0;
fscanf(fp,"%s%s/n",&token,&token1);
printf("%s%s/n",token,token1);
if(strcmp(token,"ID"))return(es=3);
fscanf(fp,"%s%s/n",&token,&token1);
printf("%s%s/n",token,token1);
if(strcmp(token,";"))return(es=4);
fscanf(fp,"%s%s/n",&token,&token1);
printf("%s%s/n",token,token1);
return(es);
}
int statement_list()
{
int es=0;
while(strcmp(token,"}"))
{
es=statement();
if(es>0)return(es);
}
return(es);
}
int statement()
{
int es=0;
if(es==0 && strcmp(token,"if")==0) es=if_stat();
if(es==0 && strcmp(token,"while")==0) es=while_stat();
if(es==0 && strcmp(token,"for")==0) es=for_stat();
if(es==0 && strcmp(token,"read")==0) es=read_stat();
if(es==0 && strcmp(token,"write")==0) es=write_stat();
if(es==0 && strcmp(token,"{")==0) es=compound_stat();
if(es==0 && strcmp(token,"ID")==0 || strcmp(token,"NUM")==0 || strcmp(token,"(")==0) es=expression_stat();
return(es);
}
int if_stat(){
int es=0;
fscanf(fp,"%s%s/n",&token,&token1);
printf("%s%s/n",token,token1);
if(strcmp(token,"("))return(es=5);
fscanf(fp,"%s%s/n",&token,&token1);
printf("%s%s/n",token,token1);
es=expression();
if(es>0)return(es);
if(strcmp(token,")"))return(es=6);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=statement();
if(es>0)return(es);
if(strcmp(token,"else")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=statement();
if(es>0)return(es);
}
return(es);
}
int while_stat()
{
int es=0;
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
if(strcmp(token,"("))return(es=5);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=expression();
if(es>0)return(es);
if(strcmp(token,")"))return(es=6);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=statement();
return(es);
}
int for_stat()
{
int es=0;
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
if(strcmp(token,"("))return(es=5);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=expression();
if(es>0)return(es);
if(strcmp(token,";")) return(es=4);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=expression();
if(es>0)return(es);
if(strcmp(token,";"))return(es=4);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=expression();
if(es>0)return(es);
if(strcmp(token,")"))return(es=6);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=statement();
return(es);
}
int write_stat()
{
int es=0;
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=expression();
if(es>0)return(es);
if(strcmp(token,";"))return(es=4);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
return(es);
}
int read_stat()
{
int es=0;
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
if(strcmp(token,"ID"))return(es=3);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
if(strcmp(token,";")) return(es=4);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
return(es);
}
int compound_stat(){
int es=0;
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=statement_list();
return(es);
}
int expression_stat()
{
int es=0;
if(strcmp(token,";")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
return(es);
}
es=expression();
if(es>0)return(es);
if(es==0 && strcmp(token,";")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
return(es);
}else
{
es=4;
return(es);
}
}
int expression()
{
int es=0,fileadd;
char token2[20],token3[40];
if(strcmp(token,"ID")==0)
{
fileadd=ftell(fp);
fscanf(fp,"%s%s/n",&token2,token3);
printf("%s%s/n",token2,token3);
if(strcmp(token2,"=")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=bool_expr();
if(es>0)return(es);
}else
{
fseek(fp,fileadd,0);
printf("%s%s/n",token,token1);
es=bool_expr();
if(es>0)return(es);
}
}else es=bool_expr();
return(es);
}
int bool_expr()
{
int es=0;
es=additive_expr();
if(es>0)return(es);
if(strcmp(token,">")==0 || strcmp(token,">=")==0 || strcmp(token,"<")==0 || strcmp(token,"<=")==0 || strcmp(token,"==")==0 || strcmp(token,"!=")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=additive_expr();
if(es>0)return(es);
}
return(es);
}
int additive_expr()
{
int es=0;
es=additive_expr();
if(es>0)return(es);
while(strcmp(token,"+")==0 || strcmp(token,"-")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=term();
if(es>0)return(es);
}
return(es);
}
int term()
{
int es=0;
es=factor();
if(es>0)return(es);
while(strcmp(token,"*")==0 || strcmp(token,"/")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=factor();
if(es>0)return(es);
}
return(es);
}
int factor()
{
int es=0;
if(strcmp(token,"(")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
es=expression();
if(strcmp(token,")"))return(es=6);
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
}else
{
if(strcmp(token,"ID")==0 || strcmp(token,"NUM")==0)
{
fscanf(fp,"%s%s/n",&token,token1);
printf("%s%s/n",token,token1);
return(es);
}else
{
es=7;
return(es);
}
}
return(es);
}
//TESTmain.c
#include<stdio.h>
#include<ctype.h>
extern int TESTscan();
extern int TESTparse();
char Scanin[300],Scanout[300];
FILE *fin,*fout;
void main(){
int es=0;
es=TESTscan();
if(es>0) printf("词法分析有错,编译停止!");
else printf("词法分析成功!/n");
if(es==0)
{
es=TESTscan();
if(es==0) printf("语法分析成功!/n");
else printf("语法分析错误!/n");
}
}
六.实验心得
鉴于上一次实验,在这一次实验中,少走了很多弯路,除了在输入代码时输入错误,其它就没什么问题了.只是觉得对语法分析的认识还是觉得有点模糊,不过这次实验让我更加认识到学习编译原理的重要性,还需继续努力。
注:为本人拟定,有错误,请勿COPY,仅供参考,谢谢合作