2017春季學期編譯原理期末實驗報告

URNOTJANET發表於2017-12-13

實驗名:PL/0編譯器的實現 一、實驗目的 理解編譯器的工作機制,掌握編譯器的構造方法 掌握詞法分析器的生成工具LEX的用法 掌握語法分析器的生成工具YACC的用法

二、實驗內容簡要概括 1.實驗分為三個部分: 分別是詞法分析、語法分析、語義分析和程式碼生成部分 三個部分對應PL/0編譯程式的編譯過程,使得在學習原理的過程中可以更好的體會到分析過程。

2.詞法分析    編寫PL/0語言識別程式,並藉助flex工具生成一個PL/0語言的詞法分析程式,對輸入的PL/0語言的源程式進行掃描,識別出單詞符號的類別,輸出各種符號的資訊。

參考LEX源程式的格式,自定義宣告,輔助定義,識別規則和子程式。

3.語法分析 編寫一個PL/0語言的語法分析程式,藉助bison工具生成,使得程式可以對輸入的PL/0源程式進行語法分析,並按語法歸約過程輸出歸約時所用的語法規則。

4.語義分析 使用C語言編寫PL/0的語義分析程式,要求將其轉換成一個類pcode語言

三、實驗環境: OS:Windows10 1607 Compiler:Cygwin64 Terminal,yacc,lex,bison, code:blocks:13.12

輔助:sublime text 3126, notepad++ 7.41 使用語言:C

四、實驗設計說明 1.第一部分:詞法分析

實驗具體輸入輸出要求如下

輸入:PL0源程式

輸出:將單詞符號分為下面五類,然後統計PL0源程式中各單詞符號出現的次數

K類(關鍵字)I類(識別符號)C類(常量)P類(算符及界符)O類(其他)

根據要求,再參考lex的語法格式,設計思路大致如下:

1)對五類關鍵詞分別建立結構體,類似於Hash的連結串列法一樣,一個關鍵詞中對應一個陣列,將每一個讀入的,相同型別但是不同內容的符號插在對應類別的結構體後面。結構體設計如圖。

1.png

2)輔助定義環節新增關鍵詞資訊與對應的語義動作insert

  1. 對讀進來的PL/0檔案進行分析,將結果輸出到另外一個檔案中

該部分的最大難度在於語義動作insert

本次實驗對輸入的字串有長度限制,需要在分析語言的過程中給予警告,但同時也不能終止編譯動作,因為如果每次編譯報錯,只能報一行錯誤,會使得編譯器的分析效率十分低下。本次實驗中insert動作對應的函式如下:

2.png

2.第二部分:語法分析 實驗具體輸入輸出要求如下

輸入:PL0源程式

輸出:關於該程式的語法結構分析說明

參考bison的說明,大致明白這次實驗是在詞法分析的基礎之上多加了對於語法規則的定義,其中定義的語句要符合C語言文法。

語法格式:左部(非終結符):右部(文法符號串);

非終結符名稱通常用小寫字母,終結符名稱通常用大寫字母。

右部為空表示左部的非終結符可以匹配空串。

左部相同的語法規則應儘量合併。

語義動作出現在規則的尾部時,bison在歸約前執行它;語義動作出現在規則的中間時,bison在識別出它前面的若干文法符號後執行它。

實現思路參考詞法分析實驗,只是這次在對應的語義動作環節直接輸出,而不需要insert到結構體中。

實驗輸出如下:

3.png

3.第三部分:語義分析和目標語言的生成

實驗具體輸入輸出要求如下

輸入:PL0源程式

輸出:類Pcode程式碼

首先需要對類Pcode進行了解

目的碼類pcode是一種棧式機的組合語言。

棧式機系統結構:沒有累加器和暫存器,只有儲存棧指標所有運算都在棧頂

指令格式fla

f  功能碼

l  層次差 (識別符號引用層減去定義層)

a  根據不同的指令有所區別

參考類Pcode的功能表和直譯器結構,將程式分成三個部分:code.l,code.y和define.h。其中define.h定義了類Pcode的功能碼代號,符號表和指令結構,code.l屬於詞法分析部分,code.y屬於語法與語義分析部分。其中在語義動作說明部分,根據輸入情況不同用$偽變數進行壓棧出棧操作。

本次實驗中已經提供了interpret函式,所以省略了C語言中對於功能碼的具體情況說明,接下來的思路就是根據輸入的程式,先檢查詞法有無錯誤—>構建符號表-->執行interpret()的內容à輸出類Pcode結果

實驗結果圖在第五部分

五、以一個*PL0*的源程式作具體說明

原PL0程式如下:

var a, b, c;

procedure gcd;

procedure rec;

begin

    if a <> 0 then

        begin

            a := a - 1;

        end;

end;

 

begin

    if c < b then

        begin

            c := b;

            call rec;

        end;

end;

 

begin

    read(a);

    read(b);

    read(c);

    write(a);

    call gcd;

    write(a);

end.

複製程式碼

這個程式裡面存在著過程巢狀,其實這一次實驗中還實現了並列,但是在此就不贅述了。 實驗輸出結果如圖

4.png

(注:在寫報告的過程中才發現之前看錯ppt說明的指令功能表,誤將INT看成INI,但為了閱讀的方便,所以此處不再做修改)

5.PNG

6.PNG

7.PNG

相關文章