C語(yǔ)言實(shí)現(xiàn)詞法分析器
問題描述:
用C或C++語(yǔ)言編寫一個(gè)簡(jiǎn)單的詞法分析程序,掃描C語(yǔ)言小子集的源程序,根據(jù)給定的詞法規(guī)則,識(shí)別單詞,填寫相應(yīng)的表。如果產(chǎn)生詞法錯(cuò)誤,則顯示錯(cuò)誤信息、位置,并試圖從錯(cuò)誤中恢復(fù)。簡(jiǎn)單的恢復(fù)方法是忽略該字符(或單詞)重新開始掃描。
相關(guān)詞法規(guī)則
<標(biāo)識(shí)符>::=<字母>
<標(biāo)識(shí)符>::=<標(biāo)識(shí)符><字母>
<標(biāo)識(shí)符>::=<標(biāo)識(shí)符><數(shù)字>
<常量>::=<無符號(hào)整數(shù)>
<無符號(hào)整數(shù)>::=<數(shù)字序列>
<數(shù)字序列>::=<數(shù)字序列><數(shù)字>
<數(shù)字序列>::=<數(shù)字>
<字母>::=a|b|c|……|x|y|z
<數(shù)字>::=0|1|2|3|4|5|6|7|8|9
<加法運(yùn)算符>::=+|-
<乘法運(yùn)算符>::=*|/
<關(guān)系運(yùn)算符>::=<|>|!=|>=|<=|==
<分界符>::=,|;|(|)|{|}
<保留字>::=main|int|if|else|while|do
編寫詞法分析程序的步驟:
(1)確定所要翻譯的語(yǔ)言(或其子集)。
C語(yǔ)言
(2)設(shè)計(jì)屬性字,及各類表格,如標(biāo)識(shí)符表、常量表、符號(hào)及其機(jī)內(nèi)表示對(duì)照表等。
與詞法分析有關(guān)的表格:
1. 字符表
保留字:main,int,if,else,while,do
字母(全小寫):a|b|c|……|x|y|z
數(shù)字:0,1,2,3,4,5,6,7,8,9
運(yùn)算符和界符:<,>,!=,>=,<=,==,,,;,(,),{,}
2. 特定單詞機(jī)內(nèi)表示表
3.畫出總控流程圖及各個(gè)子程序的流程圖。
4. 程序
輸入:一個(gè)存放C語(yǔ)言程序的s.txt文件
輸出:存放以(單詞,種別碼)形式輸出的result.txt文件
需要6個(gè)數(shù)組:
1. 存儲(chǔ)關(guān)鍵字 key[6]
2. 存儲(chǔ)對(duì)應(yīng)下標(biāo)關(guān)鍵字的種別碼 keyNum[6]
3. 存儲(chǔ)運(yùn)算符和界符 symbol[17]
4. 存儲(chǔ)運(yùn)算符對(duì)應(yīng)下標(biāo)的種別碼 symbolNum[17]
5. 存儲(chǔ)從文件中取出的每個(gè)字符(不包括括號(hào))letter[1000]
主要函數(shù):
TakeWord();
功能:將文件letter[]中每個(gè)字符進(jìn)行提取,找出關(guān)鍵字,輸出種別碼
Num作為全局變量保存提取到字符的哪個(gè)下標(biāo)
1. 先提取一個(gè)字符,如果是字母,進(jìn)入case1,調(diào)用identifier(),不斷的提取字母或數(shù)字進(jìn)行連接,沒連接一個(gè)字符用int isKeyWord()程序(返回關(guān)鍵字種別碼)判斷是否為關(guān)鍵字,是就退出函數(shù)返回string,不是就繼續(xù)執(zhí)行函數(shù),直到連接的字符不再是字母或數(shù)字,即此時(shí)字符串為標(biāo)識(shí)符
2. 如果是數(shù)字,進(jìn)入case 2,調(diào)用Number()函數(shù),不斷進(jìn)行字符串連接,知道下一個(gè)連接字符不再是數(shù)字
3. 如果是符號(hào),進(jìn)入case 3,調(diào)用symbolStr()函數(shù),如果是=,>,<,!,則要繼續(xù)進(jìn)行下個(gè)字符判斷,其余符號(hào)可以直接返回
其他輔助函數(shù):
int isSymbol()判斷運(yùn)算符和界符,并返回種別碼
bool isNum() 判斷是否為數(shù)字
bool isLetter()判斷是否為字母
int isKeyWord()判斷是否為關(guān)鍵字,是返回種別碼
int typeword()返回單個(gè)字符的類型
string identifier()標(biāo)識(shí)符的連接
string symbolStr()符號(hào)和界符的連接
string Number()數(shù)字的連接
void print()輸出
程序:
#include <iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> using namespace std; //關(guān)鍵字 string key[6]={"main","int","if","else","while","do"}; //關(guān)鍵字的種別碼 int keyNum[6]={1,2,3,4,5,6}; //運(yùn)算符和界符 string symbol[17]={"<",">","!=",">=","<=","==",",",";","(",")","{","}","+","-","*","/","="}; //char symbol[12]={'<','>','!=','>=','<=','==',',',';','(',')','{','}'}; //運(yùn)算符和界符的種別碼 int symbolNum[17]={7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}; //存放文件取出的字符 string letter[1000]; //將字符轉(zhuǎn)換為單詞 string words[1000]; int length; //保存程序中字符的數(shù)目 int num; int isSymbol(string s){ //判斷運(yùn)算符和界符 int i; for(i=0;i<17;i++){ if(s==symbol[i]) return symbolNum[i]; } return 0; } //判斷是否為數(shù)字 bool isNum(string s){ if(s>="0" && s<="9") return true; return false; } //判斷是否為字母 bool isLetter(string s) { if(s>="a" && s<="z") return true; return false; } //判斷是否為關(guān)鍵字,是返回種別碼 int isKeyWord(string s){ int i; for(i=0;i<6;i++){ if(s==key[i]) return keyNum[i]; } return 0; } //返回單個(gè)字符的類型 int typeword(string str){ if(str>="a" && str<="z") // 字母 return 1; if(str>="0" && str<="9") //數(shù)字 return 2; if(str==">"||str=="="||str=="<"||str=="!"||str==","||str==";"||str=="("||str==")"||str=="{"||str=="}" ||str=="+"||str=="-"||str=="*"||str=="/") //判斷運(yùn)算符和界符 return 3; } string identifier(string s,int n){ int j=n+1; int flag=1; while(flag){ if(isNum(letter[j]) || isLetter(letter[j])){ s=(s+letter[j]).c_str(); if(isKeyWord(s)){ j++; num=j; return s; } j++; } else{ flag=0; } } num=j; return s; } string symbolStr(string s,int n){ int j=n+1; string str=letter[j]; if(str==">"||str=="="||str=="<"||str=="!") { s=(s+letter[j]).c_str(); j++; } num=j; return s; } string Number(string s,int n){ int j=n+1; int flag=1; while(flag){ if(isNum(letter[j])){ s=(s+letter[j]).c_str(); j++; } else{ flag=0; } } num=j; return s; } void print(string s,int n){ cout<<"("<<s<<","<<n<<")"<<endl; } void TakeWord(){ //取單詞 int k; for(num=0;num<length;){ string str1,str; str=letter[num]; k=typeword(str); switch(k){ case 1: { str1=identifier(str,num); if(isKeyWord(str1)) print(str1,isKeyWord(str1)); else print(str1,0); break; } case 2: { str1=Number(str,num); print(str1,24); break; } case 3: { str1=symbolStr(str,num); print(str1,isSymbol(str1)); break; } } } } int main(){ char w; int i,j; freopen("s.txt","r",stdin); freopen("result.txt","w",stdout); //從控制臺(tái)輸出,而不是文本輸出 length=0; while(cin>>w){ if(w!=' '){ letter[length]=w; length++; } //去掉程序中的空格 } TakeWord(); // for(j=0;j<length;j++){ // cout<<letter[j]<<endl; // } fclose(stdin);//關(guān)閉文件 fclose(stdout);//關(guān)閉文件 return 0; }
運(yùn)行結(jié)果:
s.txt
Result.txt
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C語(yǔ)言二維數(shù)組幾種常用的表示方法
- C語(yǔ)言項(xiàng)目全正整數(shù)后再計(jì)算的三種參考解答方法
- C語(yǔ)言項(xiàng)目爬樓梯的兩種實(shí)現(xiàn)方法參考
- C語(yǔ)言程序打豆豆(函數(shù)版)
- 劍指offer之C語(yǔ)言不修改數(shù)組找出重復(fù)的數(shù)字
- C語(yǔ)言測(cè)試n的階乘和x的n次方
- C語(yǔ)言數(shù)組a和&a的區(qū)別講解
- C++稀疏矩陣的各種基本運(yùn)算并實(shí)現(xiàn)加法乘法
- Dijkstra算法最短路徑的C++實(shí)現(xiàn)與輸出路徑
- 判斷兩顆二叉樹是否相似的兩種方法
相關(guān)文章
C語(yǔ)言中結(jié)構(gòu)體和共用體實(shí)例教程
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中結(jié)構(gòu)體和共用體的相關(guān)資料,結(jié)構(gòu)體是一種自定義的復(fù)合數(shù)據(jù)類型,共用體也叫聯(lián)合體,使幾個(gè)不同類型的變量共占一段內(nèi)存(相互覆蓋),需要的朋友可以參考下2021-06-06詳解C++?STL模擬實(shí)現(xiàn)vector
這篇文章主要為大家詳細(xì)介紹了C++如何模擬實(shí)現(xiàn)STL容器vector,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定幫助,需要的可以參考一下2023-01-01淺析設(shè)計(jì)模式中的代理模式在C++編程中的運(yùn)用
這篇文章主要介紹了設(shè)計(jì)模式中的代理模式在C++編程中的運(yùn)用,代理模式最大的好處就是實(shí)現(xiàn)了邏輯和實(shí)現(xiàn)的徹底解耦,需要的朋友可以參考下2016-03-03C++的try塊與異常處理及調(diào)試技術(shù)實(shí)例解析
這篇文章主要介紹了C++的try塊與異常處理及調(diào)試技術(shù)實(shí)例解析,有助于讀者加深對(duì)try塊調(diào)試技術(shù)的認(rèn)識(shí),需要的朋友可以參考下2014-07-07VC++簡(jiǎn)單實(shí)現(xiàn)關(guān)機(jī)、重啟計(jì)算機(jī)實(shí)例代碼
這篇文章主要介紹了VC++簡(jiǎn)單實(shí)現(xiàn)關(guān)機(jī)、重啟計(jì)算機(jī)實(shí)例代碼,很實(shí)用的功能,需要的朋友可以參考下2014-07-07C++實(shí)現(xiàn)LeetCode(51.N皇后問題)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(51.N皇后問題),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07