개요

인터넷의 기술적 명세는 형식적인 구문 정의할 때가 많습니다.

Augmented BNF (ABNF)라는 형식으로 구문을 정의할 경우가 많은데,

RFC 5234는 그 ABNF를 정의하는 문서입니다.

규칙

규칙은 규칙과 단말 값으로 이루어져 있습니다.

규칙은 결국 터미널 값들로 이루어진 문자열로 해석됩니다.

규칙 이름

규칙 이름은 알파벳/숫자/대쉬(-)로 이루어져 있으며, 알파벳으로 시작합니다.

규칙 이름은 대소문자를 구분하지 않습니다.

원본 BNF와 달리 ABNF에서는 규칙 이름을 꺽쇠 괄호로 묶지 않아도 됩니다.

규칙 형식

규칙은 (규칙 이름) = (내용) 형태로 정의됩니다.

두 줄 이상이 되면 두번째 줄부터는 들여쓰기를 해야 합니다.

단말 값

단말 값, 즉 글자는 0이나 양의 정수입니다. 문맥에 따라 인코딩이 주어질 수 있습니다.

b는 2진수, d는 10진수, x는 16진수를 나타내며 %(밑)(수) 형식으로 나타낼 수 있습니다.

%d48은 ASCII 48에 해당하는 0이 되고, %x300이 됩니다.

%(밑)(수).(수).(수)처럼 .으로 여러개의 단말 값을 구분할 수 있습니다.

예를 들어 %d97.98.99 (abc)는 %d97 %d98 %d99와 같습니다.

따옴표로 감싼 문자열 리터럴도 단말 값이 될 수 있지만, 대소문자를 구분하지 않습니다.

외부 표

단말 값을 나타내는 외부 표현이 있을 수 있지만, ABNF의 범위를 벗어납니다.

연산자

연결

규칙 여러개를 띄어쓰기로 구분해서 나열함으로써 연결을 나타낼 수 있습니다.

예를 들어 rule1rule2를 연결하려면 rule1 rule2로 쓰면 됩니다.

foo    = %x61
bar    = %x62
mumble = foo bar foo

역사적으로 사이에 암시적으로 공백을 허용하기도 했지만, ABNF는 이에 대해 명세하지 않습니다.

사이에 공백을 허용하려면 반드시 이를 명시해야 합니다.

OR (Alternatives)

여러가지 중 하나가 될 수 있는 경우 슬래시로 구분해서 표현할 수 있습니다.

foo-or-bar = foo / bar

또는, 여러 줄로 표현하는 경우 =/로 기존 규칙에 선택지를 추가할 수 있습니다.

my-rule =  rule1 / rule2
my-rule =/ rule3
my-rule =/ rule4 / rule5

; 위 규칙은 아래처럼 나타낼 수도 있습니다.

my-rule = rule1 / rule2 / rule3 / rule4 / rule5

연산자 우선순위는 /가 ``(연결)보다 낮습니다.

값 범위

단말 값에 대쉬(-)를 사용해 값의 범위를 나타낼 수 있습니다.

DIGIT = %x30-3

; 위 규칙은 아래처럼 나타낼 수도 있습니다.

DIGIT = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"

그룹

여러개를 하나로 감싸 하나인 것처럼 만들 수 있습니다.

a b / c da (b / c) d가 아닌 (a b) / (c d)가 되는데, 이런 경우 괄호를 쓰는 것이 좋습니다.

반복

앞에 (최소 반복 횟수)*(최대 반복 횟수)를 붙여 반복을 나타낼 수 있습니다.

최소 반복 횟수와 최대 반복 횟수는 생략할 수 있고, 기본값은 각각 0, 무한입니다.

최소 반복 횟수가 최대 반복 횟수가 같은 경우 (수)*(수)(수)로 쓸 수 있습니다.

any-number-of-foo = *foo
one-or-more-foo   = 1*foo
one-or-two-foo    = 1*2foo
optional-foo      = *1foo
three-foo         = 3foo

선택적

선택적이라는 것을 *1로 나타낼 수도 있지만, 대괄호로 감싸서 나타낼 수도 있습니다.

주석

세미콜론(;)부터 그 줄의 끝까지는 주석이 됩니다.

ABNF로 나타낸 ABNF

rulelist = 1*( rule / (*c-wsp c-nl) )

rule = rulename defined-as elements c-nl
    ; continues if next line starts
    ; with white space

rulename = ALPHA *(ALPHA / DIGIT / "-")

defined-as = *c-wsp ("=" / "=/") *c-wsp
    ; basic rules definition and
    ; incremental alternatives

elements = alternation *c-wsp

c-wsp = WSP / (c-nl WSP)

c-nl = comment / CRLF
    ; comment or newline

comment = ";" *(WSP / VCHAR) CRLF

alternation = concatenation
    *(*c-wsp "/" *c-wsp concatenation)

concatenation = repetition *(1*c-wsp repetition)

repetition = [repeat] element

repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)

element = rulename / group / option /
    char-val / num-val / prose-val

group = "(" *c-wsp alternation *c-wsp ")"

option = "[" *c-wsp alternation *c-wsp "]"

char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
    ; quoted string of SP and VCHAR
    ; without DQUOTE

num-val = "%" (bin-val / dec-val / hex-val)

bin-val = "b" 1*BIT
    [ 1*("." 1*BIT) / ("-" 1*BIT) ]
    ; series of concatenated bit values
    ; or single ONEOF range

dec-val = "d" 1*DIGIT
    [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]

hex-val = "x" 1*HEXDIG
    [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]

prose-val = "<" *(%x20-3D / %x3F-7E) ">"
    ; bracketed string of SP and VCHAR
    ; without angles
    ; prose description, to be used as
    ; last resort

RFC 7405

지금까지의 내용은 RFC 5234에 대한 내용이었습니다.

RFC 7405에서는 RFC 5234에서 추가로 대소문자를 구분하는 문자열 리터럴을 추가합니다.

대소문자를 구분하지 않는 문자열은 %i를, 구분하는 문자열은 %s를 붙일 수 있습니다.

예를 들어 %s"abc"는 대소문자를 구분하는 abc를 나타내는 문자열 리터럴입니다.

이 변경사항은 ABNF로 나타낸 ABNF에도 약간의 영향을 줍니다.

char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE

; 위: 기존 char-val, 아래: 새 char-val

char-val = case-insensitive-string /
    case-sensitive-string

case-insensitive-string =
    [ "%i" ] quoted-string

case-sensitive-string =
    "%s" quoted-string

quoted-string = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
    ; quoted string of SP and VCHAR
    ; without DQUOTE