语法表示说明
本文介绍的是一种 EBNF 的变体,用于描述字符写成的编程语言语法。这个变体将每一个非终结符的产生式都表示成了一个正则表达式,以此来使得语言定义写起来更加精炼。
本变体的格式大量参考了 Rust 的语法描述语言。
非终结符
非终结符由一段由字母、数字或下划线组成的字符串表示,例如 expr
, if_stmt
。其中,字母全大写的字符串,如 IDENT
,表示这个非终结符是一个单词(token)。
终结符
终结符包括字符串、字符范围和正则表达式。其中:
-
字符串由双引号
"
或单引号'
包括,表示等同于内容的字符序列,如"while"
、"y"
、"+="
。 -
字符范围由方括号包括,内部填写包括的字符或字符范围,表示符合要求的任一字符。其中,用短横线
-
连接的两个字符表示字符编码中介于两个字符值之间(含端点)的字符。如[abcde]
(等同于[a-e]
)、[_0-9a-zA-Z]
。以
^
开头的字符范围表示不在范围内的任一字符,如[^abc]
、[^A-Z]
。 -
正则表达式由
regex(
)
包括,内部是正则表达式,如regex(\w+)
、regex(\w+://(\w+\.)+\.com)
字符范围和字符串遵循 C 风格的转义序列,即使用反斜线 \\
后跟随字符组成。如果某个转义序列没有含义,则表示反斜线后的字符本身。
产生式
产生式左侧是非终结符,右侧是一个由终结符和非终结符组成的正则表达式,中间以箭头 ->
连接。一个产生式占一行和之后缩进的所有行,如:
sign -> [+-]
fractional_part -> "." dec_number
my_expression ->
this_is_a_very_long_keyword this_is_a_very_long_expression ";"
当一个非终结符有多个产生式时,右侧的不同产生式用竖线 |
分隔,表示“或”的关系。当产生式过长时,也可另起一行缩进书写。如:
my_keyword -> "fn" | "class"
binary_operator ->
"+" | "-" | "*" | "/"
| "=" | ">" | "<" | ">=" | "<=" | "==" | "!="
和正则表达式相同,可以省略的表达式用问号 ?
修饰,如 "public"? "class" identifier
;
可以重复一次或多次的表达式用加号 +
修饰,如 [0-9a-f]+
;
可以重复零次或多次的表达式用星号 *
修饰,如 [1-9] [0-9]*
;
可以重复指定次数次的表达式后面用大括号括起来数字修饰,其中:
{m}
表示指定重复m
次;{m,n}
表示重复m
到n
次;{m,}
表示重复m
次及以上;{,n}
表示重复 0 到n
次;
将一系列符号用小括号 (
)
包括起来表示分组,分组内的符号作为一个整体看待,如 (item ",")+
。