1. 實驗題目:詞法分析
實驗目的
- 根據PL/0語言的文法規範,編寫PL/0語言的詞法分析程序;或者調研詞法分析程序的自動生成工具LEX或FLEX,設計並實現一個能夠輸出單詞序列的詞法分析器。
- 通過設計調試詞法分析程序,實現從源程序中分出各種單詞的方法;加深對課堂教學的理解;提高詞法分析方法的實踐能力。
- 掌握從源程序文件中讀取有效字符的方法和產生源程序的內部表示文件的法。
- 掌握詞法分析的實現方法。上機調試編出的詞法分析程序。
實驗內容
已給PL/0語言文法,輸出單詞符號(關鍵字、專用符號以及其它標記)。
實驗要求
- 把詞法分析器設計成一個獨立一遍的過程。
- 詞法分析器的輸出形式採用二元式序列,即:(單詞種類,單詞的值)
輸入輸出
輸入:
const a=10;
var b,c;
begin
read(b);
c:=a+b;
write©;
end.
輸出:
(constsym, const)
(ident , a)
(eql, =)
(number, 10)
(semicolon, ; )
(varsym, var)
(ident,b)
(comma, ,)
(ident, c)
(semicolon, ; )
(beginsym, begin)
(readsym, read )
(lparen,( )
(ident, b)
(rparen, ))
(semicolon, ; )
(ident, c)
(becomes, := )
(ident, a)
(plus, +)
(ident,b )
(semicolon, ; )
(writesym,write)
(lparen, ( )
(ident, c)
(rparen,) )
(endsym, end )
(period, .)
2. 設計思想
基本字:
單詞(編碼) | 正規式r |
---|---|
begin(beginsym) | begin |
call(callsym) | call |
const(constsym) | const |
do(dosys) | do |
end(endsym) | end |
if(ifsym) | if |
odd(oddsym) | odd |
procedure(proceduresym) | procedure |
read(readsym) | read |
var(varsym) | var |
while(whilesym) | while |
write(writesym) | write |
then(thensym) | then |
標識符:
單詞(編碼) | 正規式r |
---|---|
<標識符>(ident) | (字母)(字母 |數字)* |
常數:
單詞(編碼) | 正規式r |
---|---|
<常數>(ident) | (數字)(數字)* |
運算符:
單詞(編碼) | 正規式r |
---|---|
+(plus) | + |
-(minus) | - |
*(times) | * |
/(slash) | / |
=(eql) | = |
<>(neq) | <> |
<(lss) | < |
<=(leq) | <= |
>(gtr) | > |
>=(geq) | >= |
:=(becomes) | := |
界符:
單詞(編碼) | 正規式r |
---|---|
( (lparen) | ( |
) (rparen) | ) |
, (comma) | , |
; (semicolon) | ; |
. (period) | . |
NFA(非確定有限自動機):
3.算法流程
- 詞法分析程序打開源文件,讀取文件內容,直至遇上文件結束符,然後讀取結束。
- 接下來就要對源文件從頭到尾進行掃描了,從頭開始掃描,這個時候掃描程序首先要詢問當前的字符是不是空格,若是空格,則繼續掃描下一個字符,直至不是空格。然後詢問這個字符是不是字母,若是則進行標識符和保留字的識別;若這個字符爲數字,則進行數字的判斷。否則,依次對這個字符可能的情況進行判斷(界符和運算符),若將所有可能都走了一遍還是沒有知道它是誰,則認定爲錯誤符號,輸出該無法識別error,程序結束。每次成功識別了一個單詞後,單詞都會存在word1[]數組中,然後字符指針往後移,進行下一個單詞的識別。
- 主控程序需要負責對每次識別的種別碼進行判斷,對於不同的單詞種別做出不同的反應,直至文件結束。
- 本次實驗我採用了map這個STL關聯容器,主要是考慮到詞法分析中的數據映射的關係,因此採用這種結構。map提供一對一的數據處理能力,其中第一個可以稱爲關鍵字,每個關鍵字只能在map中出現一次,第二個可能稱爲該關鍵字的值。這個容器是非常方便使用的,對於查找可以直接使用迭代器進行,利用find()函數,若一直到末尾都未找到,則是不能識別或爲標識符。
4. 源程序
#include<fstream>
#include<cstring>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<map>
#include<bits/stdc++.h>
using namespace std;
map<string,string> word;//應用map數據結構形成一個string->string的對應
std::map<string,string>::iterator it;//用來遍歷整個對應關係的迭代器
void map_init(){//對應關係進行初始化
word["begin"]="beginsym";
word["call"]="callsym";
word["const"]="constsym";
word["do"]="dosym";
word["end"]="endsym";
word["if"]="ifsym";
word["odd"]="oddsym";
word["procedure"]="proceduresym";
word["read"]="readsym";
word["then"]="thensym";
word["var"]="varsym";
word["while"]="whilesym";
word["write"]="writesym";
word["+"]="plus";
word["-"]="minus";
word["*"]="times";
word["/"]="slash";
word["="]="eql";
word["<>"]="neq";
word["<"]="lss";
word["<="]="leq";
word[">"]="gtr";
word[">="]="geq";
word[":="]="becomes";
word["("]="lparen";
word[")"]="rparen";
word[","]="comma";
word[";"]="semicolon";
word["."]="period";
}
int main(){
map_init();//初始化
char ch;
char a;
string word1;//string變量識別單詞
string str;//string變量進行字符識別
ifstream infile("F:\\編譯原理\\第一次實驗\\analysis.txt");//文件輸入流
ofstream outfile("F:\\編譯原理\\第一次實驗\\result.txt");//文件輸出流
ostringstream buf;
while(buf&&infile.get(ch)) buf.put(ch);//將文件中的字符讀出來
str= buf.str();//將得到的字符儲存到string類型變量中
int csize=str.length();
for(int i=0;i<csize;i++){//對整個字符串進行遍歷
while(str[i]==' '||str[i]=='\n') i++;//若最開始爲空格或換行符,則將指針的位置往後移
if(isalpha(str[i])){//對標識符和基本字進行識別,調用庫函數isalpha()
word1=str[i++];
while(isalpha(str[i])||isdigit(str[i])){
word1+=str[i++];
}
it=word.find(word1);
if(it!=word.end()){//判斷是不是基本字,若爲基本字則進行輸出
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}
else{//否則直接輸出
cout<<"(ident"<<","<<word1<<")"<<endl;
}
i--;
}
else if(isdigit(str[i])){//判斷是不是常數,調用庫函數isdigit()
word1=str[i++];
while(isdigit(str[i])){
word1+=str[i++];
}
if(isalpha(str[i])){
cout<<"error!"<<endl;
break;
}
else{
cout<<"(number"<<","<<word1<<")"<<endl;
}
i--;
}else if(str[i]=='<'){//對<,<=分別進行判斷
word1=str[i++];
if(str[i]=='>'){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}else if(str[i]=='='){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}else{
cout<<"error!"<<endl;
break;
}
i--;
}else if(str[i]=='>'){//對>,>=分別進行判斷
word1=str[i++];
if(str[i]=='='){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}else{
cout<<"error!"<<endl;
break;
}
i--;
}else if(str[i]==':'){//對:=進行判斷
word1=str[i++];
if(str[i]=='='){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}else{
cout<<"error!"<<endl;
break;
}
i--;
}else{//對其他的基本字依次進行判斷
word1=str[i];
it=word.find(word1);
if(it!=word.end()){
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
}else{
cout<<"error!"<<endl;
break;
}
}
}
infile.close();
return 0;
}
5. 調試數據
待輸入的文件流:
輸出數據: