一、實驗目的
通過做上機題加深對編譯器構造原理和方法的理解,鞏固所學知識。
<1> 會用正規式和產生式設計簡單語言的語法;
<2> 會用遞歸下降子程序編寫編譯器或解釋器;
<3> 會寫上機報告。
二、實驗環境
Dev C++ 5.11
三、題目及要求
為函數繪圖語言編寫一個解釋器,解釋器接受用繪圖語言編寫的源程序,經語法和語義分析之后,將源程序所規定的圖形顯示在顯示屏(或窗口)中。通過自己動手編寫解釋器,掌握語言翻譯特別是語言識別的基本方法。
四、實驗內容
1、詞法分析器的構造
步驟:正規式-NFA-DFA-最小DFA-編寫程序-測試
1.1 記號的設計
<1> 詞法分析器的三個任務:
1.濾掉源程序中的無用成分;
2.輸出記號供語法分析器使用;
3.識別非法輸入,並將其標記為“出錯記號”。
<2> 記號的組成:記號的類別和屬性。
<3> 記號的數據結構:
struct Token // 記號的數據結構
{ Token_Type type; // 類別
char * lexeme; // 屬性,原始輸入的字符串
double value; // 屬性,若記號是常數則是常數的值
double (* FuncPtr)(double);
// 屬性,若記號是函數則是函數指針
};
<4> 函數繪圖語言中記號的分類與表示
enum Token_Type // 記號的類別,共22個
{ ORIGIN, SCALE, ROT, IS, // 保留字(一字一碼)
TO, STEP, DRAW,FOR, FROM, // 保留字
T, // 參數
SEMICO, L_BRACKET, R_BRACKET, COMMA,// 分隔符
PLUS, MINUS, MUL, DIV, POWER, // 運算符
FUNC, // 函數(調用)
CONST_ID, // 常數
NONTOKEN, // 空記號(源程序結束)
ERRTOKEN // 出錯記號(非法輸入)
};
1.2 模式的正規式表示
1.3 區分記號的符號表
2、語法分析器的構造
2.1 語法分析器的任務:分析語言的結構
(1)為句子(表達式)構造語法樹;
(2)檢查程序(語句)中的語法錯誤。
2.2 主要工作:
(1)設計函數繪圖語言的文法,使其適合遞歸下降分析;
(2)設計語法樹的節點,用於存放表達式的語法樹;
(3)設計遞歸下降子程序,分析句子並構造表達式的語法樹;
(4)設計測試程序和測試用例,檢驗分析器是否正確。
2.3 函數繪圖語言的文法
<1> 文法
Program → ε| Program Statement SEMICO
Statement → OriginStatment | ScaleStatment
| RotStatment | ForStatment
OriginStatment → ORIGIN IS
L_BRACKET Expression COMMA Expression R_BRACKET
ScaleStatment → SCALE IS
L_BRACKET Expression COMMA Expression R_BRACKET
RotStatment → ROT IS Expression
<2> 改寫文法為無二義文法
<3> 消除左遞歸和提取左因子
消除program產生式的左遞歸
Program → Program Statement SEMICO |ε
Program → ε Program’
Program’ → Statement SEMICO Program’|ε
Program → Statement SEMICO Program |ε
<4> 改寫左結合的產生式為EBNF形式(避免子程序調用)
改寫為EBNF形式,以減少不必要的子程序調用。
Program → { Statement SEMICO }的子程序:
void Program()
{ while (token != NONTOKEN)
{ Statement(); MathchToken(SEMICO); }
}
3、語法制導翻譯繪制圖形
3.1 繪圖語言的語義
(1)表達式值的計算:深度優先后序遍歷語法樹
(2)圖形的繪制:畫出每個坐標點
3.2 繪圖所需的語義處理:
(1)從origin、rot和scale中得到坐標變換所需的信息;
(2)for_draw語句根據t的每一個值進行如下處理:
計算被繪制點的橫、縱坐標值;
根據坐標變換信息進行坐標變換,得到實際坐標;
根據點的實際坐標畫出該點。
3.3 語法制導翻譯的基本步驟
(1)為文法符號設計屬性;
(2)設計語義規則中所需的輔助函數;
(3)為產生式設計語義規則。
3.4 語義函數的設計
<1> 全程變量:
double Parameter=0; // 為參數T分配的變量
double Origin_x=0.0, Origin_y=0.0;// 用於記錄平移距離
double Rot_ang=0.0; // 用於記錄旋轉角度
double Scale_x=1, Scale_y=1; // 用於記錄比例因子
<2> 輔助語義函數
a) 計算表達式的值:深度優先后序遍歷語法樹
double GetExprValue(struct ExprNode * root);
b) 計算點的坐標值:首先獲取坐標值,然后進行坐標變換
static void CalcCoord( struct ExprNode * x_nptr,
struct ExprNode * y_nptr,
double &x_val,
double &y_val);
c) 繪制一個點(與環境有關):
void DrawPixel(unsigned long x, unsigned long y);
d) 循環繪制所有的點:
void DrawLoop( double Start,
double End,
double Step,
struct ExprNode * HorPtr,
struct ExprNode * VerPtr);
4、解釋器的源程序組織(看實際環境)
一、心得體會
C++對C的發展不僅是提供了對面向對象方法的支持,還擴展了常量定義、類屬機制、異常處理,等等;靈活利用C++提供的機制可提高程序的可讀性與可維護性;低層次的語言支持機制,可以給程序員以更大的靈活性,並產生更高效的目標代碼;
通過編譯原理的實驗,在自已動手體驗的情況下,我們更加透徹地理解了詞法分析的過程以及該算法。對於以后由模型向程序代碼的轉化能力上,有了很大的鍛煉。我們會更加專心的研究計算機知識,不斷將現實中遇到的實際問題,向程序方面轉變,做到靈活運用所學知識。