📄 wordanalyser.c
字号:
/******************************************************************************
*模块名:词法分析器
*
*功能:从源程序文件中(文本文件)识别出单词符号,以二元组保存输出
*
*开始时间:2004.10.8
*
*修改时间:2004.10.10, 10.12, 10.15, 10.17, 10.29, 11.18
*
*完成时间:2004.10.17
*
*作者: 邸晓峰,胡彬,宋如强
*
*
*******************************************************************************/
#include "complier.h"
//全局常量
int KEYINDEX[16]={4,14,10,8,5,11,6,3,1,15,12,7,13,2,9,16}; //关键字编码表
char* KEYWORD[16]={"begin","call","do","else","end","for","if","procedure","program","read","step"
,"then","until","var","while","write"}; //关键字表
//全局变量
char buffer[50]; //预输入缓冲区
char readchar; //分析时存放读入的新字符
char strToken[21]; //分析时存放构成的单词符号串
//用户自定义标识符最多20个字符,否则只取前20个
int linenum; //行数
int searchpoint; //搜索指示器
FILE* sfp; //源文件指针
FILE* dfp; //目的文件指针
DuaDualist Dualist; //二元式链表
//////////////////////////////////////////////////////////////////////////////////////////////
//此函数初始化各公共变量
void initilize(){
linenum=1;
searchpoint=0;
readchar='\0';
Dualist.head=(Duatype*)malloc(sizeof(Duatype)); //带头结点
Dualist.head->index=0;
Dualist.head->value=NULL;
Dualist.head->next=NULL;
Dualist.tail=Dualist.head;
}
//////////////////////////////////////////////////////////////////////////////////////////////
//此函数判断源程序文件是否存在
//存在函数返回true,不存在函数返回false
int isFile(){
char fname[20]; //源程序文件名
printf("Please input the name of the source file:");
scanf("%s",fname);
sfp=fopen(fname,"r");
if(sfp==NULL){
printf("This file does not exit!Please input the name of the source file again!");
return false;
}
else{
printf("Success!");
printf("\n");
return true;
}
}
////////////////////////////////////////////////////////////////////////////////////////////
//此函数判断readchar读入字符是否为字母
//若是字母,则返回true;否则返回false
int isLetter(char readchar){
if(readchar>='a' && readchar<='z')
return true;
else
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////
//此函数判断readchar读入字符是否为数字
//若是数字,则返回true;否则返回false
int isDigit(char readchar){
if(readchar>='0' && readchar<='9')
return true;
else
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////
//此函数清空指定字符缓冲区中已有字符
//参数为缓冲区首地址和缓冲区长度
void Clear(char* strBuffer,int lengthBuffer){
int i;
for(i=0;i<lengthBuffer;i++) //清空strBuffer,以备下次使用
strBuffer[i]='\0';
}
///////////////////////////////////////////////////////////////////////////////////////////////
//此函数从源程序文件中预输入到缓冲区buffer50
//参数为缓冲区首地址,若源文件读完返回true;未读完而缓冲区满返回false
int BeforehandInput(char* buffer){
int i=0;
readchar=fgetc(sfp);
while(readchar!=EOF && i<50){
if(readchar>='A' && readchar<='Z'){
readchar=readchar+32; //大写字母转化成小写,便于后续处理,源程序中不区分大小写
buffer[i]=readchar;
i++;
readchar=getc(sfp);
}
else if(readchar==' ' || readchar=='\t'){ //连续空格只保留一个
if(buffer[i-1]==' ' || buffer[i-1]=='\n')
readchar=getc(sfp);
else{
buffer[i]=' '; //制表符转化程空格,便于后续处理
i++;
readchar=getc(sfp);
}
}
else{
buffer[i]=readchar;
i++;
readchar=getc(sfp);
}
}
if(i>=50){
fseek(sfp,-1,SEEK_CUR);
if(readchar==EOF) return true;
else return false;
}
else{
buffer[i]='\0'; //把EOF转化为'/0'放入缓冲区,作为源文件输入结束的标志
fclose(sfp);
return true;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
//此函数相当于哈希函数,辅助查询关键字表
//参数为需识别标识符strtoken首字符,返回值为以此字母开头的关键字在关键字表中的起始位置(下标值)
int LocinKEYWORD(char fc){
switch(fc){
case 'b':
return 0;
break;
case 'c':
return 1;
break;
case 'd':
return 2;
break;
case 'e':
return 3;
break;
case 'f':
return 5;
break;
case 'g':
case 'h':
case 'i':
return 6;
break;
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
return 7;
break;
case 'q':
case 'r':
return 9;
break;
case 's':
return 10;
break;
case 't':
return 11;
break;
case 'u':
return 12;
break;
case 'v':
return 13;
break;
case 'w':
return 14;
break;
default:
return 16;
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//此函数把从缓冲区读入的字符readchar和strToken中字串相拼接
void Concat(){
char temp[2]={readchar,'\0'};
strcat(strToken,temp);
}
///////////////////////////////////////////////////////////////////////////////////////////////
//此函数对strToken中字串查找关键字表
//返回值为关键字编码;若不是关键字,返回17
int SearchKey(){
int start,end,i;
start=LocinKEYWORD(strToken[0]);
end=LocinKEYWORD(strToken[0]+1);
if(start==16)
return 17; //非关键字;
else
for(i=start;i<end;i++){ //根据首字符索引查找关键字,提高效率,返回相应编码
if((strcmp(strToken,KEYWORD[i]))==0)
return KEYINDEX[i];
}
return 17; //关键表中查不到
}
///////////////////////////////////////////////////////////////////////////////////////////////
//此函数对分析出的单词符号生成二元式结点并插入二元式链表
void Insert(){
Duatype* temp;
temp=(Duatype*)malloc(sizeof(Duatype));
temp->value=(char*)malloc((strlen(strToken)+1)*sizeof(char));
strcpy(temp->value,strToken);
temp->next=NULL;
Dualist.tail->next=temp;
Dualist.tail=temp;
}
///////////////////////////////////////////////////////////////////////////////////////////////
//此函数清查上一个缓冲区中剩余的字符串或数字串
void CheckLeft(){
if(isalpha(strToken[0])){
Insert();
Dualist.tail->index=SearchKey();
Clear(strToken,21);
}
else if(isdigit(strToken[0])){
Insert();
Clear(strToken,21);
Dualist.tail->index=18;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//此函数为词法分析过程
//参数为缓冲区首地址,生成二元式链表
void WordAnalyse(char* buffer){
searchpoint=0;
while(searchpoint<50){
readchar=buffer[searchpoint];
searchpoint++;
if(isLetter(readchar)){
do{
if(strlen(strToken)<20) //用户标识符最多20个字符,多余的略过不读
Concat();
if(searchpoint>=50)
break;
readchar=buffer[searchpoint];
searchpoint++;
}while(isLetter(readchar) || isDigit(readchar));
if(isLetter(readchar) || isDigit(readchar))
break;
searchpoint--;
Insert();
Dualist.tail->index=SearchKey();
Clear(strToken,21);
continue;
}
else if(isDigit(readchar)){
do{
if(strlen(strToken)<20) //用户标识符最多20个字符,多余的略过不读
Concat();
if(searchpoint>=50)
break;
readchar=buffer[searchpoint];
searchpoint++;
}while(isDigit(readchar));
if(isDigit(readchar))
break;
searchpoint--;
Insert();
Clear(strToken,21);
Dualist.tail->index=18;
continue;
}
else if(readchar==' '){
if(searchpoint>=50)
break;
else if(isLetter(strToken[0])){
Insert();
Dualist.tail->index=SearchKey();
Clear(strToken,21);
}
else if(isDigit(strToken[0])){
Insert();
Dualist.tail->index=18;
Clear(strToken,21);
}
else
continue; //空格跳过
}
else if(readchar=='+'){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=19;
if(searchpoint>=50)
break;
}
else if(readchar=='-'){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=20;
if(searchpoint>=50)
break;
}
else if(readchar=='*'){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=21;
if(searchpoint>=50)
break;
}
else if(readchar=='/'){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=22;
if(searchpoint>=50)
break;
}
else if(readchar==':'){
CheckLeft();
Concat();
if(searchpoint>=50)
break;
readchar=buffer[searchpoint];
searchpoint++;
if(readchar=='='){
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=23;
if(searchpoint>=50)
break;
}
else{
searchpoint--;
}
}
else if(readchar=='='){
CheckLeft();
Concat();
Insert();
if(strlen(strToken)==2){ //":="
if(strToken[0]==':')
Dualist.tail->index=23;
else if(strToken[0]=='<') //"<="
Dualist.tail->index=29;
else if(strToken[0]=='>') //">="
Dualist.tail->index=27;
}
else
Dualist.tail->index=24; //"="
Clear(strToken,21);
if(searchpoint>=50)
break;
}
else if(readchar=='<'){
CheckLeft();
Concat();
if(searchpoint>=50)
break;
readchar=buffer[searchpoint];
searchpoint++;
if(readchar=='='){ //"<="
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=29;
if(searchpoint>=50)
break;
}
else if(readchar=='>'){ //"<>"
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=25;
if(searchpoint>=50)
break;
}
else{ //"<"
searchpoint--;
Insert();
Clear(strToken,21);
Dualist.tail->index=28;
if(searchpoint>=50)
break;
}
}
else if(readchar=='>'){
CheckLeft();
Concat();
if(searchpoint>=50)
break;
readchar=buffer[searchpoint];
searchpoint++;
if(readchar=='='){ //">="
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=27;
if(searchpoint>=50)
break;
}
else{
searchpoint--;
Insert();
if(strlen(strToken)==2)
Dualist.tail->index=25; //"<>"
else
Dualist.tail->index=26; //">"
Clear(strToken,21);
if(searchpoint>=50)
break;
}
}
else if(readchar=='('){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=30;
if(searchpoint>=50)
break;
}
else if(readchar==')'){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=31;
if(searchpoint>=50)
break;
}
else if(readchar==','){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=32;
if(searchpoint>=50)
break;
}
else if(readchar==';'){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=33;
if(searchpoint>=50)
break;
}
else if(readchar=='.'){
CheckLeft();
Concat();
Insert();
Clear(strToken,21);
Dualist.tail->index=34;
if(searchpoint>=50)
break;
}
else if(readchar=='\n'){
linenum++;
CheckLeft();
strcat(strToken,"newline");
Insert();
Clear(strToken,21);
Dualist.tail->index=35;
if(searchpoint>=50)
break;
}
else if(readchar=='\0') //源文件结束标志,结束词法分析
break;
else //非法字符
printf("Line %d: unknown word.",linenum);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//此函数为词法分析器
void WordAnalyser(){
int index=1;
int flagbuffer=false; //判断源文件是否读完标志
char strIndex[10];
Duatype* p;
initilize();
while(!isFile()); //直到正确打开文件
while(!flagbuffer){
flagbuffer=BeforehandInput(buffer);
WordAnalyse(buffer);
}
dfp=fopen("duality.txt","w");
for(p=Dualist.head->next;p!=NULL;p=p->next){
itoa(p->index,strIndex,10);
putc('(',dfp);
fputs(p->value,dfp);
putc(',',dfp);
fputs(strIndex,dfp);
putc(')',dfp);
putc('\n',dfp);
}
fclose(dfp);
}
main()
{
WordAnalyser();
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -