L25 编译器采用 Java 实现。该编译器支持词法分析、语法分析、语义分析、符号表管理、目标代码(P-Code)生成及解释执行。相比原始 PL/0,本编译器进行了扩展,支持数组、结构体等高级特性。
- 支持变量、函数、数组、结构体等声明
- 支持基本的算术、关系运算
- 支持条件语句、循环语句、函数调用
- 支持 try-catch 语句
- 生成中间代码(P-Code),并可解释执行
- 输出符号表、P-Code、运行结果等信息
- 支持单行和多行注释
以下为扩展后的 L25 语言文法:
<program> = "program" <ident> "{" <block> "}"
<block> = {<struct_dec>} {<func_def>} "main" "{" <stmt_list> "}"
<struct_dec> = "struct" <ident> "{" [ <member_list> ] "}"
<member_list> = <member_dec> { "," <member_dec> }
<member_dec> = <ident> | <ident> ":" "[" <number> "]"
<func_def> = "func" <ident> "(" [param_list] ")" "{" <stmt_list> "return" <expr> ";" "}"
<param_list> = <ident> { "," <ident> }
<stmt_list> = <stmt> ";" { <stmt> ";" }
<stmt> = <declare_stmt> | <assign_stmt> | <if_stmt> | <while_stmt> | <input_stmt> | <output_stmt> | <func_call> | <try_stmt>
<try_stmt> = "try" "{" <stmt_list> "}" "catch" "{" <stmt_list> "}"
<declare_stmt> = "let" <ident> (
| "=" <expr>
| ":" <array_suffix> [ "=" <array_init_expr> ]
| ":" <struct_suffix> [ "=" <struct_init_expr> ]
| ε
)
<array_suffix> = "[" <number> "]"
<array_init_expr> = "[" <expr> { "," <expr> } "]"
<array_ref> = <ident> "[" <expr> "]"
<struct_suffix> = <ident>
<struct_init_expr> = "{" <expr> { "," <expr> } "}"
<struct_ref> = <ident> "." <ident> | <ident> "." <ident> "[" <expr> "]"
<assign_stmt> = <factor> "=" <expr>
<if_stmt> = "if" "(" <bool_expr> ")" "{" <stmt_list> "}" [ "else" "{" <stmt_list> "}" ]
<while_stmt> = "while" "(" <bool_expr> ")" "{" <stmt_list> "}"
<func_call> = <ident> "(" [ <arg_list> ] ")"
<arg_list> = <expr> { "," <expr> }
<input_stmt> = "input" "(" <ident> { "," <ident> } ")"
<output_stmt> = "output" "(" <expr> { "," <expr> } ")"
<bool_expr> = <expr> ("==" | "!=" | "<" | "<=" | ">" | ">=") <expr>
<expr> = [ "+" | "-" ] <term> { ("+" | "-") <term> }
<term> = <factor> { ("*" | "/") <factor> }
<factor> = <ident> | <number> | "(" <expr> ")" | <func_call> | <array_ref> | <struct_ref>
<ident> = <letter> { <letter> | <digit> }
<number> = <digit> { <digit> }
<letter> = "a" | "b" | ... | "z" | "A" | "B" | ... | "Z"
<digit> = "0" | "1" | ... | "9"
项目目录结构如下:
L25/
├─ src/
│ ├─ L25.java // 主程序入口
│ ├─ Scanner.java // 词法分析器
│ ├─ Parser.java // 语法分析器
│ ├─ Interpreter.java // P-Code 解释器
│ ├─ Table.java // 符号表管理
│ ├─ Symbol.java // 符号定义
│ ├─ SymSet.java // 符号集合
│ ├─ Err.java // 错误处理
│ └─ L25GUI.java // 图形界面
├─ myTest/ // 测试用例
├─ fa.tmp // P-Code 输出
├─ fa1.tmp // 源文件及首地址
├─ fa2.tmp // 运行结果
├─ fas.tmp // 符号表输出
└─ ...
L25.java:主类,负责整体流程控制,包括文件输入、编译、运行等。Scanner.java:词法分析,将源代码分解为记号(Token)。Parser.java:语法分析,递归下降分析器,负责语法检查和中间代码生成。Interpreter.java:P-Code 解释器,执行中间代码。Table.java:符号表管理,记录变量、常量、过程等信息。Err.java:错误处理与报告。
-
编译所有 Java 源文件:
在
src目录下执行:javac *.java -
运行主程序:
java L25
-
按提示输入 L25 源文件名(如
../test01.txt),选择是否输出 P-Code 和符号表。 -
编译成功后自动解释执行,输出结果。
-
编译所有 Java 文件(同上):
-
运行 GUI :
java L25GUI
按界面提示选择测试用例。



