简介
PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。
PL/0 语法规范
PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核心概念。以下是完整的 PL/0 语法规范(使用扩展巴科斯范式 EBNF 描述):
1. 字符集
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
letter = "a" | "b" | ... | "z" | "A" | "B" | ... | "Z" ;
symbol = "+" | "-" | "*" | "/" | "(" | ")" | "=" | "," | "." | ";" | ":" | "<" | ">" | "#" ;
2. 词法单元
ident = letter { letter | digit } ; (* 标识符 *)
number = digit { digit } ; (* 无符号整数 *)
operator = "+" | "-" | "*" | "/" | "=" | "#" | "<" | ">" | "<=" | ">=" ; (* 运算符 *)
delimiter = "(" | ")" | "," | "." | ";" | ":" ; (* 分隔符 *)
keyword = "begin" | "call" | "const" | "do" | "end" | "if" | "odd" | "procedure"
| "read" | "then" | "var" | "while" | "write"; (* 关键字 *)
3. 语法结构(EBNF)
程序结构
program = block "." ; (* 程序由块和句点组成 *)
block = [ "const" ident "=" number {"," ident "=" number} ";" ]
[ "var" ident {"," ident} ";" ]
{ "procedure" ident ";" block ";" }
statement ; (* 块包含常量/变量声明和过程 *)
语句
statement = [ ident ":=" expression (* 赋值语句 *)
| "call" ident (* 过程调用 *)
| "begin" statement { ";" statement } "end" (* 复合语句 *)
| "if" condition "then" statement (* 条件语句 *)
| "while" condition "do" statement (* 循环语句 *)
| "read" ident (* 输入语句 *)
| "write" expression (* 输出语句 *)
| "skip" (* 空语句 *)
] ;
条件表达式
condition = "odd" expression (* 奇偶判断 *)
| expression ("=" | "#" | "<" | "<=" | ">" | ">=") expression ; (* 关系运算 *)
算术表达式
expression = [ "+" | "-" ] term { ( "+" | "-" ) term } ; (* 可带符号的表达式 *)
term = factor { ( "*" | "/" ) factor } ; (* 项 *)
factor = ident | number | "(" expression ")" ; (* 因子:标识符/数字/子表达式 *)
4. 语法图示(语法图)
Program
┌───────────────┐
│ Block │
└──────┬────────┘
│
●
Block
┌─────┬───────────┬───────────────┬────────────┐
│const│ Ident = Num│ ( , Ident=Num)│ ; │
├─────┼───────────┼───────────────┼────────────┤
│ var │ Ident │ ( , Ident) │ ; │
├─────┼───────────┼───────────────┼────────────┤
│ proc│ Ident ; │ Block │ ; │
├─────┴───────────┴───────────────┴────────────┤
│ Statement │
└──────────────────────────────────────────────┘
Statement
┌───────────────────────────────────────────────────────────────────────────────┐
│ ┌───────────┐ ┌─────────┐ ┌─────────┐ ┌────────────┐ │
├──┤ Ident := ├──Expr──┤ call ├─Ident──┤ begin ├─Stmt─(─┤ ; Stmt )─end│ │
│ └───────────┘ └─────────┘ └─────────┘ └────────────┘ │
│ ┌───────────┐ ┌─────────┐ ┌─────────┐ ┌───────────┐ │
├──┤ if ├─Cond──┤ then ├─Stmt──┤ while ├─Cond──┤ do Stmt │ │
│ └───────────┘ └─────────┘ └─────────┘ └───────────┘ │
│ ┌───────────┐ ┌───────────┐ │
└──┤ read ├─Ident─┤ write ├─Expr──┐ │
└───────────┘ └───────────┘ │ │
┌───────────┐ │ │
└─── skip ──┘ │ │
┌───────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────┘
5. 语义规则
作用域规则:
嵌套过程结构(最多3层)
静态作用域(词法作用域)
标识符必须先声明后使用
类型系统:
仅支持整数类型
无类型声明(所有变量默认为整数)
过程调用:
无参数传递
递归调用支持(通过栈实现)
最大调用深度由实现决定
6. PL/0 程序示例
const max = 100;
var n, f;
procedure factorial;
begin
if n <= 1 then
f := 1
else begin
n := n - 1;
call factorial;
n := n + 1;
f := n * f
end
end;
begin
read n;
call factorial;
write f
end.
7. PL/0 语言特性总结
特性 | 支持情况 | 限制 |
---|---|---|
数据类型 | 仅整数 | 无浮点数/字符串 |
控制结构 | if-then, while-do | 无for循环,无switch |
过程 | 支持嵌套过程 | 无参数,无返回值 |
输入输出 | read/write 基本I/O | 仅控制台操作 |
数据结构 | 简单变量 | 无数组/记录结构 |
作用域 | 静态作用域(3层嵌套) | 无全局变量 |
异常处理 | 无 | 运行时错误导致终止 |
PL/0 的设计体现了编译器的核心组成部分:
词法分析(识别标识符/数字/关键字)
语法分析(递归下降法)
语义分析(符号表管理)
代码生成(栈式虚拟机指令)
解释执行(P-code 解释器)
这种精简的设计使其成为学习编译原理的理想教学语言,实际编译器实现通常只需 1000-2000 行代码。
PL/0 语法分析器实现
下面是一个完整的 PL/0 语法分析器实现,使用 JavaScript 构建,包含可视化界面和交互功能。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PL/0 语法分析器</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1e3c72, #2a5298);
color: #f0f0f0;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 25px;
}
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr;
}
}
header {
grid-column: 1 / -1;
text-align: center;
padding: 20px 0;
margin-bottom: 20px;
border-bottom: 2px solid #4cc9f0;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
color: #4cc9f0;
text-shadow: 0 0 10px rgba(76, 201, 240, 0.5);
}
.subtitle {
font-size: 1.2rem;
color: #a1c4fd;
max-width: 800px;
margin: 0 auto;
}
.panel {
background: rgba(30, 30, 46, 0.8);
border-radius: 15px;
padding: 25px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
backd