PL/0 是 Pascal 的子集,本項目使用 Java 實現其編譯器與解釋執行系統。目標代碼面向假想棧式計算機,具備跨平台特性。編譯過程採用單遍掃描,以遞歸下降語法分析為核心,結合符號表管理、目標代碼生成與錯誤處理,最終由解釋器執行目標代碼。
核心產生式包括:
<prog> → program <id> ; <block><block> → [<condecl>][<vardecl>][<proc>]<body>| 指令 | 格式 | 功能 |
|---|---|---|
| LIT | 0, a | 常量 a 入棧 |
| OPR | 0, a | 執行運算(a 表示運算類型) |
| LOD | L, a | 變量入棧(層差 L,相對地址 a) |
| STO | L, a | 棧頂存入變量 |
| CAL | L, a | 調用過程(層差 L,入口地址 a) |
| INT | 0, a | 棧頂指針增加 a(分配數據區) |
| JMP | 0, a | 無條件跳轉 |
| JPC | 0, a | 條件跳轉(棧頂為假則跳轉) |
| RED | L, a | 讀入變量 |
| WRT | 0, 0 | 輸出棧頂值 |
指令編碼:F 段操作碼,L 段層差,A 段位移量。
每個過程調用分配:RA(返回地址)、SL(靜態鏈)、DL(動態鏈) + 變量空間。過程返回相當於特殊 OPR 運算。
識別關鍵字(29個)、運算符、界符、關系運算符、標識符、數字。輸出 lex.txt,格式:(符號碼, 值)。如 program → (1, -),標識符 v1 → (30, v1),數字 12 → (31, 12)。
遞歸下降法,每個非終結符對應一子程序。如 program 檢查關鍵字、標識符、分號,隨後調用 block()。
符號表管理:存儲變量(名、層次、偏移)、常量(名、值、層次)、過程(名、入口地址、層次、參數個數)。全局變量 level(層次,主程序為1)、address(偏移量)輔助分配。
目標代碼生成(回填技術關鍵點):
<block>:入口生成 JMP 佔位,分析完聲明部分回填入口地址;記錄過程入口地址到符號表 value 域供 CALL 使用。<statement>:
STO L, AJPC、JMP,回填跳轉地址JPC、JMP 實現循環CAL L, A,A 從符號表取RED、WRT 配合賦值/輸出運行時棧分配:每調用一過程,棧頂預留 3 單元存 SL、DL、RA,再分配變量空間。參數傳遞:形參視為局部變量,調用時將實參值按位置賦值給形參區,然後分配新活動記錄。
RValue + LexAnalysis + chTable → 詞法分析AllPcode + PerPcode → 目標代碼生成SymTable + TableRow → 符號表管理Interpreter → 解釋執行MpgAnalysis → 語法分析 + 錯誤處理(showError)本 PL/0 編譯器完整實現了從源代碼到目標代碼的編譯、鏈接、解釋執行全流程,涵蓋編譯原理核心知識:詞法/語法分析、符號表、中間代碼生成、運行時存儲組織、棈式機器模擬。代碼採用模塊化設計,便於擴展與維護,是學習編譯器構造的優秀實踐項目。