Initial import

This commit is contained in:
Anders Nygren 2009-02-24 17:59:56 -06:00
commit 9446a8cea0
38 changed files with 4817 additions and 0 deletions

10
Makefile Executable file
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,2 @@
RFC 2616 uses an older variant of ABNF that is not yet supported by
ABNFC.

View 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
View 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

View 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

View 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
View 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

View 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 / "-" / "+")

View 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
View 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

View 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

View File

@ -0,0 +1,5 @@
-import(rfc3261, ['COMMA'/0,
'HCOLON'/0,
'addr-spec'/0,
'name-addr'/0
]).

1011
samples/rfc3325/rfc3325.txt Normal file

File diff suppressed because it is too large Load Diff

12
samples/sdp/Makefile Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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'.

1
vsn.mk Executable file
View File

@ -0,0 +1 @@
ABNFC_VSN=0.3