; Copyright Glen Knowles 2016 - 2022.
; Distributed under the Boost Software License, Version 1.0.
;
; xml.abnf - dim xml
;
; rules to parse xml
%root = document
%api.prefix = XmlBase
%api.namespace = Dim::Detail

; abnf grammer rules for xml
; The number notations, such as "[1]" refer to the same numbered ABNF
; lines in the xml spec fifth edition at:
;   https://www.w3.org/TR/2008/REC-xml-20081126/

; Document
document = [utf8-bom] prolog element *Misc     ; [1]
utf8-bom = %xef.bb.bf

; Character Range and White Space
ws = SP / HTAB / CR / LF { NoMinRules }
ws = SP { MinRules }
Char = ws / %x21-7f     ; [2]
mbchar = %s"Z" { MinRules }
mbchar = ; multibyte utf-8 character
    ; 2 byte: 0080 - 07ff
    (%xc2-df %x80-bf)                       ; 0080 - 07ff
    ; 3 byte: 0800 - d7ff
    / (%xe0 %xa0-bf %x80-bf)                ; 0800 - 0fff
        / (%xe1-ec %x80-bf %x80-bf)         ; 1000 - cfff
        / (%xed %x80-9f %x80-bf)            ; d000 - d7ff
    ; 3 byte: e000 - fffd
    / (%xee %x80-bf %x80-bf)                ; e000 - efff
        / (%xef %x80-be %x80-bf)            ; f000 - ffbf
        / (%xef %xbf %x80-bd)               ; ffc0 - fffd
    ; 4 byte: 01'0000 - 10'ffff
    / (%xf0 %x90-bf %x80-bf %x80-bf)        ; 01'0000 - 03'ffff
        / (%xf1-f3 %x80-bf %x80-bf %x80-bf) ; 04'0000 - 0f'ffff
        / (%xf4 %x80-8f %x80-bf %x80-bf)    ; 10'0000 - 10'ffff
    { NoMinRules }
S = 1*ws         ; [3]

; Names and Tokens
NameStartChar = ":" / ALPHA / "_" / NameStartCharMulti ; [4]
NameStartCharMulti = %s"Z" { MinRules }
NameStartCharMulti =
    ; c0 - d6
    (%xc3 %x80-96)
    ; d8 - f6
    / (%xc3 %x98-b6)
    ; f8 - 2ff
    / (%xc3 %xb8-bf)                        ; f8 - ff
        / (%xc4-cb %x80-bf)                 ; 100 - 2ff
    ; 370 - 37d
    / (%xcd %xb0-bd)
    ; 37f - 1fff
    / (%xcd %xbf) ; 37f
        / (%xce-df %x80-bf)                 ; 380 - 7ff
        / (%xe0 %xa0-bf %x80-bf)            ; 800 - fff
        / (%xe1 %x80-bf %x80-bf)            ; 1000 - 1fff
    ; 200c - 200d
    / (%xe2 %x80 %x8c-8d)
    ; 2070 - 218f
    / (%xe2 %x81 %xb0-bf)                   ; 2070 - 207f
        / (%xe2 %x82-85 %x80-bf)            ; 2080 - 217f
        / (%xe2 %x86 %x80-8f)               ; 2180 - 218f
    ; 2c00 - 2fef
    / (%xe2 %xb0-be %x80-bf)                ; 2c00 - 2fbf
        / (%xe2 %xbf %x80-af)               ; 2fc0 - 2fef
    ; 3001 - d7ff
    / (%xe3 %x80 %x81-bf)                   ; 3001 - 303f
        / (%xe3 %x81-bf %x80-bf)            ; 3040 - 3fff
        / (%xe4-ec %x80-bf %x80-bf)         ; 4000 - cfff
        / (%xed %x80-9f %x80-bf)            ; d000 - d7ff
    ; f900 - fdcf
    / (%xef %xa4-b6 %x80-bf)                ; f900 - fdbf
        / (%xef %xb7 %x80-8f)               ; fdc0 - fdcf
    ; fdf0 - fffd
    / (%xef %xb7 %xb0-bf)                   ; fdf0 - fdff
        / (%xef %xb8-be %x80-bf)            ; fe00 - ffbf
        / (%xef %xbf %x80-bd)               ; ffc0 - fffd
    ; 01'0000 - 0e'ffff
    / (%xf0 %x90-bf %x80-bf %x80-bf)        ; 01'0000 - 03'ffff
        / (%xf1-f2 %x80-bf %x80-bf %x80-bf) ; 04'0000 - 0b'ffff
        / (%xf3 %x80-af %x80-bf %x80-bf)    ; 0c'0000 - 0e'ffff
    { NoMinRules }

NameChar = NameStartChar / "-" / "." / DIGIT / NameCharMulti ; [4a]
NameCharMulti = %s"Z" { MinRules }
NameCharMulti =
    ; b7
    (%xc2 %xb7)
    ; 300 - 36f
    / (%xcc %x80-bf)        ; 300 - 33f
        / (%xcd %x80-af)    ; 340 - 36f
    ; 203f - 2040
    / (%xe2 %x80 %xbf)      ; 203f
        / (%xe2 %x81 %x80)  ; 2040
    { NoMinRules }
Name = NameStartChar *(NameChar)    ; [5]
Nmtoken = 1*NameChar ; [7]

; Literals
EntityValue = ; [9]
    DQUOTE *(Char-not-AMP-DQUOTE-PCT / PEReference / Reference) DQUOTE
    / "'" *(Char-not-AMP-APOS-PCT / PEReference / Reference) "'"
	{ Start+, End+ }
Char-not-AMP-DQUOTE-PCT = mbchar / ws
    / %x21
    ; 22 - DQUOTE
    / %x23-24
    ; 25 - PCT
    ; 26 - AMP
    / %x27-7f
Char-not-AMP-APOS-PCT = mbchar / ws
    / %x21-24
    ; 25 - PCT
    ; 26 - AMP
    ; 27 - APOS
    / %x28-7f
AttValue = DQUOTE *(Char-not-ws-AMP-DQUOTE-LT / ws / Reference) DQUOTE ; [10]
    / "'" *(Char-not-ws-AMP-APOS-LT / ws / Reference) "'"
Char-not-ws-AMP-DQUOTE-LT = mbchar
	/ %x21
    ; 22 - DQUOTE
    / %x23-25
    ; 26 - AMP
    / %x27-3b
    ; 3c - LT
    / %x3d-7f
Char-not-ws-AMP-APOS-LT = mbchar
	/ %x21-25
    ; 26 - AMP
    ; 27 - APOS
    / %x28-3b
    ; 3c - LT
    / %x3d-7f
SystemLiteral = DQUOTE *Char-not-DQUOTE DQUOTE / "'" *Char-not-APOS "'" ; [11]
Char-not-DQUOTE = mbchar / ws
    / %x21
    ; 22 - DQUOTE
    / %x23-7f
Char-not-APOS = mbchar / ws
    / %x21-26
    ; 27 - APOS
    / %x28-7f
PubidLiteral = DQUOTE *PubidChar DQUOTE / "'" *PubidChar-not-APOS "'" ; [12]
PubidChar-not-APOS = SP / CR / LF / ALPHA / DIGIT
    / "-" / "(" / ")" / "+" / "," / "." / "/" / ":" / "=" / "?"
    / ";" / "!" / "*" / "#" / "@" / "$" / "_" / "%"
PubidChar = PubidChar-not-APOS / "'" ; [13]

; Attribute Value
attrValue = DQUOTE attrText DQUOTE / "'" attrTextApos "'" ; [10]
	{ Start+, End }
attrText = [attrInPlace] *((Reference / normalizable-ws) [attrCopy])
attrInPlace = *Char-not-ws-AMP-DQUOTE-LT { End+ }
attrCopy = *Char-not-ws-AMP-DQUOTE-LT { Char+ }
attrTextApos = [attrInPlaceApos] *((Reference / normalizable-ws)
    [attrCopyApos])
attrInPlaceApos = *Char-not-ws-AMP-APOS-LT { End+, As attrInPlace }
attrCopyApos = *Char-not-ws-AMP-APOS-LT { Char+, As attrCopy }
normalizable-ws = ws { Char }

; Character Data
CharData = *( ">" / "]>" / *"]" Char-not-AMP-GT-LT-RBRACKET) ; [14]
    *"]" { Char+ }
Char-not-AMP-GT-LT-RBRACKET = mbchar / ws
    / %x21-25
    ; 26 - AMP
    / %x27-3b
    ; 3c - LT
    / %x3d
    ; 3e - GT
    / %x3f-5c
    ; 5d - RBRACKET
    / %x5e-7f

; Comments
Comment = "<!--" *(Char-not-DASH  / ("-" Char-not-DASH) ) "-->" ; [15]
Char-not-DASH = mbchar / ws
    / %x21-2c
    ; 2d - DASH
    / %x2e-7f

; Processing Instructions
PI = "<?" PITarget [S piValue] "?>" ; [16]
PITarget = NameStartChar-not-x *NameChar ; [17] - see errata S01
    / %s"x" [NameChar-not-m *NameChar]
    / %s"xm" [NameChar-not-l *NameChar]
    / %s"xml" 1*NameChar
NameStartChar-not-x = %x41-5a / %x61-77 / %x79-7a / ":" / "_"
    / NameStartCharMulti
NameChar-not-m = %x41-5a / %x61-6c / %x6e-7a / ":" / "_" / "-"
    / "." / DIGIT / NameCharMulti
NameChar-not-l = %x41-5a / %x61-6b / %x6d-7a / ":" / "_" / "-"
    / "." / DIGIT / NameCharMulti
piValue = *(">" / *"?" Char-not-GT-QMARK) *"?"
Char-not-GT-QMARK = mbchar / ws
    / %x21-3d
    ; 3e - GT
    ; 3f - QMARK
    / %x40-7f

; CData Sections
CDSect = CDStart CDataWithEnd ; [18]
CDStart = %s"<![CDATA[" ; [19]
CDataWithEnd = CData CDEnd { Start+, End+ }
CData = *(">" / "]>" / *"]" Char-not-GT-RBRACKET) *"]"  ; [20]
Char-not-GT-RBRACKET = mbchar / ws
    / %x21-3d
    ; 3e - GT
    / %x3f-5c
    ; 5d - RBRACKET
    / %x5e-7f
CDEnd = "]]>" ; [21]

; Prolog
prolog = [XMLDecl] *Misc [doctypedecl *Misc] ; [22]
XMLDecl = %s"<?xml" VersionInfo [EncodingDecl] [SDDecl] [S] "?>" ; [23]
VersionInfo = S %s"version" Eq ; [24]
    ("'" VersionNum "'" / DQUOTE VersionNum DQUOTE)
Eq = [S] "=" [S] ; [25]
VersionNum = "1." 1*DIGIT ; [26]
Misc = Comment / PI / S ; [27]

; Document Type Definition
doctypedecl = %s"<!DOCTYPE" S Name [S ExternalID] [S]
    [ "[" intSubset "]" [S] ] ">" ; [28]
DeclSep = PEReference / S ; [28a]
intSubset = *(markupdecl / DeclSep) ; [28b]
markupdecl = elementdecl / AttlistDecl / EntityDecl / NotationDecl / PI
    / Comment ; [29]

; External Subset
extSubset = [TextDecl] extSubsetDecl ; [30]
extSubsetDecl = *(markupdecl / conditionalSect / DeclSep) ; [31]

; Standalone Document Declaration
SDDecl = S %s"standalone" Eq ; [32]
    ("'" (%s"yes" / %s"no") "'" / DQUOTE (%s"yes" / %s"no") DQUOTE)

; Element
element = EmptyElemTag / STag element-tail { End } ; [39]
element-tail = content ETag { Function }
STag = "<" elemName *(S Attribute) [S] ">" ; [40]
Attribute = attrName Eq attrValue ; [41]
attrName = Name { Start+, End+ }
ETag = "</" Name [S] ">" ; [42]
content = [elemText] *((element / PI / Comment / CDSect) [elemText]) ; [43]
elemText = CharData *(Reference CharData) { Start+, End }
EmptyElemTag = "<" elemName *(S Attribute) [S] "/>" ; [44]
elemName = Name { Start+, End+ }

; Element Type Declaration
elementdecl = %s"<!ELEMENT" S Name S contentspec [S] ">" ; [45]
contentspec = %s"EMPTY" / %s"ANY" / Mixed / children ; [46]
children = (choice / seq) ["?" / "*" / "+"] ; [47]
cp = (Name / choice / seq) ["?" / "*" / "+"] { Function } ; [48]
choice = "(" [S] cp 1*([S] "|" [S] cp) [S] ")" ; [49]
seq = "(" [S] cp *([S] "," [S] cp) [S] ")" ; [50]
Mixed = "(" [S] %s"#PCDATA" *([S] "|" [S] Name) [S] ")*" ; [51]
    / "(" [S] %s"#PCDATA" [S] ")"

; Attribute-list Declaration
AttlistDecl = %s"<!ATTLIST" S Name *AttDef [S] ">" ; [52]
AttDef = S attrName S AttType S DefaultDecl ; [53]
AttType = StringType / TokenizedType / EnumeratedType ; [54]
StringType = %s"CDATA" ; [55]
TokenizedType = %s"ID" / %s"IDREF" / %s"IDREFS" / %s"ENTITY" ; [56]
    / %s"ENTITIES" / %s"NMTOKEN" / %s"NMTOKENS"
EnumeratedType = NotationType / Enumeration ; [57]
NotationType = %s"NOTATION" S "(" [S] Name *([S] "|" [S] Name) [S] ")" ; [58]
Enumeration = "(" [S] Nmtoken *([S] "|" [S] Nmtoken) [S] ")" ; [59]
DefaultDecl = %s"#REQUIRED" / %s"#IMPLIED" / [%s"#FIXED" S] attrValue ; [60]

; Conditional Section
conditionalSect = includeSect / ignoreSect ; [61]
includeSect = "<![" [S] %s"INCLUDE" [S] "[" extSubsetDecl "]]>" ; [62]
ignoreSect = "<![" [S] %s"IGNORE" [S] "[" *ignoreSectContents "]]>" ; [63]
ignoreSectContents = Ignore *("<![" ignoreSectContents "]]>" Ignore)
    { Function } ; [64]
Ignore = ; char sequence with no "<![" or "]]>" ; [65]
    *(Char-not-BANG-GT-LT-LBRACKET-RBRACKET / "!" / ">" / "["
        / *"]" 1*"<" (Char-not-BANG-GT-LT-LBRACKET-RBRACKET / ">" / "[")
        / 1*"<" "!" (Char-not-BANG-GT-LT-LBRACKET-RBRACKET / "!" / ">")
        / *"<" "]" (Char-not-BANG-GT-LT-LBRACKET-RBRACKET / "!" / ">" / "[")
        / 1*"]" (Char-not-BANG-GT-LT-LBRACKET-RBRACKET / "!" / "[")
    ) (*"<" ["!" / "]"]  /  *"]" ["<"])
Char-not-BANG-GT-LT-LBRACKET-RBRACKET = mbchar / ws
    ; 21 - BANG
    / %x22-3b
    ; 3c - LT
    / %x3d
    ; 3e - GT
    / %x3f-5a
    ; 5b - LBRACKET
    / %x5c
    ; 5d - RBRACKET
    / %x5e-7f

; Character and Entity Reference
CharRef = "&#" charRefDigit ";" / "&#" %x78 charRefHexdig ";" { Start, End }
	; [66]
charRefDigit = 1*DIGIT { Char+ }
charRefHexdig = 1*HEXDIG { Char+ }
Reference = EntityRef / CharRef ; [67]
EntityRef = entityApos / entityQuot / entityGt / entityLt / entityAmp ; [68]
    / entityOther
entityApos = %s"&apos;" { End }
entityQuot = %s"&quot;" { End }
entityGt = %s"&gt;" { End }
entityLt = %s"&lt;" { End }
entityAmp = %s"&amp;" { End }
entityOther = "&" Name ";" { End+ }
PEReference = "%" Name ";" ; [69]

; Entity Declaration
EntityDecl = GEDecl / PEDecl ; [70]
GEDecl = %s"<!ENTITY" S Name S EntityDef [S] ">" ; [71]
PEDecl = %s"<!ENTITY" S "%" S Name S PEDef [S] ">" ; [72]
EntityDef = EntityValue / ExternalID [NDataDecl] ; [73]
PEDef = EntityValue / ExternalID ; [74]
ExternalID = %s"SYSTEM" S SystemLiteral ; [75]
    / %s"PUBLIC" S PubidLiteral S SystemLiteral
NDataDecl = S %s"NDATA" S Name ; [76]

; Text Declaration
TextDecl = %s"<?xml" [VersionInfo] EncodingDecl [S] "?>" ; [77]

; Well-Formed External Parsed Entity
extParsedEnt = [TextDecl] content ; [78]

; Encoding Declaration
EncodingDecl = S %s"encoding" Eq ; [80]
    (DQUOTE EncName DQUOTE / "'" EncName "'")
EncName = ALPHA *(ALPHA / DIGIT / "." / "_" / "-") ; [81]

; Notation Declarations
NotationDecl = %s"<!NOTATION" S Name S (ExternalID / PublicID) [S] ">" ; [82]
PublicID = %s"PUBLIC" S PubidLiteral ; [83]
