//這是我編譯原理的一次作業(yè),中間有許多不足之處希望大家指正
/*編寫PL/0語言的詞法分析程序
要求:
1、讀入用PL/0語言編寫的源程序,正確的進(jìn)行詞法分析,并輸出二元式序列。
2、若源程序有詞法錯誤,能夠給出出錯的準(zhǔn)確位置。
3、詞法代號如下
(+,+);
(-,-);
(*,*);
(/,/);
((,();
(),));
(,,,);
(;,;);
(.,.);
(#,#);
(=,=);
(>,>);
(<,<);
(:=,a);
(>=,b);
(<=,c);
(數(shù)字,d);
(標(biāo)識符,e);
關(guān)鍵字代號:
(begin,f);
(call,g);
(const,h);
(do,i);
(end,j);
(if,k);
(odd,l);
(procedure,m);
(read,n);
(then,o);
(var,p);
(while,q);
(write,r);
4、等于運算符號為一個 =
測試程序:
A.C
======================
CONST A=10;
VAR B,C;
PROCEDURE P;
VAR D;
PROCEDURE Q;
VAR X;
BEGIN
READ(X);
D:=X;
WHILE X<0
DO CALL P;
END;
BEGIN
WRITE(D);
CALL Q;
END;
BEGIN
CALL P;
END.
*/
/*program name:chifufenxi*/
/*作者:小萬 QQ:421404493*/
/*date:2004.10.11*/
#include
#include
#include
#include
#include
#define N 256//每一行的字符數(shù)不能超過256個
char buffer[N]; //用作存放一行字符
char word[20]; //用作存放經(jīng)過分析單詞
char *kword[13]={"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"};
char ktype[13]={'f','g','h','i','j','k','l','m','n','o','p','q','r'};
int len;//記錄每一行的長度
int count=0;//用來記錄行數(shù)
void write(char *wstr,char wc,FILE *wout)//將分析結(jié)果按照規(guī)則寫入到文件
{
fputc('(',wout);
fputs(wstr,wout);
fputc(',',wout);
fputc(wc,wout);
fputc(')',wout);
}
int readbuffer(FILE *fp)
{
char ch;
len=0;
ch=fgetc(fp);
while(!feof(fp) && ch!='\n')//讀取字符到緩沖區(qū)
{
buffer[len]=ch;
ch=fgetc(fp);
len++;
}
len--;//用來控制詞法分析時行分析中字母的個數(shù)
if(feof(fp))//標(biāo)志文件是否結(jié)束
return 0;
else
return 1;
}
void error(int type)
{
if(type==1)
printf("為無效字符,第%d行詞法出錯,標(biāo)志符不能以數(shù)字開頭\n",count);
else if(type==2)
printf("第%d行詞法出錯,賦值符應(yīng)為\:\= \n ",count);
else printf("為無效字符,第%d行詞法出錯\n",count);
}
void check(char *str,FILE *out);//聲明函數(shù),此函數(shù)用來分類單詞
void fenxi(char *row,FILE *op)//此函數(shù)用來對每一行的單詞進(jìn)行語法分析
{
//printf("%d\n",count);
int k=0;//用作控制臨時存放單詞的變量str0
int i=0;//定義兩個變量用作控制每一行是否結(jié)束,
int ferror=0;//用作出錯標(biāo)志
char str0[20];//臨時存放單詞的變量
while(i<=len)
{
k=0;//將k置0
strcpy(word,"\0");//將存放單詞的變量清空
/*去除空格*/
if(isspace(row[i]))//去出空格,跳格符,換行符
{
i++;
continue;
}
/*去出無效字符*/
while(!isalpha(row[i])&&!isdigit(row[i])&&i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
{
putchar(row[i]);
i++;
ferror=1;//設(shè)置錯誤標(biāo)志符
}
if(ferror==1)
{
error(3);//調(diào)用出錯處理函數(shù)
ferror=0;
}
/*對注釋進(jìn)行處理,假設(shè)此語言的注釋只能單行注釋以雙斜杠“//”為注釋開始標(biāo)志*/
if(row[i]=='/')
{
i++;
if(row[i]=='/')
{
i=len+1;//忽略注釋符后面的單詞
continue;
}
else
i--;
}
/*判斷是否為數(shù)字*/
if(isdigit(row[i]))
{
while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
//當(dāng)不到行尾,是數(shù)字或字母當(dāng)然有可能是無效字符
{
if(isdigit(row[i]))//是數(shù)字則將字符逐個存入臨時數(shù)組
{
str0[k]=row[i];
i++;
k++;
// putchar('e');
}
else //數(shù)字中加有字母或無效字符則報錯
{
// putchar('x');
ferror=1;break;//已經(jīng)出錯設(shè)置標(biāo)志并退出循環(huán)
}
}
if(ferror==1)//檢測是否出錯
{ /*將剛剛的那個單詞后面的數(shù)字和字母
清空,如123abc123或則123$$23等,當(dāng)出現(xiàn)錯誤后,需
要消除abc123和$$23 以免誤作為下一個標(biāo)志符*/
for(int j=0;j putchar(str0[j]);
while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
{
putchar(row[i]);
i++;
}
error(1);//putchar('e');//調(diào)用出錯處理函數(shù)
ferror=0;//重新設(shè)置錯誤標(biāo)志位
//i--;//strcpy(word,"");
}
else//未出錯照常處理
{
str0[k]='\0';
strcpy(word,str0);
i--;//減一是為了使最后取出的那個字符不在被下面的程序判斷
// str0[0]='\0';
}
}
/*判斷是否為標(biāo)志符和關(guān)鍵字即由字母開頭并且不含標(biāo)點符號用ispunct(int ch)判斷標(biāo)點符號*/
if(isalpha(row[i]))//標(biāo)志符或關(guān)鍵字由字母開頭
{
k=0;
while(i<=len&&row[i]!=32&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))//關(guān)鍵字和標(biāo)志符由數(shù)字和字母組成
{
if(isalpha(row[i])||isdigit(row[i]))//由數(shù)字和字母組成
{
str0[k]=row[i];
i++;
k++;
}
else//出錯,原因可能是出現(xiàn)了不可識別的字符
{
ferror=1;break;
}
}
if(ferror)
{
for(int j=0;j putchar(str0[j]);
while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
{
putchar(row[i]);//消除整個非法單詞
i++;
}
ferror=0;
error(3);
//i--;
}
else
{
str0[k]='\0';
strcpy(word,str0);
str0[0]='\0';
i--;
}
}
/*判斷運算符*/
if(row[i]=='+' ||row[i]=='-' ||row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'||row[i]=='.'||row[i]=='#' || row[i]=='=')
{
str0[0]=row[i];
str0[1]='\0';
strcpy(word,str0);
str0[0]='\0';
}//要先判斷單個字符的運算符,以避免諸如>=的運算符后面的=再次被判斷
if(row[i]==':')
{
i++;
if(row[i]=='=')
{
//word[0]=':';
//word[1]='=';
//word[2]='\0';
strcpy(word,">=");
}
else
{
error(2);//出錯后調(diào)用處理函數(shù)
i--;
}
}
if(row[i]=='>')
{
i++;
if(row[i]=='=')
{
strcpy(word,">=");
}
else
{
strcpy(word,">");
i--;
}
}
if(row[i]=='<')
{
i++;
if(row[i]=='=')
{
strcpy(word,"<=");
}
else
{strcpy(word,"<");i--;}
}
//puts(word);
check(word,op);/*
調(diào)用分類函數(shù),辨別每一個單詞的類別要求
輸入的每一個單詞必須符合詞法規(guī)則*/
//word[0]='\0';
i++;//使指針后移,取出下一個字母
}
}
void check(char *str,FILE *out)
{
if(isdigit(str[0]))/*如果第一個字符是數(shù)字那么整個單詞都是數(shù)字組成的,即為常數(shù)*/
{
write(str,'d',out);//調(diào)用寫函數(shù)將分好類的單詞寫入文件
}
if(isalpha(str[0]))/*如果第一個字符是字母,那么這個單詞是標(biāo)志符或關(guān)鍵字*/
{
int fyiyong=0;//用作標(biāo)記這個單詞是否已被分類
/*以下判別是否是關(guān)鍵字*/
for(int ct=0;ct<13;ct++)
{
if(!strcmp(str,kword[ct]))
{
write(str,ktype[ct],out);
fyiyong=1;
}
}
/*經(jīng)過以上判別,可以判別是否是關(guān)鍵字,不是即為標(biāo)志符*/
if(fyiyong!=1)
{
write(str,'e',out);
}
}
/*以下對運算符分類*/
if(str[0]=='>')
{
if(str[1]=='=')
{
write(str,'b',out);
}
else
{
write(str,'>',out);
}
}
if(str[0]=='<')
{
if(str[1]=='=')
{
write(str,'c',out);
}
else
{
write(str,'<',out);
}
}
if(!strcmp(str,":="))
{
write(str,'a',out);
}
if(str[0]=='+' || str[0]=='-' || str[0]=='*' || str[0]=='/' || str[0]=='(' || str[0]==')' || str[0]==',' || str[0]==';'|| str[0]=='.'|| str[0]=='#' || str[0]=='=' )
{
write(str,str[0],out);
}
}
void main()
{
count=1;
char scfilename[20],rsfilename[20];//定義用來存放輸入源文件和輸出目標(biāo)文件的名字
printf("Please input your source file name:");
gets(scfilename);
printf("Please input your result file name:");
gets(rsfilename);
FILE *fp,*op;
fp=fopen(scfilename,"r");
op=fopen(rsfilename,"w");
if(fp)//打開文件成功后調(diào)用函數(shù)對源文件進(jìn)行詞法分析
{
while(readbuffer(fp))
{
fenxi(buffer,op);
count++;//行加一
}
}
else//while the file not exist
{
printf("Your souce file not exist!!!\n");
exit(0);
}
fclose(fp);//close the files
fclose(op);
printf("ok!");//output the mark of end
getchar();
}
/*編寫PL/0語言的詞法分析程序
要求:
1、讀入用PL/0語言編寫的源程序,正確的進(jìn)行詞法分析,并輸出二元式序列。
2、若源程序有詞法錯誤,能夠給出出錯的準(zhǔn)確位置。
3、詞法代號如下
(+,+);
(-,-);
(*,*);
(/,/);
((,();
(),));
(,,,);
(;,;);
(.,.);
(#,#);
(=,=);
(>,>);
(<,<);
(:=,a);
(>=,b);
(<=,c);
(數(shù)字,d);
(標(biāo)識符,e);
關(guān)鍵字代號:
(begin,f);
(call,g);
(const,h);
(do,i);
(end,j);
(if,k);
(odd,l);
(procedure,m);
(read,n);
(then,o);
(var,p);
(while,q);
(write,r);
4、等于運算符號為一個 =
測試程序:
A.C
======================
CONST A=10;
VAR B,C;
PROCEDURE P;
VAR D;
PROCEDURE Q;
VAR X;
BEGIN
READ(X);
D:=X;
WHILE X<0
DO CALL P;
END;
BEGIN
WRITE(D);
CALL Q;
END;
BEGIN
CALL P;
END.
*/
/*program name:chifufenxi*/
/*作者:小萬 QQ:421404493*/
/*date:2004.10.11*/
#include
#include
#include
#include
#include
#define N 256//每一行的字符數(shù)不能超過256個
char buffer[N]; //用作存放一行字符
char word[20]; //用作存放經(jīng)過分析單詞
char *kword[13]={"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"};
char ktype[13]={'f','g','h','i','j','k','l','m','n','o','p','q','r'};
int len;//記錄每一行的長度
int count=0;//用來記錄行數(shù)
void write(char *wstr,char wc,FILE *wout)//將分析結(jié)果按照規(guī)則寫入到文件
{
fputc('(',wout);
fputs(wstr,wout);
fputc(',',wout);
fputc(wc,wout);
fputc(')',wout);
}
int readbuffer(FILE *fp)
{
char ch;
len=0;
ch=fgetc(fp);
while(!feof(fp) && ch!='\n')//讀取字符到緩沖區(qū)
{
buffer[len]=ch;
ch=fgetc(fp);
len++;
}
len--;//用來控制詞法分析時行分析中字母的個數(shù)
if(feof(fp))//標(biāo)志文件是否結(jié)束
return 0;
else
return 1;
}
void error(int type)
{
if(type==1)
printf("為無效字符,第%d行詞法出錯,標(biāo)志符不能以數(shù)字開頭\n",count);
else if(type==2)
printf("第%d行詞法出錯,賦值符應(yīng)為\:\= \n ",count);
else printf("為無效字符,第%d行詞法出錯\n",count);
}
void check(char *str,FILE *out);//聲明函數(shù),此函數(shù)用來分類單詞
void fenxi(char *row,FILE *op)//此函數(shù)用來對每一行的單詞進(jìn)行語法分析
{
//printf("%d\n",count);
int k=0;//用作控制臨時存放單詞的變量str0
int i=0;//定義兩個變量用作控制每一行是否結(jié)束,
int ferror=0;//用作出錯標(biāo)志
char str0[20];//臨時存放單詞的變量
while(i<=len)
{
k=0;//將k置0
strcpy(word,"\0");//將存放單詞的變量清空
/*去除空格*/
if(isspace(row[i]))//去出空格,跳格符,換行符
{
i++;
continue;
}
/*去出無效字符*/
while(!isalpha(row[i])&&!isdigit(row[i])&&i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
{
putchar(row[i]);
i++;
ferror=1;//設(shè)置錯誤標(biāo)志符
}
if(ferror==1)
{
error(3);//調(diào)用出錯處理函數(shù)
ferror=0;
}
/*對注釋進(jìn)行處理,假設(shè)此語言的注釋只能單行注釋以雙斜杠“//”為注釋開始標(biāo)志*/
if(row[i]=='/')
{
i++;
if(row[i]=='/')
{
i=len+1;//忽略注釋符后面的單詞
continue;
}
else
i--;
}
/*判斷是否為數(shù)字*/
if(isdigit(row[i]))
{
while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
//當(dāng)不到行尾,是數(shù)字或字母當(dāng)然有可能是無效字符
{
if(isdigit(row[i]))//是數(shù)字則將字符逐個存入臨時數(shù)組
{
str0[k]=row[i];
i++;
k++;
// putchar('e');
}
else //數(shù)字中加有字母或無效字符則報錯
{
// putchar('x');
ferror=1;break;//已經(jīng)出錯設(shè)置標(biāo)志并退出循環(huán)
}
}
if(ferror==1)//檢測是否出錯
{ /*將剛剛的那個單詞后面的數(shù)字和字母
清空,如123abc123或則123$$23等,當(dāng)出現(xiàn)錯誤后,需
要消除abc123和$$23 以免誤作為下一個標(biāo)志符*/
for(int j=0;j putchar(str0[j]);
while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
{
putchar(row[i]);
i++;
}
error(1);//putchar('e');//調(diào)用出錯處理函數(shù)
ferror=0;//重新設(shè)置錯誤標(biāo)志位
//i--;//strcpy(word,"");
}
else//未出錯照常處理
{
str0[k]='\0';
strcpy(word,str0);
i--;//減一是為了使最后取出的那個字符不在被下面的程序判斷
// str0[0]='\0';
}
}
/*判斷是否為標(biāo)志符和關(guān)鍵字即由字母開頭并且不含標(biāo)點符號用ispunct(int ch)判斷標(biāo)點符號*/
if(isalpha(row[i]))//標(biāo)志符或關(guān)鍵字由字母開頭
{
k=0;
while(i<=len&&row[i]!=32&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))//關(guān)鍵字和標(biāo)志符由數(shù)字和字母組成
{
if(isalpha(row[i])||isdigit(row[i]))//由數(shù)字和字母組成
{
str0[k]=row[i];
i++;
k++;
}
else//出錯,原因可能是出現(xiàn)了不可識別的字符
{
ferror=1;break;
}
}
if(ferror)
{
for(int j=0;j putchar(str0[j]);
while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
{
putchar(row[i]);//消除整個非法單詞
i++;
}
ferror=0;
error(3);
//i--;
}
else
{
str0[k]='\0';
strcpy(word,str0);
str0[0]='\0';
i--;
}
}
/*判斷運算符*/
if(row[i]=='+' ||row[i]=='-' ||row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'||row[i]=='.'||row[i]=='#' || row[i]=='=')
{
str0[0]=row[i];
str0[1]='\0';
strcpy(word,str0);
str0[0]='\0';
}//要先判斷單個字符的運算符,以避免諸如>=的運算符后面的=再次被判斷
if(row[i]==':')
{
i++;
if(row[i]=='=')
{
//word[0]=':';
//word[1]='=';
//word[2]='\0';
strcpy(word,">=");
}
else
{
error(2);//出錯后調(diào)用處理函數(shù)
i--;
}
}
if(row[i]=='>')
{
i++;
if(row[i]=='=')
{
strcpy(word,">=");
}
else
{
strcpy(word,">");
i--;
}
}
if(row[i]=='<')
{
i++;
if(row[i]=='=')
{
strcpy(word,"<=");
}
else
{strcpy(word,"<");i--;}
}
//puts(word);
check(word,op);/*
調(diào)用分類函數(shù),辨別每一個單詞的類別要求
輸入的每一個單詞必須符合詞法規(guī)則*/
//word[0]='\0';
i++;//使指針后移,取出下一個字母
}
}
void check(char *str,FILE *out)
{
if(isdigit(str[0]))/*如果第一個字符是數(shù)字那么整個單詞都是數(shù)字組成的,即為常數(shù)*/
{
write(str,'d',out);//調(diào)用寫函數(shù)將分好類的單詞寫入文件
}
if(isalpha(str[0]))/*如果第一個字符是字母,那么這個單詞是標(biāo)志符或關(guān)鍵字*/
{
int fyiyong=0;//用作標(biāo)記這個單詞是否已被分類
/*以下判別是否是關(guān)鍵字*/
for(int ct=0;ct<13;ct++)
{
if(!strcmp(str,kword[ct]))
{
write(str,ktype[ct],out);
fyiyong=1;
}
}
/*經(jīng)過以上判別,可以判別是否是關(guān)鍵字,不是即為標(biāo)志符*/
if(fyiyong!=1)
{
write(str,'e',out);
}
}
/*以下對運算符分類*/
if(str[0]=='>')
{
if(str[1]=='=')
{
write(str,'b',out);
}
else
{
write(str,'>',out);
}
}
if(str[0]=='<')
{
if(str[1]=='=')
{
write(str,'c',out);
}
else
{
write(str,'<',out);
}
}
if(!strcmp(str,":="))
{
write(str,'a',out);
}
if(str[0]=='+' || str[0]=='-' || str[0]=='*' || str[0]=='/' || str[0]=='(' || str[0]==')' || str[0]==',' || str[0]==';'|| str[0]=='.'|| str[0]=='#' || str[0]=='=' )
{
write(str,str[0],out);
}
}
void main()
{
count=1;
char scfilename[20],rsfilename[20];//定義用來存放輸入源文件和輸出目標(biāo)文件的名字
printf("Please input your source file name:");
gets(scfilename);
printf("Please input your result file name:");
gets(rsfilename);
FILE *fp,*op;
fp=fopen(scfilename,"r");
op=fopen(rsfilename,"w");
if(fp)//打開文件成功后調(diào)用函數(shù)對源文件進(jìn)行詞法分析
{
while(readbuffer(fp))
{
fenxi(buffer,op);
count++;//行加一
}
}
else//while the file not exist
{
printf("Your souce file not exist!!!\n");
exit(0);
}
fclose(fp);//close the files
fclose(op);
printf("ok!");//output the mark of end
getchar();
}