❶ c語言的詞法分析器
任務1:識別小型語言所有單詞的詞法分析程序設計
源程序設計語言
G[<程序>]
<程序>→<變數說明><BEGIN>
<語句表>
<END>.
<變數說明>→VAR<變數表>:<類型>;|<空>
<變數表>→<變數表>,<變數>|<變數>
<類型>→INTEGER
<語句表>→<語句>
|
<語句>;<語句表>
<語句>→<賦值語句>|<條件語句>|<WHILE語句>|<復合語句>
<賦值語句>→<變數>:=<算術表達式>
<條件語句>→IF<關系表達式>THEN<語句>ELSE<語句>
<WHILE語句>→WHILE<關系表達式>DO<語句>
<復合語句>→BEGIN<語句表>END
<算術表達式>→<項>|<算術表達式>+<項>|<算術表達式>-<項>
<項>→<因式>|<項>*<因式>|<項>/<因式>
<因式>→<變數>|<整數>|(<算術表達式>)
<關系表達式>→<算術表達式><關系符><算術表達式>
<變數>→<標識符>
<標識符>→<標識符><字母>|<標識符><數字>|<字母>
<整數>→0|<非零數字><泛整數>
<泛整數>→<數字>|<數字><泛整數>|ε
<關系符>→<|<=|==|>|>=|<>
<字母>
→A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
<非零數字>→1|2|3|4|5|6|7|8|9
<數字>→<非零數字>|0
<空>→
要求和提示:
詞法分析階段,可以打開任意位置和名稱的源文件進行詞法分析,可以進行非法字元和數字後邊跟字母的錯誤判斷,如果沒有錯誤則提示「詞法分析正確完成!」,並且可以選擇輸出token.txt(token文件)string.txt(符號表)兩個文件;
1.詞法分析程序的主要任務如下:
①
組織源程序的輸入,識別出源程序中的各個基本語法單位(也稱為單詞或語法符號),按規則轉換成二元式的形式;
②
刪除無用的空白字元、回車符、及其它非實質性符號;
③
刪除註解行;
④
為後面的語法和語義分析提供二元式鏈表;
單詞
編碼
單詞
編碼
標識符
1
<
15
正整數
2
<=
16
BEGIN
3
>
17
END
4
>=
18
IF
5
<>
19
THEN
6
==
20
ELSE
7
;
21
WHILE
8
.
22
DO
9
:=
23
INTEGER
10
,
24
+
11
(
25
-
12
)
26
*
13
/
14
1)
對標識符的長度控制在8個字元(包括8個)以內,超過的做截斷處理;
2)
數字不大於65535,否則報錯;
3)
能跳過源程序中的空白格:兩個單詞之間的任何空格,製表符,回車,換行都是白空格,除了用來分隔單詞以外,沒有意義;
4)
能跳過注釋:
a)
接連出現的/*到下一次接連出現的*/之間的任何文字都是注釋(多行);
b)
從某行接連出現的//到該行的結尾的任何文字都是注釋(單行)。
3.怎樣編寫詞法分析程序:
1)
預處理:把源文件一個字元一個字元的讀入詞法分析程序設置的輸入字元結構體數組中(輸入緩沖區),讀入過程要刪除注釋,刪除多餘的白空格;
2)
從源程序字元數組中獲得單詞,
編碼為二元式.:
二元式採用結構體數組存儲,
把單詞類型和詞元記錄下來。
分解單詞的方法:
1)
Case多路轉換語句根據單詞的特點直接編寫;
2)
通過描述單詞的正規文法得到相應的有窮自動機,通過case多路轉換語句完成有窮自動機的處理流程。
3.編寫詞法分析程序要注意的問題:
1)
檢查詞法是否有錯誤
檢查是否有非法字元:如
@,
&,
!
檢查標志符和數字是否滿足限制條件
檢查注釋符號是否配對
2)
符分隔單詞
能夠區分兩個單詞的符號為界符
有些界符不是單詞:如白空格
有些界符僅僅用來分隔:如;
有些界符本身還是源程序不可缺少的單詞,如(,
),
+,
/,
等等
有些界符包含兩個字元:如<>,
>=等等
3)
輸出詞法錯誤
如果有錯誤,需要報告詞法錯誤的原因。並且要能夠越過錯誤,分解下一個單詞,直到源程序結束。
4)
輸出的二元式流保存在二元式結構體數組中。
❷ 求c語言詞法分析程序
以前學c語言的時候寫的,但是沒有經過很好的設計,程序結構比較亂。運行沒有問題。也可以處理包含的頭文件。
/*************************************************
c語言分析程序
*************************************************/
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
char *key[]={"auto","bool","break","case","char","complex","const","continue","default","restrict","do","double","else","enum","extern","float","for","goto","if","imaginary","inline","int","long","register","return","stort","signed","sizeof","static","struct","switch","tyepdef","union","unsigned","void","volatile","while"};
char *limit[]={"#","(",")","[","]","'","\"",";",":","{","}","\\",","};
char *ysf[]={"!","%","^","&","*","-","+","=","~","|",".","<",">","/","?",":","+=","-=","*=","/","%=","<<=",">>=","&=","^=","|=","->","++","--","<<",">>","<=",">=","==","!=","&&","||"};
char b[30];
char fn[20]={'\0'},text1[1000]={'\0'},string[30]={'\0'},text2[1000]={'\0'},kuoru[30];
char hm[10][30],hz[10][30];
char * tempp;
int z=1,y;
int i=0,j=0,k=1,n=1,p=1,q=1,o=1,m=1,x=0,temp,k1=0,k2=0,keyy,key1=0,key2=0,key3=0,key4=0,key5=0,key6=0;
FILE * sfhead;
FILE * ofhead;
FILE * bsfhead;
FILE * zsclbhead;
FILE * fdsclbhead;
FILE * zfclbhead;
FILE * zfcclbhead;
FILE * fgfhead;
FILE * ysfhead;
FILE * blzhead;
FILE * krhead;
bool find1(char * p){
int i=0;
for(i=0;i<36;i++){
if(strcmp(key[i],p)==0)
return true;
}
return false;
} /*判斷提取的字元串是否屬於保留字*/
int bianma1(char * p){
int i=0;
for(i=0;i<36;i++){
if(strcmp(key[i],p)==0)
return i+1;
}
return -1; /*確定保留字的序號*/
}
bool find2(char p){
int i=0;
for(i=0;i<13;i++){
if(*limit[i]==p)
return true;
}
return false;
} /*判斷提取的符號是否為分隔符*/
int bianma2(char p){
int i=0;
for(i=0;i<13;i++){
if(*limit[i]==p)
return i+1;
}
return -1;
} /*確定分割符的序號*/
bool find3(char p){
int i=0;
for(i=0;i<37;i++){
if(*ysf[i]==p)
return true;
}
return false;
} /*判斷提取的符號是否為運算符*/
int bianma3(char * p){
int i=0;
for(i=0;i<37;i++){
if(strcmp(ysf[i],p)==0)
return i+1;
}
return -1;
} /*確定運算符的序號*/
int bianma4(char * p){
int i=0;
for(i=0;i<10;i++){
if(strcmp(hm[i],p)==0)
return i;
}
return -1;
}
bool search(FILE * fp,char * p){
char a[30],c[30];
rewind(fp); /*將fp指向文件頭部*/
while(!feof(fp)){
fscanf(fp,"%s",a);
if(strcmp(a,p)==0){ /*保存編碼*/
fgets(b,30,fp);
return true;
}else
fgets(c,30,fp);
}
return false;
}
void clnmb(char * text){ /*處理以數字開頭的函數*/
bool l=true;
string[j]=text[i];
i++;j++;
while(((text[i]>='0')&&(text[i]<='9'))||text[i]=='.'||text[i]=='e'||text[i]=='E'||text[i]=='-'){
string[j]=text[i];
if(text[i]=='.')
l=false;
i++;j++; /*判斷數字字元串中有無小數點,如果有則證明位浮點數*/
}
if(l){
if(search(zsclbhead,string)){ /*返回原表查詢,防止重復出現*/
fprintf(zsclbhead,"\n\r%s\t",string);
fprintf(zsclbhead,"%s",b);
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}else{
fprintf(zsclbhead,"\n\r%s\t",string);
fprintf(zsclbhead,"4\t");
fprintf(zsclbhead,"0\t");
fprintf(zsclbhead,"%d\t\n\r",m);
fprintf(ofhead,"\n\r%s\t",string);
fprintf(ofhead,"4\t");
fprintf(ofhead,"0\t");
fprintf(ofhead,"%d\t\n\r",m);
m++; /*用m標記出現整數常量的地址*/
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}
}else{
if(search(fdsclbhead,string)){ /*返回原表查詢,防止重復出現*/
fprintf(fdsclbhead,"\n\r%s\t",string);
fprintf(fdsclbhead,"%s",b);
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}else{
fprintf(fdsclbhead,"\n\r%s\t",string);
fprintf(fdsclbhead,"4\t");
fprintf(fdsclbhead,"1\t");
fprintf(fdsclbhead,"%d\t\n\r",o);
fprintf(ofhead,"\n\r%s\t",string);
fprintf(ofhead,"4\t");
fprintf(ofhead,"1\t");
fprintf(ofhead,"%d\t\n\r",o); /*用o標記出現的浮點數常量地址*/
o++;
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}
l=true;
}
}
void dayin(FILE * fp){
int i;
char temp[40];
rewind(fp);
while(!feof(fp)){
fgets(temp,40,fp);
printf("%s",temp);
}
for(i=0;i<40;i++)
temp[i]='\0';
}
/****************************************
掃描分析程序段
*****************************************/
void saomiao(char * text){
i=0;
while(text[i]!='\0'){
if((text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z')){ /*分析以字母開頭的情況*/
while((text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z')||text[i]=='_'||(text[i]>='0'&&text[i]<='9')){
string[j]=text[i];
i++;j++;
}
if(find1(string)){ /*判斷是否為保留字*/
fprintf(blzhead,"\n\r%s\t",string);
fprintf(blzhead,"0\t");
fprintf(blzhead,"%d\t\n\r",bianma1(string));
fprintf(ofhead,"\n\r%s\t",string);
fprintf(ofhead,"0\t");
fprintf(ofhead,"%d\t\n\r",bianma1(string)); /*將字元串直接寫入相應的文件和輸出文件*/
for(j=0;j<30;j++) /*將string數組清空,防止出現錯誤*/
string[j]='\0';
j=0;
}
else {
if((keyy=bianma4(string))!=-1){
temp=i;
tempp=text;
i=0;
for(j=0;j<30;j++) /*將string數組清空,防止出現錯誤*/
string[j]='\0';
j=0;
clnmb(hz[keyy]);
text=tempp;
i=temp;
}else
if(search(bsfhead,string)){ /*返回原表查詢,防止重復出現*/
fprintf(bsfhead,"\n\r%s\t",string);
fprintf(bsfhead,"%s",b);
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}else{
fprintf(bsfhead,"\n\r%s\t",string);
fprintf(bsfhead,"3\t");
fprintf(bsfhead,"%d\t\n\r",k);
fprintf(ofhead,"\n\r%s\t",string);
fprintf(ofhead,"3\t");
fprintf(ofhead,"%d\t\n\r",k);
k++; /*用k標記出現標識符的地址*/
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}
}
}
else if((text[i]>='0')&&(text[i]<='9')) /*分析以數字開頭的情況*/
clnmb(text);
else if(find2(text[i])){ /*分析以分隔符開頭的情況*/
if(text[i]=='{') key1++;
if(text[i]=='}') key2++;
if(text[i]=='[') key3++;
if(text[i]==']') key4++;
if(text[i]=='(') key5++;
if(text[i]==')') key6++;
string[0]=text[i];
if(text[i]=='\"'){ /*考慮其中可能出現的一"開頭的字元串類型常量*/
do{
string[j]=text[i];
j++;i++;
}while(text[i]!='\"');
string[j]=text[i];
i++;j++;
if(search(zfcclbhead,string)){ /*返回原表查詢,防止重復出現*/
fprintf(zfcclbhead,"\n\r%s\t",string);
fprintf(zfcclbhead,"%s",b);
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}else{
fprintf(zfcclbhead,"\n\r%s\t",string);
fprintf(zfcclbhead,"4\t");
fprintf(zfcclbhead,"3\t");
fprintf(zfcclbhead,"%d\t\n\r",q); /*用q標記出現字元串常量的地址*/
fprintf(ofhead,"\n\r%s\t",string);
fprintf(ofhead,"4\t");
fprintf(ofhead,"3\t");
fprintf(ofhead,"%d\t\n\r",q);
q++;
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}
}
if(text[i]=='\''){ /*考慮可能出現的一'開頭的字元類型常量*/
string[0]=text[i];
while(text[i]!='\''){
string[j]=text[i];
i++;j++;
}
string[j]=text[i];
if(search(zfclbhead,string)){ /*返回原表查詢,防止重復出現*/
fprintf(zfclbhead,"\n\r%c\t",text[i]);
fprintf(zfclbhead,"%s",b);
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}
else{
fprintf(zfclbhead,"\n\r%c\t",text[i]);
fprintf(zfclbhead,"4\t");
fprintf(zfclbhead,"4\t");
fprintf(zfclbhead,"%d\t\n\r",p);
fprintf(ofhead,"\n\r%c\t",text[i]);
fprintf(ofhead,"4\t");
fprintf(ofhead,"4\t");
fprintf(ofhead,"%d\t\n\r",p);
p++;
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}
}
if(text[i]=='#'){
i++;
while((text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z')){
string[j]=text[i];
j++;i++;
}
if(strcmp(string,"include")==0){ /*括入文件處理程序段*/
if(text[i]=='\"'||text[i]=='<')i++;
while((text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z'||text[i]=='.')){
kuoru[x]=text[i];
i++;x++;
}
if((krhead=fopen(kuoru,"r"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
while(!(feof(krhead)))
text2[y++]=fgetc(krhead);
text2[y]='\0';
y=0;
temp=i;
for(j=0;j<30;j++)
string[j]='\0';
j=0;
saomiao(text2);
i=temp;
for(x=0;x<30;x++)
kuoru[x]='\0';
x=0;
i++;
}
if(strcmp(string,"define")==0){
for(j=0;j<30;j++)
string[j]='\0';
j=0;
while(!(text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z'))i++;
while((text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z')||text[i]=='_'||(text[i]>='0'&&text[i]<='9')){
hm[k1][k2]=text[i];
i++;k2++;
}
k2=0;
while(!(text[i]>='0')&&(text[i]<='9'))i++;
while((text[i]>='0')&&(text[i]<='9')||text[i]=='.'||text[i]=='e'||text[i]=='E'||text[i]=='-'){
hz[k1][k2]=text[i];
i++;k2++;
}
k1++;
k2=0;
}
}else{
if(search(fgfhead,string));
else{
fprintf(fgfhead,"\n\r%c\t",text[i]);
fprintf(fgfhead,"1\t");
fprintf(fgfhead,"%d\t\n\r",bianma2(text[i]));
}
fprintf(ofhead,"\n\r%c\t",text[i]);
fprintf(ofhead,"1\t");
fprintf(ofhead,"%d\t\n\r",bianma2(text[i]));
i++;
}
}else if(find3(text[i])){ /*分析一運算符開頭的情況*/
while(find3(text[i])){
string[j]=text[i];
i++;j++; /*考慮到有多個字元組成的運算符,運算符的判斷使用字元串*/
}
if(strcmp(string,"/*")==0){
while(!(text[i-1]=='*'&&text[i]=='/'))i++; /*去掉注釋*/
if(text[i]=='/')i++;
}
if(strcmp(string,"//")==0)
while(!(text[i]=='\n'))
i++; /*去掉注釋*/
if((bianma3(string)==-1)&&text[i-1]=='-'){
i=i-1;
for(j=0;j<30;j++)
string[j]='\0';
j=0;
clnmb(text); /*處理負數的情況*/
}
if(search(ysfhead,string));
else{
if(bianma3(string)!=-1){
fprintf(ysfhead,"\n\r%s\t",string);
fprintf(ysfhead,"2\t");
fprintf(ysfhead,"%d\t\n\r",bianma3(string));
}
}
if(bianma3(string)!=-1){
fprintf(ofhead,"\n\r%s\t",string);
fprintf(ofhead,"2\t");
fprintf(ofhead,"%d\t\n\r",bianma3(string));
}
for(j=0;j<30;j++)
string[j]='\0';
j=0;
}else i++;
}
}
int main(){
printf("********************\nc語言分析程序\n********************\n");
printf("\n請輸入文件名:");
scanf("%s",fn);
if((sfhead=fopen(fn,"r"))==NULL){
printf("不能打開源文件!\n");
exit(0);
}
if((ofhead=fopen("分解源文件所得文件.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((bsfhead=fopen("標識符表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((zsclbhead=fopen("整數常量表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((fdsclbhead=fopen("浮點數常量表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((zfclbhead=fopen("字元常量表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((zfcclbhead=fopen("字元串常量表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((fgfhead=fopen("分隔符表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((ysfhead=fopen("運算符表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
if((blzhead=fopen("保留字表.txt","wb+"))==NULL){
printf("不能建立目標文件!");
exit(0);
}
fprintf(ofhead,"單詞\t");
fprintf(ofhead,"類\t");
fprintf(ofhead,"編號\t地址\t\n\r");
fprintf(bsfhead,"單詞\t");
fprintf(bsfhead,"類\t");
fprintf(bsfhead,"編號\t地址\t\n\r");
fprintf(zsclbhead,"單詞\t");
fprintf(zsclbhead,"類\t");
fprintf(zsclbhead,"編號\t地址\t\n\r");
fprintf(zfclbhead,"單詞\t");
fprintf(zfclbhead,"類\t");
fprintf(zfclbhead,"編號\t地址\t\n\r");
fprintf(zfcclbhead,"單詞\t");
fprintf(zfcclbhead,"類\t");
fprintf(zfcclbhead,"編號\t地址\t\n\r");
fprintf(fdsclbhead,"單詞\t");
fprintf(fdsclbhead,"類\t");
fprintf(fdsclbhead,"編號\t地址\t\n\r");
fprintf(fgfhead,"單詞\t");
fprintf(fgfhead,"類\t");
fprintf(fgfhead,"編號\t地址\t\n\r");
fprintf(ysfhead,"單詞\t");
fprintf(ysfhead,"類\t");
fprintf(ysfhead,"編號\t地址\t\n\r");
fprintf(blzhead,"單詞\t");
fprintf(blzhead,"類\t");
fprintf(blzhead,"編號\t地址\t\n\r"); /*初始化所需要的文件*/
while(!feof(sfhead)) /*將原程序讀入字元數組便於後面分析*/
text1[i++]=fgetc(sfhead);
text1[i++]='\0';
i=0;
saomiao(text1);
if(key1!=key2)
printf("ERROR:前後大括弧個數不相等。\n");
if(key3!=key4)
printf("ERROR:前後中括弧個數不相等。\n");
if(key5!=key6)
printf("ERROR:前後小括弧個數不相等。\n");
while(z!=0){
printf("列印:\n1分析源文件所得文件\n2保留字表\n3分隔符表\n4運算符表\n5標識符表\n6整數類型常量表\n7浮點數類型常量表\n8字元類型常量表\n9字元串類型常量表\n\n0退出程序");
printf("\n\n請輸入:");
scanf("%d",&z);
switch(z){
case 1 :{printf("**********分析源文件所得文件**********\n");dayin(ofhead);break;}
case 2 :{printf("***************保留字表***************\n");dayin(blzhead);break;}
case 3 :{printf("***************分隔符表***************\n");dayin(fgfhead);break;}
case 4 :{printf("***************運算符表***************\n");dayin(ysfhead);break;}
case 5 :{printf("***************標識符表***************\n");dayin(bsfhead);break;}
case 6 :{printf("************整數類型常量表************\n");dayin(zsclbhead);break;}
case 7 :{printf("***********浮點數類型常量表***********\n");dayin(fdsclbhead);break;}
case 8 :{printf("************字元類型常量表************\n");dayin(zfclbhead);break;}
case 9 :{printf("***********字元串類型常量表***********\n");dayin(zfcclbhead);break;}
case 10 :exit(0);
}
}
fclose(ofhead);
fclose(sfhead);
fclose(bsfhead);
fclose(fgfhead);
fclose(ysfhead);
fclose(blzhead);
fclose(fdsclbhead);
fclose(zfclbhead);
fclose(zfcclbhead);
fclose(zsclbhead);
}
❸ 編譯原理課程設計-詞法分析器設計(C語言)
#include"stdio.h"/*定義I/O庫所用的某些宏和變數*/
#include"string.h"/*定義字元串庫函數*/
#include"conio.h"/*提供有關屏幕窗口操作函數*/
#include"ctype.h"/*分類函數*/
charprog[80]={'