인터넷의 기술적 명세는 형식적인 구문 정의할 때가 많습니다.
Augmented BNF (ABNF)라는 형식으로 구문을 정의할 경우가 많은데,
RFC 5234는 그 ABNF를 정의하는 문서입니다.
규칙은 규칙과 단말 값으로 이루어져 있습니다.
규칙은 결국 터미널 값들로 이루어진 문자열로 해석됩니다.
규칙 이름은 알파벳/숫자/대쉬(-
)로 이루어져 있으며, 알파벳으로 시작합니다.
규칙 이름은 대소문자를 구분하지 않습니다.
원본 BNF와 달리 ABNF에서는 규칙 이름을 꺽쇠 괄호로 묶지 않아도 됩니다.
규칙은 (규칙 이름) = (내용)
형태로 정의됩니다.
두 줄 이상이 되면 두번째 줄부터는 들여쓰기를 해야 합니다.
단말 값, 즉 글자는 0이나 양의 정수입니다. 문맥에 따라 인코딩이 주어질 수 있습니다.
b는 2진수, d는 10진수, x는 16진수를 나타내며 %(밑)(수)
형식으로 나타낼 수 있습니다.
%d48
은 ASCII 48에 해당하는 0
이 되고, %x30
도 0
이 됩니다.
%(밑)(수).(수).(수)
처럼 .
으로 여러개의 단말 값을 구분할 수 있습니다.
예를 들어 %d97.98.99
(abc
)는 %d97 %d98 %d99
와 같습니다.
따옴표로 감싼 문자열 리터럴도 단말 값이 될 수 있지만, 대소문자를 구분하지 않습니다.
단말 값을 나타내는 외부 표현이 있을 수 있지만, ABNF의 범위를 벗어납니다.
규칙 여러개를 띄어쓰기로 구분해서 나열함으로써 연결을 나타낼 수 있습니다.
예를 들어 rule1
과 rule2
를 연결하려면 rule1 rule2
로 쓰면 됩니다.
foo = %x61
bar = %x62
mumble = foo bar foo
역사적으로 사이에 암시적으로 공백을 허용하기도 했지만, ABNF는 이에 대해 명세하지 않습니다.
사이에 공백을 허용하려면 반드시 이를 명시해야 합니다.
여러가지 중 하나가 될 수 있는 경우 슬래시로 구분해서 표현할 수 있습니다.
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 d
는 a (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
로 나타낼 수도 있지만, 대괄호로 감싸서 나타낼 수도 있습니다.
세미콜론(;
)부터 그 줄의 끝까지는 주석이 됩니다.
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 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