33人参与 • 2025-05-12 • rust
在 rust 参考手册中,有大量类似:
句法 macroinvocation : simplepath ! delimtokentree delimtokentree : ( tokentree* ) | [ tokentree* ] | { tokentree* } tokentree : token排除 定界符(delimiters) | delimtokentree macroinvocationsemi : simplepath ! ( tokentree* ) ; | simplepath ! [ tokentree* ] ; | simplepath ! { tokentree* }
这样抽象的玩意儿(宏 - rust 参考手册)。这种阅读体验差的要死的东西,一看就是学术界搞出来的东西,这篇文章就是讲这种东西应该怎么读。
在计算机科学中,当我们描述一种语言(比如编程语言、数据格式或配置文件)的结构时,需要一种精确、无歧义的方式。扩展巴科斯范式 (extended backus-naur form, ebnf) 就是这样一种元语言(描述其他语言的语言)标记法。它通过一系列严格定义的规则,清晰地表达一种语言的语法。
ebnf 源自并扩展了巴科斯范式 (backus-naur form, bnf)。bnf 最初由约翰·巴科斯 (john backus) 和彼得·诺尔 (peter naur) 为描述 algol 60 编程语言的语法而设计。ebnf 在 bnf 的基础上增加了一些方便的符号,使得语法描述更为简洁和易读。
在学习 ebnf 之前,我们需要了解几个基本概念:
表达式
, 语句
, 数字
。在一些传统 bnf 中,非终结符会被尖括号 < >
包围,如 <expression>
,但在现代 ebnf 中,直接使用名称更为常见。if
, while
)、操作符 (+
, -
, *
, /
)、数字字面量 (123
, 3.14
)、字符串字面量 ("hello"
) 等都是终结符。在 ebnf 中,终结符通常用引号 "
或 '
包围,或者直接写出(如果不会引起歧义)。ebnf 通过一些特殊符号来组织规则、非终结符和终结符:
::=
或 =
(定义为):
数字 ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
(或 / 选择):|
分隔的各项是互斥的选项。布尔值 ::= "true" | "false"
“布尔值”可以是 “true” 或者 “false”。赋值语句 ::= 标识符 "=" 表达式
一条“赋值语句”由一个“标识符”,后跟一个等号终结符,再后跟一个“表达式”组成。()
(分组):圆括号用于将一组符号括起来,形成一个逻辑单元。这使得可以将重复、可选等操作符应用于整个组。
示例:函数调用 ::= 函数名 "(" (参数列表)? ")"
这里 (参数列表)?
被括号括起来,表示可选的参数列表部分。
?
(可选 / 零次或一次):
整数 ::= ("+" | "-")? 数字序列
一个“整数”可以有一个可选的正负号,后面跟着一个“数字序列”。*
(重复零次或多次):标识符 ::= 字母 (字母 | 数字)*
一个“标识符”由一个“字母”开头,后面可以跟零个或多个“字母”或“数字”。+
(重复一次或多次):数字序列 ::= 数字+
一个“数字序列”由至少一个“数字”组成。[...]
(可选分组 - 另一种常见表示):[]
来表示一个可选的部分,等同于 (...)?
。参数列表 ::= "[" 参数 ("," 参数)* "]"
(这里假设 [
和 ]
是可选参数列表的定界符) 或者:整数 ::= ["+" | "-"] 数字序列
(等同于上面的 ("+" | "-")?
){...}
(重复分组 - 另一种常见表示):{}
来表示一个可以重复零次或多次的部分,等同于 (...)*
。注释 ::= "/*" {任意字符} "*/"
一个“注释”由 /*
开始,中间可以有零个或多个“任意字符”,并以 */
结束。"if"
, '+'
。(* 这是一个注释 *)
或类似 c 语言的 //
。本教程主要关注语法规则本身。::=
或 =
。|
时,知道这代表多个选项中的一个。*
, +
, ?
(或 []
, {}
) 的含义。()
(以及有时 []
或 {}
) 会将一部分符号视为一个整体。让我们看一些使用 ebnf 定义的例子:
ebnf
邮箱地址 ::= 用户名 "@" 域名 用户名 ::= 字符+ 域名 ::= (子域名 ".")*顶级域名 子域名 ::= 字符+ 顶级域名 ::= 字符+ 字符 ::= 字母 | 数字 | "_" | "-" 字母 ::= "a" | ... | "z" | "a" | ... | "z" // 省略所有字母 数字 ::= "0" | ... | "9" // 省略所有数字
用户名
和 字符
用了 +
表示至少一个。域名
中的 (子域名 ".")*
表示可以有零个或多个由点分隔的子域名。ebnf
表达式 ::= 项 (("+" | "-") 项)* 项 ::= 因子 (("*" | "/") 因子)* 因子 ::= 数字 | "(" 表达式 ")" 数字 ::= ("0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9")+
表达式
和 项
的定义是递归的(因子
中包含 表达式
),这允许嵌套。(("+" | "-") 项)*
表示可以有零个或多个由加号或减号连接的“项”。示例 3:一个简单列表结构
ebnf
列表 ::= "[" [元素 ("," 元素)*] "]" 元素 ::= 标识符 | 数字 标识符 ::= 字母 (字母 | 数字)* // 字母和数字的定义同上
列表
由方括号包围。[元素 ("," 元素)*]
表示方括号内的内容是可选的(因为整个被 []
包裹,这里 []
是 ebnf 的可选符号,而非列表的定界符——为了清晰,我们也可以写成 (元素 ("," 元素)*)?
)。到此这篇关于rust 中的 ebnf 介绍的文章就介绍到这了,更多相关rust 中的 ebnf 介绍内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论