【EBNF】EBNF:扩展巴克斯-诺尔范式文件格式与实用写法详解
EBNF:扩展巴克斯-诺尔范式文件格式与实用写法详解
一、什么是 EBNF?
Extended Backus-Naur Form (EBNF)是一种形式化的语法,用于指定编程语言或其他形式化语言的结构。它是Backus-Naur形式(BNF)的扩展,最初由John Backus和Peter Naur开发,用于描述Algol编程语言的语法。它主要用于:
- 编程语言的语法描述(如 Pascal、Ada、Java);
- 编译器和解释器的语法规则输入;
- 自然语言/命令式语言语法建模;
- 自定义 DSL(领域特定语言)的构建;
- 配置语法定义与语义分析工具生成器(如 ANTLR、Bison、PEG.js)中的语法规则定义。
相比传统的 BNF,EBNF 引入了更直观、结构化的写法,并支持更丰富的表达形式(如可选、重复、分组等),更便于人类编写与理解。
二、EBNF 文件基本结构
EBNF 文件一般由一组**规则定义(Rule Definitions)**组成,每条规则描述一种语法结构。
基本语法格式如下:
规则名 = 表达式 ;
规则名
是非终结符(由字母或下划线开头)=
表示定义表达式
描述语法结构;
表示定义结束
例如:
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
三、EBNF 核心语法符号说明
符号 | 含义 | 示例 | ||
---|---|---|---|---|
= | 定义规则 | A = B ; | ||
" | 字符串字面量 | "hello" | ||
` | ` | 多选一(或) | `A = “yes” | “no” ;` |
() | 分组 | `A = (“yes” | “no”) “!” ;` | |
[] | 可选(0 或 1 次) | A = ["hello"] "world" ; | ||
{} | 可重复(0 次以上) | A = {"ha"} ; | ||
' ' | 字符字面量(与 " 等价) | 'a' | ||
(* ... *) | 注释 | (* 这是一条注释 *) |
这些符号共同构建了 EBNF 的表达力,使其足以描述复杂的语法结构。
四、EBNF 与 BNF 的区别对比
特性 | BNF | EBNF |
---|---|---|
可选元素 | 不支持 | 使用 [] |
重复结构 | 不支持 | 使用 {} |
分组 | 支持(使用 () ) | 支持 |
注释 | 通常不支持 | 支持 (* ... *) |
可读性 | 稍差 | 更强,可读性好 |
表达力 | 需要辅助符号 | 原生支持多种语法结构 |
因此,在现代语法定义中,EBNF 更被广泛采用,尤其适合人工编写和工具解析。
五、典型应用场景
-
编程语言语法定义
如 W3C 使用 EBNF 描述 XML、HTML 结构;Java 语言规范也采用类似格式定义语法结构。 -
语法分析工具
如 ANTLR、PEG.js 等语法分析生成器,支持 EBNF 风格的语法定义。 -
命令解析与语音建模
在语音识别、指令解析等场景中,EBNF 可用于约束可识别的指令格式。 -
DSL 构建
定义领域专用语言的语法结构,如构建自定义配置文件、规则引擎、机器人指令等。
六、EBNF 实用语法示例
1. 定义整数
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
integer = [ "-" ] digit { digit } ;
支持:123、-456、0
2. 表达式语法定义(加减乘除)
expression = term { ("+" | "-") term } ;
term = factor { ("*" | "/") factor } ;
factor = number | "(" expression ")" ;
number = digit { digit } ;
支持:(1+2)3、5-4/2、(8+9)(7-3)
3. 时间语句定义
hour = "00" | "01" | "02" | ... | "23" ;
minute = "00" | "01" | ... | "59" ;
time = hour ":" minute ;
支持:14:30、00:00、23:59
4. 自然语言命令示例
greeting = "hello" | "hi" | "hey" ;
command = greeting [ "," ] "computer" [ "!" ] ;
支持语句:“hello computer”、“hi, computer!”、“hey computer!”
七、语义映射与工具支持(可选扩展)
虽然 EBNF 本身只定义结构,但在实际工程中,它经常与语义标签、语义动作结合使用,如:
expression = term { ("+" | "-") term } ; (* 加减运算 *)
通过配套的语义分析工具,如 ANTLR、YACC、PEG 语法等,可实现从 EBNF 到 AST(抽象语法树)结构的转换。
常用工具包括:
工具 | 特点 |
---|---|
ANTLR | 支持 Java、C#、Python 等,EBNF 风格,生成解析器 |
YACC/Bison | 用于 C/C++,常配合 Lex |
PEG.js | JS 中基于 PEG 的语法定义 |
EBNF Visualizer | 可视化展示语法树结构,在线工具丰富 |
八、示例
计算器
(* 定义数字 *)
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
number = digit { digit } ;(* 加减乘除表达式 *)
expression = term { ("+" | "-") term } ;
term = factor { ("*" | "/") factor } ;
factor = number | "(" expression ")" ;
支持输入:
3+5
(2+4)*6
10/(5-3)
解析器可据此生成语法树,并进行后续求值、代码生成等处理。
思必驰的XBNF
XBNF文件编写说明:https://www.duiopen.com/docs/ct_XBNF
xbnf文件采用 ebnf 语法作为基础语法,开发者通过编辑该文件用以限定识别范围同时规定输出的语义项格式。
示例如下:
#打开本地APP的指令
$APP_NAME=(我的程序|测试程序|当前程序|当前应用);
$OPEN=(打开|开启|关闭|退出) $APP_NAME;#打电话发短信指令
$CONTACTS=(小老弟 | 大表哥);
$CALL_A=[帮我] (打电话|发短信) 给 $CONTACTS;
$CALL_B=[帮我] 给 $CONTACTS (打电话|发短信);#计时指令
$TIME=[帮我|我要] (开始 | 停止) 计时;#调节指令
$ADJUST_SETTING = (亮度 | 音量);
$ADJUST_A= [帮我|我要] (调低 | 调高) $ADJUST_SETTING;$ADJUST_B= $ADJUST_SETTING [调] (高 | 低) [一点];
$ADJUST_C= (大 | 小)声说话;#查看指令
$SEARCH_ITEM=(天气 | 时间);
$SEARCH=[帮我] 查看 $SEARCH_ITEM;#退出(中止语音)
$EXIT_AI = (滚[开] | 退下 | 拜拜 | 再见);#返回桌面
$RETURN_HOME = [回到 | 返回] (桌面 | 主菜单);$CMD_EXCUTE= ($OPEN | $CALL_A | $CALL_B | $TIME | $ADJUST_A | $ADJUST_B | $ADJUST_C | $SEARCH | $EXIT_AI | $RETURN_HOME);
( \<s\> ( $CMD_EXCUTE ) \<\/s\> )
九、书写规范与建议
- 规则命名统一风格,建议小写加下划线或驼峰;
- 保持模块化,将重复结构定义为独立规则;
- 注释清晰,便于协作与维护;
- 分组优先级明确,用括号明确逻辑;
十、总结
EBNF 作为一种严谨且直观的语法描述语言,其清晰的结构、强大的表达能力、广泛的工具支持,使其在各类语言构建、解析器开发、语义规则建模中广泛应用。
本文带你:
- 了解了 EBNF 的定义与与 BNF 的区别;
- 掌握了核心语法结构与写法;
- 了解了多种实际应用场景;
- 学习了多个实用示例与完整文件案例;
- 掌握了调试与工具支持技巧。
无论你是构建 DSL、写解析器,还是参与语音交互、编译器设计,EBNF 都是你必须掌握的基础工具之一。