mirror of
https://github.com/valitydev/abnfc.git
synced 2024-11-06 02:35:20 +00:00
Initial import
This commit is contained in:
commit
9446a8cea0
10
Makefile
Executable file
10
Makefile
Executable file
@ -0,0 +1,10 @@
|
||||
SUBDIRS=src \
|
||||
samples/abnf \
|
||||
# samples/sdp \
|
||||
# samples/sip
|
||||
|
||||
include ./subdir.mk
|
||||
include ./vsn.mk
|
||||
|
||||
APPNAME=abnf
|
||||
DOC_OPTS=[{def,{vsn,"$(ABNF_VSN)"}}]
|
39
bin/abnfc
Executable file
39
bin/abnfc
Executable file
@ -0,0 +1,39 @@
|
||||
#!/usr/local/bin/escript
|
||||
%% -*- erlang -*-
|
||||
|
||||
main(["?"]) ->
|
||||
usage();
|
||||
main([File]) ->
|
||||
do_it(File,[]);
|
||||
main(Args) ->
|
||||
try parse_args(Args) of
|
||||
{File, Opts} ->
|
||||
do_it(File,Opts)
|
||||
catch
|
||||
_:_ ->
|
||||
usage()
|
||||
end.
|
||||
|
||||
do_it(File, Opts) ->
|
||||
ScriptDir = filename:dirname(escript:script_name()),
|
||||
EBIN = filename:join([ScriptDir,"../ebin"]),
|
||||
code:add_patha(EBIN),
|
||||
R = abnfc:file(File, Opts),
|
||||
io:format("~p~n",[R]).
|
||||
|
||||
usage() ->
|
||||
io:format("~s~n",["Usage: abnfc [-o OutDir] [-I InclDir] [-mod Module] File"]).
|
||||
|
||||
parse_args(Args) ->
|
||||
parse_args(Args, []).
|
||||
|
||||
parse_args(["-o", OutDir|More], Acc) ->
|
||||
parse_args(More, [{o,OutDir}|Acc]);
|
||||
parse_args(["-mod",Mod|More], Acc) ->
|
||||
parse_args(More, [{mod,Mod}|Acc]);
|
||||
parse_args(["-noobj"|More], Acc) ->
|
||||
parse_args(More, [noobj|Acc]);
|
||||
parse_args(["-I",IncludeDir|More], Acc) ->
|
||||
parse_args(More, [{i,IncludeDir}|Acc]);
|
||||
parse_args([File], Acc) ->
|
||||
{File, lists:reverse(Acc)}.
|
58
include.mk
Normal file
58
include.mk
Normal file
@ -0,0 +1,58 @@
|
||||
## -*- makefile -*-
|
||||
|
||||
######################################################################
|
||||
## Erlang
|
||||
|
||||
ERL := /usr/local/bin/erl
|
||||
ERLC := /usr/local/bin/erlc
|
||||
ABNFC := ../../bin/abnfc
|
||||
|
||||
ERLDIR := /usr/local/lib/erlang
|
||||
ERL_C_INCLUDE_DIR := $(ERLDIR)/usr/include
|
||||
|
||||
ERLC_FLAGS := -W -I ../include
|
||||
|
||||
ifndef no_debug_info
|
||||
ERLC_FLAGS += +debug_info
|
||||
endif
|
||||
|
||||
ifdef debug
|
||||
ERLC_FLAGS += -Ddebug
|
||||
endif
|
||||
|
||||
EBIN_DIR := ../ebin
|
||||
DOC_DIR := ../doc
|
||||
EMULATOR := beam
|
||||
|
||||
ERL_SOURCES := $(wildcard *.erl)
|
||||
ERL_HEADERS := $(wildcard *.hrl) $(wildcard ../include/*.hrl)
|
||||
ERL_OBJECTS := $(ERL_SOURCES:%.erl=$(EBIN_DIR)/%.$(EMULATOR))
|
||||
ERL_DOCUMENTS := $(ERL_SOURCES:%.erl=$(DOC_DIR)/%.html)
|
||||
MODULES = $(ERL_SOURCES:%.erl=%)
|
||||
|
||||
# Hmm, don't know if you are supposed to like this better... ;-)
|
||||
APPSCRIPT = '$$vsn=shift; $$mods=""; while(@ARGV){ $$_=shift; s/^([A-Z].*)$$/\'\''$$1\'\''/; $$mods.=", " if $$mods; $$mods .= $$_; } while(<>) { s/%VSN%/$$vsn/; s/%MODULES%/$$mods/; print; }'
|
||||
|
||||
|
||||
../ebin/%.app: %.app.src ../vsn.mk Makefile
|
||||
perl -e $(APPSCRIPT) "$(VSN)" $(MODULES) < $< > $@
|
||||
|
||||
../ebin/%.appup: %.appup
|
||||
cp $< $@
|
||||
|
||||
|
||||
$(EBIN_DIR)/%.$(EMULATOR): %.erl
|
||||
$(ERLC) $(ERLC_FLAGS) -o $(EBIN_DIR) $<
|
||||
|
||||
$(EBIN_DIR)/%.$(EMULATOR): %.abnf
|
||||
$(ABNFC) -o $(EBIN_DIR) $<
|
||||
|
||||
|
||||
# generate documentation with edoc:
|
||||
# this is still not the proper way to do it, but it works
|
||||
# (see the wumpus application for an example)
|
||||
|
||||
$(DOC_DIR)/%.html: %.erl
|
||||
${ERL} -noshell \
|
||||
-run edoc file $< -run init stop
|
||||
mv *.html $(DOC_DIR)
|
19
include/abnfc_ast.hrl
Normal file
19
include/abnfc_ast.hrl
Normal file
@ -0,0 +1,19 @@
|
||||
-record(rulelist, {mod, rules=[]}).
|
||||
|
||||
-record(rule, {type, name, body, code}).
|
||||
|
||||
-record(rulename, {name}).
|
||||
|
||||
-record(alt, {alts=[]}).
|
||||
|
||||
-record(seq, {elements=[]}).
|
||||
|
||||
-record(repeat, {min=0, max=infinity, body}).
|
||||
|
||||
-record(char_range, {from, to}).
|
||||
|
||||
-record(char_alt, {alts=[]}).
|
||||
|
||||
-record(char_seq, {elements=[]}).
|
||||
|
||||
-record(char_val, {value=[]}).
|
31
samples/Makefile
Executable file
31
samples/Makefile
Executable file
@ -0,0 +1,31 @@
|
||||
LIBS := rfc1035 \
|
||||
rfc2806 \
|
||||
rfc3325 \
|
||||
sdp \
|
||||
sip \
|
||||
uri
|
||||
# http_1_1
|
||||
|
||||
all: $(LIBS)
|
||||
|
||||
docs:
|
||||
@for dir in $(LIBS); do \
|
||||
if [ ! -f $@/SKIP ]; then \
|
||||
(cd $$dir; $(MAKE) $@) \
|
||||
fi \
|
||||
done
|
||||
|
||||
clean:
|
||||
@for dir in $(LIBS); do \
|
||||
if [ ! -f $@/SKIP ]; then \
|
||||
(cd $$dir; $(MAKE) $@) \
|
||||
fi \
|
||||
done
|
||||
|
||||
$(LIBS):
|
||||
@if [ ! -f $@/SKIP ]; then \
|
||||
(cd $@; $(MAKE) all) \
|
||||
fi
|
||||
|
||||
.PHONY: $(LIBS)
|
||||
|
2
samples/http_1_1/README
Normal file
2
samples/http_1_1/README
Normal file
@ -0,0 +1,2 @@
|
||||
RFC 2616 uses an older variant of ABNF that is not yet supported by
|
||||
ABNFC.
|
509
samples/http_1_1/rfc2616.abnf
Normal file
509
samples/http_1_1/rfc2616.abnf
Normal file
@ -0,0 +1,509 @@
|
||||
;;;=====================================================================
|
||||
;;; ABNF for HTTP 1.1, according to RFC 2616.
|
||||
;;; See http://tools.ietf.org/html/rfc2616
|
||||
;;; Note: that this file contains a non standard ABNF notation.
|
||||
;;;=====================================================================
|
||||
;
|
||||
; OCTET = <any 8-bit sequence of data>
|
||||
; CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
; UPALPHA = <any US-ASCII uppercase letter "A".."Z">
|
||||
; LOALPHA = <any US-ASCII lowercase letter "a".."z">
|
||||
; ALPHA = UPALPHA | LOALPHA
|
||||
; DIGIT = <any US-ASCII digit "0".."9">
|
||||
; CTL = <any US-ASCII control character
|
||||
; (octets 0 - 31) and DEL (127)>
|
||||
; CR = <US-ASCII CR, carriage return (13)>
|
||||
; LF = <US-ASCII LF, linefeed (10)>
|
||||
; SP = <US-ASCII SP, space (32)>
|
||||
; HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
; <"> = <US-ASCII double-quote mark (34)>
|
||||
|
||||
CRLF = CR LF
|
||||
|
||||
LWS = [CRLF] 1*( SP | HT )
|
||||
|
||||
TEXT = <any OCTET except CTLs, but including LWS>
|
||||
|
||||
HEX = "A" | "B" | "C" | "D" | "E" | "F"
|
||||
| "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
|
||||
|
||||
token = 1*<any CHAR except CTLs or separators>
|
||||
|
||||
separators = "(" | ")" | "<" | ">" | "@"
|
||||
| "," | ";" | ":" | "\" | <">
|
||||
| "/" | "[" | "]" | "?" | "="
|
||||
| "{" | "}" | SP | HT
|
||||
|
||||
comment = "(" *( ctext | quoted-pair | comment ) ")"
|
||||
|
||||
ctext = <any TEXT excluding "(" and ")">
|
||||
|
||||
quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
|
||||
|
||||
qdtext = <any TEXT except <">>
|
||||
|
||||
quoted-pair = "\" CHAR
|
||||
|
||||
|
||||
HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
|
||||
|
||||
http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
|
||||
|
||||
HTTP-date = rfc1123-date | rfc850-date | asctime-date
|
||||
|
||||
rfc1123-date = wkday "," SP date1 SP time SP "GMT"
|
||||
|
||||
rfc850-date = weekday "," SP date2 SP time SP "GMT"
|
||||
|
||||
asctime-date = wkday SP date3 SP time SP 4DIGIT
|
||||
|
||||
date1 = 2DIGIT SP month SP 4DIGIT
|
||||
; day month year (e.g., 02 Jun 1982)
|
||||
|
||||
date2 = 2DIGIT "-" month "-" 2DIGIT
|
||||
; day-month-year (e.g., 02-Jun-82)
|
||||
|
||||
date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
|
||||
; month day (e.g., Jun 2)
|
||||
|
||||
time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
|
||||
; 00:00:00 - 23:59:59
|
||||
|
||||
wkday = "Mon" | "Tue" | "Wed"
|
||||
| "Thu" | "Fri" | "Sat" | "Sun"
|
||||
|
||||
weekday = "Monday" | "Tuesday" | "Wednesday"
|
||||
| "Thursday" | "Friday" | "Saturday" | "Sunday"
|
||||
|
||||
month = "Jan" | "Feb" | "Mar" | "Apr"
|
||||
| "May" | "Jun" | "Jul" | "Aug"
|
||||
| "Sep" | "Oct" | "Nov" | "Dec"
|
||||
|
||||
delta-seconds = 1*DIGIT
|
||||
|
||||
charset = token
|
||||
|
||||
content-coding = token
|
||||
|
||||
transfer-coding = "chunked" | transfer-extension
|
||||
|
||||
transfer-extension = token *( ";" parameter )
|
||||
|
||||
parameter = attribute "=" value
|
||||
|
||||
attribute = token
|
||||
|
||||
value = token | quoted-string
|
||||
|
||||
Chunked-Body = *chunk
|
||||
last-chunk
|
||||
trailer
|
||||
CRLF
|
||||
|
||||
chunk = chunk-size [ chunk-extension ] CRLF chunk-data CRLF
|
||||
|
||||
chunk-size = 1*HEX
|
||||
|
||||
last-chunk = 1*("0") [ chunk-extension ] CRLF
|
||||
|
||||
chunk-extension = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
|
||||
|
||||
chunk-ext-name = token
|
||||
|
||||
chunk-ext-val = token | quoted-string
|
||||
|
||||
chunk-data = chunk-size(OCTET)
|
||||
|
||||
trailer = *(entity-header CRLF)
|
||||
|
||||
media-type = type "/" subtype *( ";" parameter )
|
||||
|
||||
type = token
|
||||
|
||||
subtype = token
|
||||
|
||||
product = token ["/" product-version]
|
||||
|
||||
product-version = token
|
||||
|
||||
qvalue = ( "0" [ "." 0*3DIGIT ] )
|
||||
| ( "1" [ "." 0*3("0") ] )
|
||||
|
||||
|
||||
language-tag = primary-tag *( "-" subtag )
|
||||
|
||||
primary-tag = 1*8ALPHA
|
||||
|
||||
subtag = 1*8ALPHA
|
||||
|
||||
entity-tag = [ weak ] opaque-tag
|
||||
|
||||
weak = "W/"
|
||||
|
||||
opaque-tag = quoted-string
|
||||
|
||||
range-unit = bytes-unit | other-range-unit
|
||||
|
||||
bytes-unit = "bytes"
|
||||
|
||||
other-range-unit = token
|
||||
|
||||
HTTP-message = Request | Response ; HTTP/1.1 messages
|
||||
|
||||
generic-message = start-line
|
||||
*(message-header CRLF)
|
||||
CRLF
|
||||
[ message-body ]
|
||||
|
||||
start-line = Request-Line | Status-Line
|
||||
|
||||
message-header = field-name ":" [ field-value ]
|
||||
|
||||
field-name = token
|
||||
|
||||
field-value = *( field-content | LWS )
|
||||
|
||||
field-content = <the OCTETs making up the field-value
|
||||
and consisting of either *TEXT or combinations
|
||||
of token, separators, and quoted-string>
|
||||
|
||||
message-body = entity-body
|
||||
| <entity-body encoded as per Transfer-Encoding>
|
||||
|
||||
general-header = Cache-Control ; Section 14.9
|
||||
| Connection ; Section 14.10
|
||||
| Date ; Section 14.18
|
||||
| Pragma ; Section 14.32
|
||||
| Trailer ; Section 14.40
|
||||
| Transfer-Encoding ; Section 14.41
|
||||
| Upgrade ; Section 14.42
|
||||
| Via ; Section 14.45
|
||||
| Warning ; Section 14.46
|
||||
|
||||
Request = Request-Line ; Section 5.1
|
||||
*(( general-header ; Section 4.5
|
||||
| request-header ; Section 5.3
|
||||
| entity-header ) CRLF) ; Section 7.1
|
||||
CRLF
|
||||
[ message-body ] ; Section 4.3
|
||||
|
||||
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
|
||||
|
||||
Method = "OPTIONS" ; Section 9.2
|
||||
| "GET" ; Section 9.3
|
||||
| "HEAD" ; Section 9.4
|
||||
| "POST" ; Section 9.5
|
||||
| "PUT" ; Section 9.6
|
||||
| "DELETE" ; Section 9.7
|
||||
| "TRACE" ; Section 9.8
|
||||
| "CONNECT" ; Section 9.9
|
||||
| extension-method
|
||||
|
||||
extension-method = token
|
||||
|
||||
Request-URI = "*" | absoluteURI | abs_path | authority
|
||||
|
||||
request-header = Accept ; Section 14.1
|
||||
| Accept-Charset ; Section 14.2
|
||||
| Accept-Encoding ; Section 14.3
|
||||
| Accept-Language ; Section 14.4
|
||||
| Authorization ; Section 14.8
|
||||
| Expect ; Section 14.20
|
||||
| From ; Section 14.22
|
||||
| Host ; Section 14.23
|
||||
| If-Match ; Section 14.24
|
||||
| If-Modified-Since ; Section 14.25
|
||||
| If-None-Match ; Section 14.26
|
||||
| If-Range ; Section 14.27
|
||||
| If-Unmodified-Since ; Section 14.28
|
||||
| Max-Forwards ; Section 14.31
|
||||
| Proxy-Authorization ; Section 14.34
|
||||
| Range ; Section 14.35
|
||||
| Referer ; Section 14.36
|
||||
| TE ; Section 14.39
|
||||
| User-Agent ; Section 14.43
|
||||
|
||||
Response = Status-Line ; Section 6.1
|
||||
*(( general-header ; Section 4.5
|
||||
| response-header ; Section 6.2
|
||||
| entity-header ) CRLF) ; Section 7.1
|
||||
CRLF
|
||||
[ message-body ] ; Section 7.2
|
||||
|
||||
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
|
||||
|
||||
Status-Code = "100" ; Section 10.1.1: Continue
|
||||
| "101" ; Section 10.1.2: Switching Protocols
|
||||
| "200" ; Section 10.2.1: OK
|
||||
| "201" ; Section 10.2.2: Created
|
||||
| "202" ; Section 10.2.3: Accepted
|
||||
| "203" ; Section 10.2.4: Non-Authoritative Information
|
||||
| "204" ; Section 10.2.5: No Content
|
||||
| "205" ; Section 10.2.6: Reset Content
|
||||
| "206" ; Section 10.2.7: Partial Content
|
||||
| "300" ; Section 10.3.1: Multiple Choices
|
||||
| "301" ; Section 10.3.2: Moved Permanently
|
||||
| "302" ; Section 10.3.3: Found
|
||||
| "303" ; Section 10.3.4: See Other
|
||||
| "304" ; Section 10.3.5: Not Modified
|
||||
| "305" ; Section 10.3.6: Use Proxy
|
||||
| "307" ; Section 10.3.8: Temporary Redirect
|
||||
| "400" ; Section 10.4.1: Bad Request
|
||||
| "401" ; Section 10.4.2: Unauthorized
|
||||
| "402" ; Section 10.4.3: Payment Required
|
||||
| "403" ; Section 10.4.4: Forbidden
|
||||
| "404" ; Section 10.4.5: Not Found
|
||||
| "405" ; Section 10.4.6: Method Not Allowed
|
||||
| "406" ; Section 10.4.7: Not Acceptable
|
||||
| "407" ; Section 10.4.8: Proxy Authentication Required
|
||||
| "408" ; Section 10.4.9: Request Time-out
|
||||
| "409" ; Section 10.4.10: Conflict
|
||||
| "410" ; Section 10.4.11: Gone
|
||||
| "411" ; Section 10.4.12: Length Required
|
||||
| "412" ; Section 10.4.13: Precondition Failed
|
||||
| "413" ; Section 10.4.14: Request Entity Too Large
|
||||
| "414" ; Section 10.4.15: Request-URI Too Large
|
||||
| "415" ; Section 10.4.16: Unsupported Media Type
|
||||
| "416" ; Section 10.4.17: Requested range not satisfiable
|
||||
| "417" ; Section 10.4.18: Expectation Failed
|
||||
| "500" ; Section 10.5.1: Internal Server Error
|
||||
| "501" ; Section 10.5.2: Not Implemented
|
||||
| "502" ; Section 10.5.3: Bad Gateway
|
||||
| "503" ; Section 10.5.4: Service Unavailable
|
||||
| "504" ; Section 10.5.5: Gateway Time-out
|
||||
| "505" ; Section 10.5.6: HTTP Version not supported
|
||||
| extension-code
|
||||
|
||||
extension-code = 3DIGIT
|
||||
|
||||
Reason-Phrase = *<TEXT, excluding CR, LF>
|
||||
|
||||
response-header = Accept-Ranges ; Section 14.5
|
||||
| Age ; Section 14.6
|
||||
| ETag ; Section 14.19
|
||||
| Location ; Section 14.30
|
||||
| Proxy-Authenticate ; Section 14.33
|
||||
| Retry-After ; Section 14.37
|
||||
| Server ; Section 14.38
|
||||
| Vary ; Section 14.44
|
||||
| WWW-Authenticate ; Section 14.47
|
||||
|
||||
entity-header = Allow ; Section 14.7
|
||||
| Content-Encoding ; Section 14.11
|
||||
| Content-Language ; Section 14.12
|
||||
| Content-Length ; Section 14.13
|
||||
| Content-Location ; Section 14.14
|
||||
| Content-MD5 ; Section 14.15
|
||||
| Content-Range ; Section 14.16
|
||||
| Content-Type ; Section 14.17
|
||||
| Expires ; Section 14.21
|
||||
| Last-Modified ; Section 14.29
|
||||
| extension-header
|
||||
|
||||
extension-header = message-header
|
||||
|
||||
entity-body = *OCTET
|
||||
|
||||
|
||||
|
||||
Accept = "Accept" ":" #( media-range [ accept-params ] )
|
||||
|
||||
media-range = ( "*/*" | ( type "/" "*" ) | ( type "/" subtype ))
|
||||
*( ";" parameter )
|
||||
|
||||
accept-params = ";" "q" "=" qvalue *( accept-extension )
|
||||
|
||||
accept-extension = ";" token [ "=" ( token | quoted-string ) ]
|
||||
|
||||
Accept-Charset = "Accept-Charset" ":" 1#( ( charset | "*" )
|
||||
[ ";" "q" "=" qvalue ] )
|
||||
|
||||
Accept-Encoding = "Accept-Encoding" ":"
|
||||
1#( codings [ ";" "q" "=" qvalue ] )
|
||||
|
||||
codings = ( content-coding | "*" )
|
||||
|
||||
Accept-Language = "Accept-Language" ":"
|
||||
1#( language-range [ ";" "q" "=" qvalue ] )
|
||||
language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
|
||||
|
||||
Accept-Ranges = "Accept-Ranges" ":" acceptable-ranges
|
||||
|
||||
acceptable-ranges = 1#range-unit | "none"
|
||||
|
||||
Age = "Age" ":" age-value
|
||||
age-value = delta-seconds
|
||||
|
||||
Allow = "Allow" ":" #Method
|
||||
|
||||
Authorization = "Authorization" ":" credentials
|
||||
|
||||
Cache-Control = "Cache-Control" ":" 1#cache-directive
|
||||
|
||||
cache-directive = cache-request-directive | cache-response-directive
|
||||
|
||||
cache-request-directive =
|
||||
"no-cache" ; Section 14.9.1
|
||||
| "no-store" ; Section 14.9.2
|
||||
| "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
|
||||
| "max-stale" [ "=" delta-seconds ]; Section 14.9.3
|
||||
| "min-fresh" "=" delta-seconds ; Section 14.9.3
|
||||
| "no-transform" ; Section 14.9.5
|
||||
| "only-if-cached" ; Section 14.9.4
|
||||
| cache-extension ; Section 14.9.6
|
||||
|
||||
cache-response-directive =
|
||||
"public" ; Section 14.9.1
|
||||
| "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
|
||||
| "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
|
||||
| "no-store" ; Section 14.9.2
|
||||
| "no-transform" ; Section 14.9.5
|
||||
| "must-revalidate" ; Section 14.9.4
|
||||
| "proxy-revalidate" ; Section 14.9.4
|
||||
| "max-age" "=" delta-seconds ; Section 14.9.3
|
||||
| "s-maxage" "=" delta-seconds ; Section 14.9.3
|
||||
| cache-extension ; Section 14.9.6
|
||||
|
||||
cache-extension = token [ "=" ( token | quoted-string ) ]
|
||||
|
||||
Connection = "Connection" ":" 1#(connection-token)
|
||||
|
||||
connection-token = token
|
||||
|
||||
Content-Encoding = "Content-Encoding" ":" 1#content-coding
|
||||
|
||||
Content-Language = "Content-Language" ":" 1#language-tag
|
||||
|
||||
Content-Length = "Content-Length" ":" 1*DIGIT
|
||||
|
||||
Content-Location = "Content-Location" ":" ( absoluteURI | relativeURI )
|
||||
|
||||
Content-MD5 = "Content-MD5" ":" md5-digest
|
||||
|
||||
md5-digest = <base64 of 128 bit MD5 digest as per RFC 1864>
|
||||
|
||||
Content-Range = "Content-Range" ":" content-range-spec
|
||||
|
||||
content-range-spec = byte-content-range-spec
|
||||
|
||||
byte-content-range-spec = bytes-unit SP byte-range-resp-spec "/"
|
||||
( instance-length | "*" )
|
||||
|
||||
byte-range-resp-spec = (first-byte-pos "-" last-byte-pos) | "*"
|
||||
|
||||
instance-length = 1*DIGIT
|
||||
|
||||
Content-Type = "Content-Type" ":" media-type
|
||||
|
||||
Date = "Date" ":" HTTP-date
|
||||
|
||||
ETag = "ETag" ":" entity-tag
|
||||
|
||||
Expect = "Expect" ":" 1#expectation
|
||||
|
||||
expectation = "100-continue" | expectation-extension
|
||||
|
||||
expectation-extension = token [ "=" ( token | quoted-string )
|
||||
*expect-params ]
|
||||
|
||||
expect-params = ";" token [ "=" ( token | quoted-string ) ]
|
||||
|
||||
Expires = "Expires" ":" HTTP-date
|
||||
|
||||
From = "From" ":" mailbox
|
||||
|
||||
Host = "Host" ":" host [ ":" port ] ; Section 3.2.2
|
||||
|
||||
If-Match = "If-Match" ":" ( "*" | 1#entity-tag )
|
||||
|
||||
If-Modified-Since = "If-Modified-Since" ":" HTTP-date
|
||||
|
||||
If-None-Match = "If-None-Match" ":" ( "*" | 1#entity-tag )
|
||||
|
||||
If-Range = "If-Range" ":" ( entity-tag | HTTP-date )
|
||||
|
||||
If-Unmodified-Since = "If-Unmodified-Since" ":" HTTP-date
|
||||
|
||||
Last-Modified = "Last-Modified" ":" HTTP-date
|
||||
|
||||
Location = "Location" ":" absoluteURI
|
||||
|
||||
Max-Forwards = "Max-Forwards" ":" 1*DIGIT
|
||||
|
||||
Pragma = "Pragma" ":" 1#pragma-directive
|
||||
|
||||
pragma-directive = "no-cache" | extension-pragma
|
||||
|
||||
extension-pragma = token [ "=" ( token | quoted-string ) ]
|
||||
|
||||
Proxy-Authenticate = "Proxy-Authenticate" ":" 1#challenge
|
||||
|
||||
Proxy-Authorization = "Proxy-Authorization" ":" credentials
|
||||
|
||||
ranges-specifier = byte-ranges-specifier
|
||||
|
||||
byte-ranges-specifier = bytes-unit "=" byte-range-set
|
||||
|
||||
byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
|
||||
|
||||
byte-range-spec = first-byte-pos "-" [last-byte-pos]
|
||||
|
||||
first-byte-pos = 1*DIGIT
|
||||
|
||||
last-byte-pos = 1*DIGIT
|
||||
|
||||
suffix-byte-range-spec = "-" suffix-length
|
||||
|
||||
suffix-length = 1*DIGIT
|
||||
|
||||
Range = "Range" ":" ranges-specifier
|
||||
|
||||
Referer = "Referer" ":" ( absoluteURI | relativeURI )
|
||||
|
||||
Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
|
||||
|
||||
Server = "Server" ":" 1*( product | comment )
|
||||
|
||||
TE = "TE" ":" #( t-codings )
|
||||
|
||||
t-codings = "trailers"
|
||||
| ( transfer-extension [ accept-params ] )
|
||||
|
||||
Trailer = "Trailer" ":" 1#field-name
|
||||
|
||||
Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
|
||||
|
||||
Upgrade = "Upgrade" ":" 1#product
|
||||
|
||||
User-Agent = "User-Agent" ":" 1*( product | comment )
|
||||
|
||||
Vary = "Vary" ":" ( "*" | 1#field-name )
|
||||
|
||||
Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
|
||||
|
||||
received-protocol = [ protocol-name "/" ] protocol-version
|
||||
|
||||
protocol-name = token
|
||||
|
||||
protocol-version = token
|
||||
|
||||
received-by = ( host [ ":" port ] ) | pseudonym
|
||||
|
||||
pseudonym = token
|
||||
|
||||
Warning = "Warning" ":" 1#warning-value
|
||||
|
||||
warning-value = warn-code SP warn-agent SP warn-text [SP warn-date]
|
||||
|
||||
warn-code = 3DIGIT
|
||||
|
||||
warn-agent = ( host [ ":" port ] ) | pseudonym
|
||||
; the name or pseudonym of the server adding
|
||||
; the Warning header, for use in debugging
|
||||
|
||||
warn-text = quoted-string
|
||||
|
||||
warn-date = <"> HTTP-date <">
|
||||
|
||||
WWW-Authenticate = "WWW-Authenticate" ":" 1#challenge
|
||||
|
12
samples/rfc1035/Makefile
Executable file
12
samples/rfc1035/Makefile
Executable file
@ -0,0 +1,12 @@
|
||||
include ../../include.mk
|
||||
|
||||
ABNF_SOURCES := $(wildcard *.abnf)
|
||||
ABNF_OBJECTS := $(ABNF_SOURCES:%.abnf=./%.erl)
|
||||
ERL_OBJECTS := $(ABNF_SOURCES:%.abnf=$(EBIN_DIR)/%.$(EMULATOR))
|
||||
|
||||
all: $(ERL_OBJECTS)
|
||||
|
||||
clean:
|
||||
-rm $(ERL_OBJECTS) $(ABNF_OBJECTS)
|
||||
|
||||
$(EBIN_DIR)/rfc1035.beam: rfc1035.hrl
|
29
samples/rfc1035/rfc1035.abnf
Normal file
29
samples/rfc1035/rfc1035.abnf
Normal file
@ -0,0 +1,29 @@
|
||||
;<domain> ::= <subdomain> | " "
|
||||
;
|
||||
;<subdomain> ::= <label> | <subdomain> "." <label>
|
||||
;
|
||||
;<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
|
||||
;
|
||||
;<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
|
||||
;
|
||||
;<let-dig-hyp> ::= <let-dig> | "-"
|
||||
;
|
||||
;<let-dig> ::= <letter> | <digit>
|
||||
;
|
||||
;<letter> ::= any one of the 52 alphabetic characters A through Z in
|
||||
;upper case and a through z in lower case
|
||||
;
|
||||
;<digit> ::= any one of the ten digits 0 through 9
|
||||
|
||||
|
||||
domain = subdomain / " "
|
||||
|
||||
subdomain = label *( "." label)
|
||||
|
||||
label = ALPHA *ldh-str 1*let-dig
|
||||
|
||||
ldh-str = let-dig-hyp ldh-str / let-dig-hyp
|
||||
|
||||
let-dig-hyp = let-dig / "-"
|
||||
|
||||
let-dig = ALPHA / DIGIT
|
20
samples/rfc1035/rfc1035.hrl
Normal file
20
samples/rfc1035/rfc1035.hrl
Normal file
@ -0,0 +1,20 @@
|
||||
-import(core, [
|
||||
'ALPHA'/0,
|
||||
%% 'BIT'/0,
|
||||
%% 'CRLF'/0,
|
||||
'DIGIT'/0
|
||||
%% 'DQUOTE'/0,
|
||||
%% 'HEXDIG'/0,
|
||||
%% 'HTAB'/0,
|
||||
%% 'OCTET'/0,
|
||||
%% 'SP'/0,
|
||||
%% 'WSP'/0
|
||||
%% 'VCHAR'/0,
|
||||
]).
|
||||
|
||||
label_cb(L) ->
|
||||
lists:flatten(L).
|
||||
|
||||
subdomain_cb(L) ->
|
||||
lists:flatten(L).
|
||||
|
12
samples/rfc2806/Makefile
Executable file
12
samples/rfc2806/Makefile
Executable file
@ -0,0 +1,12 @@
|
||||
include ../../include.mk
|
||||
|
||||
ABNF_SOURCES := $(wildcard *.abnf)
|
||||
ABNF_OBJECTS := $(ABNF_SOURCES:%.abnf=./%.erl)
|
||||
ERL_OBJECTS := $(ABNF_SOURCES:%.abnf=$(EBIN_DIR)/%.$(EMULATOR))
|
||||
|
||||
all: $(ERL_OBJECTS)
|
||||
|
||||
clean:
|
||||
-rm $(ERL_OBJECTS) $(ABNF_OBJECTS)
|
||||
|
||||
$(EBIN_DIR)/rfc2806.beam: rfc2806.hrl
|
136
samples/rfc2806/rfc2806.abnf
Normal file
136
samples/rfc2806/rfc2806.abnf
Normal file
@ -0,0 +1,136 @@
|
||||
;;;===================================================================
|
||||
;;; ABNF for RFC 2806, "URLs for Telephone Calls"
|
||||
;;; See http://tools.ietf.org/html/rfc2806
|
||||
;;;===================================================================
|
||||
|
||||
telephone-url = telephone-scheme ":"
|
||||
telephone-subscriber
|
||||
|
||||
telephone-scheme = "tel"
|
||||
|
||||
telephone-subscriber = global-phone-number / local-phone-number
|
||||
|
||||
global-phone-number = "+" base-phone-number [isdn-subaddress]
|
||||
[post-dial] *(area-specifier /
|
||||
service-provider / future-extension)
|
||||
|
||||
base-phone-number = 1*phonedigit
|
||||
|
||||
local-phone-number = 1*(phonedigit / dtmf-digit /
|
||||
pause-character) [isdn-subaddress]
|
||||
[post-dial] area-specifier
|
||||
*(area-specifier / service-provider /
|
||||
future-extension)
|
||||
|
||||
isdn-subaddress = ";isub=" 1*phonedigit
|
||||
|
||||
post-dial = ";postd=" 1*(phonedigit /
|
||||
dtmf-digit / pause-character)
|
||||
|
||||
area-specifier = ";" phone-context-tag "=" phone-context-ident
|
||||
|
||||
phone-context-tag = "phone-context"
|
||||
|
||||
phone-context-ident = network-prefix / private-prefix
|
||||
|
||||
network-prefix = global-network-prefix / local-network-prefix
|
||||
|
||||
global-network-prefix = "+" 1*phonedigit
|
||||
|
||||
local-network-prefix = 1*(phonedigit / dtmf-digit / pause-character)
|
||||
|
||||
private-prefix = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
|
||||
%x3C-40 / %x45-4F / %x51-56 / %x58-60 /
|
||||
%x65-6F / %x71-76 / %x78-7E)
|
||||
*(%x21-3A / %x3C-7E)
|
||||
; Characters in URLs must follow escaping rules
|
||||
; as explained in [RFC2396]
|
||||
; See sections 1.2 and 2.5.2
|
||||
|
||||
service-provider = ";" provider-tag "=" provider-hostname
|
||||
|
||||
provider-tag = "tsp"
|
||||
|
||||
provider-hostname = domain ; <domain> is defined in [RFC1035]
|
||||
; See section 2.5.10
|
||||
|
||||
future-extension = ";" 1*(token-char) ["=" ((1*(token-char)
|
||||
["?" 1*(token-char)]) / quoted-string )]
|
||||
; See section 2.5.11 and [RFC2543]
|
||||
|
||||
token-char = (%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
|
||||
/ %x41-5A / %x5E-7A / %x7C / %x7E)
|
||||
; Characters in URLs must follow escaping rules
|
||||
; as explained in [RFC2396]
|
||||
; See sections 1.2 and 2.5.11
|
||||
|
||||
quoted-string = %x22 *( "\" CHAR / (%x20-21 / %x23-7E
|
||||
/ %x80-FF )) %x22
|
||||
; Characters in URLs must follow escaping rules
|
||||
; as explained in [RFC2396]
|
||||
; See sections 1.2 and 2.5.11
|
||||
|
||||
phonedigit = DIGIT / visual-separator
|
||||
|
||||
visual-separator = "-" / "." / "(" / ")"
|
||||
|
||||
pause-character = one-second-pause / wait-for-dial-tone
|
||||
|
||||
one-second-pause = "p"
|
||||
|
||||
wait-for-dial-tone = "w"
|
||||
|
||||
dtmf-digit = "*" / "#" / "A" / "B" / "C" / "D"
|
||||
|
||||
|
||||
|
||||
fax-url = fax-scheme ":" fax-subscriber
|
||||
|
||||
fax-scheme = "fax"
|
||||
|
||||
fax-subscriber = fax-global-phone / fax-local-phone
|
||||
|
||||
fax-global-phone = "+" base-phone-number [isdn-subaddress]
|
||||
[t33-subaddress] [post-dial]
|
||||
*(area-specifier / service-provider /
|
||||
future-extension)
|
||||
|
||||
fax-local-phone = 1*(phonedigit / dtmf-digit /
|
||||
pause-character) [isdn-subaddress]
|
||||
[t33-subaddress] [post-dial]
|
||||
area-specifier
|
||||
*(area-specifier / service-provider /
|
||||
future-extension)
|
||||
|
||||
t33-subaddress = ";tsub=" 1*phonedigit
|
||||
|
||||
modem-url = modem-scheme ":" remote-host
|
||||
|
||||
modem-scheme = "modem"
|
||||
|
||||
remote-host = telephone-subscriber *(modem-params
|
||||
/ recommended-params)
|
||||
|
||||
modem-params = ";type=" data-capabilities
|
||||
|
||||
recommended-params = ";rec=" data-capabilities
|
||||
|
||||
data-capabilities = accepted-modem ["?" data-bits parity
|
||||
stop-bits]
|
||||
|
||||
accepted-modem = "V21" / "V22" / "V22b" /
|
||||
"V23" / "V26t" / "V32" /
|
||||
"V32b" / "V34" / "V90" /
|
||||
"V110" / "V120" / "B103" /
|
||||
"B212" / "X75" /
|
||||
"vnd." vendor-name "." modem-type
|
||||
|
||||
data-bits = "7" / "8"
|
||||
|
||||
parity = "n" / "e" / "o" / "m" / "s"
|
||||
|
||||
stop-bits = "1" / "2"
|
||||
|
||||
vendor-name = 1*(ALPHA / DIGIT / "-" / "+")
|
||||
|
||||
modem-type = 1*(ALPHA / DIGIT / "-" / "+")
|
16
samples/rfc2806/rfc2806.hrl
Normal file
16
samples/rfc2806/rfc2806.hrl
Normal file
@ -0,0 +1,16 @@
|
||||
-import(core, [
|
||||
'ALPHA'/0,
|
||||
%% 'BIT'/0,
|
||||
'CHAR'/0,
|
||||
'CRLF'/0,
|
||||
'DIGIT'/0,
|
||||
'DQUOTE'/0,
|
||||
'HEXDIG'/0,
|
||||
'HTAB'/0,
|
||||
'OCTET'/0,
|
||||
'SP'/0,
|
||||
'WSP'/0
|
||||
%% 'VCHAR'/0,
|
||||
]).
|
||||
|
||||
-import(rfc1035,[domain/0]).
|
12
samples/rfc3325/Makefile
Executable file
12
samples/rfc3325/Makefile
Executable file
@ -0,0 +1,12 @@
|
||||
include ../../include.mk
|
||||
|
||||
ABNF_SOURCES := $(wildcard *.abnf)
|
||||
ABNF_OBJECTS := $(ABNF_SOURCES:%.abnf=./%.erl)
|
||||
ERL_OBJECTS := $(ABNF_SOURCES:%.abnf=$(EBIN_DIR)/%.$(EMULATOR))
|
||||
|
||||
all: $(ERL_OBJECTS)
|
||||
|
||||
clean:
|
||||
-rm $(ERL_OBJECTS) $(ABNF_OBJECTS)
|
||||
|
||||
$(EBIN_DIR)/rfc3325.beam: rfc3325.hrl
|
9
samples/rfc3325/rfc3325.abnf
Normal file
9
samples/rfc3325/rfc3325.abnf
Normal file
@ -0,0 +1,9 @@
|
||||
PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
|
||||
*(COMMA PAssertedID-value)
|
||||
|
||||
PAssertedID-value = name-addr / addr-spec
|
||||
|
||||
PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
|
||||
*(COMMA PPreferredID-value)
|
||||
|
||||
PPreferredID-value = name-addr / addr-spec
|
5
samples/rfc3325/rfc3325.hrl
Normal file
5
samples/rfc3325/rfc3325.hrl
Normal file
@ -0,0 +1,5 @@
|
||||
-import(rfc3261, ['COMMA'/0,
|
||||
'HCOLON'/0,
|
||||
'addr-spec'/0,
|
||||
'name-addr'/0
|
||||
]).
|
1011
samples/rfc3325/rfc3325.txt
Normal file
1011
samples/rfc3325/rfc3325.txt
Normal file
File diff suppressed because it is too large
Load Diff
12
samples/sdp/Makefile
Executable file
12
samples/sdp/Makefile
Executable file
@ -0,0 +1,12 @@
|
||||
include ../../include.mk
|
||||
|
||||
ABNF_SOURCES := $(wildcard *.abnf)
|
||||
ABNF_OBJECTS := $(ABNF_SOURCES:%.abnf=./%.erl)
|
||||
ERL_OBJECTS := $(ABNF_SOURCES:%.abnf=$(EBIN_DIR)/%.$(EMULATOR))
|
||||
|
||||
all: $(ERL_OBJECTS)
|
||||
|
||||
clean:
|
||||
-rm $(ERL_OBJECTS) $(ABNF_OBJECTS)
|
||||
|
||||
$(EBIN_DIR)/rfc4566.beam: rfc4566.hrl
|
247
samples/sdp/rfc4566.abnf
Normal file
247
samples/sdp/rfc4566.abnf
Normal file
@ -0,0 +1,247 @@
|
||||
session-description = proto-version
|
||||
origin-field
|
||||
session-name-field
|
||||
information-field
|
||||
; uri-field
|
||||
; email-fields
|
||||
phone-fields
|
||||
[ connection-field ]
|
||||
bandwidth-fields
|
||||
time-fields
|
||||
key-field
|
||||
attribute-fields
|
||||
media-descriptions
|
||||
|
||||
proto-version = %x76 "=" 1*DIGIT CRLF : {'proto-version', _YY3}.
|
||||
|
||||
origin-field = %x6F "=" username SP sess-id SP sess-version SP
|
||||
nettype SP addrtype SP unicast-address CRLF :
|
||||
{'origin-field', _YY3, _YY5, _YY7, _YY9, _YY11, _YY13}.
|
||||
|
||||
session-name-field = %x73 "=" text CRLF : {'session-name-field', _YY3}.
|
||||
|
||||
information-field = [%x69 "=" text CRLF] : {'information-field', _YY}.
|
||||
|
||||
uri-field = [%x75 "=" uri CRLF]
|
||||
|
||||
;email-fields = *(%x65 "=" email-address CRLF)
|
||||
|
||||
phone-fields = *(%x70 "=" phone-number CRLF) : {'phone-fields', _YY}.
|
||||
|
||||
connection-field = %x63 "=" nettype SP addrtype SP
|
||||
connection-address CRLF :
|
||||
case _YY of
|
||||
[_,_,P1,_,P2,_,P3,_] ->
|
||||
{'connection-field', P1,P2,P3};
|
||||
[] -> {'connection-field', undefined, undefined, undefined}
|
||||
end.
|
||||
|
||||
bandwidth-fields = *(%x62 "=" bwtype ":" bandwidth CRLF) :
|
||||
{'bandwidth-fields', [{Type, BW}||[_,_,Type,_,BW,_]<-_YY]}.
|
||||
|
||||
time-fields = 1*( %x74 "=" start-time SP stop-time
|
||||
*(CRLF repeat-fields) CRLF)
|
||||
[zone-adjustments CRLF] : {'time-fields', _YY}.
|
||||
|
||||
repeat-fields = %x72 "=" repeat-interval SP typed-time
|
||||
1*(SP typed-time)
|
||||
|
||||
zone-adjustments = %x7a "=" timex SP ["-"] typed-time
|
||||
*(SP timex SP ["-"] typed-time)
|
||||
|
||||
key-field = [%x6b "=" key-type CRLF]
|
||||
|
||||
attribute-fields = *(%x61 "=" attribute CRLF) :
|
||||
{'attribute-field', [AF||[_,_,AF,_]<-_YY]}.
|
||||
|
||||
media-descriptions = *( media-field
|
||||
information-field
|
||||
*connection-field
|
||||
bandwidth-fields
|
||||
key-field
|
||||
attribute-fields ) : {'media-descriptions',_YY}.
|
||||
|
||||
media-field = %x6D "=" media SP port ["/" integer]
|
||||
SP proto 1*(SP fmt) CRLF :
|
||||
{'media-field', _YY3, _YY5, _YY6, _YY8,
|
||||
[Fmt||['SP',Fmt]<-_YY9]}.
|
||||
|
||||
; sub-rules of 'o='
|
||||
username = non-ws-string
|
||||
; ;pretty wide definition, but doesn't
|
||||
; ;include space
|
||||
|
||||
sess-id = 1*DIGIT
|
||||
; ;should be unique for this username/host
|
||||
|
||||
sess-version = 1*DIGIT
|
||||
|
||||
nettype = token
|
||||
; ;typically "IN"
|
||||
|
||||
addrtype = token
|
||||
; ;typically "IP4" or "IP6"
|
||||
;
|
||||
|
||||
|
||||
uri = URI-reference
|
||||
; ; see RFC 3986
|
||||
; sub-rules of 'e=', see RFC 2822 for definitions
|
||||
|
||||
;email-address = address-and-comment/ dispname-and-address/ addr-spec
|
||||
|
||||
;address-and-comment = addr-spec 1*SP "(" 1*email-safe ")"
|
||||
|
||||
;dispname-and-address = 1*email-safe 1*SP "<" addr-spec ">"
|
||||
|
||||
; sub-rules of 'p='
|
||||
phone-number = phone *SP "(" 1*email-safe ")"/
|
||||
1*email-safe "<" phone ">"/
|
||||
phone
|
||||
|
||||
phone = ["+"] DIGIT 1*(SP/ "-"/ DIGIT)
|
||||
|
||||
; sub-rules of 'c='
|
||||
connection-address = unicast-address / multicast-address
|
||||
|
||||
; sub-rules of 'b='
|
||||
bwtype = token
|
||||
|
||||
bandwidth = 1*DIGIT
|
||||
|
||||
; sub-rules of 't='
|
||||
start-time = timex/ "0"
|
||||
|
||||
stop-time = timex/ "0"
|
||||
|
||||
timex = POS-DIGIT 9*DIGIT
|
||||
; ; Decimal representation of NTP time in
|
||||
; ; seconds since 1900. The representation
|
||||
; ; of NTP time is an unbounded length field
|
||||
; ; containing at least 10 digits. Unlike the
|
||||
; ; 64-bit representation used elsewhere, time
|
||||
; ; in SDP does not wrap in the year 2036.
|
||||
|
||||
; sub-rules of 'r=' and 'z='
|
||||
repeat-interval = POS-DIGIT *DIGIT [fixed-len-time-unit]
|
||||
|
||||
typed-time = 1*DIGIT [fixed-len-time-unit]
|
||||
|
||||
fixed-len-time-unit = %x64/ %x68/ %x6D/ %x73
|
||||
|
||||
; sub-rules of 'k='
|
||||
;key-type = %x70 %x72 %x6F %x6D %x70 %x74/ ; "prompt"
|
||||
; %x63 %x6C %x65 %x61 %x72 ":" text/ ; "clear:"
|
||||
; %x62 %x61 %x73 %x65 "64:" base64/ ; "base64:"
|
||||
; %x75 %x72 %x69 ":" uri ; "uri:"
|
||||
key-type = %x70 %x72 %x6F %x6D %x70 %x74/
|
||||
%x63 %x6C %x65 %x61 %x72 ":" text/
|
||||
%x62 %x61 %x73 %x65 "64:" base64/
|
||||
%x75 %x72 %x69 ":" uri
|
||||
|
||||
base64 = *base64-unit [base64-pad]
|
||||
|
||||
base64-unit = 4base64-char
|
||||
|
||||
base64-pad = 2base64-char "=="/ 3base64-char "="
|
||||
|
||||
base64-char = ALPHA/ DIGIT/ "+"/ "/"
|
||||
|
||||
; sub-rules of 'a='
|
||||
attribute = (att-field ":" att-value)/ att-field : {attribute, _YY}.
|
||||
|
||||
att-field = token
|
||||
|
||||
att-value = byte-string
|
||||
|
||||
; sub-rules of 'm='
|
||||
media = token
|
||||
; ;typically "audio", "video", "text", or
|
||||
; ;"application"
|
||||
|
||||
fmt = token
|
||||
; ;typically an RTP payload type for audio
|
||||
; ;and video media
|
||||
|
||||
proto = token *("/" token) : {proto, _YY1, _YY2}.
|
||||
|
||||
|
||||
port = 1*DIGIT
|
||||
|
||||
; generic sub-rules: addressing
|
||||
unicast-address = IP4-address/ IP6-address/ FQDN/ extn-addr
|
||||
|
||||
multicast-address = IP4-multicast/ IP6-multicast/ FQDN/ extn-addr
|
||||
|
||||
IP4-multicast = m1 3( "." decimal-uchar ) "/" ttl [ "/" integer ]
|
||||
; ; IPv4 multicast addresses may be in the
|
||||
; ; range 224.0.0.0 to 239.255.255.255
|
||||
;
|
||||
|
||||
m1 = ("22" ("4"/ "5"/ "6"/ "7"/ "8"/ "9"))/ ("23" DIGIT )
|
||||
|
||||
IP6-multicast = hexpart [ "/" integer ]
|
||||
; ; IPv6 address starting with FF
|
||||
|
||||
ttl = (POS-DIGIT *2DIGIT) / "0"
|
||||
|
||||
FQDN = 4*(alpha-numeric/ "-"/ ".")
|
||||
; ; fully qualified domain name as specified
|
||||
; ; in RFC 1035 (and updates)
|
||||
|
||||
IP4-address = b1 3("." decimal-uchar) : lists:flatten(_YY).
|
||||
|
||||
b1 = decimal-uchar
|
||||
; ; less than "224"
|
||||
|
||||
; The following is consistent with RFC 2373 [30], Appendix B.
|
||||
IP6-address = hexpart [ ":" IP4-address ]
|
||||
|
||||
hexpart = hexseq/ hexseq "::" [ hexseq ]/ "::" [ hexseq ]
|
||||
|
||||
hexseq = hex4 *( ":" hex4)
|
||||
|
||||
hex4 = 1*4HEXDIG
|
||||
|
||||
; Generic for other address families
|
||||
extn-addr = non-ws-string
|
||||
|
||||
; generic sub-rules: datatypes
|
||||
text = byte-string
|
||||
; ;default is to interpret this as UTF8 text.
|
||||
; ;ISO 8859-1 requires "a=charset:ISO-8859-1"
|
||||
; ;session-level attribute to be used
|
||||
|
||||
byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
|
||||
; ;any byte except NUL, CR, or LF
|
||||
|
||||
non-ws-string = 1*(VCHAR/%x80-FF)
|
||||
; ;string of visible characters
|
||||
|
||||
token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
|
||||
/ %x41-5A / %x5E-7E
|
||||
|
||||
token = 1*(token-char)
|
||||
|
||||
email-safe = %x01-09/%x0B-0C/%x0E-27/%x2A-3B/%x3D/%x3F-FF
|
||||
; ;any byte except NUL, CR, LF, or the quoting
|
||||
; ;characters ()<>
|
||||
|
||||
integer = POS-DIGIT *DIGIT
|
||||
|
||||
; generic sub-rules: primitives
|
||||
alpha-numeric = ALPHA / DIGIT
|
||||
|
||||
POS-DIGIT = %x31-39 ; 1 - 9
|
||||
|
||||
decimal-uchar = ("2" "5" ("0"/"1"/"2"/"3"/"4"/"5"))
|
||||
/ ("2" ("0"/"1"/"2"/"3"/"4") DIGIT)
|
||||
/ ("1" 2*(DIGIT))
|
||||
/ POS-DIGIT DIGIT
|
||||
/ DIGIT
|
||||
|
||||
; external references:
|
||||
; ALPHA, DIGIT, CRLF, SP, VCHAR: from RFC 4234
|
||||
; URI-reference: from RFC 3986
|
||||
; addr-spec: from RFC 2822
|
||||
|
15
samples/sdp/rfc4566.hrl
Normal file
15
samples/sdp/rfc4566.hrl
Normal file
@ -0,0 +1,15 @@
|
||||
-import(rfc4234_core, [
|
||||
'ALPHA'/0,
|
||||
%% 'BIT'/0,
|
||||
'CRLF'/0,
|
||||
'DIGIT'/0,
|
||||
'DQUOTE'/0,
|
||||
'HEXDIG'/0,
|
||||
'HTAB'/0,
|
||||
'OCTET'/0,
|
||||
'SP'/0,
|
||||
'WSP'/0,
|
||||
'VCHAR'/0
|
||||
]).
|
||||
|
||||
-import(rfc3986,['URI-reference'/0]).
|
12
samples/sip/Makefile
Executable file
12
samples/sip/Makefile
Executable file
@ -0,0 +1,12 @@
|
||||
include ../../include.mk
|
||||
|
||||
ABNF_SOURCES := $(wildcard *.abnf)
|
||||
ABNF_OBJECTS := $(ABNF_SOURCES:%.abnf=./%.erl)
|
||||
ERL_OBJECTS := $(ABNF_SOURCES:%.abnf=$(EBIN_DIR)/%.$(EMULATOR))
|
||||
|
||||
all: $(ERL_OBJECTS)
|
||||
|
||||
clean:
|
||||
-rm $(ERL_OBJECTS) $(ABNF_OBJECTS)
|
||||
|
||||
../ebin/rfc3261.beam: rfc3261.hrl
|
849
samples/sip/rfc3261.abnf
Normal file
849
samples/sip/rfc3261.abnf
Normal file
@ -0,0 +1,849 @@
|
||||
; The following rules are used throughout this specification to
|
||||
; describe basic parsing constructs. The US-ASCII coded character set
|
||||
; is defined by ANSI X3.4-1986.
|
||||
|
||||
alphanum = ALPHA / DIGIT
|
||||
|
||||
; Several rules are incorporated from RFC 2396 [5] but are updated to
|
||||
; make them compliant with RFC 2234 [10]. These include:
|
||||
|
||||
reserved = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+"
|
||||
/ "$" / ","
|
||||
unreserved = alphanum / mark
|
||||
|
||||
mark = "-" / "_" / "." / "!" / "~" / "*" / "'"
|
||||
/ "(" / ")"
|
||||
|
||||
escaped = "%" HEXDIG HEXDIG
|
||||
|
||||
; SIP header field values can be folded onto multiple lines if the
|
||||
; continuation line begins with a space or horizontal tab. All linear
|
||||
; white space, including folding, has the same semantics as SP. A
|
||||
; recipient MAY replace any linear white space with a single SP before
|
||||
; interpreting the field value or forwarding the message downstream.
|
||||
; This is intended to behave exactly as HTTP/1.1 as described in RFC
|
||||
; 2616 [8]. The SWS construct is used when linear white space is
|
||||
; optional, generally between tokens and separators.
|
||||
|
||||
LWS = [*WSP CRLF] 1*WSP : 'LWS'.
|
||||
|
||||
SWS = [LWS] : 'SWS'.
|
||||
|
||||
; To separate the header name from the rest of value, a colon is used,
|
||||
; which, by the above rule, allows whitespace before, but no line
|
||||
; break, and whitespace after, including a linebreak. The HCOLON
|
||||
; defines this construct.
|
||||
|
||||
HCOLON = *( SP / HTAB ) ":" SWS : 'HCOLON'.
|
||||
|
||||
; The TEXT-UTF8 rule is only used for descriptive field contents and
|
||||
; values that are not intended to be interpreted by the message parser.
|
||||
; Words of *TEXT-UTF8 contain characters from the UTF-8 charset (RFC
|
||||
; 2279 [7]). The TEXT-UTF8-TRIM rule is used for descriptive field
|
||||
; contents that are n t quoted strings, where leading and trailing LWS
|
||||
; is not meaningful. In this regard, SIP differs from HTTP, which uses
|
||||
; the ISO 8859-1 character set.
|
||||
|
||||
TEXT-UTF8-TRIM = 1*TEXT-UTF8char *(*LWS TEXT-UTF8char)
|
||||
|
||||
TEXT-UTF8char = %x21-7E / UTF8-NONASCII
|
||||
|
||||
UTF8-NONASCII = %xC0-DF 1UTF8-CONT
|
||||
/ %xE0-EF 2UTF8-CONT
|
||||
/ %xF0-F7 3UTF8-CONT
|
||||
/ %xF8-FB 4UTF8-CONT
|
||||
/ %xFC-FD 5UTF8-CONT
|
||||
|
||||
UTF8-CONT = %x80-BF
|
||||
|
||||
; A CRLF is allowed in the definition of TEXT-UTF8-TRIM only as part of
|
||||
; a header field continuation. It is expected that the folding LWS
|
||||
; will be replaced with a single SP before interpretation of the TEXT-
|
||||
; UTF8-TRIM value.
|
||||
|
||||
; Hexadecimal numeric characters are used in several protocol elements.
|
||||
; Some elements (authentication) force hex alphas to be lower case.
|
||||
|
||||
LHEX = DIGIT / %x61-66 ;lowercase a-f
|
||||
|
||||
; Many SIP header field values consist of words separated by LWS or
|
||||
; special characters. Unless otherwise stated, tokens are case-
|
||||
; insensitive. These special characters MUST be in a quoted string to
|
||||
; be used within a parameter value. The word construct is used in
|
||||
; Call-ID to allow most separators to be used.
|
||||
|
||||
token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
|
||||
/ "_" / "+" / "`" / "'" / "~" )
|
||||
|
||||
separators = "(" / ")" / "<" / ">" / "@" /
|
||||
"," / ";" / ":" / "\" / DQUOTE /
|
||||
"/" / "[" / "]" / "?" / "=" /
|
||||
"{" / "}" / SP / HTAB
|
||||
|
||||
word = 1*(alphanum / "-" / "." / "!" / "%" / "*" /
|
||||
"_" / "+" / "`" / "'" / "~" /
|
||||
"(" / ")" / "<" / ">" /
|
||||
":" / "\" / DQUOTE /
|
||||
"/" / "[" / "]" / "?" /
|
||||
"{" / "}" )
|
||||
|
||||
; When tokens are used or separators are used between elements,
|
||||
; whitespace is often allowed before or after these characters:
|
||||
|
||||
STAR = SWS "*" SWS : 'STAR'.
|
||||
|
||||
SLASH = SWS "/" SWS : 'SLASH'.
|
||||
|
||||
EQUAL = SWS "=" SWS : 'EQUAL'.
|
||||
|
||||
LPAREN = SWS "(" SWS : 'LPAREN'.
|
||||
|
||||
RPAREN = SWS ")" SWS : 'RPAREN'.
|
||||
|
||||
RAQUOT = ">" SWS : 'RAQUOT'.
|
||||
|
||||
LAQUOT = SWS "<" : 'LAQUOT'.
|
||||
|
||||
COMMA = SWS "," SWS : 'COMMA'.
|
||||
|
||||
SEMI = SWS ";" SWS : 'SEMI'.
|
||||
|
||||
COLON = SWS ":" SWS : 'COLON'.
|
||||
|
||||
LDQUOT = SWS DQUOTE : 'LDQUOT'.
|
||||
|
||||
RDQUOT = DQUOTE SWS : 'RDQUOT'.
|
||||
|
||||
; Comments can be included in some SIP header fields by surrounding the
|
||||
; comment text with parentheses. Comments are only allowed in fields
|
||||
; containing "comment" as part of their field value definition. In all
|
||||
; other fields, parentheses are considered part of the field value.
|
||||
|
||||
comment = LPAREN *(ctext / quoted-pair / comment) RPAREN
|
||||
|
||||
ctext = %x21-27 / %x2A-5B / %x5D-7E / UTF8-NONASCII
|
||||
/ LWS
|
||||
|
||||
; ctext includes all chars except left and right parens and backslash.
|
||||
; A string of text is parsed as a single word if it is quoted using
|
||||
; double-quote marks. In quoted strings, quotation marks (") and
|
||||
; backslashes (\) need to be escaped.
|
||||
|
||||
quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
|
||||
|
||||
qdtext = LWS / %x21 / %x23-5B / %x5D-7E
|
||||
/ UTF8-NONASCII
|
||||
|
||||
; The backslash character ("\") MAY be used as a single-character
|
||||
; quoting mechanism only within quoted-string and comment constructs.
|
||||
; Unlike HTTP/1.1, the characters CR and LF cannot be escaped by this
|
||||
; mechanism to avoid conflict with line folding and header separation.
|
||||
|
||||
quoted-pair = "\" (%x00-09 / %x0B-0C
|
||||
/ %x0E-7F)
|
||||
|
||||
SIP-URI = "sip:" [ userinfo ] hostport
|
||||
uri-parameters [ headers ] : {'SIP-URI', _YY2, _YY3, _YY4, _YY5}.
|
||||
|
||||
SIPS-URI = "sips:" [ userinfo ] hostport
|
||||
uri-parameters [ headers ]
|
||||
|
||||
userinfo = ( user / telephone-subscriber ) [ ":" password ] "@" : {userinfo, _YY1, _YY2}.
|
||||
|
||||
user = 1*( unreserved / escaped / user-unreserved ) : {user, lists:flatten(_YY)}.
|
||||
|
||||
user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
|
||||
|
||||
password = *( unreserved / escaped /
|
||||
"&" / "=" / "+" / "$" / "," )
|
||||
|
||||
hostport = host [ ":" port ] : {hostport, _YY1, case _YY2 of [] -> []; [[_, Port]] -> list_to_integer(Port) end}.
|
||||
|
||||
host = hostname / IPv4address / IPv6reference
|
||||
|
||||
hostname = *( domainlabel "." ) toplabel [ "." ] : lists:flatten(_YY).
|
||||
|
||||
domainlabel = *( alphanum / "-" )
|
||||
; This should really be
|
||||
;(alphanum *( alphanum / "-" ) alphanum) /
|
||||
; alphanum
|
||||
|
||||
toplabel = *( alphanum / "-" )
|
||||
;this should really be
|
||||
;ALPHA / ALPHA *( alphanum / "-" ) alphanum
|
||||
|
||||
IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
|
||||
|
||||
IPv6reference = "[" IPv6address "]"
|
||||
|
||||
IPv6address = hexpart [ ":" IPv4address ]
|
||||
|
||||
hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
|
||||
|
||||
hexseq = hex4 *( ":" hex4)
|
||||
|
||||
hex4 = 1*4HEXDIG
|
||||
|
||||
port = 1*DIGIT
|
||||
|
||||
; The BNF for telephone-subscriber can be found in RFC 2806 [9]. Note,
|
||||
; however, that any characters allowed there that are not allowed in
|
||||
; the user part of the SIP URI MUST be escaped.
|
||||
|
||||
uri-parameters = *( ";" uri-parameter) : {'uri-parameters', [P || [$;,P] <- _YY]}.
|
||||
|
||||
uri-parameter = transport-param / user-param / method-param
|
||||
/ ttl-param / maddr-param / lr-param / other-param
|
||||
|
||||
transport-param = "transport="
|
||||
( "udp" / "tcp" / "sctp" / "tls"
|
||||
/ other-transport) : {transport, _YY2}.
|
||||
|
||||
other-transport = token
|
||||
|
||||
user-param = "user=" ( "phone" / "ip" / other-user) : {'user-param', _YY2}.
|
||||
|
||||
other-user = token
|
||||
|
||||
method-param = "method=" Method : {'method-param', _YY2}.
|
||||
|
||||
ttl-param = "ttl=" ttl : {'ttl-param', _YY2}.
|
||||
|
||||
maddr-param = "maddr=" host : {'maddr-param', _YY2}.
|
||||
|
||||
lr-param = "lr" : lr.
|
||||
|
||||
other-param = pname [ "=" pvalue ] :
|
||||
case _YY2 of
|
||||
[[_,Val]] ->
|
||||
{'other-param', _YY1, Val};
|
||||
[] -> {'other-param', _YY1}
|
||||
end.
|
||||
|
||||
pname = 1*paramchar
|
||||
|
||||
pvalue = 1*paramchar
|
||||
|
||||
paramchar = param-unreserved / unreserved / escaped
|
||||
|
||||
param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
|
||||
|
||||
headers = "?" header *( "&" header )
|
||||
|
||||
header = hname "=" hvalue
|
||||
|
||||
hname = 1*( hnv-unreserved / unreserved / escaped )
|
||||
|
||||
hvalue = *( hnv-unreserved / unreserved / escaped )
|
||||
|
||||
hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
|
||||
|
||||
SIP-message = Request / Response
|
||||
|
||||
Request = Request-Line
|
||||
*( message-header )
|
||||
CRLF
|
||||
[ message-body ] : {'Request', _YY1, _YY2, _YY4}.
|
||||
|
||||
Request-Line = Method SP Request-URI SP SIP-Version CRLF :
|
||||
{'Request-Line', _YY1, _YY3, _YY5}.
|
||||
|
||||
Request-URI = SIP-URI / SIPS-URI / absoluteURI
|
||||
|
||||
absoluteURI = scheme ":" ( hier-part / opaque-part )
|
||||
|
||||
hier-part = ( net-path / abs-path ) [ "?" query ]
|
||||
|
||||
net-path = "//" authority [ abs-path ]
|
||||
|
||||
abs-path = "/" path-segments
|
||||
|
||||
opaque-part = uric-no-slash *uric
|
||||
|
||||
uric = reserved / unreserved / escaped
|
||||
|
||||
uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@"
|
||||
/ "&" / "=" / "+" / "$" / ","
|
||||
|
||||
path-segments = segment *( "/" segment )
|
||||
|
||||
segment = *pchar *( ";" param )
|
||||
|
||||
param = *pchar
|
||||
|
||||
pchar = unreserved / escaped /
|
||||
":" / "@" / "&" / "=" / "+" / "$" / ","
|
||||
|
||||
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
|
||||
authority = srvr / reg-name
|
||||
|
||||
srvr = [ [ userinfo "@" ] hostport ]
|
||||
|
||||
reg-name = 1*( unreserved / escaped / "$" / ","
|
||||
/ ";" / ":" / "@" / "&" / "=" / "+" )
|
||||
|
||||
query = *uric
|
||||
|
||||
SIP-Version = "SIP" "/" 1*DIGIT "." 1*DIGIT
|
||||
|
||||
message-header = (Accept
|
||||
/ Accept-Encoding
|
||||
/ Accept-Language
|
||||
/ Alert-Info
|
||||
/ Allow
|
||||
/ Authentication-Info
|
||||
; / Authorization
|
||||
/ Call-ID
|
||||
/ Call-Info
|
||||
/ Contact
|
||||
/ Content-Disposition
|
||||
/ Content-Encoding
|
||||
/ Content-Language
|
||||
/ Content-Length
|
||||
/ Content-Type
|
||||
/ CSeq
|
||||
/ Date
|
||||
/ Error-Info
|
||||
/ Expires
|
||||
/ From
|
||||
/ In-Reply-To
|
||||
/ Max-Forwards
|
||||
/ MIME-Version
|
||||
/ Min-Expires
|
||||
/ Organization
|
||||
/ Priority
|
||||
/ Proxy-Authenticate
|
||||
; / Proxy-Authorization
|
||||
/ Proxy-Require
|
||||
/ Record-Route
|
||||
/ Reply-To
|
||||
/ Require
|
||||
/ Retry-After
|
||||
/ Route
|
||||
/ Server
|
||||
/ Subject
|
||||
/ Supported
|
||||
/ Timestamp
|
||||
/ To
|
||||
/ Unsupported
|
||||
/ User-Agent
|
||||
/ Via
|
||||
/ Warning
|
||||
/ WWW-Authenticate
|
||||
/ extension-header) CRLF : _YY1.
|
||||
|
||||
INVITEm = %x49.4E.56.49.54.45
|
||||
; INVITE in caps
|
||||
|
||||
ACKm = %x41.43.4B
|
||||
; ACK in caps
|
||||
|
||||
OPTIONSm = %x4F.50.54.49.4F.4E.53
|
||||
; OPTIONS in caps
|
||||
|
||||
BYEm = %x42.59.45
|
||||
; BYE in caps
|
||||
|
||||
CANCELm = %x43.41.4E.43.45.4C
|
||||
; CANCEL in caps
|
||||
|
||||
REGISTERm = %x52.45.47.49.53.54.45.52
|
||||
; REGISTER in caps
|
||||
|
||||
Method = INVITEm / ACKm / OPTIONSm / BYEm
|
||||
/ CANCELm / REGISTERm
|
||||
/ extension-method
|
||||
|
||||
extension-method = token
|
||||
|
||||
Response = Status-Line
|
||||
*( message-header )
|
||||
CRLF
|
||||
[ message-body ]
|
||||
|
||||
Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
|
||||
|
||||
Status-Code = Informational
|
||||
/ Redirection
|
||||
/ Success
|
||||
/ Client-Error
|
||||
/ Server-Error
|
||||
/ Global-Failure
|
||||
/ extension-code
|
||||
|
||||
extension-code = 3DIGIT
|
||||
|
||||
Reason-Phrase = *(reserved / unreserved / escaped
|
||||
/ UTF8-NONASCII / UTF8-CONT / SP / HTAB)
|
||||
|
||||
Informational = "100" ; Trying
|
||||
/ "180" ; Ringing
|
||||
/ "181" ; Call Is Being Forwarded
|
||||
/ "182" ; Queued
|
||||
/ "183" ; Session Progress
|
||||
|
||||
Success = "200" ; OK
|
||||
|
||||
Redirection = "300" ; Multiple Choices
|
||||
/ "301" ; Moved Permanently
|
||||
/ "302" ; Moved Temporarily
|
||||
/ "305" ; Use Proxy
|
||||
/ "380" ; Alternative Service
|
||||
|
||||
Client-Error = "400" ; Bad Request
|
||||
/ "401" ; Unauthorized
|
||||
/ "402" ; Payment Required
|
||||
/ "403" ; Forbidden
|
||||
/ "404" ; Not Found
|
||||
/ "405" ; Method Not Allowed
|
||||
/ "406" ; Not Acceptable
|
||||
/ "407" ; Proxy Authentication Required
|
||||
/ "408" ; Request Timeout
|
||||
/ "410" ; Gone
|
||||
/ "413" ; Request Entity Too Large
|
||||
/ "414" ; Request-URI Too Large
|
||||
/ "415" ; Unsupported Media Type
|
||||
/ "416" ; Unsupported URI Scheme
|
||||
/ "420" ; Bad Extension
|
||||
/ "421" ; Extension Required
|
||||
/ "423" ; Interval Too Brief
|
||||
/ "480" ; Temporarily not available
|
||||
/ "481" ; Call Leg/Transaction Does Not Exist
|
||||
/ "482" ; Loop Detected
|
||||
/ "483" ; Too Many Hops
|
||||
/ "484" ; Address Incomplete
|
||||
/ "485" ; Ambiguous
|
||||
/ "486" ; Busy Here
|
||||
/ "487" ; Request Terminated
|
||||
/ "488" ; Not Acceptable Here
|
||||
/ "491" ; Request Pending
|
||||
/ "493" ; Undecipherable
|
||||
|
||||
Server-Error = "500" ; Internal Server Error
|
||||
/ "501" ; Not Implemented
|
||||
/ "502" ; Bad Gateway
|
||||
/ "503" ; Service Unavailable
|
||||
/ "504" ; Server Time-out
|
||||
/ "505" ; SIP Version not supported
|
||||
/ "513" ; Message Too Large
|
||||
|
||||
Global-Failure = "600" ; Busy Everywhere
|
||||
/ "603" ; Decline
|
||||
/ "604" ; Does not exist anywhere
|
||||
/ "606" ; Not Acceptable
|
||||
|
||||
Accept = "Accept" HCOLON
|
||||
[ accept-range *(COMMA accept-range) ] :
|
||||
Accept = case _YY3 of
|
||||
[] -> [];
|
||||
[[[A1], As]] ->
|
||||
[A1|[A||['COMMA',A] <- As]]
|
||||
end,
|
||||
{'Accept', Accept}.
|
||||
|
||||
accept-range = media-range *(SEMI accept-param) : [_YY1|[A||['SEMI',A]<- _YY2]].
|
||||
|
||||
media-range = ( "*/*"
|
||||
/ ( m-type SLASH "*" )
|
||||
/ ( m-type SLASH m-subtype )
|
||||
) *( SEMI m-parameter ) :
|
||||
case _YY1 of
|
||||
%% "*/*" -> "*/*";
|
||||
[Type, 'SLASH', SubType] -> {'media-range',Type, SubType}
|
||||
end.
|
||||
|
||||
accept-param = ("q" EQUAL qvalue) / generic-param
|
||||
|
||||
qvalue = ( "0" [ "." 0*3DIGIT ] )
|
||||
/ ( "1" [ "." 0*3("0") ] )
|
||||
|
||||
generic-param = token [ EQUAL gen-value ]
|
||||
|
||||
gen-value = token / host / quoted-string
|
||||
|
||||
Accept-Encoding = "Accept-Encoding" HCOLON
|
||||
[ encoding *(COMMA encoding) ]
|
||||
|
||||
encoding = codings *(SEMI accept-param)
|
||||
|
||||
codings = content-coding / "*"
|
||||
|
||||
content-coding = token
|
||||
|
||||
Accept-Language = "Accept-Language" HCOLON
|
||||
[ language *(COMMA language) ]
|
||||
|
||||
language = language-range *(SEMI accept-param)
|
||||
|
||||
language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
|
||||
|
||||
Alert-Info = "Alert-Info" HCOLON alert-param *(COMMA alert-param)
|
||||
|
||||
alert-param = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
|
||||
|
||||
Allow = "Allow" HCOLON [Method *(COMMA Method)] :
|
||||
Allowed = case _YY3 of
|
||||
[] -> [];
|
||||
[[M1,Ms]] -> [M1|[M||['COMMA',M]<-Ms]]
|
||||
end,
|
||||
{'Allow', Allowed}.
|
||||
|
||||
Authorization = "Authorization" HCOLON credentials
|
||||
|
||||
credentials = ("Digest" LWS digest-response)
|
||||
/ other-response
|
||||
|
||||
digest-response = dig-resp *(COMMA dig-resp)
|
||||
|
||||
dig-resp = username / realm / nonce / digest-uri
|
||||
/ dresponse / algorithm / cnonce
|
||||
/ opaque / message-qop
|
||||
/ nonce-count / auth-param
|
||||
|
||||
username = "username" EQUAL username-value
|
||||
|
||||
username-value = quoted-string
|
||||
|
||||
digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
|
||||
|
||||
digest-uri-value = rquest-uri ; Equal to request-uri as specified
|
||||
; by HTTP/1.1
|
||||
|
||||
message-qop = "qop" EQUAL qop-value
|
||||
|
||||
cnonce = "cnonce" EQUAL cnonce-value
|
||||
|
||||
cnonce-value = nonce-value
|
||||
|
||||
nonce-count = "nc" EQUAL nc-value
|
||||
|
||||
nc-value = 8LHEX
|
||||
|
||||
dresponse = "response" EQUAL request-digest
|
||||
|
||||
request-digest = LDQUOT 32LHEX RDQUOT
|
||||
|
||||
auth-param = auth-param-name EQUAL
|
||||
( token / quoted-string )
|
||||
|
||||
auth-param-name = token
|
||||
|
||||
other-response = auth-scheme LWS auth-param
|
||||
*(COMMA auth-param)
|
||||
|
||||
auth-scheme = token
|
||||
|
||||
Authentication-Info = "Authentication-Info" HCOLON ainfo
|
||||
*(COMMA ainfo)
|
||||
|
||||
ainfo = nextnonce / message-qop
|
||||
/ response-auth / cnonce
|
||||
/ nonce-count
|
||||
|
||||
nextnonce = "nextnonce" EQUAL nonce-value
|
||||
|
||||
response-auth = "rspauth" EQUAL response-digest
|
||||
|
||||
response-digest = LDQUOT *LHEX RDQUOT
|
||||
|
||||
Call-ID = ( "Call-ID" / "i" ) HCOLON callid : {'Call-ID', _YY3}.
|
||||
|
||||
callid = word [ "@" word ] : lists:flatten(_YY).
|
||||
|
||||
Call-Info = "Call-Info" HCOLON info *(COMMA info)
|
||||
|
||||
info = LAQUOT absoluteURI RAQUOT *( SEMI info-param)
|
||||
|
||||
info-param = ( "purpose" EQUAL ( "icon" / "info"
|
||||
/ "card" / token ) ) / generic-param
|
||||
|
||||
Contact = ("Contact" / "m" ) HCOLON
|
||||
( STAR / (contact-param *(COMMA contact-param))) :
|
||||
{'Contact', _YY3}.
|
||||
|
||||
contact-param = (name-addr / addr-spec) *(SEMI contact-params)
|
||||
|
||||
name-addr = [ display-name ] LAQUOT addr-spec RAQUOT : {'name-addr', _YY1, _YY3}.
|
||||
|
||||
addr-spec = SIP-URI / SIPS-URI / absoluteURI
|
||||
|
||||
display-name = quoted-string / *(token LWS)
|
||||
|
||||
contact-params = c-p-q / c-p-expires
|
||||
/ contact-extension
|
||||
|
||||
c-p-q = "q" EQUAL qvalue : {'c-p-q', _YY3}.
|
||||
|
||||
c-p-expires = "expires" EQUAL delta-seconds : {'c-p-expires', _YY3}.
|
||||
|
||||
contact-extension = generic-param : {'contact-extension', _YY}.
|
||||
|
||||
delta-seconds = 1*DIGIT : list_to_integer(_YY).
|
||||
|
||||
Content-Disposition = "Content-Disposition" HCOLON
|
||||
disp-type *( SEMI disp-param )
|
||||
|
||||
disp-type = "render" / "session" / "icon" / "alert"
|
||||
/ disp-extension-token
|
||||
|
||||
disp-param = handling-param / generic-param
|
||||
|
||||
handling-param = "handling" EQUAL
|
||||
( "optional" / "required"
|
||||
/ other-handling )
|
||||
|
||||
other-handling = token
|
||||
|
||||
disp-extension-token = token
|
||||
|
||||
Content-Encoding = ( "Content-Encoding" / "e" ) HCOLON
|
||||
content-coding *(COMMA content-coding)
|
||||
|
||||
Content-Language = "Content-Language" HCOLON
|
||||
language-tag *(COMMA language-tag)
|
||||
|
||||
language-tag = primary-tag *( "-" subtag )
|
||||
|
||||
primary-tag = 1*8ALPHA
|
||||
|
||||
subtag = 1*8ALPHA
|
||||
|
||||
Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT : {'Content-Length', list_to_integer(_YY3)}.
|
||||
|
||||
Content-Type = ( "Content-Type" / "c" ) HCOLON media-type : {'Content-Type', _YY3}.
|
||||
|
||||
media-type = m-type SLASH m-subtype *(SEMI m-parameter) :
|
||||
{'media-type', _YY1, _YY3, [P||['SEMI',P]<-_YY4]}.
|
||||
|
||||
m-type = discrete-type / composite-type
|
||||
|
||||
discrete-type = "text" / "image" / "audio" / "video"
|
||||
/ "application" / extension-token
|
||||
|
||||
composite-type = "message" / "multipart" / extension-token
|
||||
|
||||
extension-token = ietf-token / x-token
|
||||
|
||||
ietf-token = token
|
||||
|
||||
x-token = "x-" token
|
||||
|
||||
m-subtype = extension-token / iana-token
|
||||
|
||||
iana-token = token
|
||||
|
||||
m-parameter = m-attribute EQUAL m-value : {'m-parameter', _YY1, _YY3}.
|
||||
|
||||
m-attribute = token
|
||||
|
||||
m-value = token / quoted-string
|
||||
|
||||
CSeq = "CSeq" HCOLON 1*DIGIT LWS Method : {'CSeq', list_to_integer(_YY3), _YY5}.
|
||||
|
||||
Date = "Date" HCOLON SIP-date
|
||||
|
||||
SIP-date = rfc1123-date
|
||||
|
||||
rfc1123-date = wkday "," SP date1 SP timex SP "GMT"
|
||||
|
||||
date1 = 2DIGIT SP month SP 4DIGIT
|
||||
; day month year (e.g., 02 Jun 1982)
|
||||
|
||||
timex = 2DIGIT ":" 2DIGIT ":" 2DIGIT
|
||||
; 00:00:00 - 23:59:59
|
||||
|
||||
wkday = "Mon" / "Tue" / "Wed"
|
||||
/ "Thu" / "Fri" / "Sat" / "Sun"
|
||||
|
||||
month = "Jan" / "Feb" / "Mar" / "Apr"
|
||||
/ "May" / "Jun" / "Jul" / "Aug"
|
||||
/ "Sep" / "Oct" / "Nov" / "Dec"
|
||||
|
||||
Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
|
||||
|
||||
error-uri = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
|
||||
|
||||
Expires = "Expires" HCOLON delta-seconds
|
||||
|
||||
From = ( "From" / "f" ) HCOLON from-spec : {'From', _YY3}.
|
||||
|
||||
from-spec = ( name-addr / addr-spec )
|
||||
*( SEMI from-param ) : {'from-spec', _YY1, [P||['SEMI',P] <-_YY2]}.
|
||||
|
||||
from-param = tag-param / generic-param
|
||||
|
||||
tag-param = "tag" EQUAL token : {tag, _YY3}.
|
||||
|
||||
In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
|
||||
|
||||
Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT : {'Max-Forwards', list_to_integer(_YY3)}.
|
||||
|
||||
MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
|
||||
|
||||
Min-Expires = "Min-Expires" HCOLON delta-seconds : {'Min-Expires', _YY3}.
|
||||
|
||||
Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
|
||||
|
||||
Priority = "Priority" HCOLON priority-value
|
||||
|
||||
priority-value = "emergency" / "urgent" / "normal"
|
||||
/ "non-urgent" / other-priority
|
||||
|
||||
other-priority = token
|
||||
|
||||
Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
|
||||
|
||||
challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
|
||||
/ other-challenge
|
||||
|
||||
other-challenge = auth-scheme LWS auth-param
|
||||
*(COMMA auth-param)
|
||||
|
||||
digest-cln = realm / domain / nonce
|
||||
/ opaque / stale / algorithm
|
||||
/ qop-options / auth-param
|
||||
|
||||
realm = "realm" EQUAL realm-value
|
||||
|
||||
realm-value = quoted-string
|
||||
|
||||
domain = "domain" EQUAL LDQUOT URI
|
||||
*( 1*SP URI ) RDQUOT
|
||||
|
||||
URI = absoluteURI / abs-path
|
||||
|
||||
nonce = "nonce" EQUAL nonce-value
|
||||
|
||||
nonce-value = quoted-string
|
||||
|
||||
opaque = "opaque" EQUAL quoted-string
|
||||
|
||||
stale = "stale" EQUAL ( "true" / "false" )
|
||||
|
||||
algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
|
||||
/ token )
|
||||
|
||||
qop-options = "qop" EQUAL LDQUOT qop-value
|
||||
*("," qop-value) RDQUOT
|
||||
|
||||
qop-value = "auth" / "auth-int" / token
|
||||
|
||||
Proxy-Authorization = "Proxy-Authorization" HCOLON credentials
|
||||
|
||||
Proxy-Require = "Proxy-Require" HCOLON option-tag
|
||||
*(COMMA option-tag)
|
||||
option-tag = token
|
||||
|
||||
Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route) :
|
||||
{'Record-Route', [_YY3|[RR||['COMMA',RR]<- _YY4]]}.
|
||||
|
||||
rec-route = name-addr *( SEMI rr-param )
|
||||
|
||||
rr-param = generic-param
|
||||
|
||||
Reply-To = "Reply-To" HCOLON rplyto-spec
|
||||
|
||||
rplyto-spec = ( name-addr / addr-spec )
|
||||
*( SEMI rplyto-param )
|
||||
|
||||
rplyto-param = generic-param
|
||||
|
||||
Require = "Require" HCOLON option-tag *(COMMA option-tag)
|
||||
|
||||
Retry-After = "Retry-After" HCOLON delta-seconds
|
||||
[ comment ] *( SEMI retry-param )
|
||||
|
||||
retry-param = ("duration" EQUAL delta-seconds)
|
||||
/ generic-param
|
||||
|
||||
Route = "Route" HCOLON route-param *(COMMA route-param) : {'Route', [_YY3|[P||['COMMA',P]<- _YY4]]}.
|
||||
|
||||
route-param = name-addr *( SEMI rr-param ) :
|
||||
{'route-param', _YY1, [P||['SEMI',P]<-_YY2]}.
|
||||
|
||||
Server = "Server" HCOLON server-val *(LWS server-val)
|
||||
|
||||
server-val = product / comment
|
||||
|
||||
product = token [SLASH product-version]
|
||||
|
||||
product-version = token
|
||||
|
||||
Subject = ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
|
||||
|
||||
Supported = ( "Supported" / "k" ) HCOLON
|
||||
[option-tag *(COMMA option-tag)]
|
||||
|
||||
Timestamp = "Timestamp" HCOLON 1*(DIGIT)
|
||||
[ "." *(DIGIT) ] [ LWS delay ]
|
||||
|
||||
delay = *(DIGIT) [ "." *(DIGIT) ]
|
||||
|
||||
To = ( "To" / "t" ) HCOLON ( name-addr
|
||||
/ addr-spec ) *( SEMI to-param ) : {'To', _YY3, [P||[_,P]<- _YY4]}.
|
||||
|
||||
to-param = tag-param / generic-param
|
||||
|
||||
Unsupported = "Unsupported" HCOLON option-tag *(COMMA option-tag)
|
||||
|
||||
User-Agent = "User-Agent" HCOLON server-val *(LWS server-val)
|
||||
|
||||
Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm) :
|
||||
{'Via', [_YY3| [VP||['COMMA',VP]<-_YY4]]}.
|
||||
|
||||
via-parm = sent-protocol LWS sent-by *( SEMI via-params ) :
|
||||
{'via-parm', _YY1, _YY3, [P||['SEMI',P]<-_YY4]}.
|
||||
|
||||
via-params = via-ttl / via-maddr
|
||||
/ via-received / via-branch
|
||||
/ via-extension
|
||||
|
||||
via-ttl = "ttl" EQUAL ttl : {'via-ttl', _YY3}.
|
||||
|
||||
via-maddr = "maddr" EQUAL host : {'via-maddr', _YY3}.
|
||||
|
||||
via-received = "received" EQUAL (IPv4address / IPv6address) : {'via-received', _YY3}.
|
||||
|
||||
via-branch = "branch" EQUAL token : {'via-branch', _YY3}.
|
||||
|
||||
via-extension = generic-param
|
||||
|
||||
sent-protocol = protocol-name SLASH protocol-version
|
||||
SLASH transport : {'sent-protocol', _YY1, _YY3, _YY5}.
|
||||
|
||||
protocol-name = "SIP" / token
|
||||
|
||||
protocol-version = token
|
||||
|
||||
transport = "UDP" / "TCP" / "TLS" / "SCTP"
|
||||
/ other-transport
|
||||
|
||||
sent-by = host [ COLON port ] : {'sent-by', _YY1, case _YY2 of [] -> []; [['COLON', Port]] -> Port end}.
|
||||
|
||||
ttl = 1*3DIGIT ; 0 to 255
|
||||
|
||||
Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
|
||||
|
||||
warning-value = warn-code SP warn-agent SP warn-text
|
||||
|
||||
warn-code = 3DIGIT
|
||||
|
||||
warn-agent = hostport / pseudonym
|
||||
; the name or pseudonym of the server adding
|
||||
; the Warning header, for use in debugging
|
||||
|
||||
warn-text = quoted-string
|
||||
|
||||
pseudonym = token
|
||||
|
||||
WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
|
||||
|
||||
extension-header = header-name HCOLON header-value : {'extension-header', _YY1, _YY3}.
|
||||
|
||||
header-name = token
|
||||
|
||||
header-value = *(TEXT-UTF8char / UTF8-CONT / LWS)
|
||||
|
||||
message-body = *OCTET
|
||||
|
18
samples/sip/rfc3261.hrl
Normal file
18
samples/sip/rfc3261.hrl
Normal file
@ -0,0 +1,18 @@
|
||||
-import(rfc4234_core, [
|
||||
'ALPHA'/0,
|
||||
%% 'BIT'/0,
|
||||
'CRLF'/0,
|
||||
'DIGIT'/0,
|
||||
'DQUOTE'/0,
|
||||
'HEXDIG'/0,
|
||||
'HTAB'/0,
|
||||
'OCTET'/0,
|
||||
'SP'/0,
|
||||
'WSP'/0
|
||||
%% 'VCHAR'/0,
|
||||
]).
|
||||
|
||||
-import(rfc2806, ['telephone-subscriber'/0]).
|
||||
|
||||
-import(http_1_1, ['rquest-uri'/0]).
|
||||
|
12
samples/uri/Makefile
Executable file
12
samples/uri/Makefile
Executable file
@ -0,0 +1,12 @@
|
||||
include ../../include.mk
|
||||
|
||||
ABNF_SOURCES := $(wildcard *.abnf)
|
||||
ABNF_OBJECTS := $(ABNF_SOURCES:%.abnf=./%.erl)
|
||||
ERL_OBJECTS := $(ABNF_SOURCES:%.abnf=$(EBIN_DIR)/%.$(EMULATOR))
|
||||
|
||||
all: $(ERL_OBJECTS)
|
||||
|
||||
clean:
|
||||
-rm $(ERL_OBJECTS) $(ABNF_OBJECTS)
|
||||
|
||||
../ebin/rfc3986.beam: rfc3986.hrl
|
95
samples/uri/rfc3986.abnf
Normal file
95
samples/uri/rfc3986.abnf
Normal file
@ -0,0 +1,95 @@
|
||||
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||
|
||||
hier-part = "//" authority path-abempty
|
||||
/ path-absolute
|
||||
/ path-rootless
|
||||
/ path-empty
|
||||
|
||||
URI-reference = URI / relative-ref
|
||||
|
||||
absolute-URI = scheme ":" hier-part [ "?" query ]
|
||||
|
||||
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
|
||||
|
||||
relative-part = "//" authority path-abempty
|
||||
/ path-absolute
|
||||
/ path-noscheme
|
||||
/ path-empty
|
||||
|
||||
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
|
||||
authority = [ userinfo "@" ] host [ ":" port ]
|
||||
|
||||
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
|
||||
|
||||
host = IP-literal / IPv4address / reg-name
|
||||
|
||||
port = *DIGIT
|
||||
|
||||
IP-literal = "[" ( IPv6address / IPvFuture ) "]"
|
||||
|
||||
IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
|
||||
|
||||
IPv6address = 6( h16 ":" ) ls32
|
||||
/ "::" 5( h16 ":" ) ls32
|
||||
/ [ h16 ] "::" 4( h16 ":" ) ls32
|
||||
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
|
||||
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
|
||||
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
|
||||
/ [ *4( h16 ":" ) h16 ] "::" ls32
|
||||
/ [ *5( h16 ":" ) h16 ] "::" h16
|
||||
/ [ *6( h16 ":" ) h16 ] "::"
|
||||
|
||||
h16 = 1*4HEXDIG
|
||||
|
||||
ls32 = ( h16 ":" h16 ) / IPv4address
|
||||
|
||||
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
|
||||
|
||||
dec-octet = DIGIT ; 0-9
|
||||
/ %x31-39 DIGIT ; 10-99
|
||||
/ "1" 2DIGIT ; 100-199
|
||||
/ "2" %x30-34 DIGIT ; 200-249
|
||||
/ "25" %x30-35 ; 250-255
|
||||
|
||||
reg-name = *( unreserved / pct-encoded / sub-delims )
|
||||
|
||||
path = path-abempty ; begins with "/" or is empty
|
||||
/ path-absolute ; begins with "/" but not "//"
|
||||
/ path-noscheme ; begins with a non-colon segment
|
||||
/ path-rootless ; begins with a segment
|
||||
/ path-empty ; zero characters
|
||||
|
||||
path-abempty = *( "/" segment )
|
||||
|
||||
path-absolute = "/" [ segment-nz *( "/" segment ) ]
|
||||
|
||||
path-noscheme = segment-nz-nc *( "/" segment )
|
||||
|
||||
path-rootless = segment-nz *( "/" segment )
|
||||
|
||||
path-empty = 0pchar
|
||||
|
||||
segment = *pchar
|
||||
|
||||
segment-nz = 1*pchar
|
||||
|
||||
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
|
||||
; ; non-zero-length segment without any colon ":"
|
||||
|
||||
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
|
||||
query = *( pchar / "/" / "?" )
|
||||
|
||||
fragment = *( pchar / "/" / "?" )
|
||||
|
||||
pct-encoded = "%" HEXDIG HEXDIG
|
||||
|
||||
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
|
||||
reserved = gen-delims / sub-delims
|
||||
|
||||
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
|
||||
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
/ "*" / "+" / "," / ";" / "="
|
8
samples/uri/rfc3986.hrl
Normal file
8
samples/uri/rfc3986.hrl
Normal file
@ -0,0 +1,8 @@
|
||||
-import(rfc4234_core, ['ALPHA'/0,
|
||||
'DIGIT'/0,
|
||||
%% 'WSP'/0,
|
||||
%% 'CRLF'/0,
|
||||
%% 'VCHAR'/0,
|
||||
%% 'DQUOTE'/0,
|
||||
%% 'BIT'/0,
|
||||
'HEXDIG'/0]).
|
14
src/Makefile
Executable file
14
src/Makefile
Executable file
@ -0,0 +1,14 @@
|
||||
include ../vsn.mk
|
||||
|
||||
VSN=$(ABNFC_VSN)
|
||||
|
||||
include ../include.mk
|
||||
|
||||
all: $(ERL_OBJECTS) ../ebin/abnfc.app
|
||||
|
||||
clean:
|
||||
-rm $(ERL_OBJECTS)
|
||||
|
||||
$(EBIN_DIR)/abnf_gen.beam: ../include/abnfc_ast.hrl
|
||||
$(EBIN_DIR)/abnfc_rfc4234.beam: abnfc_rfc4234.hrl ../include/abnfc_ast.hrl
|
||||
$(EBIN_DIR)/rfc4234_core.beam: rfc4234_core.hrl
|
9
src/abnfc.app.src
Executable file
9
src/abnfc.app.src
Executable file
@ -0,0 +1,9 @@
|
||||
%% -*- erlang -*-
|
||||
{application, abnfc,
|
||||
[{description,"ABNF parser generator"},
|
||||
{vsn,"%VSN%"},
|
||||
{modules,[%MODULES%]},
|
||||
{applications,[kernel,stdlib]},
|
||||
{registered,[]},
|
||||
{env,[]}
|
||||
]}.
|
160
src/abnfc.erl
Normal file
160
src/abnfc.erl
Normal file
@ -0,0 +1,160 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright 2009 Anders Nygren
|
||||
%%% @version {@vsn}
|
||||
%%% @author Anders Nygren <anders.nygren@gmail.com>
|
||||
%%% @doc
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(abnfc).
|
||||
|
||||
%% API
|
||||
-export([file/1, file/2,
|
||||
parse/1, parse/2]).
|
||||
|
||||
-export([erlangcode/0]).
|
||||
|
||||
-compile(export_all).
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec (File::string()) -> {ok, AST, Rest::binary()} | Error
|
||||
%% @doc Compile an ABNF file.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
file(File) ->
|
||||
file(File,[]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec (File::string(), Opts) -> {ok, AST, Rest::binary()} | Error
|
||||
%% Opts = [Option]
|
||||
%% Option = OutFile
|
||||
%% OutFile = string()
|
||||
%% @doc Compile an ABNF file.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
file(File, Opts) when is_list(Opts) ->
|
||||
case read_file(File) of
|
||||
{ok, Name, Text} ->
|
||||
POpts = [],
|
||||
GenOpts = gen_opts(Name, Opts),
|
||||
COpts = compiler_opts(Opts),
|
||||
case parse(Text, POpts) of
|
||||
{ok, AST, _Rest} ->
|
||||
AST1 = abnfc_ast:ast_to_int_form(AST),
|
||||
{ok, Code} = abnfc_gen:generate(AST1, GenOpts),
|
||||
{ok, GenFile} = write_file(Code, GenOpts),
|
||||
compile_file(GenFile, COpts);
|
||||
Error ->
|
||||
Error
|
||||
end;
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec (Text) -> {ok, AST, Rest::binary()} | fail
|
||||
%% Text = list() | binary()
|
||||
%% @doc Parse a list or binary.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
parse(Bin) ->
|
||||
parse(Bin, []).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec (Text, Opts) -> {ok, AST, Rest::list()} | fail
|
||||
%% Text = list() | binary()
|
||||
%% @doc Parse a list or binary.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
parse(Bin, Opts) when is_binary(Bin) ->
|
||||
parse(binary_to_list(Bin), Opts);
|
||||
|
||||
parse(String, _Opts) when is_list(String) ->
|
||||
case catch abnfc_rfc4234:rulelist_dec(String) of
|
||||
{ok, _Rulelist, []} =Result ->
|
||||
Result;
|
||||
_Error ->
|
||||
io:format("abnfc: failed~n",[])
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec () -> list()
|
||||
%% @doc Scan erlang code.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
erlangcode() ->
|
||||
fun (T) ->
|
||||
scan(T)
|
||||
end.
|
||||
|
||||
scan(Input) ->
|
||||
case erl_scan:tokens([], Input, 1) of
|
||||
{done, {ok, Toks, _EndLine}, Extra} ->
|
||||
Code = toks_to_list(Toks),
|
||||
{ok, Code, Extra};
|
||||
{more, _Cont} ->
|
||||
throw(end_of_input)
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @spec (Tokens) -> list()
|
||||
%% @doc Convert tokens returned by erl_scan to a string again.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
toks_to_list(Tokens) ->
|
||||
lists:foldl(fun({atom,L,Name},{Line, Acc}) ->
|
||||
{L,["'",Name,"'",sep(L,Line)|Acc]};
|
||||
({string,L,Name},{Line, Acc}) ->
|
||||
{L,["\"",Name,"\"",sep(L,Line)|Acc]};
|
||||
({_Type,L,Name},{Line, Acc}) ->
|
||||
{L,[Name,sep(L,Line)|Acc]};
|
||||
({dot,_L},{_Line,Acc}) ->
|
||||
lists:concat(lists:reverse(Acc));
|
||||
({Reserved, L},{Line,Acc}) ->
|
||||
{L,[Reserved,sep(L,Line)|Acc]}
|
||||
end, {1,[]}, Tokens).
|
||||
|
||||
sep(L,L) ->
|
||||
" ";
|
||||
sep(_,_) ->
|
||||
"\n".
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
||||
read_file(File) ->
|
||||
case string:tokens(filename:basename(File), ".") of
|
||||
[Name,"set","abnf"] ->
|
||||
{ok, Files} = file:consult(File),
|
||||
{ok, Name, lists:flatten([read_file1(F) || F <- Files])};
|
||||
[Name, "abnf"] ->
|
||||
{ok, Name, read_file1(File)}
|
||||
end.
|
||||
|
||||
read_file1(File) ->
|
||||
{ok, Bin} = file:read_file(File),
|
||||
binary_to_list(Bin).
|
||||
|
||||
gen_opts(Name, Opts) ->
|
||||
Mod = proplists:get_value(mod, Opts, Name),
|
||||
[{mod,Mod}].
|
||||
|
||||
compiler_opts(Opts) ->
|
||||
OutDir = proplists:get_value(o, Opts, "./"),
|
||||
IncludeDirs = [{i,Dir}||Dir <- proplists:get_all_values(i, Opts)],
|
||||
[{outdir,OutDir}|IncludeDirs].
|
||||
|
||||
write_file(Code, Opts) ->
|
||||
Name = filename:join(proplists:get_value(o, Opts, "."),
|
||||
proplists:get_value(mod, Opts))++".erl",
|
||||
io:format("abnfc: writing to ~p~n",[Name]),
|
||||
file:write_file(Name, Code),
|
||||
erl_tidy:file(Name,[{backups,false}]),
|
||||
{ok,Name}.
|
||||
|
||||
compile_file(File, Opts) ->
|
||||
io:format("abnfc: compiling ~p opts = ~p~n",[File, Opts]),
|
||||
compile:file(File, Opts).
|
||||
|
68
src/abnfc_ast.erl
Normal file
68
src/abnfc_ast.erl
Normal file
@ -0,0 +1,68 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright 2009 Anders Nygren
|
||||
%%% @version {@vsn}
|
||||
%%% @author Anders Nygren <anders.nygren@gmail.com>
|
||||
%%% @doc
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(abnfc_ast).
|
||||
|
||||
%% API
|
||||
%%-export([transform/2]).
|
||||
-compile(export_all).
|
||||
|
||||
-include("abnfc_ast.hrl").
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec (AST) -> INT_FORM
|
||||
%% @doc Transform an AST to the intermediate format.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
ast_to_int_form(#rulelist{rules=Rules}) ->
|
||||
[R#rule{body=transform(R#rule.body)}||R <- Rules].
|
||||
|
||||
|
||||
int_transform(INT, Fun) ->
|
||||
[R#rule{body=Fun(R#rule.body)} || R <- INT].
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
||||
|
||||
transform(#rule{body=Body}=R) ->
|
||||
R#rule{body=transform(Body)};
|
||||
transform(#alt{alts=Alts}=A) ->
|
||||
Alts1 = [transform(Alt)||Alt <- Alts],
|
||||
case char_alts(Alts1) of
|
||||
[C] when is_record(C,char_alt) ->
|
||||
C;
|
||||
Alts2 ->
|
||||
A#alt{alts=Alts2}
|
||||
end;
|
||||
transform(#seq{elements=Elems}=S) ->
|
||||
Elems1 = [transform(Elem)||Elem <- Elems],
|
||||
S#seq{elements=Elems1};
|
||||
transform(#repeat{body=Body}=R) ->
|
||||
R#repeat{body=transform(Body)};
|
||||
transform(Element) ->
|
||||
Element.
|
||||
|
||||
char_alts(Alts) ->
|
||||
char_alts(Alts, {[],[]}).
|
||||
|
||||
char_alts([Alt|Alts], {Chars,Others}) when is_record(Alt, char_val);
|
||||
is_record(Alt, char_range) ->
|
||||
char_alts(Alts,{Chars++[Alt], Others});
|
||||
char_alts([Alt|Alts], {Chars,Others}) ->
|
||||
char_alts(Alts,{Chars, Others++[Alt]});
|
||||
char_alts([], {[], Others}) ->
|
||||
Others;
|
||||
char_alts([], {Chars, Others}) ->
|
||||
[#char_alt{alts=lists:sort(Chars)}|Others].
|
||||
|
||||
%%====================================================================
|
||||
%% Test functions
|
||||
%%====================================================================
|
271
src/abnfc_gen.erl
Normal file
271
src/abnfc_gen.erl
Normal file
@ -0,0 +1,271 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright 2009 Anders Nygren
|
||||
%%% @version {@vsn}
|
||||
%%% @author Anders Nygren <anders.nygren@gmail.com>
|
||||
%%% @doc Code generation.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(abnfc_gen).
|
||||
|
||||
%% API
|
||||
-export([generate/2]).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("abnfc_ast.hrl").
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec
|
||||
%% @doc
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
generate(AST, Opts) ->
|
||||
{{Year,Month,Day},{Hour,Min,Sec}} = erlang:localtime(),
|
||||
DT = lists:flatten(
|
||||
io_lib:format("~w-~2.2.0w-~2.2.0w ~2.2.0w:~2.2.0w:~2.2.0w",
|
||||
[Year,Month,Day,Hour,Min,Sec])),
|
||||
Body = [gen_rule(R) || R <- AST],
|
||||
Module = proplists:get_value(mod,Opts),
|
||||
{ok, lists:flatten(io_lib:format(template(), [DT, Module, Module, Body]))}.
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
||||
|
||||
gen_rule(#rule{name=Name, body=Element, code=nocode}) ->
|
||||
io:format("abnfc_gen: generating rule ~p~n",[Name]),
|
||||
Body = lists:flatten(gen_elem(Element, 1)),
|
||||
mk_rule_fun(Name, Body);
|
||||
|
||||
gen_rule(#rule{name=Name, body=Element, code=Code}) ->
|
||||
Vars = gen_vars(Element),
|
||||
io:format("abnfc_gen: generating rule ~p~n",[Name]),
|
||||
Body = lists:flatten(gen_elem(Element, 1)),
|
||||
mk_rule_fun(Name, Body, Vars, Code).
|
||||
|
||||
gen_elem(#seq{elements=Elements}, Level) ->
|
||||
Str = "'__seq'(~n[~s~n])",
|
||||
Body = string:join([gen_elem(Element, Level+1)||Element <- Elements], ",\n"),
|
||||
io_lib:format(Str, [Body]);
|
||||
|
||||
gen_elem(#alt{alts=Elements}, Level) ->
|
||||
Str = "'__alt'(~n[~s~n])",
|
||||
Body = string:join([gen_elem(Element, Level+1)||Element <- Elements], ",\n"),
|
||||
io_lib:format(Str, [Body]);
|
||||
|
||||
gen_elem(#repeat{min=0, max=1, body=Elem}, Level) ->
|
||||
Str =
|
||||
"fun (Str) ->\n"
|
||||
" case (~s)(Str) of\n"
|
||||
" fail -> {ok, [], Str};\n"
|
||||
" {ok, _Res, _Tail} -> {ok,[_Res],_Tail}\n"
|
||||
" end\n"
|
||||
"end\n",
|
||||
io_lib:format(Str, [gen_elem(Elem, Level+1)]);
|
||||
|
||||
gen_elem(#repeat{min=Min, max=Max, body=Elem}, Level) ->
|
||||
Str = "'__repeat'(~n~p, ~p, ~n~s~n)",
|
||||
io_lib:format(Str, [Min, Max, gen_elem(Elem, Level+1)]);
|
||||
|
||||
gen_elem(#char_val{value=Num}, _Level) ->
|
||||
Str =
|
||||
"fun ([C|Tl]) \n"
|
||||
"when C==~p ->\n"
|
||||
" {ok, C, Tl};\n"
|
||||
" (_) ->\n"
|
||||
" fail\n"
|
||||
"end",
|
||||
io_lib:format(Str, [Num]);
|
||||
|
||||
gen_elem(#char_range{from=From, to=To}, _Level) ->
|
||||
Str =
|
||||
"fun([C|Tl]) when (C>=~p) and (C=<~p) ->~n"
|
||||
" {ok, C, Tl};\n"
|
||||
" (_) ->~n"
|
||||
" fail~n"
|
||||
" end",
|
||||
io_lib:format(Str, [From, To]);
|
||||
|
||||
gen_elem(#char_alt{alts=Alts}, _Level) ->
|
||||
Guard = num_alt_guard(1,Alts),
|
||||
ParList="C1",
|
||||
Str =
|
||||
"fun ([~s|Tl]) \n"
|
||||
"when ~s ->\n"
|
||||
" {ok, ~s, Tl};\n"
|
||||
" (_) ->\n"
|
||||
" fail\n"
|
||||
"end",
|
||||
io_lib:format(Str, [ParList, Guard, "C1"]);
|
||||
|
||||
gen_elem(#char_seq{elements=Nums}, _Level) ->
|
||||
Pars=[lists:flatten(io_lib:format("C~p",[N])) || N <- lists:seq(1,length(Nums))],
|
||||
ParList = num_par_list(length(Nums)),
|
||||
Guard = num_guard(Nums),
|
||||
Result = string:join(Pars,","),
|
||||
Str =
|
||||
"fun (~s) \n"
|
||||
"when ~s ->\n"
|
||||
" {ok, [~s], Tl};\n"
|
||||
" (_) ->\n"
|
||||
" fail\n"
|
||||
"end",
|
||||
io_lib:format(Str, [ParList, Guard, Result]);
|
||||
|
||||
gen_elem(#rulename{name=Rule}, _Level) when is_atom(Rule) ->
|
||||
Str = "~p()",
|
||||
io_lib:format(Str, [Rule]).
|
||||
|
||||
mk_rule_fun(Name, Body) ->
|
||||
Name1 = list_to_atom(atom_to_list(Name)++"_dec"),
|
||||
Str =
|
||||
"~p() ->~n"
|
||||
" fun (T) ->~n"
|
||||
" __P=~s,~n"
|
||||
" __P(T)~n"
|
||||
" end.~n"
|
||||
"~p(Str) ->~n"
|
||||
" (~p())(Str).~n~n",
|
||||
io_lib:format(Str, [Name, Body, Name1, Name]).
|
||||
|
||||
mk_rule_fun(Name, Body, Vars, Code) ->
|
||||
Name1 = list_to_atom(atom_to_list(Name)++"_dec"),
|
||||
Str =
|
||||
"~p() ->~n"
|
||||
" fun (T) -> ~n"
|
||||
" __P=~s,~n"
|
||||
" case __P(T) of~n"
|
||||
" {ok, ~s, __Rest} ->~n"
|
||||
" __Ret = begin~n"
|
||||
" ~s~n"
|
||||
" end,~n"
|
||||
" {ok, __Ret, __Rest};~n"
|
||||
" fail ->~n"
|
||||
" fail~n"
|
||||
" end~n"
|
||||
" end.~n~n"
|
||||
"~p(Str) ->~n"
|
||||
" (~p())(Str).~n~n",
|
||||
io_lib:format(Str, [Name, Body, Vars, Code, Name1, Name]).
|
||||
|
||||
gen_vars(#seq{elements=Es}) ->
|
||||
Vs = string:join([lists:concat(["_YY",N]) ||N<-lists:seq(1,length(Es))],", "),
|
||||
lists:concat(["[",Vs,"]=_YY"]);
|
||||
gen_vars(_) ->
|
||||
"_YY".
|
||||
|
||||
num_guard(Cs) ->
|
||||
{_,R} = lists:foldl(
|
||||
fun (#char_range{from=From,to=To},{Pos,Acc}) ->
|
||||
{Pos+1, [io_lib:format("((C~p>=~p) and (C~p=<~p))",
|
||||
[Pos,From, Pos, To])|Acc]};
|
||||
(#char_val{value=C}, {Pos,Acc}) ->
|
||||
{Pos+1, [io_lib:format("C~p==~p",[Pos,C])|Acc]};
|
||||
(#char_alt{alts=Alts}, {Pos,Acc}) ->
|
||||
{Pos+1,[num_alt_guard(Pos,Alts)|Acc]}
|
||||
end, {1,[]}, Cs),
|
||||
string:join(lists:reverse(R),",\n").
|
||||
|
||||
num_par_list(Len) ->
|
||||
lists:flatten(
|
||||
io_lib:format("[~s|Tl]",
|
||||
[string:join(
|
||||
[io_lib:format("C~p",[N]) || N <- lists:seq(1,Len)],",")])).
|
||||
|
||||
|
||||
num_alt_guard(Var, Alts) ->
|
||||
R = lists:foldl(
|
||||
fun (#char_range{from=From,to=To},Acc) ->
|
||||
[io_lib:format("((C~p>=~p) and (C~p=<~p))",
|
||||
[Var,From, Var, To])|Acc];
|
||||
(#char_val{value=C}, Acc) ->
|
||||
[io_lib:format("(C~p==~p)",[Var, C])|Acc]
|
||||
end, [], Alts),
|
||||
"("++string:join(lists:reverse(R)," or ")++")".
|
||||
|
||||
num_seq_guard(Es) ->
|
||||
{_,R} = lists:foldl(
|
||||
fun (E, {Pos,Acc}) ->
|
||||
Var = lists:concat(["C",Pos]),
|
||||
{Pos+1, ["("++num_alt_guard(Var, E)++")"|Acc]}
|
||||
end, {1, []}, Es),
|
||||
string:join(lists:reverse(R),"\nand ").
|
||||
|
||||
|
||||
template() ->
|
||||
"%% Do not modify this file, it is automatically\n"
|
||||
"%% generated by abnfc. All changes will be lost\n"
|
||||
"%% when it is regenerated.\n"
|
||||
"%% Generated by abnfc_gen on ~s\n\n"
|
||||
"-module(~s).\n"
|
||||
"-export([]).\n"
|
||||
"-compile(export_all).\n\n"
|
||||
"-include(\"~s.hrl\").\n\n"
|
||||
"~s\n"
|
||||
"\n\n"
|
||||
"%%================================================\n"
|
||||
"%% Run-time support functions\n"
|
||||
"%%================================================\n\n"
|
||||
"%% Match one of several parsers.\n"
|
||||
"'__alt'([P|Ps]) ->\n"
|
||||
" fun (T) ->\n"
|
||||
" case P(T) of\n"
|
||||
" {ok, R, T1} -> \n"
|
||||
" {ok, R, T1};\n"
|
||||
" fail -> \n"
|
||||
" case Ps of\n"
|
||||
" [] ->\n"
|
||||
" fail;\n"
|
||||
" _ ->\n"
|
||||
" ('__alt'(Ps))(T)\n"
|
||||
" end\n"
|
||||
" end\n"
|
||||
" end.\n"
|
||||
"\n\n"
|
||||
"%% Match between Min and Max repetitions of parser P\n"
|
||||
"'__repeat'(Min, Max, P) ->\n"
|
||||
" '__repeat'(Min, Max, P, 0).\n"
|
||||
"'__repeat'(Min, Max, P, Found) ->\n"
|
||||
" fun (T) ->\n"
|
||||
" case P(T) of\n"
|
||||
" {ok,R1,T1} when Max==Found+1 ->\n"
|
||||
" {ok, [R1], T1};\n"
|
||||
" {ok,R1,T1} ->\n"
|
||||
" case ('__repeat'(Min, Max, P, Found+1))(T1) of\n"
|
||||
" {ok,R2,T2} ->\n"
|
||||
" {ok,[R1|R2],T2};\n"
|
||||
" fail when Found >= Min ->\n"
|
||||
" {ok,[R1],T1};\n"
|
||||
" fail ->\n"
|
||||
" fail\n"
|
||||
" end;\n"
|
||||
" fail when Found >= Min ->\n"
|
||||
" {ok,[],T};\n"
|
||||
" fail ->\n"
|
||||
" fail\n"
|
||||
" end\n"
|
||||
" end.\n"
|
||||
"\n\n"
|
||||
"%% Match a sequence of parsers.\n"
|
||||
"'__seq'([P|Ps]) ->\n"
|
||||
" fun (T) ->\n"
|
||||
" case P(T) of\n"
|
||||
" {ok, R1, T1} ->\n"
|
||||
" case ('__seq'(Ps))(T1) of\n"
|
||||
" {ok, R2, T2} ->\n"
|
||||
" {ok, [R1|R2], T2};\n"
|
||||
" fail ->\n"
|
||||
" fail\n"
|
||||
" end;\n"
|
||||
" fail ->\n"
|
||||
" fail\n"
|
||||
" end\n"
|
||||
" end;\n"
|
||||
"'__seq'([]) ->\n"
|
||||
" fun(T) ->\n"
|
||||
" {ok,[],T}\n"
|
||||
" end.\n".
|
||||
|
104
src/abnfc_rfc4234.abnf
Normal file
104
src/abnfc_rfc4234.abnf
Normal file
@ -0,0 +1,104 @@
|
||||
rulelist = 1*( rule/ (*c-wsp c-nl)) :
|
||||
#rulelist{rules=[Rule || Rule <- _YY, is_tuple(Rule)]}.
|
||||
|
||||
rule = rulename defined-as elements [*WSP ":" *WSP erlangcode] c-nl :
|
||||
#rule{type=_YY2, name=element(2,_YY1), body=_YY3,
|
||||
code=case _YY4 of
|
||||
[[_,_,_,Code]] -> Code;
|
||||
[] -> nocode
|
||||
end}.
|
||||
|
||||
rulename = ALPHA *(ALPHA/ DIGIT/ "-") :
|
||||
#rulename{name=list_to_atom(lists:flatten(_YY))}.
|
||||
|
||||
defined-as = *c-wsp ("="/ "=/") *c-wsp :
|
||||
case _YY2 of
|
||||
$= -> def_rule;
|
||||
_ -> app_rule
|
||||
end.
|
||||
|
||||
elements = alternation *c-wsp : _YY1.
|
||||
|
||||
c-wsp = WSP/ (c-nl WSP) : 'c-wsp'.
|
||||
|
||||
c-nl = comment/ CRLF : 'c-nl'.
|
||||
|
||||
comment = ";" *(WSP/ VCHAR) CRLF : comment.
|
||||
|
||||
alternation = concatenation *(*c-wsp "/" *c-wsp concatenation) :
|
||||
case [Alt || [_,_,_,Alt] <- _YY2] of
|
||||
[] -> _YY1;
|
||||
Alts -> #alt{alts=[_YY1 | Alts]}
|
||||
end.
|
||||
|
||||
concatenation = repetition *(1*c-wsp repetition) :
|
||||
case [Rule || [_,Rule] <- _YY2] of
|
||||
[] -> _YY1;
|
||||
More -> #seq{elements=[_YY1 | More]}
|
||||
end.
|
||||
|
||||
repetition = [repeat] element :
|
||||
case _YY1 of
|
||||
[{Min,Max}] -> #repeat{min=Min,max=Max,body=_YY2};
|
||||
[] -> _YY2
|
||||
end.
|
||||
|
||||
repeat = (*DIGIT "*" *DIGIT)/ 1*DIGIT :
|
||||
case _YY of
|
||||
[[],$*,[]] -> {0, infinity};
|
||||
[Min, $*, []] -> {list_to_integer(Min), infinity};
|
||||
[[], $*, Max] -> {0, list_to_integer(Max)};
|
||||
[Min, $*, Max] -> {list_to_integer(Min), list_to_integer(Max)};
|
||||
Number -> {list_to_integer(Number), list_to_integer(Number)}
|
||||
end.
|
||||
|
||||
element = rulename/ group/ option/ char-val/ num-val/ prose-val
|
||||
|
||||
group = "(" *c-wsp alternation *c-wsp ")" : _YY3.
|
||||
|
||||
option = "[" *c-wsp alternation *c-wsp "]" :
|
||||
{repeat, 0, 1, _YY3}.
|
||||
|
||||
char-val = DQUOTE *(%x20-21/ %x23-7E) DQUOTE :
|
||||
F = fun (Char) ->
|
||||
case {string:to_lower(Char),string:to_upper(Char)} of
|
||||
{Char,Char} -> #char_val{value=Char};
|
||||
{Low,Up} -> #char_alt{alts=[#char_val{value=Low},
|
||||
#char_val{value=Up}]}
|
||||
end
|
||||
end,
|
||||
case _YY2 of
|
||||
[C] -> F(C);
|
||||
Chars -> #char_seq{elements=[F(C)||C<-Chars]}
|
||||
end.
|
||||
|
||||
num-val = "%" (bin-val/ dec-val/ hex-val) : _YY2.
|
||||
|
||||
bin-val = "b" 1*BIT [ 1*("." 1*BIT)/ ("-" 1*BIT)] :
|
||||
First = bin_to_int(_YY2),
|
||||
case _YY3 of
|
||||
[] -> #char_val{value=First};
|
||||
[[$-,To]] -> #char_range{from=First, to=bin_to_int(To)};
|
||||
[Vals] -> #char_seq{elements=[#char_val{value=First}|[#char_val{value=bin_to_int(Val)}||[$.,Val] <- Vals]]}
|
||||
end.
|
||||
|
||||
dec-val = "d" 1*DIGIT [ 1*("." 1*DIGIT)/ ("-" 1*DIGIT)] :
|
||||
First = list_to_integer(_YY2),
|
||||
case _YY3 of
|
||||
[] -> #char_val{value=First};
|
||||
[[$-,To]] -> #char_range{from=First, to=list_to_integer(To)};
|
||||
[Vals] -> #char_seq{elements=[#char_val{value=First}|[#char_val{value=list_to_integer(Val)}||[$.,Val] <- Vals]]}
|
||||
end.
|
||||
|
||||
hex-val = "x" 1*HEXDIG [ 1*("." 1*HEXDIG)/ ("-" 1*HEXDIG)] :
|
||||
First = hex_to_int(_YY2),
|
||||
case _YY3 of
|
||||
[] -> #char_val{value=First};
|
||||
[[$-,To]] -> #char_range{from=First, to=hex_to_int(To)};
|
||||
[Vals] -> #char_seq{elements=[#char_val{value=First}|[#char_val{value=hex_to_int(Val)}||[$.,Val] <- Vals]]}
|
||||
end.
|
||||
|
||||
|
||||
prose-val = "<" *(%x20-3D/ %x3F-7E) ">" :
|
||||
{'prose-val', lists:flatten(_YY2)}.
|
||||
|
644
src/abnfc_rfc4234.erl
Normal file
644
src/abnfc_rfc4234.erl
Normal file
@ -0,0 +1,644 @@
|
||||
%% Do not modify this file, it is automatically
|
||||
%% generated by abnfc. All changes will be lost
|
||||
%% when it is regenerated.
|
||||
%% Generated by abnfc_gen on 2009-02-24 17:14:16
|
||||
|
||||
-module(abnfc_rfc4234).
|
||||
|
||||
-export([]).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("abnfc_rfc4234.hrl").
|
||||
|
||||
rulelist() ->
|
||||
fun (T) ->
|
||||
__P = '__repeat'(1, infinity,
|
||||
'__alt'([rule(),
|
||||
'__seq'(['__repeat'(0, infinity,
|
||||
'c-wsp'()),
|
||||
'c-nl'()])])),
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
#rulelist{rules =
|
||||
[Rule || Rule <- _YY, is_tuple(Rule)]}
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
rulelist_dec(Str) -> (rulelist())(Str).
|
||||
|
||||
rule() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([rulename(), 'defined-as'(), elements(),
|
||||
fun (Str) ->
|
||||
case ('__seq'(['__repeat'(0, infinity,
|
||||
'WSP'()),
|
||||
fun ([C | Tl]) when C == 58 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(0, infinity,
|
||||
'WSP'()),
|
||||
erlangcode()]))(Str)
|
||||
of
|
||||
fail -> {ok, [], Str};
|
||||
{ok, _Res, _Tail} -> {ok, [_Res], _Tail}
|
||||
end
|
||||
end,
|
||||
'c-nl'()]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3, _YY4, _YY5] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
#rule{type = _YY2, name = element(2, _YY1),
|
||||
body = _YY3,
|
||||
code =
|
||||
case _YY4 of
|
||||
[[_, _, _, Code]] -> Code;
|
||||
[] -> nocode
|
||||
end}
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
rule_dec(Str) -> (rule())(Str).
|
||||
|
||||
rulename() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'(['ALPHA'(),
|
||||
'__repeat'(0, infinity,
|
||||
'__alt'([fun ([C1 | Tl]) when C1 == 45 ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'ALPHA'(), 'DIGIT'()]))]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
#rulename{name = list_to_atom(lists:flatten(_YY))}
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
rulename_dec(Str) -> (rulename())(Str).
|
||||
|
||||
'defined-as'() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'(['__repeat'(0, infinity, 'c-wsp'()),
|
||||
'__alt'([fun ([C1 | Tl]) when C1 == 61 ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
fun ([C1, C2 | Tl])
|
||||
when C1 == 61, C2 == 47 ->
|
||||
{ok, [C1, C2], Tl};
|
||||
(_) -> fail
|
||||
end]),
|
||||
'__repeat'(0, infinity, 'c-wsp'())]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
case _YY2 of
|
||||
61 -> def_rule;
|
||||
_ -> app_rule
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'defined-as_dec'(Str) -> ('defined-as'())(Str).
|
||||
|
||||
elements() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([alternation(),
|
||||
'__repeat'(0, infinity, 'c-wsp'())]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2] = _YY, __Rest} ->
|
||||
__Ret = begin _YY1 end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
elements_dec(Str) -> (elements())(Str).
|
||||
|
||||
'c-wsp'() ->
|
||||
fun (T) ->
|
||||
__P = '__alt'(['WSP'(), '__seq'(['c-nl'(), 'WSP'()])]),
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'c-wsp' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'c-wsp_dec'(Str) -> ('c-wsp'())(Str).
|
||||
|
||||
'c-nl'() ->
|
||||
fun (T) ->
|
||||
__P = '__alt'([comment(), 'CRLF'()]),
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'c-nl' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'c-nl_dec'(Str) -> ('c-nl'())(Str).
|
||||
|
||||
comment() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C | Tl]) when C == 59 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(0, infinity,
|
||||
'__alt'(['WSP'(), 'VCHAR'()])),
|
||||
'CRLF'()]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3] = _YY, __Rest} ->
|
||||
__Ret = begin comment end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
comment_dec(Str) -> (comment())(Str).
|
||||
|
||||
alternation() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([concatenation(),
|
||||
'__repeat'(0, infinity,
|
||||
'__seq'(['__repeat'(0, infinity,
|
||||
'c-wsp'()),
|
||||
fun ([C | Tl]) when C == 47 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(0, infinity,
|
||||
'c-wsp'()),
|
||||
concatenation()]))]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
case [Alt || [_, _, _, Alt] <- _YY2] of
|
||||
[] -> _YY1;
|
||||
Alts -> #alt{alts = [_YY1 | Alts]}
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
alternation_dec(Str) -> (alternation())(Str).
|
||||
|
||||
concatenation() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([repetition(),
|
||||
'__repeat'(0, infinity,
|
||||
'__seq'(['__repeat'(1, infinity,
|
||||
'c-wsp'()),
|
||||
repetition()]))]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
case [Rule || [_, Rule] <- _YY2] of
|
||||
[] -> _YY1;
|
||||
More -> #seq{elements = [_YY1 | More]}
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
concatenation_dec(Str) -> (concatenation())(Str).
|
||||
|
||||
repetition() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun (Str) ->
|
||||
case (repeat())(Str) of
|
||||
fail -> {ok, [], Str};
|
||||
{ok, _Res, _Tail} -> {ok, [_Res], _Tail}
|
||||
end
|
||||
end,
|
||||
element()]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
case _YY1 of
|
||||
[{Min, Max}] ->
|
||||
#repeat{min = Min, max = Max, body = _YY2};
|
||||
[] -> _YY2
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
repetition_dec(Str) -> (repetition())(Str).
|
||||
|
||||
repeat() ->
|
||||
fun (T) ->
|
||||
__P = '__alt'(['__seq'(['__repeat'(0, infinity,
|
||||
'DIGIT'()),
|
||||
fun ([C | Tl]) when C == 42 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(0, infinity, 'DIGIT'())]),
|
||||
'__repeat'(1, infinity, 'DIGIT'())]),
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
case _YY of
|
||||
[[], 42, []] -> {0, infinity};
|
||||
[Min, 42, []] -> {list_to_integer(Min), infinity};
|
||||
[[], 42, Max] -> {0, list_to_integer(Max)};
|
||||
[Min, 42, Max] ->
|
||||
{list_to_integer(Min), list_to_integer(Max)};
|
||||
Number ->
|
||||
{list_to_integer(Number),
|
||||
list_to_integer(Number)}
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
repeat_dec(Str) -> (repeat())(Str).
|
||||
|
||||
element() ->
|
||||
fun (T) ->
|
||||
__P = '__alt'([rulename(), group(), option(),
|
||||
'char-val'(), 'num-val'(), 'prose-val'()]),
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
element_dec(Str) -> (element())(Str).
|
||||
|
||||
group() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C | Tl]) when C == 40 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(0, infinity, 'c-wsp'()), alternation(),
|
||||
'__repeat'(0, infinity, 'c-wsp'()),
|
||||
fun ([C | Tl]) when C == 41 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3, _YY4, _YY5] = _YY, __Rest} ->
|
||||
__Ret = begin _YY3 end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
group_dec(Str) -> (group())(Str).
|
||||
|
||||
option() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C | Tl]) when C == 91 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(0, infinity, 'c-wsp'()), alternation(),
|
||||
'__repeat'(0, infinity, 'c-wsp'()),
|
||||
fun ([C | Tl]) when C == 93 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3, _YY4, _YY5] = _YY, __Rest} ->
|
||||
__Ret = begin {repeat, 0, 1, _YY3} end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
option_dec(Str) -> (option())(Str).
|
||||
|
||||
'char-val'() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'(['DQUOTE'(),
|
||||
'__repeat'(0, infinity,
|
||||
fun ([C1 | Tl])
|
||||
when (C1 >= 32) and (C1 =< 33) or
|
||||
(C1 >= 35) and
|
||||
(C1 =< 126) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end),
|
||||
'DQUOTE'()]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
F = fun (Char) ->
|
||||
case {string:to_lower(Char),
|
||||
string:to_upper(Char)}
|
||||
of
|
||||
{Char, Char} ->
|
||||
#char_val{value = Char};
|
||||
{Low, Up} ->
|
||||
#char_alt{alts =
|
||||
[#char_val{value =
|
||||
Low},
|
||||
#char_val{value =
|
||||
Up}]}
|
||||
end
|
||||
end,
|
||||
case _YY2 of
|
||||
[C] -> F(C);
|
||||
Chars ->
|
||||
#char_seq{elements = [F(C) || C <- Chars]}
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'char-val_dec'(Str) -> ('char-val'())(Str).
|
||||
|
||||
'num-val'() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C | Tl]) when C == 37 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__alt'(['bin-val'(), 'dec-val'(), 'hex-val'()])]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2] = _YY, __Rest} ->
|
||||
__Ret = begin _YY2 end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'num-val_dec'(Str) -> ('num-val'())(Str).
|
||||
|
||||
'bin-val'() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C1 | Tl])
|
||||
when (C1 == 98) or (C1 == 66) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(1, infinity, 'BIT'()),
|
||||
fun (Str) ->
|
||||
case ('__alt'(['__repeat'(1, infinity,
|
||||
'__seq'([fun ([C
|
||||
| Tl])
|
||||
when
|
||||
C
|
||||
==
|
||||
46 ->
|
||||
{ok,
|
||||
C,
|
||||
Tl};
|
||||
(_) ->
|
||||
fail
|
||||
end,
|
||||
'__repeat'(1,
|
||||
infinity,
|
||||
'BIT'())])),
|
||||
'__seq'([fun ([C | Tl])
|
||||
when C ==
|
||||
45 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(1,
|
||||
infinity,
|
||||
'BIT'())])]))(Str)
|
||||
of
|
||||
fail -> {ok, [], Str};
|
||||
{ok, _Res, _Tail} -> {ok, [_Res], _Tail}
|
||||
end
|
||||
end]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
First = bin_to_int(_YY2),
|
||||
case _YY3 of
|
||||
[] -> #char_val{value = First};
|
||||
[[45, To]] ->
|
||||
#char_range{from = First,
|
||||
to = bin_to_int(To)};
|
||||
[Vals] ->
|
||||
#char_seq{elements =
|
||||
[#char_val{value = First}
|
||||
| [#char_val{value =
|
||||
bin_to_int(Val)}
|
||||
|| [46, Val] <- Vals]]}
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'bin-val_dec'(Str) -> ('bin-val'())(Str).
|
||||
|
||||
'dec-val'() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C1 | Tl])
|
||||
when (C1 == 100) or (C1 == 68) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(1, infinity, 'DIGIT'()),
|
||||
fun (Str) ->
|
||||
case ('__alt'(['__repeat'(1, infinity,
|
||||
'__seq'([fun ([C
|
||||
| Tl])
|
||||
when
|
||||
C
|
||||
==
|
||||
46 ->
|
||||
{ok,
|
||||
C,
|
||||
Tl};
|
||||
(_) ->
|
||||
fail
|
||||
end,
|
||||
'__repeat'(1,
|
||||
infinity,
|
||||
'DIGIT'())])),
|
||||
'__seq'([fun ([C | Tl])
|
||||
when C ==
|
||||
45 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(1,
|
||||
infinity,
|
||||
'DIGIT'())])]))(Str)
|
||||
of
|
||||
fail -> {ok, [], Str};
|
||||
{ok, _Res, _Tail} -> {ok, [_Res], _Tail}
|
||||
end
|
||||
end]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
First = list_to_integer(_YY2),
|
||||
case _YY3 of
|
||||
[] -> #char_val{value = First};
|
||||
[[45, To]] ->
|
||||
#char_range{from = First,
|
||||
to = list_to_integer(To)};
|
||||
[Vals] ->
|
||||
#char_seq{elements =
|
||||
[#char_val{value = First}
|
||||
| [#char_val{value =
|
||||
list_to_integer(Val)}
|
||||
|| [46, Val] <- Vals]]}
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'dec-val_dec'(Str) -> ('dec-val'())(Str).
|
||||
|
||||
'hex-val'() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C1 | Tl])
|
||||
when (C1 == 120) or (C1 == 88) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(1, infinity, 'HEXDIG'()),
|
||||
fun (Str) ->
|
||||
case ('__alt'(['__repeat'(1, infinity,
|
||||
'__seq'([fun ([C
|
||||
| Tl])
|
||||
when
|
||||
C
|
||||
==
|
||||
46 ->
|
||||
{ok,
|
||||
C,
|
||||
Tl};
|
||||
(_) ->
|
||||
fail
|
||||
end,
|
||||
'__repeat'(1,
|
||||
infinity,
|
||||
'HEXDIG'())])),
|
||||
'__seq'([fun ([C | Tl])
|
||||
when C ==
|
||||
45 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(1,
|
||||
infinity,
|
||||
'HEXDIG'())])]))(Str)
|
||||
of
|
||||
fail -> {ok, [], Str};
|
||||
{ok, _Res, _Tail} -> {ok, [_Res], _Tail}
|
||||
end
|
||||
end]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3] = _YY, __Rest} ->
|
||||
__Ret = begin
|
||||
First = hex_to_int(_YY2),
|
||||
case _YY3 of
|
||||
[] -> #char_val{value = First};
|
||||
[[45, To]] ->
|
||||
#char_range{from = First,
|
||||
to = hex_to_int(To)};
|
||||
[Vals] ->
|
||||
#char_seq{elements =
|
||||
[#char_val{value = First}
|
||||
| [#char_val{value =
|
||||
hex_to_int(Val)}
|
||||
|| [46, Val] <- Vals]]}
|
||||
end
|
||||
end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'hex-val_dec'(Str) -> ('hex-val'())(Str).
|
||||
|
||||
'prose-val'() ->
|
||||
fun (T) ->
|
||||
__P = '__seq'([fun ([C | Tl]) when C == 60 ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
'__repeat'(0, infinity,
|
||||
fun ([C1 | Tl])
|
||||
when (C1 >= 32) and (C1 =< 61) or
|
||||
(C1 >= 63) and
|
||||
(C1 =< 126) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end),
|
||||
fun ([C | Tl]) when C == 62 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end]),
|
||||
case __P(T) of
|
||||
{ok, [_YY1, _YY2, _YY3] = _YY, __Rest} ->
|
||||
__Ret = begin {'prose-val', lists:flatten(_YY2)} end,
|
||||
{ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'prose-val_dec'(Str) -> ('prose-val'())(Str).
|
||||
|
||||
'__alt'([P | Ps]) ->
|
||||
fun (T) ->
|
||||
case P(T) of
|
||||
{ok, R, T1} -> {ok, R, T1};
|
||||
fail ->
|
||||
case Ps of
|
||||
[] -> fail;
|
||||
_ -> ('__alt'(Ps))(T)
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
'__repeat'(Min, Max, P) -> '__repeat'(Min, Max, P, 0).
|
||||
|
||||
'__repeat'(Min, Max, P, Found) ->
|
||||
fun (T) ->
|
||||
case P(T) of
|
||||
{ok, R1, T1} when Max == Found + 1 -> {ok, [R1], T1};
|
||||
{ok, R1, T1} ->
|
||||
case ('__repeat'(Min, Max, P, Found + 1))(T1) of
|
||||
{ok, R2, T2} -> {ok, [R1 | R2], T2};
|
||||
fail when Found >= Min -> {ok, [R1], T1};
|
||||
fail -> fail
|
||||
end;
|
||||
fail when Found >= Min -> {ok, [], T};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'__seq'([P | Ps]) ->
|
||||
fun (T) ->
|
||||
case P(T) of
|
||||
{ok, R1, T1} ->
|
||||
case ('__seq'(Ps))(T1) of
|
||||
{ok, R2, T2} -> {ok, [R1 | R2], T2};
|
||||
fail -> fail
|
||||
end;
|
||||
fail -> fail
|
||||
end
|
||||
end;
|
||||
'__seq'([]) -> fun (T) -> {ok, [], T} end.
|
33
src/abnfc_rfc4234.hrl
Normal file
33
src/abnfc_rfc4234.hrl
Normal file
@ -0,0 +1,33 @@
|
||||
-import(abnfc,[erlangcode/0]).
|
||||
-import(rfc4234_core, ['ALPHA'/0,
|
||||
'DIGIT'/0,
|
||||
'WSP'/0,
|
||||
'CRLF'/0,
|
||||
'VCHAR'/0,
|
||||
'DQUOTE'/0,
|
||||
'BIT'/0,
|
||||
'HEXDIG'/0]).
|
||||
|
||||
-include("abnfc_ast.hrl").
|
||||
|
||||
hex_to_int(Ds) ->
|
||||
lists:foldl(fun(D,Acc) ->
|
||||
Dint = case D of
|
||||
D when D >= $0, D =< $9 ->
|
||||
D-$0;
|
||||
D when D >= $a, D =< $f ->
|
||||
D-$a+10;
|
||||
D when D >= $A, D =< $F ->
|
||||
D-$A+10
|
||||
end,
|
||||
Acc*16 + Dint
|
||||
end, 0, Ds).
|
||||
|
||||
dec_to_int(Ds) ->
|
||||
list_to_integer(Ds).
|
||||
|
||||
bin_to_int(Ds) ->
|
||||
lists:foldl(fun(D,Acc) ->
|
||||
Dint = D-$0,
|
||||
Acc*2 + Dint
|
||||
end, 0, Ds).
|
32
src/rfc4234_core.abnf
Normal file
32
src/rfc4234_core.abnf
Normal file
@ -0,0 +1,32 @@
|
||||
ALPHA = %x41-5A/ %x61-7A
|
||||
|
||||
BIT = "0"/ "1"
|
||||
|
||||
CHAR = %x01-7F
|
||||
|
||||
CR = %x0D
|
||||
|
||||
CRLF = LF/ (CR LF)
|
||||
|
||||
CTL = %x00-1F/ %x7F
|
||||
|
||||
DIGIT = %x30-39
|
||||
|
||||
DQUOTE = %x22
|
||||
|
||||
HEXDIG = DIGIT/ "A"/ "B"/ "C"/ "D"/ "E"/ "F"
|
||||
|
||||
HTAB = %x09
|
||||
|
||||
LF = %x0A
|
||||
|
||||
LWSP = *(WSP/ CRLF WSP)
|
||||
|
||||
OCTET = %x00-FF
|
||||
|
||||
SP = %x20
|
||||
|
||||
VCHAR = %x21-7E
|
||||
|
||||
WSP = SP/ HTAB
|
||||
|
273
src/rfc4234_core.erl
Normal file
273
src/rfc4234_core.erl
Normal file
@ -0,0 +1,273 @@
|
||||
%% Do not modify this file, it is automatically
|
||||
%% generated by abnfc. All changes will be lost
|
||||
%% when it is regenerated.
|
||||
%% Generated by abnfc_gen on 2009-02-24 17:13:56
|
||||
|
||||
-module(rfc4234_core).
|
||||
|
||||
-export([]).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("rfc4234_core.hrl").
|
||||
|
||||
'ALPHA'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C1 | Tl])
|
||||
when (C1 >= 65) and (C1 =< 90) or
|
||||
(C1 >= 97) and (C1 =< 122) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'ALPHA_dec'(Str) -> ('ALPHA'())(Str).
|
||||
|
||||
'BIT'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C1 | Tl]) when (C1 == 48) or (C1 == 49) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'BIT_dec'(Str) -> ('BIT'())(Str).
|
||||
|
||||
'CHAR'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when (C >= 1) and (C =< 127) ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'CHAR_dec'(Str) -> ('CHAR'())(Str).
|
||||
|
||||
'CR'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when C == 13 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'CR' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'CR_dec'(Str) -> ('CR'())(Str).
|
||||
|
||||
'CRLF'() ->
|
||||
fun (T) ->
|
||||
__P = '__alt'(['LF'(), '__seq'(['CR'(), 'LF'()])]),
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'CRLF' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'CRLF_dec'(Str) -> ('CRLF'())(Str).
|
||||
|
||||
'CTL'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C1 | Tl])
|
||||
when (C1 == 127) or (C1 >= 0) and (C1 =< 31) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'CTL_dec'(Str) -> ('CTL'())(Str).
|
||||
|
||||
'DIGIT'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when (C >= 48) and (C =< 57) ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'DIGIT_dec'(Str) -> ('DIGIT'())(Str).
|
||||
|
||||
'DQUOTE'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when C == 34 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'DQUOTE' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'DQUOTE_dec'(Str) -> ('DQUOTE'())(Str).
|
||||
|
||||
'HEXDIG'() ->
|
||||
fun (T) ->
|
||||
__P = '__alt'(['DIGIT'(),
|
||||
fun ([C1 | Tl]) when (C1 == 97) or (C1 == 65) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
fun ([C1 | Tl]) when (C1 == 98) or (C1 == 66) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
fun ([C1 | Tl]) when (C1 == 99) or (C1 == 67) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
fun ([C1 | Tl]) when (C1 == 100) or (C1 == 68) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
fun ([C1 | Tl]) when (C1 == 101) or (C1 == 69) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
fun ([C1 | Tl]) when (C1 == 102) or (C1 == 70) ->
|
||||
{ok, C1, Tl};
|
||||
(_) -> fail
|
||||
end]),
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'HEXDIG_dec'(Str) -> ('HEXDIG'())(Str).
|
||||
|
||||
'HTAB'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when C == 9 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'HTAB' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'HTAB_dec'(Str) -> ('HTAB'())(Str).
|
||||
|
||||
'LF'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when C == 10 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'LF' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'LF_dec'(Str) -> ('LF'())(Str).
|
||||
|
||||
'LWSP'() ->
|
||||
fun (T) ->
|
||||
__P = '__repeat'(0, infinity,
|
||||
'__alt'(['WSP'(), '__seq'(['CRLF'(), 'WSP'()])])),
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'LWSP' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'LWSP_dec'(Str) -> ('LWSP'())(Str).
|
||||
|
||||
'OCTET'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when (C >= 0) and (C =< 255) ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'OCTET_dec'(Str) -> ('OCTET'())(Str).
|
||||
|
||||
'SP'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when C == 32 -> {ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'SP' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'SP_dec'(Str) -> ('SP'())(Str).
|
||||
|
||||
'VCHAR'() ->
|
||||
fun (T) ->
|
||||
__P = fun ([C | Tl]) when (C >= 33) and (C =< 126) ->
|
||||
{ok, C, Tl};
|
||||
(_) -> fail
|
||||
end,
|
||||
__P(T)
|
||||
end.
|
||||
|
||||
'VCHAR_dec'(Str) -> ('VCHAR'())(Str).
|
||||
|
||||
'WSP'() ->
|
||||
fun (T) ->
|
||||
__P = '__alt'(['SP'(), 'HTAB'()]),
|
||||
case __P(T) of
|
||||
{ok, _YY, __Rest} ->
|
||||
__Ret = begin 'WSP' end, {ok, __Ret, __Rest};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'WSP_dec'(Str) -> ('WSP'())(Str).
|
||||
|
||||
'__alt'([P | Ps]) ->
|
||||
fun (T) ->
|
||||
case P(T) of
|
||||
{ok, R, T1} -> {ok, R, T1};
|
||||
fail ->
|
||||
case Ps of
|
||||
[] -> fail;
|
||||
_ -> ('__alt'(Ps))(T)
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
'__repeat'(Min, Max, P) -> '__repeat'(Min, Max, P, 0).
|
||||
|
||||
'__repeat'(Min, Max, P, Found) ->
|
||||
fun (T) ->
|
||||
case P(T) of
|
||||
{ok, R1, T1} when Max == Found + 1 -> {ok, [R1], T1};
|
||||
{ok, R1, T1} ->
|
||||
case ('__repeat'(Min, Max, P, Found + 1))(T1) of
|
||||
{ok, R2, T2} -> {ok, [R1 | R2], T2};
|
||||
fail when Found >= Min -> {ok, [R1], T1};
|
||||
fail -> fail
|
||||
end;
|
||||
fail when Found >= Min -> {ok, [], T};
|
||||
fail -> fail
|
||||
end
|
||||
end.
|
||||
|
||||
'__seq'([P | Ps]) ->
|
||||
fun (T) ->
|
||||
case P(T) of
|
||||
{ok, R1, T1} ->
|
||||
case ('__seq'(Ps))(T1) of
|
||||
{ok, R2, T2} -> {ok, [R1 | R2], T2};
|
||||
fail -> fail
|
||||
end;
|
||||
fail -> fail
|
||||
end
|
||||
end;
|
||||
'__seq'([]) -> fun (T) -> {ok, [], T} end.
|
10
src/rfc4234_core.hrl
Normal file
10
src/rfc4234_core.hrl
Normal file
@ -0,0 +1,10 @@
|
||||
%% Callback functions for rfc 4234 core rules.
|
||||
|
||||
'LF_cb'(_) ->'LF'.
|
||||
'CR_cb'(_) -> 'CR'.
|
||||
'CRLF_cb'(_) -> 'CRLF'.
|
||||
'DQUOTE_cb'(_) -> 'DQUOTE'.
|
||||
'HTAB_cb'(_) -> 'HTAB'.
|
||||
'LWSP_cb'(_) -> 'LWSP'.
|
||||
'SP_cb'(_) -> 'SP'.
|
||||
'WSP_cb'(_) -> 'WSP'.
|
Loading…
Reference in New Issue
Block a user