词法分析实验
【文法定义】:
<标识符>::=<字母>{<字母>|<数字>}//标识符和关键字都不区分大小写,比如if和IF均为关键字,不允许出现与关键字相同的标识符
<字母>::=_|a|...|z|A|...|Z
<数字>::=0|1|...|9
<整数>::=[+|-]<无符号整数>
<无符号整数>::=<数字>{<数字>}
<字符>::='<加法运算符>'|'<乘法运算符>'|'<字母>'|'<数字>'
<加法运算符>::=+|-
<乘法运算符>::=*|/
<字符串>::="{十进制编码为32,33,35-126的ASCII字符}" //字符串中要求至少有一个字符
【问题描述】
请根据给定的文法设计并实现词法分析程序,从源程序中识别出单词,记录其单词类别和单词值,输入输出及处理要求如下:
- 数据结构和与语法分析程序的接口请自行定义;类别码需按下表格式统一定义;
- 为了方便进行自动评测,输入的被编译源文件统一命名为testfile.txt;输出的结果文件统一命名为output.txt,输入输出文件路径为相对路径,不要写成绝对路径。
- 结果文件中每行按如下方式组织:
单词类别码 单词的字符/字符串形式(中间仅用一个空格间隔)
单词的类别码请统一按如下形式定义:
【输入形式】testfile.txt中的符合文法要求的测试程序。
【输出形式】要求将词法分析结果输出至output.txt中。
【样例输入】
const int const1 = 1, const2 = -100;
const char const3 = '_';
int change1;
char change3;
int gets1(int var1,int var2){
change1 = var1 + var2;
return (change1);
}
void main(){
printf("Hello World");
printf(gets1(10, 20));
}
【样例输出】
CONSTTK const
INTTK int
IDENFR const1
ASSIGN =
INTCON 1
COMMA ,
IDENFR const2
ASSIGN =
MINU -
INTCON 100
SEMICN ;
CONSTTK const
CHARTK char
IDENFR const3
ASSIGN =
CHARCON _
SEMICN ;
INTTK int
IDENFR change1
SEMICN ;
CHARTK char
IDENFR change3
SEMICN ;
INTTK int
IDENFR gets1
LPARENT (
INTTK int
IDENFR var1
COMMA ,
INTTK int
IDENFR var2
RPARENT )
LBRACE {
IDENFR change1
ASSIGN =
IDENFR var1
PLUS +
IDENFR var2
SEMICN ;
RETURNTK return
LPARENT (
IDENFR change1
RPARENT )
SEMICN ;
RBRACE }
VOIDTK void
MAINTK main
LPARENT (
RPARENT )
LBRACE {
PRINTFTK printf
LPARENT (
STRCON Hello World
RPARENT )
SEMICN ;
PRINTFTK printf
LPARENT (
IDENFR gets1
LPARENT (
INTCON 10
COMMA ,
INTCON 20
RPARENT )
RPARENT )
SEMICN ;
RBRACE }
代码:
#include<stdio.h>
#include<string.h>
struct Symbol
{
char name[10];//名字
char real[3];//真实的符号
} ;
char c;
int i;
FILE *inFile,*outFile;
int split();
char buffer[1024];
int result=0;
char CONSTTKS[][7]= {"CONST","INT","CHAR","RETURN","VOID","MAIN","PRINTF"};
struct Symbol symbols[]= {{"COMMA",","},{"SEMICN",";"},{"MINU","-"},{"PLUS","+"},{"DIV","/"},{"LSS","<"},{"GRE",">"},
{"ASSIGN","="},{"LPARENT","("},{"RPARENT",")"},{"LBRACK","["},{"RBRACK","]"},{"LBRACE","{"},{"RBRACE","}"}
};
int comp(char* a,char* b)
{
int i;
for(i=0; a[i]!='\0'&&b[i]!='\0'; i++)
{
if(a[i]!=b[i]&&a[i]-b[i]!=32&&a[i]-b[i]!=-32)
return 1;
}
if(a[i]==b[i]&&a[i]=='\0')
return 0;
else return 1;
}
int isConsttks(char* c)
{
int i;
for(i=0; i<7; i++)
{
if(comp(CONSTTKS[i],c)==0)
{
return i;
}
}
return -1;
}
//判断一个字母是否是字母:a-zA-Z_,
//返回1代表是,0 代表不是
int isAlpheBelta(char c)
{
return (c>='A'&&c<='Z')||(c>='a'&&c<='z')||c=='_';
}
int isDigit(char c)
{
return c>='0'&&c<='9';
}
/**
* 分割单词的时候,通过;空格 ,‘’“”(){}进行分割
*/
int main()
{
int toFile=1;
int kind;
int temp2;
inFile=fopen("testfile.txt","r");
outFile=fopen("output.txt","w");
if(inFile==NULL)
{
printf("打开文件失败!程序退出!");
return -1;
}
if(outFile==NULL)
{
printf("创建输出文件失败!程序退出!");
return -1;
}
else
{
while((kind=split())!=-1)
{
if(buffer[0]!='\0')
{
if(kind==15)//如果是char类型
{
if(toFile)
fprintf(outFile,"CHARCON %c\n",buffer[0]);
else
printf("CHARCON %c\n",buffer[0]);
buffer[0]='\0';
result=0;
}
else if(kind==16)
{
if(toFile)
fprintf(outFile,"STRCON %s\n",buffer);
else printf("STRCON %s\n",buffer);
buffer[0]='\0';
result=0;
}
else
{
temp2=isConsttks(buffer);
if(temp2>=0)
{
if(toFile)
fprintf(outFile,"%sTK %s\n",CONSTTKS[temp2],buffer);
else printf("%sTK %s\n",CONSTTKS[temp2],buffer);
}
else if(toFile)
fprintf(outFile,"IDENFR %s\n",buffer);
else printf("IDENFR %s\n",buffer);
if(kind==111)
{
if(toFile)
fprintf(outFile,"LEQ <=\n");
else printf("LEQ <=\n");
}
else if(kind==112)
{
if(toFile)
fprintf(outFile,"GEQ >=\n");
else printf("GEQ >=\n");
}
else if(kind==113)
{
if(toFile)
fprintf(outFile,"EQL ==\n");
else printf("EQL ==\n");
}
else if(kind==114)
{
if(toFile)
{
fprintf(outFile,"NEQ !=\n");
}
else printf("NEQ !=\n");
}
}
}
if(kind>0&&kind<=14)
{
if(toFile)
fprintf(outFile,"%s %s\n",symbols[kind-1].name,symbols[kind-1].real);
else printf("%s %s\n",symbols[kind-1].name,symbols[kind-1].real);
}
}
}
printf("分析完成!");
return 0;
}
//分词程序,返回值用来控制下一个输出
int split()
{
int count=0;
int flag=0;
while(!feof(inFile)&&!flag)
{
i=fgetc(inFile);
c=(char)i;
if(result==16)
{
if(i==32||i==33||(i>=35&&i<=126))
buffer[count++]=c;
else if(i==34)
{
buffer[count]='\0';
flag=1;
}
}
else if(result==15)
{
if(i==32||i==33||(i>=35&&i<=126))
{
buffer[count++]=c;
buffer[count]='\0';
flag=1;
}
}
else
{
if(isAlpheBelta(i)) //如果是字母
{
result=0;
buffer[count++]=c;
}
else if(isDigit(c))
{
result=0;
//如果是数字
buffer[count++]=c;
}
else
{
flag=1;
buffer[count]='\0';
switch(c)
{
case ' ':
case '\t':
case '\n':
if(result==16)
{
result=16;
flag=0;
buffer[count++]=c;
}
else if(result==15)
{
result=15;
buffer[count++]=c;
buffer[count]='\0';
}
else result=0;
break;
case ',':
result=1;//
break;
case ';':
result=2;
break;
case '-':
result=3;
break;
case '+':
result=4;
break;
case '/':
result=5;
break;
case '<':
result=6;
if((char)fgetc(inFile)=='=')
{
result=111;
}
else
{
fseek(inFile,-1,SEEK_CUR);
}
break;
case '>':
result=7;
if((char)fgetc(inFile)=='=')
{
result=112;
}
else
{
fseek(inFile,-1,SEEK_CUR);
}
break;
case '=':
result=8;
if((char)fgetc(inFile)=='=')
{
result=113;
}
else
{
fseek(inFile,-1,SEEK_CUR);
}
break;
case '(':
result=9;
break;
case ')':
result=10;
break;
case '[':
result=11;
break;
case ']':
result=12;
break;
case '{':
result=13;
break;
case '}':
result=14;
break;
case '\'':
result=15;
break;
case '\"':
result=16;
break;
case '!':
c=(char)fgetc(inFile);
if(c=='=')
{
result=114;
}
else
{
fseek(inFile,-1,SEEK_CUR);
}
break;
}
}
}
}
if(feof(inFile))
return -1;
if (flag==1)
{
return result;
}
return -1;
}
运行效果: