TL;DR
EBNF (Extended Backus–Naur Form) 是 BNF (Backus–Naur Form) 的扩展,是用来描述例如 HTML、XML 、C# 、Java 等精确的形式语言的语法结构的语言,它可以认为是一种元语言,因为它是描述其它语言的语言。EBNF 对应的标准是 ISO/IEC 14977:1996 。编写的 EBNF 代码通常用来由语法分析器生成器例如 ANTLR 生成由编程语言、工具、框架使用的语法分析器(比如 VS Code 、TypeScript 、Babel 、React 等)。
终端/非终端
编程语言的标识符、关键字、字面量、分隔符、定界符等组成了语句,语句组成函数和方法,方法组成类等。其中像标识符、关键字等不可分的基本元素称为终端,而语句、方法、类等称为非终端。这就像一颗树,其中主干、支干对应于编程语言的类、方法、语句,而叶子就相当于编程语言中的标识符、关键字、字面量、分隔符等。
EBNF 规则:以 ANTLR 为例
不同的编程语言、工具、框架可能对 EBNF 有不同的实现,不过它们大体相同,理解一种特定的 EBNF 实现后可以很快理解其它的实现。
基本结构
这是一条 EBNF 规则,这条 EBNF 规则被 : 分为左手边 (left-hand side, LHS) 和右手边 (right-hand side, RHS) ,并且以 ; 表示这条规则结束。左手边是一个单词,它以大写字母 P 开头说明这是一条词法分析器规则的规则名称。右手边的 '+' 表示匹配字符 + ,显然这条规则定义了 JavaScript 的加号运算符。
Plus: '+';
备选项
此规则定义了 JavaScript 的布尔字面量,表示布尔字面量可以是 true 或 false 。备选项之间使用 | 隔开。
BooleanLiteral: 'true'
| 'false';
顺序与可选项
此规则定义了 JavaScript 的代码块。其中右手边的 '{' 、 statementList? 和 '}' 必须按顺序出现,其中 statementList? 后面的 ? 代表语句列表是可选的。statementList 指引用了这个名称的规则,它是一个非终端语法结构。
block
: '{' statementList? '}'
;
至少一个
+ 代表前面的规则 statement 至少出现一次,还有一个符号 * 代表前面的规则可以匹配零次、一次或多次。这里具体而言代表语句列表至少有一条语句。
statementList
: statement+
;
子规则
在圆括号中的 ',' 和 variableDeclaration 是子规则。* 代表前面的子规则可以匹配零次、一次或多次。 这里是说在 JavaScript 中,变量定义语句可以同时定义多个变量,后续变量定义前面必须有一个 , 符号。在子规则中顺序同样是很重要的。
variableDeclarationList
: varModifier variableDeclaration (',' variableDeclaration)*
;
请继续前进
学无止境,这只是一个开始。学习如何构建语法解析器甚至是编译器、解释器等会让你变的更强大,可以解决更高阶的问题。如果你对 ANTLR 感兴趣,可以访问 ANTLR 官网 学习了解更多内容。