當前位置:編程學習大全網 - 源碼下載 - pl0怎麽擴展++,--功能?

pl0怎麽擴展++,--功能?

那我給妳網站吧,我找很久了.那個東西是很需要的

/source/191218

PL/0語言是Pascal語言的壹個子集,這裏分析的PL/0的編譯程序包括了對PL/0語

言源程序進行分析處理、編譯生成類PCODE代碼,並在虛擬機上解釋運行生成的類PCODE代碼的功能。

PL/0語言編譯程序采用以語法分析為核心、壹遍掃描的編譯方法。詞法分析和代碼生成作為獨立的子程序供語法分析程序調用。語法分析的同時,提供了出錯報告和出錯恢復的功能。在源程序沒有錯誤編譯通過的情況下,調用類PCODE解釋程序解釋執行生成的類PCODE代碼。

2.各功能模塊描述

詞法分析子程序分析:

詞法分析子程序名為GETSYM,功能是從源程序中讀出壹個單詞符號(TOTAKEN),把它的信息放入全局變量 SYM、ID和NUM中,字符變量放入CH中,語法分析器需要單詞時,直接從這三個變量中獲得。Getch過程通過反復調用Getch子過程從源程序過獲取字符,並把它們拼成單詞。GETCH過程中使用了行緩沖區技術以提高程序運行效率。

詞法分析器的分析過程:調用GETSYM時,它通過GETCH過程從源程序中獲得壹個字符。如果這個字符是字母,則繼續獲取字符或數字,最終可以拼成壹個單詞,查保留字表,如果查到為保留字,則把SYM變量賦成相應的保留字類型值;如果沒有查到,則這個單詞應是壹個用戶自定義的標識符(可能是變量名、常量名或是過程的名字),把SYM置為IDENT,把這個單詞存入ID變量。查保留字表時使用了二分法查找以提高效率。如果Getch獲得的字符是數字,則繼續用Getch獲取數字,並把它們拼成壹個整數或實數,然後把SYM置為 INTEGER或REAL,並把拼成的數值放入NUM變量。如果識別出其它合法的符號(比如:賦值號、大於號、小於等於號等),則把SYM則成相應的類型。如果遇到不合法的字符,把SYM置成NUL。

語法分析子程序分析:

語法分析子程序采用了自頂向下的遞歸子程序法,語法分析同時也根據程序的語義生成相應三元代碼,並提供了出錯處理的機制。語法分析主要由分程序分析過程(BLOCK)、參數變量分析過程(ParaDeclaration)、參數變量處理過程(ParaGetSub)、數組處理過程(ParaGetSub)、常量定義分析過程(ConstDeclaration)、變量定義分析過程(Vardeclaration)、語句分析過程(Statement)、表達式處理過程(Expression)、項處理過程(Term)、因子處理過程(Factor)和條件處理過程(Condition)構成。這些過程在結構上構成壹個嵌套的層次結構。除此之外,還有出錯報告過程(Error)、代碼生成過程(Gen)、測試單詞合法性及出錯恢復過程(Test)、登錄名字表過程(Enter)、查詢名字表函數(Position)以及列出類 PCODE代碼過程(Listcode)作過語法分析的輔助過程。

由PL/0的語法圖可知:壹個完整的PL/0程序是由分程序和句號構成的。因此,本編譯程序在運行的時候,通過主程序中調用分程序處理過程block來分析分程序部分(分程序分析過程中還可能會遞歸調用block過程),然後,判斷最後讀入的符號是否為句號。如果是句號且分程序分析中未出錯,則是壹個合法的PL/0程序,可以運行生成的代碼,否則就說明源PL/0程序是不合法的,輸出出錯提示即可。

下面按各語法單元分析PL/0編譯程序的運行機制。

分程序處理過程:

語法分析開始後,首先調用分程序處理過程(Block)處理分程序。過程入口參數置為:0層、符號表位置0、出錯恢復單詞集合為句號、聲明符或語句開始符。進入Block過程後,首先把局部數據段分配指針設為3,準備分配3個單元供運行期存放靜態鏈SL、動態鏈DL 和返回地址RA。然後用Tx0記錄下當前符號表位置並產生壹條Jmp指令,準備跳轉到主程序的開始位置,由於當前還沒有知到主程序究竟在何處開始,所以 Jmp的目標暫時填為0,稍後再改。同時在符號表的當前位置記錄下這個Jmp指令在代碼段中的位置。在判斷了嵌套層數沒有超過規定的層數後,開始分析源程序。首先判斷是否遇到了常量聲明,如果遇到則開始常量定義,把常量存入符號表。接下去用同樣的方法分析變量聲明,變量定義過程中會用Dx變量記錄下局部數據段分配的空間個數。然後如果遇到Procedure保留字則進行過程聲明和定義,聲明的方法是把過程的名字和所在的層次記入符號表,過程定義的方法就是通過遞歸調用Block過程,因為每個過程都是壹個分程序。由於這是分程序中的分程序,因此調用Block時需把當前的層次號Lev加壹傳遞給Block 過程。分程序聲明部分完成後,即將進入語句的處理,這時的代碼分配指針CX的值正好指向語句的開始位置,這個位置正是前面的Jmp指令需要跳轉到的位置。於是通過前面記錄下來的地址值,把這個Jmp指令的跳轉位置改成當前cx的位置。並在符號表中記錄下當前的代碼段分配地址和局部數據段要分配的大小(DX 的值)。生成壹條INT指令,分配DX個空間,作為這個分程序段的第壹條指令。下面就調用語句處理過程Statement分析語句。分析完成後,生成操作數為0的OPR指令,用於從分程序返回(對於0層的主程序來說,就是程序運行完成,退出)。

常量定義過程:

通過循環,反復獲得標識符和對應的值,存入符號表。符號表中記錄下標識符的名字和它對應的值。

變量定義過程:

與常量定義類似,通過循環,反復獲得標識符,存入符號表。符號表中記錄下標識符的名字、它所在的層及它在所在層中的偏移地址。

參變量定義過程:

類似變量定義,將參變量,存入符號表中。

參變量處理過程:

如果函數用參變量,依照形參的類型、個數,由實參進行賦值。

數組處理過程:

計算數組括號內的偏移值,存入棧頂用於後面生成的STOARR和LODARR指令調用實際的數組中元素的地址。

語句處理過程:

語句處理過程是壹個嵌套子程序,通過調用表達式處理、項處理、因子處理等過程及遞歸調用自己來實現對語句的分析。語句處理過程可以識別的語句包括賦值語句、read語句、write語句、++語句、--語句、+=語句、-=語句、if-else-then語句、while語句、For語句、repeat 語句。當遇到begin/end語句時,就遞歸調用自己來分析。分析的同時生成相應的類PCODE指令。

賦值語句的處理:

首先獲取賦值號左邊的標識符,從符號表中找到它的信息,並確認這個標識符確為變量名。然後通過調用表達式處理過程算得賦值號右部的表達式的值並生成相應的指令保證這個值放在運行期的數據棧頂。最後通過前面查到的左部變量的位置信息,生成相應的STO指令,把棧頂值存入指定的變量的空間,實現了賦值操作。返回函數值也是用賦值語句進行返回值的儲存。

對函數與過程調用的處理:

首先判斷讀入的標識符屬性為FUNCTION或PROCEDURE,從符號表中找到此標識符,獲得其所在層次和偏移地址。然後生成相應的cal指令。至於調用子過程所需的保護現場等工作是由類PCODE解釋程序在解釋執行cal指令時自動完成的。如果此標識符不在第0層而且是該層函數的函數名則作為返回值返回。

read語句的處理:

確定read語句語法合理的前提下(否則報錯),由變量的類型生成相應的指令:

對於整型,第壹條是16號操作的opr指令,實現從標準輸入設備上讀壹個整數值,放在數據棧頂。如果讀入是實數就報錯,第二條是sto指令,把棧頂的值存入read語句括號中的變量所在的單元。

對於實型,第壹條是15號操作的opr指令,實現從標準輸入設備上讀壹個實數值,放在數據棧頂。第二條是sto指令,把棧頂的值存入read語句括號中的變量所在的單元。

對於字符型,第壹條是20號操作的opr指令,實現從標準輸入設備上讀壹個字符值,第二條是sto指令,把棧頂的值存入read語句括號中的變量所在的單元。

write語句的處理:

與read語句相似。在語法正確的前提下,生成指令:通過循環調用表達式處理過程分析write語句括號中的每壹個表達式,生成相應指令保證把表達式的值算出並放到數據棧頂並生成指令,輸出表達式的值,如果是數字類型則生成14號操作的opr指令,如果是字符類型則生成19號操作的opr指令。

if-then-else語句的處理:

按if語句的語法,首先調用邏輯表達式處理過程處理if語句的條件,把相應的真假值放到數據棧頂。接下去記錄下代碼段分配位置(即下面生成的jpc指令的位置),然後生成條件轉移jpc指令(遇0或遇假轉移),轉移地址未知暫時填0。然後調用語句處理過程處理 then語句後面的語句或語句塊。then後的語句處理完後,如果遇到else,就調用語句處理過程處理else語句後面的語句或語句塊,這時當前代碼段分配指針的位置就應該是上面的jpc指令的轉移位置。通過前面記錄下的jpc指令的位置,把它的跳轉位置改成當前的代碼段指針位置,否則沒遇到else,那麽此時的當前代碼段分配指針的位置也是上面jpc指令的轉移位置,也是通過前面記錄下的jpc位置指令的位置,把它的跳轉到當前的代碼段指針位置。

begin/end語句的處理:

通過循環遍歷begin/end語句塊中的每壹個語句,通過遞歸調用語句分析過程分析並生成相應代碼。

while語句的處理:

首先用cx1變量記下當前代碼段分配位置,作為循環的開始位置。然後處理while語句中的條件表達式生成相應代碼把結果放在數據棧頂,再用cx2變量記下當前位置,生成條件轉移指令,轉移位置未知,填0。通過遞歸調用語句分析過程分析do語句後的語句或語句塊並生成相應代碼。最後生成壹條無條件跳轉指令 jmp,跳轉到cx1所指位置,並把cx2所指的條件跳轉指令的跳轉位置改成當前代碼段分配位置。

Repeat語句的處理:

首先用CX1變量記下當前代碼段分配位置,作為循環的開始位置。然後通過遞歸調用語句分析過程分析,直到遇到until保留字,如果未對應until則出錯。調用條件表達式處理過程生成相應代碼把結果放在數據棧頂,再生成條件轉移指令,轉移位置為上面記錄的CX1。

For語句的處理:

按For語句的語法,首先對For後面的壹個標識符進行初值的賦值過程(類似賦值語句處理),生成相應的代碼。之後遇到TO或DOWNTO保留字,如果未對應則出錯。用CX1變量記下當前代碼段分配的位置,作為以後JMP循環的開始位置。對上面識別的標識符變量進行存取,與TO或DOWNTO後面的表達式進行比較,生成比較指令(TO為13、DOWNTO為11),再用CX2變量記下當前代碼段分配的位置,生成JPC指令,跳轉地址未知,之後可用CX2記錄下的位置進行回填。然後處理DO保留字後的循環體,第壹步遞歸調用語句分析過程,第二步將原先For後的標識符變量進行自加處理,生成相應代碼,然後生成無條件跳轉語句JMP跳轉代碼為CX1。最後將此時的代碼段位置回填到JPC跳轉指令上。

表達式、項、因子處理:

根據PL/0語法可知,表達式應該是由正負號或無符號開頭、由若幹個項以加減號連接而成。而項是由若幹個因子以乘除號,mod、div符號或++、--符號連接而成,因子則可能是壹個標識符或壹個數字,或是壹個以括號括起來的子表達式。根據這樣的結構,構造出相應的過程,遞歸調用就完成了表達式的處理。把項和因子獨立開處理解決了加減號與乘除號的優先級問題。在這幾個過程的反復調用中,始終傳遞fsys變量的值,保證可以在出錯的情況下跳過出錯的符號,使分析過程得以進行下去。

邏輯表達式的處理:

首先判斷是否為壹元邏輯表達式:判奇偶。如果是,則通過調用表達式處理過程分析計算表達式的值,然後生成判奇指令。如果不是,則肯定是二元邏輯運算符,通過調用表達式處理過程依次分析運算符左右兩部分的值,放在棧頂的兩個空間中,然後依不同的邏輯運算符,生成相應的邏輯判斷指令,放入代碼段。

判斷單詞合法性與出錯恢復過程分析:

本過程有三個參數,s1、s2為兩個符號集合,n為出錯代碼。本過程的功能是:測試當前符號(即sym變量中的值)是否在s1集合中,如果不在,就通過調用出錯報告過程輸出出錯代碼n,並放棄當前符號,通過詞法分析過程獲取壹下單詞,直到這個單詞出現在s1或s2集合中為止。

這個過程在實際使用中很靈活,主要有兩個用法:

在進入某個語法單位時,調用本過程,檢查當前符號是否屬於該語法單位的開始符號集合。若不屬於,則濾去開始符號和後繼符號集合外的所有符號。

在語法單位分析結束時,調用本過程,檢查當前符號是否屬於調用該語法單位時應有的後繼符號集合。若不屬於,則濾去後繼符號和開始符號集合外的所有符號。

通過這樣的機制,可以在源程序出現錯誤時,及時跳過出錯的部分,保證語法分析可以繼續下去。

語法分析過程中調用的其它子過程相對比較簡單,請參考源程序的註釋。

類PCODE代碼解釋執行過程分析:

這個過程模擬了壹臺可以運行類PCODE指令的棧式計算機。它擁有壹個棧式數據段用於存放運行期數據、擁有壹個代碼段用於存放類PCODE程序代碼。同時還擁用數據段分配指針、指令指針、指令寄存器、局部段基址指針等寄存器。

解釋執行類PCODE代碼時,數據段存儲分配方式如下:

對於源程序的每壹個過程(包括主程序),在被調用時,首先在數據段中開辟三個空間,存放靜態鏈SL、動態鏈DL和返回地址RA。靜態鏈記錄了定義該過程的直接外過程(或主程序)運行時最新數據段的基地址。動態鏈記錄調用該過程前正在運行的過程的數據段基址。返回地址記錄了調用該過程時程序運行的斷點位置。對於主程序來說,SL、DL和RA的值均置為0。靜態鏈的功能是在壹個子過程要引用它的直接或間接父過程(這裏的父過程是按定義過程時的嵌套情況來定的,而不是按執行時的調用順序定的)的變量時,可以通過靜態鏈,跳過個數為層差的數據段,找到包含要引用的變量所在的數據段基址,然後通過偏移地址訪問它。

在過程返回時,解釋程序通過返回地址恢復指令指針的值到調用前的地址,通過當前段基址恢復數據段分配指針,通過動態鏈恢復局部段基址指針。實現子過程的返回。對於主程序來說,解釋程序會遇到返回地址為0的情況,這時就認為程序運行結束。

解釋程序過程中的base函數的功能,就是用於沿著靜態鏈,向前查找相差指定層數的局部數據段基址。這在使用sto、lod、stoArr、lodArr等訪問局部變量的指令中會經常用到。

類PCODE代碼解釋執行的部分通過循環和簡單的case判斷不同的指令,做出相應的動作。當遇到主程序中的返回指令時,指令指針會指到0位置,把這樣壹個條件作為終至循環的條件,保證程序運行可以正常的結束

  • 上一篇:kindle paperwhite 越獄後 怎麽改屏保
  • 下一篇:如何使用eclipse創建Maven工程及其子模塊
  • copyright 2024編程學習大全網