C/C++實(shí)現(xiàn)詞法分析程序的示例代碼
一、實(shí)驗(yàn)內(nèi)容
通過(guò)完成詞法分析程序,了解詞法分析的過(guò)程。編制一個(gè)讀單詞程序,對(duì)PL/0語(yǔ)言進(jìn)行詞法分析,把輸入的字符串形式的源程序分割成一個(gè)個(gè)單詞符號(hào),即基本保留字、標(biāo)識(shí)符、常數(shù)、運(yùn)算符、分界符五大類(lèi)。
對(duì)PL/0語(yǔ)言進(jìn)行詞法分析,把輸入的字符串形式的源程序分割成一個(gè)個(gè)單詞符號(hào),其詞法描述如下:
(1)關(guān)鍵字:
begin,call,const,do,end,if,odd,procedure,read,then,var,while,write
(2) 標(biāo)識(shí)符:用來(lái)表示各種名字,必須以字母開(kāi)頭小于10位字符組成
(3) 數(shù)字:以0-9組成小于14位的數(shù)字
(4) 運(yùn)算符:+,-,*,/,:=,<,<=,>,>=,#
(5) 分界符:, ,. ,; ,( ,)
二、實(shí)驗(yàn)代碼
#include<iostream> #include<stdio.h> #include<string.h> #include<iomanip> using namespace std; //創(chuàng)建四個(gè)表,儲(chǔ)存符號(hào) const char *k[13]={"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"};//關(guān)鍵字表 const char *s1[5]={",",".",";","(",")"};//界符表 const char *s2[6]={"+","-","*","/","++","--",};//運(yùn)算符號(hào)表 const char *s3[9]={"<=",">",">=","=",">",">=","<>",":=","#"}; //關(guān)系運(yùn)算符號(hào)表 //定義全局變量 int row=1,line=1; int t,p=0;//單詞類(lèi)別碼以及記錄移動(dòng)指針 char instring[100];//保存輸入的程序代碼緩存數(shù)組 char outtoken[10];//輸出 char ci[8],id[10];//暫時(shí)保存數(shù)字和字符 //函數(shù)的聲明 void analysis();//分析函數(shù),決定調(diào)用哪個(gè)函數(shù)進(jìn)行分析 void symbol();//分析以非字母數(shù)字開(kāi)頭的字符 void constant();//分析常數(shù) void alphabet();//分析標(biāo)識(shí)符和關(guān)鍵字 void show();//打印輸出函數(shù) bool isnumber(char x);//判斷是否是數(shù)字 bool isalpha(char x);//判斷是否是字母 int main(){ cout<<"請(qǐng)輸入一段程序代碼并以@結(jié)束:"<<endl; //輸出程序代碼 do{ instring[p++]=getchar(); } while(instring[p-1]!='@'); getchar();//吸收回車(chē)鍵 instring[p-1]='\0';//抵消掉@ p=0;//移動(dòng)指針歸零 cout<<left; cout<<"------------------------------------------------------------------------------"<<endl; cout<<setw(6)<<"單詞"<<" "<<setw(6)<<"二元序列"<<" "<<setw(6)<<"類(lèi)型"<<" "<<endl; //掃描輸入的字符 while(p<strlen(instring)){ analysis(); show(); } cout<<"------------------------------------------------------------------------------"<<endl; cout<<"[注]:"<<endl; cout<<"t=1:關(guān)鍵字,"<<"t=2:分界符,"<<"t=3:算術(shù)運(yùn)算符,"<<"t=4:關(guān)系運(yùn)算符,"<<"t=5:常數(shù),"<<"t=6:標(biāo)識(shí)符,"<<"t==7:詞法出錯(cuò)"<<endl; cout<<"@為結(jié)束符,不參與到詞法分析中"<<endl; cout<<endl; return 0; } //判斷是否是數(shù)字 bool isnumber(char x){ return x>='0'&&x<='9'; } //判斷是否是字母 bool isalpha(char x){ return (x>='a'&&x<='z'||x>='A'&&x<='Z'); } //分析函數(shù),決定調(diào)用哪個(gè)函數(shù)進(jìn)行分析 void analysis(){ strcpy(outtoken,"");//清空outtoken數(shù)組 while(instring[p]==' '||instring[p]=='\n'){ if(instring[p]=='\n'){ row++; line=1; } p++; } //執(zhí)行完之后指向第一個(gè)不為空格的字符 char ch=instring[p]; //按照字符的類(lèi)別調(diào)用不同的分析處理函數(shù) if(isalpha(ch)) alphabet(); else if(isnumber(ch)) constant(); else symbol(); } //常數(shù)處理函數(shù) void constant(){ strcpy(ci,"");//清空ci t=5;//類(lèi)別碼 int i=0; while(isnumber(instring[p])){ ci[i++]=instring[p++]; } while(isalpha(instring[p])||isnumber(instring[p])){ ci[i++]=instring[p++]; t=7;//出錯(cuò) } ci[i]='\0';//結(jié)束符 //strcpy_s(outtoken,strlen(ci)+1,ci); strcpy(outtoken,ci); line++; return; } //標(biāo)識(shí)符和關(guān)鍵字的分析函數(shù) void alphabet(){ strcpy(id,"");//清空id int i=0; //讀取連續(xù)的字母數(shù)字序列 while(isalpha(instring[p])||isnumber(instring[p])){ id[i++]=instring[p++];//p指向連續(xù)序列之后的第一個(gè)字符 } id[i]='\0'; //查關(guān)鍵字表 for(i=0;i<8;i++){ if(strcmp(id,k[i])==0){ t=1;//表示關(guān)鍵字 line++; strcpy(outtoken,id); return; //是關(guān)鍵字的話,直接退出 } } //查看是否是標(biāo)識(shí)符 for(i=0;i<strlen(id);i++){ if(!(isalpha(id[i])||isnumber(id[i]))){ t=7; strcpy(outtoken,id); line++; return; } } line++; t=6;//不是關(guān)鍵字且沒(méi)有出錯(cuò)即為標(biāo)識(shí)符 strcpy(outtoken,id); } //其它運(yùn)算符的分析函數(shù) void symbol(){ char ch=instring[p++]; char ch2=instring[p]; t=7; switch(ch){ case '+': if(ch2=='+') t=3; break; case '-': if(ch2=='-') t=3; break; case '>': if(ch2=='=') t=4; break; case '<': if(ch2=='='||ch2=='>') t=4; break; case ':': if(ch2=='=') t=3; break; } //判斷是否具有兩個(gè)符號(hào)的運(yùn)算符 if(ch=='>'&&ch2=='='||ch=='<'&&ch2=='='||ch=='<'&&ch2=='>'||ch=='+'&&ch2=='+'||ch=='-'&&ch2=='-'||ch==':'&&ch2=='='){ p++; outtoken[0]=ch; outtoken[1]=ch2; outtoken[2]='\0'; line++; return; } else{ char chq[2]; chq[0]=ch; chq[1]='\0'; //分界符比較 for(int i=0;i<6;i++){ if(strcmp(chq,s1[i])==0){ t=2; break; } } //算術(shù)運(yùn)算符比較 for(int i=0;i<6;i++){ if(strcmp(chq,s2[i])==0){ t=3; break; } } //關(guān)系運(yùn)算符比較 for(int i=0;i<9;i++){ if(strcmp(chq,s3[i])==0){ t=4; break; } } } line++; outtoken[0]=ch; outtoken[1]='\0'; return; } //輸出函數(shù),根據(jù)以上分析函數(shù)進(jìn)行打印輸出分析的結(jié)果 void show(){ cout<<left; //setw(6)表示占位寬度為6個(gè)字符 if(t==7){ cout<<setw(6)<<outtoken<<" "<<setw(6)<<"ERROR!"<<setw(11)<<" "<<setw(10)<<"ERROR!"; }else{ cout<<left; cout<<setw(6)<<outtoken<<" "<<"<"<<t<<","<<outtoken; cout<<setw(6-strlen(outtoken))<<">"<<" "; switch(t){ case 1:cout<<left<<setw(10)<<"關(guān)鍵字";break; case 2:cout<<left<<setw(10)<<"分界符";break; case 3:cout<<left<<setw(10)<<"算術(shù)運(yùn)算符";break; case 4:cout<<left<<setw(10)<<"關(guān)系運(yùn)算符";break; case 5:cout<<left<<setw(10)<<"常數(shù)";break; case 6:cout<<left<<setw(10)<<"標(biāo)識(shí)符";break; } } cout<<endl; } /*變量說(shuō)明: k數(shù)組:關(guān)鍵字表; s數(shù)組:分界符表,其中分界符,算術(shù)運(yùn)算符,關(guān)系運(yùn)算符分別存放在s1,s2,s3數(shù)組中 id:標(biāo)識(shí)符; ci:常數(shù) ;row:行 line:列,單詞的位置 instring數(shù)組:為輸入源程序代碼的單詞緩存; outtoken數(shù)組:記錄為輸出內(nèi)部表示緩存 symbol:分析//后的注釋;constant:常數(shù)分析;alphabet:標(biāo)識(shí)符和關(guān)鍵字分析 analysis:分析函數(shù),根據(jù)輸入字符判斷調(diào)用哪一個(gè)函數(shù) ;show:輸出打印函數(shù) t:單詞的種類(lèi) t=1:關(guān)鍵字 t=2:分界符 t=3:算術(shù)運(yùn)算符 t=4:關(guān)系運(yùn)算符 t=5:常數(shù) t=6:標(biāo)識(shí)符 t=7:出錯(cuò)*/
三、實(shí)驗(yàn)結(jié)果
測(cè)試一
測(cè)試二
四、實(shí)驗(yàn)總結(jié)
整體的代碼思路是創(chuàng)建四個(gè)數(shù)組分別存放關(guān)鍵字表、界符表、運(yùn)算符號(hào)表、關(guān)系運(yùn)算符號(hào)表,這樣若想新增符號(hào)只需要在數(shù)組中修改即可,實(shí)現(xiàn)動(dòng)態(tài)變化而非寫(xiě)死的。
下面進(jìn)行模塊化設(shè)計(jì),總共分為analysis()、symbol()、constant()、alphabet()、show()、isnumber()、isalpha()七個(gè)函數(shù),analysis函數(shù)作為總的分析函數(shù),通過(guò)分析當(dāng)前字符是否是字母還是數(shù)字或者其它符號(hào),分別調(diào)用不同的函數(shù)進(jìn)行具體的分析,然后將結(jié)果存儲(chǔ)在全局變量outtoken和t中,前者代表輸出的二元組,后者代表該單詞的類(lèi)型,難點(diǎn)在于兩個(gè)符號(hào)的運(yùn)算符的判斷。
本題還有一個(gè)細(xì)節(jié)之處,在輸入完代碼后敲的那個(gè)回車(chē)鍵會(huì)多余需要使用一個(gè)getchar()函數(shù)來(lái)吸收掉,并且結(jié)束符@為自定義的,不參與到詞法分析中,所以在輸入完程序代碼后使用instring[p-1]='\0';//抵消掉@,這樣就使得instring數(shù)組里存放的是完整的有效的程序代碼,不含結(jié)束符。
到此這篇關(guān)于C/C++實(shí)現(xiàn)詞法分析程序的示例代碼的文章就介紹到這了,更多相關(guān)C++詞法分析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++?Queue隊(duì)列類(lèi)模版實(shí)例詳解
這篇文章主要為大家詳細(xì)介紹C++?Queue隊(duì)列類(lèi)模版實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02C++內(nèi)存池的簡(jiǎn)單實(shí)現(xiàn)
內(nèi)存池是一種動(dòng)態(tài)內(nèi)存分配與管理技術(shù)。本文主要介紹了C++內(nèi)存池的簡(jiǎn)單實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07VSCode 配置C++開(kāi)發(fā)環(huán)境的方法步驟
這篇文章主要介紹了VSCode 配置C++開(kāi)發(fā)環(huán)境的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03基于C語(yǔ)言實(shí)現(xiàn)點(diǎn)餐系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了基于C語(yǔ)言實(shí)現(xiàn)點(diǎn)餐系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11對(duì)C語(yǔ)言編程標(biāo)準(zhǔn)以及聲明的基本理解
這篇文章主要介紹了對(duì)C語(yǔ)言編程標(biāo)準(zhǔn)以及聲明的基本理解,有助于對(duì)C語(yǔ)言編寫(xiě)時(shí)的結(jié)構(gòu)有更加清晰的認(rèn)識(shí),需要的朋友可以參考下2015-11-11C++如何計(jì)算二進(jìn)制數(shù)中1的個(gè)數(shù)
這篇文章主要介紹了C++如何計(jì)算二進(jìn)制數(shù)中1的個(gè)數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07