1. 實驗題目:自上而下語法分析
實驗目的
- 給出 PL/0 文法規範,要求編寫 PL/0 語言的語法分析程序。
- 通過設計、編制、調試一個典型的自上而下語法分析程序,實現對詞法分析程序所提供的單詞序列進行語法檢查和結構分析,進一步掌握常用的語法分析方法。
- 選擇最有代表性的語法分析方法,如遞歸下降分析法、預測分析法;選擇對各種常見程序語言都具備的語法結構,如賦值語句,特別是表達式,作爲分析對象。
實驗內容
已給 PL/0 語言文法,構造表達式部分的語法分析器。
分析對象〈算術表達式〉的 BNF 定義如下:
<表達式> ::= [+|-]<項>{<加法運算符> <項>}
<項> ::= <因子>{<乘法運算符> <因子>}
<因子> ::= <標識符>|<無符號整數>| ‘(’<表達式>‘)’
<加法運算符> ::= +|-
<乘法運算符> ::= *|/
<關係運算符> ::= =|#|<|<=|>|>=
實驗要求
- 將實驗一“詞法分析”的輸出結果,作爲表達式語法分析器的輸入,進行語法解析,對於語法正確的表達式,報告“語法正確法錯誤的表達式,報告“語法錯誤”, 指出錯誤原因。
- 把語法分析器設計成一個獨立一遍的過程。
- 採用遞歸下降分析法或者採用預測分析法實現語法分析。
輸入輸出
輸入:
PL/0 表達式,用實驗一的輸出形式作爲輸入。例如: 對於 PL/0 表達式,(a+15)*b 用下列形式作爲輸入:
(lparen,( )
(ident, a)
(plus, + )
(number, 15)
(rparen,) )
(times, * )
(ident, b )
輸出:
對於語法正確的表達式,報告“語法正確”;
對於語法錯誤的表達式,報告“語法錯誤”, 指出錯誤原因
2. 設計思想
遞歸下降分析法的原理是利用函數之間的遞歸調用來模擬語法樹自上而下的構建過程。從根節點出發,自頂向下爲輸入串中尋找一個最左匹配序列,建立一棵語法樹。在不含左遞歸和每個非終結符的所有候選終結首字符集都兩兩不相交條件下,我們就可能構造出一個不帶回溯的自頂向下的分析程序,這個分析程序是由一組遞歸過程(或函數)組成的,每個過程(或函數)對應文法的而一個非終結符。
語法:
<表達式> ->[+|-]<項>{<加法運算符> <項>}
<項> -><因子>{<乘法運算符> <因子>}
<因子> -> <標識符>|<無符號整數>|(<表達式>)
<加法運算符> -> +|-
<乘法運算符> -> *|/
可以得到其語法圖
表達式:
項:
因子:
計算FIRST集:
FIRST(<表達式>)={ +, -, (, <標識符>, <無符號整數> }
FIRST(<因子>)={ <標識符>, <無符號整數>, ( }
FIRST(<項>)={ <標識符>, <無符號整數>, ( }
FIRST(<加法運算符>)={ +, - }
FIRST(<乘法運算符>)={ *, / }
計算FOLLOW集:
FOLLOW(<表達式>)={ ) }
FOLLOW (<項>)={ +,- }
FOLLOW (<因子>)={ *,/ }
FOLLOW (<加法運算符>)={ <標識符>, <無符號整數>, ( }
FOLLOW (<乘法運算符>)={ <標識符>, <無符號整數>, ( }
3. 算法流程
- 每一個非終結符對應於一個函數(子過程);
- 非終結符所對應的右側產生式爲函數體;
- 每遇到一個終結符,則需要判斷所輸入字符是否與之匹配,若匹配則讀取下一個,若不匹配,則進行出錯處理。
算法過程可以寫成:
PROCEDURE <表達式>:
BEGIN
IF SYM=’+’ OR SYM=’-’ THEN
BEGIN
ADVANCE; <項>;
WHILE SYM=’+’ OR SYM=’-’ DO
BEGIN
ADVANCE; <項>;
END
END
ELSE IF SYM=FIRST(<項>) THEN
BEGIN
<項>;
WHILE SYM=’+’ OR SYM=’-’ DO
BEGIN
ADVANCE; <項>;
END
END
ELSE ERROR
END
PROCEDURE <因子>:
BEGIN
IF SYM=’*’ OR SYM=’/’ THEN
BEGIN
ADVANCE; <因子>;
WHILE SYM=’*’ OR SYM=’/’ DO
BEGIN
ADVANCE; <因子>;
END
END
ELSE IF SYM=FIRST(<因子>) THEN
BEGIN
<因子>;
WHILE SYM=’*’ OR SYM=’/’ DO
BEGIN
ADVANCE; <因子>;
END
END
ELSE ERROR
END
PROCEDURE <表達式>:
BEGIN
IF SYM=’標識符’ OR SYM=<無符號整數> THEN
BEGIN
ADVANCE;
END
ELSE IF SYM=’(’ THEN
BEGIN
<表達式>
IF SYM=’)’ THEN
BEGIN
ADVANCE;
END
ELSE ERROR
END
ELSE ERROR
END
PROGRAM PAESER
BEGIN
ADVANCE;
<表達式>;
IF SYM<>’#’ THEN ERROR
END
語法分析過程的依賴關係:
4. 源程序
#include<fstream>
#include<cstring>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<map>
#include<bits/stdc++.h>
using namespace std;
ifstream infile("F:\\編譯原理\\第二次實驗\\result.txt");
map<string,string> word;//應用map數據結構形成一個string->string的對應
std::map<string,string>::iterator it;//用來遍歷整個對應關係的迭代器
string str;//string變量進行字符識別
string sym; //指針
void expressionAnalysis();//表達式分析
void termAnaysis();//項分析
void factorAnalysis();//因子分析
int advance();
int conterr=0;//記錄錯誤
int lpnum=0;//記錄左括號
int found;//提取字符串中指針的位置
int flag=0;//記錄往後移動一個指針SYM是否正確
int main(){
flag=advance();
if(flag){
expressionAnalysis();
}
if(flag!=-1&&!conterr){
cout<<"語法正確"<<endl;
}
return 0;
}
int advance(){//SYM的移動
if(!getline(infile,str)){//從文件中提取字符
return 0;
}
found=str.find(',',0);
if(found==-1){//當爲error的時候,沒有‘,’
conterr++;
cout<<"語法錯誤 識別字符錯誤"<<endl;
return -1;
}
sym=str.substr(1,found-1);
cout<<sym<<endl;
return 1;
}
void factorAnalysis(){
if(sym=="ident"||sym=="number"){//如果是標識符和無符號整數,指針就往後移動
flag=advance();
if(conterr){
return;
}
if(lpnum==0&&sym=="rparen"){
conterr++;
cout<<"語法錯誤 ')'不匹配"<<endl;
return;
}
}
else if(sym=="lparen"){//如果是左括號,就要接下來判斷是否爲表達式,指針往後移動
lpnum++;
cout<<lpnum<<endl;
flag=advance();
if(conterr){
return;
}
if(flag==0){//當爲最後一個標誌的時候,若沒有右括號匹配就錯誤
conterr++;
cout<<"語法錯誤 '('後缺少表達式"<<endl;
return;
}
expressionAnalysis();
if(conterr){
return;
}
if(flag==0||sym!="rparen"){
conterr++;
cout<<"語法錯誤 表達式後面缺少')'"<<endl;
return;
}else{
lpnum--;
flag=advance();
if(conterr){
return;
}
if(flag==0){
return;
}
}
}else{
cout<<"語法錯誤 因子首部不爲<標識符>|<無符號整數>|'('"<<endl;
conterr++;
return;
}
return;
}
void termAnalysis(){
factorAnalysis();
if(conterr){
return;
}
while((sym=="times")||(sym=="slash")){//當爲'*'或'/'的時候,一直往後識別因子並循環
flag=advance();
if(conterr){
return;
}
if(flag==0){
conterr++;
cout<<"語法錯誤 <乘法運算符>後缺因子"<<endl;
return;
}
if(conterr){
return;
}
factorAnalysis();
if(conterr){
return;
}
}
return;
}
void expressionAnalysis(){
if(conterr){
return;
}
if((sym=="plus")||(sym=="minus")){//當爲'*'或'/'的時候
flag=advance();
if(!conterr){
return;
}
if(flag==0){
cout<<"語法錯誤 <加法運算符>後缺項"<<endl;
conterr++;
return;
}
}
termAnalysis();
if(conterr){
return;
}
while((sym=="plus")||(sym=="minus")){//當爲'+'或'-'的時候,一直往後識別項並循環
flag=advance();
if(conterr){
return;
}
if(flag==0){
cout<<"語法錯誤 <加法運算符>後缺項"<<endl;
conterr++;
return;
}
termAnalysis();
if(conterr){
return;
}
}
return;
}
5. 調試數據
輸入:
輸出: