[GH-ISSUE #575] Use EBNF instead of an own non-standard modified BNF #7394

Open
opened 2026-06-20 17:26:28 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @Vampire on GitHub (Jun 12, 2020).
Original GitHub issue: https://github.com/semver/semver/issues/575

I'd like to suggest using EBNF according to ISO 14977 instead of a non-standard modified BNF like currently, it is much more readable and makes the result much more concise, e. g. by eliminating the need for recursion and introducing optionals.

E. g.

<pre-release> ::= <dot-separated pre-release identifiers>
<dot-separated pre-release identifiers> ::= <pre-release identifier> | <pre-release identifier> "." <dot-separated pre-release identifiers>

could be written as

pre_release = pre_release_identifier, { ".", pre_release_identifier };

Reuse nonterminals where possible

<numeric identifier> ::= "0"
                       | <positive digit>
                       | <positive digit> <digits>

should be

<numeric identifier> ::= <digit>
                       | <positive digit> <digits>

Simplify the BNF form, even if not using EBNF

e. g. if

<identifier characters> ::= <identifier character>
                          | <identifier character> <identifier characters>

is changed to

<identifier characters> ::= | <identifier character> <identifier characters>

you can simplify

<alphanumeric identifier> ::= <non-digit>
                            | <non-digit> <identifier characters>
                            | <identifier characters> <non-digit>
                            | <identifier characters> <non-digit> <identifier characters>

to

<alphanumeric identifier> ::= <identifier characters> <non-digit> <identifier characters>

as now <identifier characters> can be empty

Originally created by @Vampire on GitHub (Jun 12, 2020). Original GitHub issue: https://github.com/semver/semver/issues/575 I'd like to suggest using EBNF according to ISO 14977 instead of a non-standard modified BNF like currently, it is much more readable and makes the result much more concise, e. g. by eliminating the need for recursion and introducing optionals. E. g. ``` <pre-release> ::= <dot-separated pre-release identifiers> <dot-separated pre-release identifiers> ::= <pre-release identifier> | <pre-release identifier> "." <dot-separated pre-release identifiers> ``` could be written as ``` pre_release = pre_release_identifier, { ".", pre_release_identifier }; ``` ## Reuse nonterminals where possible ``` <numeric identifier> ::= "0" | <positive digit> | <positive digit> <digits> ``` should be ``` <numeric identifier> ::= <digit> | <positive digit> <digits> ``` ## Simplify the BNF form, even if not using EBNF e. g. if ``` <identifier characters> ::= <identifier character> | <identifier character> <identifier characters> ``` is changed to ``` <identifier characters> ::= | <identifier character> <identifier characters> ``` you can simplify ``` <alphanumeric identifier> ::= <non-digit> | <non-digit> <identifier characters> | <identifier characters> <non-digit> | <identifier characters> <non-digit> <identifier characters> ``` to ``` <alphanumeric identifier> ::= <identifier characters> <non-digit> <identifier characters> ``` as now `<identifier characters>` can be empty
GiteaMirror added the RFCupdate labels 2026-06-20 17:26:29 -05:00
Author
Owner

@Vampire commented on GitHub (Jun 20, 2020):

This would for example be a possible EBNF form I could PR:

validSemver = major, ".", minor, ".", patch, [ "-", preRelease ], [ "+", build ] ;

major = numericIdentifier ;

minor = numericIdentifier ;

patch = numericIdentifier ;

preRelease = preReleaseIdentifier, { ".", preReleaseIdentifier } ;

build = buildIdentifier, { ".", buildIdentifier } ;

preReleaseIdentifier = alphanumericIdentifier | numericIdentifier ;

buildIdentifier = { identifierCharacter }- ;

alphanumericIdentifier = { digit }, nonDigit, { identifierCharacter } ;

numericIdentifier = "0" | positiveDigit, { digit } ;

identifierCharacter = digit | nonDigit ;

nonDigit = letter | "-" ;

positiveDigit = digit - "0" ;

digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;

letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
       | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
       | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d"
       | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n"
       | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
       | "y" | "z" ;

Or maybe even better than ISO 14977 EBNF would be RFC 5234 ABNF:

validSemver = major "." minor "." patch ["-" preRelease] ["+" build]

major = numericIdentifier

minor = numericIdentifier

patch = numericIdentifier

preRelease = preReleaseIdentifier *("." preReleaseIdentifier)

build = buildIdentifier *("." buildIdentifier)

preReleaseIdentifier = alphanumericIdentifier / numericIdentifier

buildIdentifier = 1*identifierCharacter

alphanumericIdentifier = *DIGIT nonDigit *identifierCharacter

numericIdentifier = "0" / positiveDigit *DIGIT

identifierCharacter = DIGIT / nonDigit

nonDigit = ALPHA / "-"

positiveDigit = %x31-39
<!-- gh-comment-id:646922679 --> @Vampire commented on GitHub (Jun 20, 2020): This would for example be a possible EBNF form I could PR: ``` validSemver = major, ".", minor, ".", patch, [ "-", preRelease ], [ "+", build ] ; major = numericIdentifier ; minor = numericIdentifier ; patch = numericIdentifier ; preRelease = preReleaseIdentifier, { ".", preReleaseIdentifier } ; build = buildIdentifier, { ".", buildIdentifier } ; preReleaseIdentifier = alphanumericIdentifier | numericIdentifier ; buildIdentifier = { identifierCharacter }- ; alphanumericIdentifier = { digit }, nonDigit, { identifierCharacter } ; numericIdentifier = "0" | positiveDigit, { digit } ; identifierCharacter = digit | nonDigit ; nonDigit = letter | "-" ; positiveDigit = digit - "0" ; digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" ; ``` Or maybe even better than ISO 14977 EBNF would be RFC 5234 ABNF: ``` validSemver = major "." minor "." patch ["-" preRelease] ["+" build] major = numericIdentifier minor = numericIdentifier patch = numericIdentifier preRelease = preReleaseIdentifier *("." preReleaseIdentifier) build = buildIdentifier *("." buildIdentifier) preReleaseIdentifier = alphanumericIdentifier / numericIdentifier buildIdentifier = 1*identifierCharacter alphanumericIdentifier = *DIGIT nonDigit *identifierCharacter numericIdentifier = "0" / positiveDigit *DIGIT identifierCharacter = DIGIT / nonDigit nonDigit = ALPHA / "-" positiveDigit = %x31-39 ```
Author
Owner

@davbrito commented on GitHub (Nov 10, 2020):

I like the idea of use ABNF from RFC 5234

<!-- gh-comment-id:724881168 --> @davbrito commented on GitHub (Nov 10, 2020): I like the idea of use ABNF from RFC 5234
Author
Owner

@greggirwin commented on GitHub (Feb 22, 2021):

Here's a visible comparison of the 3 formats, as syntax diagrams.

ABNF

semver-abnf

#EBNF
semver-ebnf

#BNF
semver-bnf

<!-- gh-comment-id:782984249 --> @greggirwin commented on GitHub (Feb 22, 2021): Here's a visible comparison of the 3 formats, as syntax diagrams. # ABNF ![semver-abnf](https://user-images.githubusercontent.com/460079/108647234-57533a80-7475-11eb-9a47-95965ede93fa.png) #EBNF ![semver-ebnf](https://user-images.githubusercontent.com/460079/108647238-57ebd100-7475-11eb-84a1-ebfcd76d448d.png) #BNF ![semver-bnf](https://user-images.githubusercontent.com/460079/108647237-57ebd100-7475-11eb-9075-50af596e100c.png)
Author
Owner

@greggirwin commented on GitHub (Feb 22, 2021):

Oy, sorry about that. They show large in the comments.

<!-- gh-comment-id:782984378 --> @greggirwin commented on GitHub (Feb 22, 2021): Oy, sorry about that. They show large in the comments.
Author
Owner

@greggirwin commented on GitHub (Jul 7, 2021):

Any follow-up on this from maintainers?

<!-- gh-comment-id:875970241 --> @greggirwin commented on GitHub (Jul 7, 2021): Any follow-up on this from maintainers?
Author
Owner

@steveklabnik commented on GitHub (Jul 15, 2021):

I generally am in favor of using standard things over non-standard things, but haven't had the opportunity to review this in detail at all.

<!-- gh-comment-id:880992923 --> @steveklabnik commented on GitHub (Jul 15, 2021): I generally am in favor of using standard things over non-standard things, but haven't had the opportunity to review this in detail at all.
Author
Owner

@greggirwin commented on GitHub (Jul 15, 2021):

Here's an ABNF version, minus the ABNF standard values.

validSemver = major "." minor "." patch ["-" preRelease] ["+" build]

major = numericIdentifier

minor = numericIdentifier

patch = numericIdentifier

preRelease = preReleaseIdentifier *("." preReleaseIdentifier)

build = buildIdentifier *("." buildIdentifier)

preReleaseIdentifier = alphanumericIdentifier / numericIdentifier

buildIdentifier = 1*identifierCharacter

alphanumericIdentifier = *DIGIT nonDigit *identifierCharacter

numericIdentifier = "0" / positiveDigit *DIGIT

identifierCharacter = DIGIT / nonDigit

nonDigit = ALPHA / "-"

positiveDigit = %x31-39
<!-- gh-comment-id:881035969 --> @greggirwin commented on GitHub (Jul 15, 2021): Here's an ABNF version, minus the ABNF standard values. ``` validSemver = major "." minor "." patch ["-" preRelease] ["+" build] major = numericIdentifier minor = numericIdentifier patch = numericIdentifier preRelease = preReleaseIdentifier *("." preReleaseIdentifier) build = buildIdentifier *("." buildIdentifier) preReleaseIdentifier = alphanumericIdentifier / numericIdentifier buildIdentifier = 1*identifierCharacter alphanumericIdentifier = *DIGIT nonDigit *identifierCharacter numericIdentifier = "0" / positiveDigit *DIGIT identifierCharacter = DIGIT / nonDigit nonDigit = ALPHA / "-" positiveDigit = %x31-39 ```
Author
Owner

@greggirwin commented on GitHub (Sep 10, 2021):

Ping. Any thoughts?

<!-- gh-comment-id:916540250 --> @greggirwin commented on GitHub (Sep 10, 2021): Ping. Any thoughts?
Author
Owner

@ghost commented on GitHub (Aug 19, 2022):

May I suggest BNF for Java?
https://sourceforge.net/projects/bnf-for-java/
In 2007, I wrote this parser-generator in Java, and conforms to ISO-14977.
In 2022, I am re-writing the compiler in Antlr. Wish me luck!

<!-- gh-comment-id:1220815694 --> @ghost commented on GitHub (Aug 19, 2022): May I suggest BNF for Java? https://sourceforge.net/projects/bnf-for-java/ In 2007, I wrote this parser-generator in Java, and conforms to ISO-14977. In 2022, I am re-writing the compiler in Antlr. Wish me luck!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/semver#7394