语法表示说明

本文介绍的是一种 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} 表示重复 mn 次;
  • {m,} 表示重复 m 次及以上;
  • {,n} 表示重复 0 到 n 次;

将一系列符号用小括号 ( ) 包括起来表示分组,分组内的符号作为一个整体看待,如 (item ",")+