Skip to content

Changing "specs/grammar.txt" to an EBNF understood by https://www.bottlecaps.de/rr/ui #281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mingodad opened this issue Dec 20, 2023 · 10 comments

Comments

@mingodad
Copy link

mingodad commented Dec 20, 2023

If we change "specs/grammar.txt" to an EBNF understood by https://www.bottlecaps.de/rr/ui we can get a nice navigable railroad diagram representation of it that can help document/develop/debug this project grammar, follow the instructions shown bellow:

//
// EBNF to be viewd at https://www.bottlecaps.de/rr/ui
//
// Copy and paste this at https://www.bottlecaps.de/rr/ui in the 'Edit Grammar' tab
// then click the 'View Diagram' tab.
//

//
//To facilitate start navigating
//

cplusplus ::=
	preprocessing-file? translation-unit

//== lex.tex

n-char ::=
     "{any member of the translation character set except the \unicode{007d}{right curly bracket} or new-line character}"

n-char-sequence ::=
    n-char
  | n-char-sequence n-char

named-universal-character ::=
    "\N{" n-char-sequence "}"

hex-quad ::=
    hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit

simple-hexadecimal-digit-sequence ::=
    hexadecimal-digit
  | simple-hexadecimal-digit-sequence hexadecimal-digit

universal-character-name ::=
    "\u" hex-quad
  | "\U" hex-quad hex-quad
  | "\u{" simple-hexadecimal-digit-sequence "}"
  | named-universal-character

preprocessing-token ::=
    header-name
  | "import"
  | "module"
  | "export"
  | identifier
  | pp-number
  | character-literal
  | user-defined-character-literal
  | string-literal
  | user-defined-string-literal
  | preprocessing-op-or-punc
  | "{each non-whitespace character that cannot be one of the above}"

//token ::=
//    identifier
//  | keyword
//  | literal
//  | operator-or-punctuator

header-name ::=
    "<" h-char-sequence ">"
  | '"' q-char-sequence '"'

h-char-sequence ::=
    h-char
  | h-char-sequence h-char

h-char ::=
    "{any member of the translation character set except new-line and \unicode{003e}{greater-than sign}}"

q-char-sequence ::=
    q-char
  | q-char-sequence q-char

q-char ::=
    "{any member of the translation character set except new-line and \unicode{0022}{quotation mark}}"

pp-number ::=
    digit
  | "." digit
  | pp-number identifier-continue
  | pp-number "'" digit
  | pp-number "'" nondigit
  | pp-number "e" sign
  | pp-number "E" sign
  | pp-number "p" sign
  | pp-number "P" sign
  | pp-number "."

identifier ::=
    identifier-start
  | identifier identifier-continue

identifier-start ::=
    nondigit
  | "{an element of the translation character set with the Unicode property XID_Start}"

identifier-continue ::=
    digit
  | nondigit
  | "{an element of the translation character set with the Unicode property XID_Continue}"

nondigit ::=
    "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" | "_"

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

keyword ::=
    "{any identifier listed in lex.key}"
  | "import"
  | "module"
  | "export"

preprocessing-op-or-punc ::=
    preprocessing-operator
  | operator-or-punctuator

preprocessing-operator ::=
    "#" | "##" | "%:" | "%:%:"

operator-or-punctuator ::=
    "{" | "}" | "[" | "]" | "(" | ")"
  | "<:" | ":>" | "<%" | "%>" | ";" | ":" | "..."
  | "?" | "::" | "." | ".*" | "->" | "->*" | "~"
  | "!" | "+" | "-" | "*" | "/" | "%" | "^" | "&" | "|"
  | "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&=" | "|="
  | "==" | "!=" | "<" | ">" | "<=" | ">=" | "<=>" | "&&" | "||"
  | "<<" | ">>" | "<<=" | ">>=" | "++" | "--" | ","
  | "and" | "or" | "xor" | "not" | "bitand" | "bitor" | "compl"
  | "and_eq" | "or_eq" | "xor_eq" | "not_eq"

literal ::=
    integer-literal
  | character-literal
  | floating-point-literal
  | string-literal
  | boolean-literal
  | pointer-literal
  | user-defined-literal

integer-literal ::=
    binary-literal integer-suffix?
  | octal-literal integer-suffix?
  | decimal-literal integer-suffix?
  | hexadecimal-literal integer-suffix?

binary-literal ::=
    "0b" binary-digit
  | "0B" binary-digit
  | binary-literal "'"? binary-digit

octal-literal ::=
    "0"
  | octal-literal "'"? octal-digit

decimal-literal ::=
    nonzero-digit
  | decimal-literal "'"? digit

hexadecimal-literal ::=
    hexadecimal-prefix hexadecimal-digit-sequence

binary-digit ::=
    "0" | "1"

octal-digit ::=
    "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"

nonzero-digit ::=
    "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

hexadecimal-prefix ::=
    "0x" | "0X"

hexadecimal-digit-sequence ::=
    hexadecimal-digit
  | hexadecimal-digit-sequence "'"? hexadecimal-digit

hexadecimal-digit ::=
    "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
  | "a" | "b" | "c" | "d" | "e" | "f"
  | "A" | "B" | "C" | "D" | "E" | "F"

integer-suffix ::=
    unsigned-suffix long-suffix?
  | unsigned-suffix long-long-suffix?
  | unsigned-suffix size-suffix?
  | long-suffix unsigned-suffix?
  | long-long-suffix unsigned-suffix?
  | size-suffix unsigned-suffix?

unsigned-suffix ::=
    "u" | "U"

long-suffix ::=
    "l" | "L"

long-long-suffix ::=
    "ll" | "LL"

size-suffix ::=
   "z" | "Z"

character-literal ::=
    encoding-prefix? "'" c-char-sequence "'"

encoding-prefix ::=
    "u8" | "u" | "U" | "L"

c-char-sequence ::=
    c-char
  | c-char-sequence c-char

c-char ::=
    basic-c-char
  | escape-sequence
  | universal-character-name

basic-c-char ::=
    "{any member of the translation character set except the \unicode{0027}{apostrophe},}"
        "{\unicode{005c}{reverse solidus}, or new-line character}"

escape-sequence ::=
    simple-escape-sequence
  | numeric-escape-sequence
  | conditional-escape-sequence

simple-escape-sequence ::=
    "\" simple-escape-sequence-char

simple-escape-sequence-char ::=
    "'" | '"' | "?" | "\" | "a" | "b" | "f" | "n" | "r" | "t" | "v"

numeric-escape-sequence ::=
    octal-escape-sequence
  | hexadecimal-escape-sequence

simple-octal-digit-sequence ::=
    octal-digit
  | simple-octal-digit-sequence octal-digit

octal-escape-sequence ::=
    "\" octal-digit
  | "\" octal-digit octal-digit
  | "\" octal-digit octal-digit octal-digit
  | "\o{" simple-octal-digit-sequence "}"

hexadecimal-escape-sequence ::=
    "\x" simple-hexadecimal-digit-sequence
  | "\x{" simple-hexadecimal-digit-sequence "}"

conditional-escape-sequence ::=
    "\" conditional-escape-sequence-char

conditional-escape-sequence-char ::=
    '{any member of the basic character set that is not an octal-digit, a simple-escape-sequence-char, or the characters "N", "o", "u", "U", or "x"}'

floating-point-literal ::=
    decimal-floating-point-literal
  | hexadecimal-floating-point-literal

decimal-floating-point-literal ::=
    fractional-constant exponent-part? floating-point-suffix?
  | digit-sequence exponent-part floating-point-suffix?

hexadecimal-floating-point-literal ::=
    hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part floating-point-suffix?
  | hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part floating-point-suffix?

fractional-constant ::=
    digit-sequence? "." digit-sequence
  | digit-sequence "."

hexadecimal-fractional-constant ::=
    hexadecimal-digit-sequence? "." hexadecimal-digit-sequence
  | hexadecimal-digit-sequence "."

exponent-part ::=
    "e" sign? digit-sequence
  | "E" sign? digit-sequence

binary-exponent-part ::=
    "p" sign? digit-sequence
  | "P" sign? digit-sequence

sign ::=
    "+" | "-"

digit-sequence ::=
    digit
  | digit-sequence "'"? digit

floating-point-suffix ::=
    "f" | "l" | "f16" | "f32" | "f64" | "f128" | "bf16" | "F" | "L" | "F16" | "F32" | "F64" | "F128" | "BF16"

string-literal ::=
    encoding-prefix? '"' s-char-sequence? '"'
  | encoding-prefix? "R" raw-string

s-char-sequence ::=
    s-char
  | s-char-sequence s-char

s-char ::=
    basic-s-char
  | escape-sequence
  | universal-character-name

basic-s-char ::=
    "{any member of the translation character set except the \unicode{0022}{quotation mark},}"
        "{\unicode{005c}{reverse solidus}, or new-line character}"

raw-string ::=
    '"' d-char-sequence? "(" r-char-sequence? ")" d-char-sequence? '"'

r-char-sequence ::=
    r-char
  | r-char-sequence r-char

r-char ::=
    "{any member of the translation character set, except a \unicode{0029}{right parenthesis} followed by}"
        "{the initial d-char-sequence (which may be empty) followed by a \unicode{0022}{quotation mark}}"

d-char-sequence ::=
    d-char
  | d-char-sequence d-char

d-char ::=
    "{any member of the basic character set except:}"
        "{\unicode{0020}{space}, \unicode{0028}{left parenthesis}, \unicode{0029}{right parenthesis}, \unicode{005c}{reverse solidus},}"
        "{\unicode{0009}{character tabulation}, \unicode{000b}{line tabulation}, \unicode{000c}{form feed}, and new-line}"

unevaluated-string ::=
    string-literal

boolean-literal ::=
    "false"
  | "true"

pointer-literal ::=
    "nullptr"

user-defined-literal ::=
    user-defined-integer-literal
  | user-defined-floating-point-literal
  | user-defined-string-literal
  | user-defined-character-literal

user-defined-integer-literal ::=
    decimal-literal ud-suffix
  | octal-literal ud-suffix
  | hexadecimal-literal ud-suffix
  | binary-literal ud-suffix

user-defined-floating-point-literal ::=
    fractional-constant exponent-part? ud-suffix
  | digit-sequence exponent-part ud-suffix
  | hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part ud-suffix
  | hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part ud-suffix

user-defined-string-literal ::=
    string-literal ud-suffix

user-defined-character-literal ::=
    character-literal ud-suffix

ud-suffix ::=
    identifier

//== basic.tex

translation-unit ::=
    declaration-seq?
  | global-module-fragment? module-declaration declaration-seq? private-module-fragment?

//== expressions.tex

primary-expression ::=
    literal
  | "this"
  | "(" expression ")"
  | id-expression
  | lambda-expression
  | fold-expression
  | requires-expression

id-expression ::=
    unqualified-id
  | qualified-id
  | pack-index-expression

unqualified-id ::=
    identifier
  | operator-function-id
  | conversion-function-id
  | literal-operator-id
  | "~" type-name
  | "~" computed-type-specifier
  | template-id

qualified-id ::=
    nested-name-specifier "template"? unqualified-id

nested-name-specifier ::=
    "::"
  | type-name "::"
  | namespace-name "::"
  | computed-type-specifier "::"
  | nested-name-specifier identifier "::"
  | nested-name-specifier "template"? simple-template-id "::"

pack-index-expression ::=
    id-expression "..." "[" constant-expression "]"

lambda-expression ::=
    lambda-introducer attribute-specifier-seq? lambda-declarator compound-statement
  | lambda-introducer "<" template-parameter-list ">" requires-clause? attribute-specifier-seq?
         lambda-declarator compound-statement

lambda-introducer ::=
    "[" lambda-capture? "]"

lambda-declarator ::=
    lambda-specifier-seq noexcept-specifier? attribute-specifier-seq? trailing-return-type?
  | noexcept-specifier attribute-specifier-seq? trailing-return-type?
  | trailing-return-type?
  | "(" parameter-declaration-clause ")" lambda-specifier-seq? noexcept-specifier? attribute-specifier-seq?
         trailing-return-type? requires-clause?

lambda-specifier ::=
    "consteval"
  | "constexpr"
  | "mutable"
  | "static"

lambda-specifier-seq ::=
    lambda-specifier
  | lambda-specifier lambda-specifier-seq

lambda-capture ::=
    capture-default
  | capture-list
  | capture-default "," capture-list

capture-default ::=
    "&"
  | "="

capture-list ::=
    capture
  | capture-list "," capture

capture ::=
    simple-capture
  | init-capture

simple-capture ::=
    identifier "..."?
  | "&" identifier "..."?
  | "this"
  | "*" "this"

init-capture ::=
    "..."? identifier initializer
  | "&" "..."? identifier initializer

fold-expression ::=
    "(" cast-expression fold-operator "..." ")"
  | "(" "..." fold-operator cast-expression ")"
  | "(" cast-expression fold-operator "..." fold-operator cast-expression ")"

fold-operator ::=
    "+" | "-" | "*" | "/" | "%" | "^" | "&" | "|" | "<<" | ">>"
  | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&=" | "|=" | "<<=" | ">>=" | "="
  | "==" | "!=" | "<" | ">" | "<=" | ">=" | "&&" | "||" | "," | ".*" | "->*"

requires-expression ::=
    "requires" requirement-parameter-list? requirement-body

requirement-parameter-list ::=
    "(" parameter-declaration-clause ")"

requirement-body ::=
    "{" requirement-seq "}"

requirement-seq ::=
    requirement
  | requirement requirement-seq

requirement ::=
    simple-requirement
  | type-requirement
  | compound-requirement
  | nested-requirement

simple-requirement ::=
    expression ";"

type-requirement ::=
    "typename" nested-name-specifier? type-name ";"

compound-requirement ::=
    "{" expression "}" "noexcept"? return-type-requirement? ";"

return-type-requirement ::=
    "->" type-constraint

nested-requirement ::=
    "requires" constraint-expression ";"

postfix-expression ::=
    primary-expression
  | postfix-expression "[" expression-list? "]"
  | postfix-expression "(" expression-list? ")"
  | simple-type-specifier "(" expression-list? ")"
  | typename-specifier "(" expression-list? ")"
  | simple-type-specifier braced-init-list
  | typename-specifier braced-init-list
  | postfix-expression "." "template"? id-expression
  | postfix-expression "->" "template"? id-expression
  | postfix-expression "++"
  | postfix-expression "--"
  | "dynamic_cast" "<" type-id ">" "(" expression ")"
  | "static_cast" "<" type-id ">" "(" expression ")"
  | "reinterpret_cast" "<" type-id ">" "(" expression ")"
  | "const_cast" "<" type-id ">" "(" expression ")"
  | "typeid" "(" expression ")"
  | "typeid" "(" type-id ")"

expression-list ::=
    initializer-list

unary-expression ::=
    postfix-expression
  | unary-operator cast-expression
  | "++" cast-expression
  | "--" cast-expression
  | await-expression
  | "sizeof" unary-expression
  | "sizeof" "(" type-id ")"
  | "sizeof" "..." "(" identifier ")"
  | "alignof" "(" type-id ")"
  | noexcept-expression
  | new-expression
  | delete-expression

unary-operator ::=
    "*" | "&" | "+" | "-" | "!" | "~"

await-expression ::=
    "co_await" cast-expression

noexcept-expression ::=
  "noexcept" "(" expression ")"

new-expression ::=
    "::"? "new" new-placement? new-type-id new-initializer?
  | "::"? "new" new-placement? "(" type-id ")" new-initializer?

new-placement ::=
    "(" expression-list ")"

new-type-id ::=
    type-specifier-seq new-declarator?

new-declarator ::=
    ptr-operator new-declarator?
  | noptr-new-declarator

noptr-new-declarator ::=
    "[" expression? "]" attribute-specifier-seq?
  | noptr-new-declarator "[" constant-expression "]" attribute-specifier-seq?

new-initializer ::=
    "(" expression-list? ")"
  | braced-init-list

delete-expression ::=
    "::"? "delete" cast-expression
  | "::"? "delete" "[" "]" cast-expression

cast-expression ::=
    unary-expression
  | "(" type-id ")" cast-expression

pm-expression ::=
    cast-expression
  | pm-expression ".*" cast-expression
  | pm-expression "->*" cast-expression

multiplicative-expression ::=
    pm-expression
  | multiplicative-expression "*" pm-expression
  | multiplicative-expression "/" pm-expression
  | multiplicative-expression "%" pm-expression

additive-expression ::=
    multiplicative-expression
  | additive-expression "+" multiplicative-expression
  | additive-expression "-" multiplicative-expression

shift-expression ::=
    additive-expression
  | shift-expression "<<" additive-expression
  | shift-expression ">>" additive-expression

compare-expression ::=
    shift-expression
  | compare-expression "<=>" shift-expression

relational-expression ::=
    compare-expression
  | relational-expression "<" compare-expression
  | relational-expression ">" compare-expression
  | relational-expression "<=" compare-expression
  | relational-expression ">=" compare-expression

equality-expression ::=
    relational-expression
  | equality-expression "==" relational-expression
  | equality-expression "!=" relational-expression

and-expression ::=
    equality-expression
  | and-expression "&" equality-expression

exclusive-or-expression ::=
    and-expression
  | exclusive-or-expression "^" and-expression

inclusive-or-expression ::=
    exclusive-or-expression
  | inclusive-or-expression "|" exclusive-or-expression

logical-and-expression ::=
    inclusive-or-expression
  | logical-and-expression "&&" inclusive-or-expression

logical-or-expression ::=
    logical-and-expression
  | logical-or-expression "||" logical-and-expression

conditional-expression ::=
    logical-or-expression
  | logical-or-expression "?" expression ":" assignment-expression

  yield-expression ::=
  "co_yield" assignment-expression
  | "co_yield" braced-init-list

throw-expression ::=
    "throw"  assignment-expression?

assignment-expression ::=
    conditional-expression
  | yield-expression
  | throw-expression
  | logical-or-expression assignment-operator initializer-clause

assignment-operator ::=
    "=" | "*=" | "/=" | "%=" | "+=" | "-=" | ">>=" | "<<=" | "&=" | "^=" | "|="

expression ::=
    assignment-expression
  | expression "," assignment-expression

constant-expression ::=
    conditional-expression

//== statements.tex

statement ::=
    labeled-statement
  | attribute-specifier-seq? expression-statement
  | attribute-specifier-seq? compound-statement
  | attribute-specifier-seq? selection-statement
  | attribute-specifier-seq? iteration-statement
  | attribute-specifier-seq? jump-statement
  | declaration-statement
  | attribute-specifier-seq? try-block

init-statement ::=
    expression-statement
  | simple-declaration
  | alias-declaration

condition ::=
    expression
  | attribute-specifier-seq? decl-specifier-seq declarator brace-or-equal-initializer

label ::=
    attribute-specifier-seq? identifier ":"
  | attribute-specifier-seq? "case" constant-expression ":"
  | attribute-specifier-seq? "default" ":"

labeled-statement ::=
    label statement

expression-statement ::=
    expression? ";"

compound-statement ::=
    "{" statement-seq? label-seq? "}"

statement-seq ::=
    statement
  | statement-seq statement

label-seq ::=
    label
  | label-seq label

selection-statement ::=
    "if" "constexpr"? "(" init-statement? condition ")" statement
  | "if" "constexpr"? "(" init-statement? condition ")" statement "else" statement
  | "if" "!"? "consteval" compound-statement
  | "if" "!"? "consteval" compound-statement "else" statement
  | "switch" "(" init-statement? condition ")" statement

iteration-statement ::=
    "while" "(" condition ")" statement
  | "do" statement "while" "(" expression ")" ";"
  | "for" "(" init-statement condition? ";" expression? ")" statement
  | "for" "(" init-statement? for-range-declaration ":" for-range-initializer ")" statement

for-range-declaration ::=
    attribute-specifier-seq? decl-specifier-seq declarator
  | attribute-specifier-seq? decl-specifier-seq ref-qualifier? "[" identifier-list "]"

for-range-initializer ::=
    expr-or-braced-init-list

jump-statement ::=
    "break" ";"
  | "continue" ";"
  | "return" expr-or-braced-init-list? ";"
  | coroutine-return-statement
  | "goto" identifier ";"

coroutine-return-statement ::=
    "co_return" expr-or-braced-init-list? ";"

declaration-statement ::=
    block-declaration

//== declarations.tex

declaration-seq ::=
    declaration
  | declaration-seq declaration

declaration ::=
    name-declaration
  | special-declaration

name-declaration ::=
    block-declaration
  | nodeclspec-function-declaration
  | function-definition
  | template-declaration
  | deduction-guide
  | linkage-specification
  | namespace-definition
  | empty-declaration
  | attribute-declaration
  | module-import-declaration

special-declaration ::=
    explicit-instantiation
  | explicit-specialization
  | export-declaration

block-declaration ::=
    simple-declaration
  | asm-declaration
  | namespace-alias-definition
  | using-declaration
  | using-enum-declaration
  | using-directive
  | static_assert-declaration
  | alias-declaration
  | opaque-enum-declaration

nodeclspec-function-declaration ::=
    attribute-specifier-seq? declarator ";"

alias-declaration ::=
    "using" identifier attribute-specifier-seq? "=" defining-type-id ";"

simple-declaration ::=
    decl-specifier-seq init-declarator-list? ";"
  | attribute-specifier-seq decl-specifier-seq init-declarator-list ";"
  | attribute-specifier-seq? decl-specifier-seq ref-qualifier? "[" identifier-list "]" initializer ";"

static_assert-message ::=
  unevaluated-string
  | constant-expression

static_assert-declaration ::=
  "static_assert" "(" constant-expression ")" ";"
  | "static_assert" "(" constant-expression "," static_assert-message ")" ";"

empty-declaration ::=
    ";"

attribute-declaration ::=
    attribute-specifier-seq ";"

decl-specifier ::=
    storage-class-specifier
  | defining-type-specifier
  | function-specifier
  | "friend"
  | "typedef"
  | "constexpr"
  | "consteval"
  | "constinit"
  | "inline"

decl-specifier-seq ::=
    decl-specifier attribute-specifier-seq?
  | decl-specifier decl-specifier-seq

storage-class-specifier ::=
    "static"
  | "thread_local"
  | "extern"
  | "mutable"

function-specifier ::=
    "virtual"
  | explicit-specifier

explicit-specifier ::=
    "explicit" "(" constant-expression ")"
  | "explicit"

typedef-name ::=
    identifier
  | simple-template-id

type-specifier ::=
  simple-type-specifier
  | elaborated-type-specifier
  | typename-specifier
  | cv-qualifier

type-specifier-seq ::=
    type-specifier attribute-specifier-seq?
  | type-specifier type-specifier-seq

defining-type-specifier ::=
    type-specifier
  | class-specifier
  | enum-specifier

defining-type-specifier-seq ::=
  defining-type-specifier attribute-specifier-seq?
  | defining-type-specifier defining-type-specifier-seq

simple-type-specifier ::=
    nested-name-specifier? type-name
  | nested-name-specifier "template" simple-template-id
  | computed-type-specifier
  | placeholder-type-specifier
  | nested-name-specifier? template-name
  | "char"
  | "char8_t"
  | "char16_t"
  | "char32_t"
  | "wchar_t"
  | "bool"
  | "short"
  | "int"
  | "long"
  | "signed"
  | "unsigned"
  | "float"
  | "double"
  | "void"

type-name ::=
    class-name
  | enum-name
  | typedef-name

computed-type-specifier ::=
    decltype-specifier
  | pack-index-specifier

pack-index-specifier ::=
    typedef-name "..." "[" constant-expression "]"

elaborated-type-specifier ::=
    class-key attribute-specifier-seq? nested-name-specifier? identifier
  | class-key simple-template-id
  | class-key nested-name-specifier "template"? simple-template-id
  | "enum" nested-name-specifier? identifier

decltype-specifier ::=
  "decltype" "(" expression ")"

placeholder-type-specifier ::=
  type-constraint? "auto"
  | type-constraint? "decltype" "(" "auto" ")"

init-declarator-list ::=
    init-declarator
  | init-declarator-list "," init-declarator

init-declarator ::=
    declarator initializer?
  | declarator requires-clause

declarator ::=
    ptr-declarator
  | noptr-declarator parameters-and-qualifiers trailing-return-type

ptr-declarator ::=
    noptr-declarator
  | ptr-operator ptr-declarator

noptr-declarator ::=
    declarator-id attribute-specifier-seq?
  | noptr-declarator parameters-and-qualifiers
  | noptr-declarator "[" constant-expression? "]" attribute-specifier-seq?
  | "(" ptr-declarator ")"

parameters-and-qualifiers ::=
    "(" parameter-declaration-clause ")" cv-qualifier-seq?
        ref-qualifier? noexcept-specifier? attribute-specifier-seq?

trailing-return-type ::=
    "->" type-id

ptr-operator ::=
    "*" attribute-specifier-seq? cv-qualifier-seq?
  | "&" attribute-specifier-seq?
  | "&&" attribute-specifier-seq?
  | nested-name-specifier "*" attribute-specifier-seq? cv-qualifier-seq?

cv-qualifier-seq ::=
    cv-qualifier cv-qualifier-seq?

cv-qualifier ::=
    "const"
  | "volatile"

ref-qualifier ::=
    "&"
  | "&&"

declarator-id ::=
    "..."? id-expression

type-id ::=
    type-specifier-seq abstract-declarator?

defining-type-id ::=
    defining-type-specifier-seq abstract-declarator?

abstract-declarator ::=
    ptr-abstract-declarator
  | noptr-abstract-declarator? parameters-and-qualifiers trailing-return-type
  | abstract-pack-declarator

ptr-abstract-declarator ::=
    noptr-abstract-declarator
  | ptr-operator ptr-abstract-declarator?

noptr-abstract-declarator ::=
    noptr-abstract-declarator? parameters-and-qualifiers
  | noptr-abstract-declarator? "[" constant-expression? "]" attribute-specifier-seq?
  | "(" ptr-abstract-declarator ")"

abstract-pack-declarator ::=
    noptr-abstract-pack-declarator
  | ptr-operator abstract-pack-declarator

noptr-abstract-pack-declarator ::=
    noptr-abstract-pack-declarator parameters-and-qualifiers
  | "..."

parameter-declaration-clause ::=
    parameter-declaration-list? "..."?
  | parameter-declaration-list "," "..."

parameter-declaration-list ::=
    parameter-declaration
  | parameter-declaration-list "," parameter-declaration

parameter-declaration ::=
    attribute-specifier-seq? "this"? decl-specifier-seq declarator
  | attribute-specifier-seq? decl-specifier-seq declarator "=" initializer-clause
  | attribute-specifier-seq? "this"? decl-specifier-seq abstract-declarator?
  | attribute-specifier-seq? decl-specifier-seq abstract-declarator? "=" initializer-clause

initializer ::=
    brace-or-equal-initializer
  | "(" expression-list ")"

brace-or-equal-initializer ::=
    "=" initializer-clause
  | braced-init-list

initializer-clause ::=
    assignment-expression
  | braced-init-list

braced-init-list ::=
    "{" initializer-list ","? "}"
  | "{" designated-initializer-list ","? "}"
  | "{" "}"

initializer-list ::=
    initializer-clause "..."?
  | initializer-list "," initializer-clause "..."?

designated-initializer-list ::=
    designated-initializer-clause
  | designated-initializer-list "," designated-initializer-clause

designated-initializer-clause ::=
    designator brace-or-equal-initializer

designator ::=
    "." identifier

expr-or-braced-init-list ::=
    expression
  | braced-init-list

function-definition ::=
    attribute-specifier-seq? decl-specifier-seq? declarator virt-specifier-seq? function-body
  | attribute-specifier-seq? decl-specifier-seq? declarator requires-clause function-body

function-body ::=
    ctor-initializer? compound-statement
  | function-try-block
  | "=" "default" ";"
  | "=" "delete" ";"

enum-name ::=
    identifier

enum-specifier ::=
    enum-head "{" enumerator-list? "}"
  | enum-head "{" enumerator-list "," "}"

enum-head ::=
    enum-key attribute-specifier-seq? enum-head-name? enum-base?

enum-head-name ::=
    nested-name-specifier? identifier

opaque-enum-declaration ::=
    enum-key attribute-specifier-seq? enum-head-name enum-base? ";"

enum-key ::=
    "enum"
  | "enum" "class"
  | "enum" "struct"

enum-base ::=
    ":" type-specifier-seq

enumerator-list ::=
    enumerator-definition
  | enumerator-list "," enumerator-definition

enumerator-definition ::=
    enumerator
  | enumerator "=" constant-expression

enumerator ::=
    identifier attribute-specifier-seq?

using-enum-declaration ::=
    "using" "enum" using-enum-declarator ";"

using-enum-declarator ::=
    nested-name-specifier? identifier
  | nested-name-specifier? simple-template-id

namespace-name ::=
        identifier
  | namespace-alias

namespace-definition ::=
        named-namespace-definition
  | unnamed-namespace-definition
  | nested-namespace-definition

named-namespace-definition ::=
        "inline"? "namespace" attribute-specifier-seq? identifier "{" namespace-body "}"

unnamed-namespace-definition ::=
        "inline"? "namespace" attribute-specifier-seq? "{" namespace-body "}"

nested-namespace-definition ::=
        "namespace" enclosing-namespace-specifier "::" "inline"? identifier "{" namespace-body "}"

enclosing-namespace-specifier ::=
        identifier
  | enclosing-namespace-specifier "::" "inline"? identifier

namespace-body ::=
        declaration-seq?

namespace-alias ::=
        identifier

namespace-alias-definition ::=
        "namespace" identifier "=" qualified-namespace-specifier ";"

qualified-namespace-specifier ::=
    nested-name-specifier? namespace-name

using-directive ::=
    attribute-specifier-seq? "using" "namespace" nested-name-specifier? namespace-name ";"

using-declaration ::=
    "using" using-declarator-list ";"

using-declarator-list ::=
    using-declarator "..."?
  | using-declarator-list "," using-declarator "..."?

using-declarator ::=
    "typename"? nested-name-specifier unqualified-id

asm-declaration ::=
    attribute-specifier-seq? "asm" "(" balanced-token-seq ")" ";"

linkage-specification ::=
    "extern" unevaluated-string "{" declaration-seq? "}"
  | "extern" unevaluated-string name-declaration

attribute-specifier-seq ::=
  attribute-specifier-seq? attribute-specifier

attribute-specifier ::=
  "[" "[" attribute-using-prefix? attribute-list "]" "]"
  | alignment-specifier

alignment-specifier ::=
  "alignas" "(" type-id "..."? ")"
  | "alignas" "(" constant-expression "..."? ")"

attribute-using-prefix ::=
  "using" attribute-namespace ":"

attribute-list ::=
  attribute?
  | attribute-list "," attribute?
  | attribute "..."
  | attribute-list "," attribute "..."

attribute ::=
    attribute-token attribute-argument-clause?

attribute-token ::=
    identifier
  | attribute-scoped-token

attribute-scoped-token ::=
    attribute-namespace "::" identifier

attribute-namespace ::=
    identifier

attribute-argument-clause ::=
    "(" balanced-token-seq? ")"

balanced-token-seq ::=
    balanced-token
  | balanced-token-seq balanced-token

balanced-token ::=
    "(" balanced-token-seq? ")"
  | "[" balanced-token-seq? "]"
  | "{" balanced-token-seq? "}"
  | "{any token other than a parenthesis, a bracket, or a brace}"

//== modules.tex

module-declaration ::=
    "export"? "module" module-name module-partition? attribute-specifier-seq? ";"

module-name ::=
    module-name-qualifier? identifier

module-partition ::=
    ":" module-name-qualifier? identifier

module-name-qualifier ::=
    identifier "."
  | module-name-qualifier identifier "."

export-declaration ::=
    "export" name-declaration
  | "export" "{" declaration-seq? "}"
  | "export" module-import-declaration

module-import-declaration ::=
    "import" module-name attribute-specifier-seq? ";"
  | "import" module-partition attribute-specifier-seq? ";"
  | "import" header-name attribute-specifier-seq? ";"

global-module-fragment ::=
    "module" ";" declaration-seq?

private-module-fragment ::=
    "module" ":" "private" ";" declaration-seq?

//== classes.tex

class-name ::=
    identifier
  | simple-template-id

class-specifier ::=
    class-head "{" member-specification? "}"

class-head ::=
    class-key attribute-specifier-seq? class-head-name class-virt-specifier? base-clause?
  | class-key attribute-specifier-seq? base-clause?

class-head-name ::=
    nested-name-specifier? class-name

class-virt-specifier ::=
    "final"

class-key ::=
    "class"
  | "struct"
  | "union"

member-specification ::=
    member-declaration member-specification?
  | access-specifier ":" member-specification?

member-declaration ::=
    attribute-specifier-seq? decl-specifier-seq? member-declarator-list? ";"
  | function-definition
  | using-declaration
  | using-enum-declaration
  | static_assert-declaration
  | template-declaration
  | explicit-specialization
  | deduction-guide
  | alias-declaration
  | opaque-enum-declaration
  | empty-declaration

member-declarator-list ::=
    member-declarator
  | member-declarator-list "," member-declarator

member-declarator ::=
    declarator virt-specifier-seq? pure-specifier?
  | declarator requires-clause
  | declarator brace-or-equal-initializer?
  | identifier? attribute-specifier-seq? ":" constant-expression brace-or-equal-initializer?

virt-specifier-seq ::=
    virt-specifier
  | virt-specifier-seq virt-specifier

virt-specifier ::=
    "override"
  | "final"

pure-specifier ::=
    "=" "0"

conversion-function-id ::=
    "operator" conversion-type-id

conversion-type-id ::=
    type-specifier-seq conversion-declarator?

conversion-declarator ::=
    ptr-operator conversion-declarator?

base-clause ::=
    ":" base-specifier-list

base-specifier-list ::=
    base-specifier "..."?
  | base-specifier-list "," base-specifier "..."?

base-specifier ::=
    attribute-specifier-seq? class-or-decltype
  | attribute-specifier-seq? "virtual" access-specifier? class-or-decltype
  | attribute-specifier-seq? access-specifier "virtual"? class-or-decltype

class-or-decltype ::=
    nested-name-specifier? type-name
  | nested-name-specifier "template" simple-template-id
  | decltype-specifier

access-specifier ::=
    "private"
  | "protected"
  | "public"

ctor-initializer ::=
    ":" mem-initializer-list

mem-initializer-list ::=
    mem-initializer "..."?
  | mem-initializer-list "," mem-initializer "..."?

mem-initializer ::=
    mem-initializer-id "(" expression-list? ")"
  | mem-initializer-id braced-init-list

mem-initializer-id ::=
    class-or-decltype
  | identifier

//== overloading.tex

operator-function-id ::=
    "operator" operator

operator ::=
    "new" | "delete" | "new[]" | "delete[]" | "co_await" | "()" | "[]" | "->" | "->*"
  | "~" | "!" | "+" | "-" | "*" | "/" | "%" | "^" | "&"
  | "|" | "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&="
  | "|=" | "==" | "!=" | "<" | ">" | "<=" | ">=" | "<=>" | "&&"
  | "||" | "<<" | ">>" | "<<=" | ">>=" | "++" | "--" | ","

literal-operator-id ::=
    "operator" unevaluated-string identifier
  | "operator" user-defined-string-literal

//== templates.tex

template-declaration ::=
  template-head declaration
  | template-head concept-definition

template-head ::=
  "template" "<" template-parameter-list ">" requires-clause?

template-parameter-list ::=
  template-parameter
  | template-parameter-list "," template-parameter

requires-clause ::=
  "requires" constraint-logical-or-expression

constraint-logical-or-expression ::=
  constraint-logical-and-expression
  | constraint-logical-or-expression "||" constraint-logical-and-expression

constraint-logical-and-expression ::=
  primary-expression
  | constraint-logical-and-expression "&&" primary-expression

template-parameter ::=
  type-parameter
  | parameter-declaration

type-parameter ::=
  type-parameter-key "..."? identifier?
  | type-parameter-key identifier? "=" type-id
  | type-constraint "..."? identifier?
  | type-constraint identifier? "=" type-id
  | template-head type-parameter-key "..."? identifier?
  | template-head type-parameter-key identifier? "=" id-expression

type-parameter-key ::=
  "class"
  | "typename"

type-constraint ::=
  nested-name-specifier? concept-name
  | nested-name-specifier? concept-name "<" template-argument-list? ">"

simple-template-id ::=
  template-name "<" template-argument-list? ">"

template-id ::=
  simple-template-id
  | operator-function-id "<" template-argument-list? ">"
  | literal-operator-id "<" template-argument-list? ">"

template-name ::=
  identifier

template-argument-list ::=
  template-argument "..."?
  | template-argument-list "," template-argument "..."?

template-argument ::=
  constant-expression
  | type-id
  | id-expression
  | braced-init-list

constraint-expression ::=
    logical-or-expression

deduction-guide ::=
    explicit-specifier? template-name "(" parameter-declaration-clause ")" "->" simple-template-id ";"

concept-definition ::=
  "concept" concept-name attribute-specifier-seq? "=" constraint-expression ";"

concept-name ::=
  identifier

typename-specifier ::=
  "typename" nested-name-specifier identifier
  | "typename" nested-name-specifier "template"? simple-template-id

explicit-instantiation ::=
  "extern"? "template" declaration

explicit-specialization ::=
  "template" "<" ">" declaration

//== exceptions.tex

try-block ::=
    "try" compound-statement handler-seq

function-try-block ::=
    "try" ctor-initializer? compound-statement handler-seq

handler-seq ::=
    handler handler-seq?

handler ::=
    "catch" "(" exception-declaration ")" compound-statement

exception-declaration ::=
    attribute-specifier-seq? type-specifier-seq declarator
  | attribute-specifier-seq? type-specifier-seq abstract-declarator?
  | "..."

noexcept-specifier ::=
    "noexcept" "(" constant-expression ")"
  | "noexcept"

//== preprocessor.tex

preprocessing-file ::=
    group?
  | module-file

module-file ::=
    pp-global-module-fragment? pp-module group? pp-private-module-fragment?

pp-global-module-fragment ::=
    "module" ";" new-line group?

pp-private-module-fragment ::=
    "module" ":" "private" ";" new-line group?

group ::=
    group-part
  | group group-part

group-part ::=
    control-line
  | if-section
  | text-line
  | "#" conditionally-supported-directive

control-line ::=
    "#" "include" pp-tokens new-line
  | pp-import
  | "#" "define" identifier replacement-list new-line
  | "#" "define" identifier lparen identifier-list? ")" replacement-list new-line
  | "#" "define" identifier lparen "..." ")" replacement-list new-line
  | "#" "define" identifier lparen identifier-list "," "..." ")" replacement-list new-line
  | "#" "undef" identifier new-line
  | "#" "line" pp-tokens new-line
  | "#" "error" pp-tokens? new-line
  | "#" "warning" pp-tokens? new-line
  | "#" "pragma" pp-tokens? new-line
  | "#" new-line

if-section ::=
    if-group elif-groups? else-group? endif-line

if-group ::=
    "#" "if" constant-expression new-line group?
  | "#" "ifdef" identifier new-line group?
  | "#" "ifndef" identifier new-line group?

elif-groups ::=
    elif-group
  | elif-groups elif-group

elif-group ::=
    "#" "elif" constant-expression new-line group?
  | "#" "elifdef" identifier new-line group?
  | "#" "elifndef" identifier new-line group?

else-group ::=
    "#" "else" new-line group?

endif-line ::=
    "#" "endif" new-line

text-line ::=
    pp-tokens? new-line

conditionally-supported-directive ::=
    pp-tokens new-line

lparen ::=
    '{a "(" character not immediately preceded by whitespace}'

identifier-list ::=
    identifier
  | identifier-list "," identifier

replacement-list ::=
    pp-tokens?

pp-tokens ::=
    preprocessing-token
  | pp-tokens preprocessing-token

new-line ::=
    "{the new-line character}"

defined-macro-expression ::=
    "defined" identifier
  | "defined" "(" identifier ")"

h-preprocessing-token ::=
    '{any preprocessing-token other than ">"}'

h-pp-tokens ::=
    h-preprocessing-token
  | h-pp-tokens h-preprocessing-token

header-name-tokens ::=
    string-literal
  | "<" h-pp-tokens ">"

has-include-expression ::=
    "has_include" "(" header-name ")"
  | "has_include" "(" header-name-tokens ")"

has-attribute-expression ::=
    "has_cpp_attribute" "(" pp-tokens ")"

pp-module ::=
    "export"? "module" pp-tokens? ";" new-line

pp-import ::=
    "export"? "import" header-name pp-tokens? ";" new-line
  | "export"? "import" header-name-tokens pp-tokens? ";" new-line
  | "export"? "import" pp-tokens ";" new-line

va-opt-replacement ::=
    "VA_OPT" "(" pp-tokens? ")"
@mingodad
Copy link
Author

Using the EBNF syntax to also give a high level view for the actual parser (not finished):

//
// EBNF to be viewd at https://www.bottlecaps.de/rr/ui
//
// Copy and paste this at https://www.bottlecaps.de/rr/ui in the 'Edit Grammar' tab
// then click the 'View Diagram' tab.
//

parse_translation_unit ::=
	parse_module_unit
	| parse_top_level_declaration_seq

parse_module_unit ::=
	parse_module_head parse_global_module_fragment
		parse_module_declaration parse_declaration_seq parse_private_module_fragment

parse_top_level_declaration_seq ::=
	parse_declaration+

parse_declaration_seq ::=
	parse_maybe_module
	| parse_declaration+

parse_declaration ::=
	parse_empty_declaration
	| parse_explicit_instantiation
	| parse_template_declaration
	| parse_linkage_specification
	| parse_namespace_definition
	| parse_deduction_guide
	| parse_export_declaration
	| parse_module_import_declaration
	| parse_attribute_declaration
	| parse_block_declaration

parse_empty_declaration ::=
	T_SEMICOLON

parse_explicit_instantiation ::=
	T_EXTERN T_TEMPLATE parse_declaration

parse_template_declaration ::=
	T_TEMPLATE T_LESS parse_template_parameter_list T_GREATER
		parse_requires_clause parse_template_declaration?
		parse_concept_definition?
		parse_template_declaration_body

parse_linkage_specification ::=
	T_EXTERN parse_optional_attribute_specifier_seq T_STRING_LITERAL
		(T_LBRACE parse_declaration_seq T_RBRACE | parse_declaration )

parse_namespace_definition ::=
	T_INLINE? T_NAMESPACE parse_optional_attribute_specifier_seq T_IDENTIFIER T_COLON_COLON
		parse_namespace_body

parse_deduction_guide ::=
	parse_explicit_specifier T_IDENTIFIER T_LPAREN parse_parameter_declaration_clause T_RPAREN
		parse_simple_template_id T_SEMICOLON

parse_export_declaration ::=
	T_EXPORT (T_LBRACE parse_declaration_seq T_RBRACE | parse_module_import_declaration? parse_declaration )

parse_module_import_declaration ::=
	parse_import_keyword parse_import_name parse_optional_attribute_specifier_seq T_SEMICOLON

parse_attribute_declaration ::=
	parse_attribute_specifier_seq T_SEMICOLON

parse_block_declaration ::=
	parse_asm_declaration
	| parse_namespace_alias_definition
	| parse_static_assert_declaration
	| parse_opaque_enum_declaration
	| parse_using_enum_declaration
	| parse_using_directive
	| parse_alias_declaration
	| parse_using_declaration
	| parse_simple_declaration

parse_asm_declaration ::=
	T_ASM AsmQualifier* T_LPAREN T_STRING_LITERAL
		AsmOutputOperandList? AsmInpputOperandList?
		T_RPAREN T_SEMICOLON

AsmQualifier ::=
	T_INLINE
	| T_VOLATILE
	| T_GOTO

AsmOutputOperandList ::=
	AsmInOutOperandList

AsmInpputOperandList ::=
	AsmInOutOperandList

AsmInOutOperandList ::=
	T_COLON parse_asm_operand (T_COMMA parse_asm_operand)*

parse_namespace_alias_definition ::=
	T_NAMESPACE T_IDENTIFIER T_EQUAL parse_qualified_namespace_specifier T_SEMICOLON

parse_static_assert_declaration ::=
	T_STATIC_ASSERT T_LPAREN parse_constant_expression (T_COMMA T_STRING_LITERAL)? T_RPAREN T_SEMICOLON

parse_opaque_enum_declaration ::=
	parse_optional_attribute_specifier_seq parse_enum_key parse_enum_head_name parse_enum_base T_SEMICOLON

parse_using_enum_declaration ::=
	T_USING parse_elaborated_enum_specifier T_SEMICOLON

parse_using_directive ::=
	T_USING T_NAMESPACE parse_optional_nested_name_specifier parse_name_id T_SEMICOLON

parse_alias_declaration ::=
	T_USING T_IDENTIFIER parse_optional_attribute_specifier_seq T_EQUAL parse_defining_type_id T_SEMICOLON

parse_using_declaration ::=
	T_USING parse_using_declarator_list T_SEMICOLON

parse_simple_declaration ::=
	parse_one_simple_declaration+

parse_one_simple_declaration ::=
	T___EXTENSION__? parse_optional_attribute_specifier_seq
		(
		T_SEMICOLON
		| parse_template_class_declaration
		| parse_empty_or_attribute_declaration
		| parse_notypespec_function_definition
		| parse_decl_specifier_seq
		| parse_type_or_forward_declaration
		| parse_structured_binding
		)

parse_module_head ::=
	T_EXPORT parse_id

parse_global_module_fragment ::=
	parse_module_keyword T_SEMICOLON parse_declaration_seq

parse_module_declaration ::=
	parse_export_keyword parse_module_keyword parse_module_name parse_module_partition
		parse_optional_attribute_specifier_seq T_SEMICOLON

parse_private_module_fragment ::=
	parse_module_keyword T_COLON T_PRIVATE T_SEMICOLON parse_declaration_seq

parse_block_declaration ::=
	parse_class_specifier parse_attribute_specifier_seq T_SEMICOLON

parse_class_specifier ::=
	parse_class_head T_LBRACE parse_class_body T_RBRACE

parse_class_head ::=
	(T_CLASS | T_STRUCT | T_UNION) parse_optional_attribute_specifier_seq
		parse_class_head_name parse_class_virt_specifier parse_base_clause

parse_class_head_name ::=
	parse_optional_nested_name_specifier check_type_traits parse_type_name

parse_class_virt_specifier ::=
	parse_final

parse_base_clause ::=
	T_COLON parse_base_specifier_list

parse_base_specifier_list ::=
	parse_base_specifier T_DOT_DOT_DOT ( T_COMMA parse_base_specifier T_DOT_DOT_DOT)*

parse_base_specifier ::=
	parse_optional_attribute_specifier_seq
		(T_VIRTUAL parse_access_specifier | parse_access_specifier T_VIRTUAL)?
		parse_class_or_decltype

parse_class_body ::=
	parse_member_specification*

parse_member_specification ::=
	parse_member_declaration

parse_member_declaration ::=
	parse_access_specifier T_COLON
	| parse_empty_declaration
	| parse_using_enum_declaration
	| parse_alias_declaration
	| parse_using_declaration
	| parse_static_assert_declaration
	| parse_deduction_guide
	| parse_opaque_enum_declaration
	| parse_template_declaration
	| parse_member_declaration_helper

parse_member_declaration_helper ::=
	T___EXTENSION__? parse_optional_attribute_specifier_seq parse_decl_specifier_seq_no_typespecs
		(parse_notypespec_function_definition | parse_decl_specifier_seq T_SEMICOLON )

parse_notypespec_function_definition ::=
	parse_declarator_id parse_function_declarator parse_requires_clause parse_virt_specifier_seq
		parse_optional_attribute_specifier_seq parse_pure_specifier (T_SEMICOLON | parse_function_body)

parse_function_body ::=
	parse_function_try_block
	| T_EQUAL T_DEFAULT T_SEMICOLON
	| T_EQUAL T_DELETE T_SEMICOLON
	| parse_ctor_initializer parse_compound_statement

parse_compound_statement ::=
	T_LBRACE finish_compound_statement? T_RBRACE

finish_compound_statement ::=
	( parse_maybe_statement	| parse_skip_statement )+

parse_maybe_statement ::=
	T___EXTENSION__? (
		parse_case_statement
		| parse_default_statement
		| parse_while_statement
		| parse_do_statement
		| parse_for_statement
		| parse_if_statement
		| parse_switch_statement
		| parse_break_statement
		| parse_continue_statement
		| parse_return_statement
		| parse_goto_statement
		| parse_coroutine_return_statement
		| parse_try_block
		| parse_maybe_compound_statement
		| parse_labeled_statement
		| parse_declaration_statement
		| parse_expression_statement
	)

parse_case_statement ::=
	T_CASE parse_constant_expression T_COLON

parse_default_statement ::=
	T_DEFAULT T_COLON

parse_while_statement ::=
	T_WHILE T_LPAREN parse_condition T_RPAREN

parse_do_statement ::=
	T_DO parse_statement T_WHILE T_LPAREN parse_expression T_RPAREN T_SEMICOLON

parse_for_statement ::=
	parse_for_range_statement
	| T_FOR T_LPAREN parse_init_statement T_SEMICOLON parse_condition T_SEMICOLON parse_expression T_RPAREN
		parse_statement

parse_for_range_statement ::=
	T_FOR T_LPAREN parse_init_statement parse_for_range_declaration T_COLON parse_for_range_initializer T_RPAREN
		parse_statement

parse_init_statement ::=
	parse_simple_declaration parse_maybe_expression

parse_for_range_declaration ::=
	parse_decl_specifier_seq ( parse_structured_binding | parse_declarator )

parse_for_range_initializer ::=
	parse_expr_or_braced_init_list

parse_if_statement ::=
	T_IF (
		T_EXCLAIM  T_CONSTEVAL parse_compound_statement (T_ELSE parse_statement)?
		| T_CONSTEXPR? T_LPAREN parse_init_statement parse_condition T_RPAREN parse_statement (T_ELSE parse_statement)?
		)

parse_switch_statement ::=
	T_SWITCH T_LPAREN parse_init_statement parse_condition T_RPAREN parse_statement

parse_break_statement ::=
	T_BREAK T_SEMICOLON

parse_continue_statement ::=
	T_CONTINUE T_SEMICOLON

parse_return_statement ::=
	T_RETURN parse_expr_or_braced_init_list? T_SEMICOLON

parse_goto_statement ::=
	T_GOTO T_IDENTIFIER T_SEMICOLON

parse_coroutine_return_statement ::=
	T_CO_RETURN parse_expr_or_braced_init_list? T_SEMICOLON

parse_try_block ::=
	T_TRY parse_compound_statement parse_handler_seq

parse_handler_seq ::=
	T_CATCH parse_handler

parse_maybe_compound_statement ::=
	parse_compound_statement?

parse_labeled_statement ::=
	T_IDENTIFIER T_COLON

parse_declaration_statement ::=
	parse_block_declaration

parse_expression_statement ::=
	T_SEMICOLON
	| parse_maybe_expression T_SEMICOLON

parse_final ::=
	parse_id

parse_optional_attribute_specifier_seq ::=
	parse_attribute_specifier*

parse_attribute_specifier ::=
	parse_cxx_attribute_specifier
	| parse_gcc_attribute
	| parse_alignment_specifier
	| parse_asm_specifier

parse_cxx_attribute_specifier ::=
	T_LBRACKET T_LBRACKET parse_attribute_using_prefix parse_attribute_list T_RBRACKET T_RBRACKET

parse_gcc_attribute ::=
	T___ATTRIBUTE__ T_LPAREN parse_skip_balanced T_RPAREN

parse_alignment_specifier ::=
	T_ALIGNAS T_LPAREN parse_type_id T_DOT_DOT_DOT T_RPAREN

parse_asm_specifier ::=
	T_ASM T_LPAREN T_STRING_LITERAL T_RPAREN

//
//Tokens
//

T_SEMICOLON ::= ';'
T_EXTERN ::= "extern"
T_TEMPLATE ::= "template"
T_LESS ::= '<'
T_GREATER ::= '>'
T_LBRACE ::= '{'
T_RBRACE ::= '}'
T_LPAREN ::= '('
T_RPAREN ::= ')'
T_LBRACKET ::= '['
T_RBRACKET ::= ']'
T_COLON ::= ':'
T_COMMA ::= ','
T_EQUAL ::= '='
T_EXCLAIM ::= '!'
T_COLON_COLON ::= "::"
T_NAMESPACE ::= "namespace"
T_INLINE ::= "inline"
T_EXPORT ::= "export"
T_ASM ::= "asm"
T_VOLATILE ::= "volatile"
T_GOTO ::= "goto"
T_STATIC_ASSERT ::= "static_assert"
T_USING ::= "using"
T___EXTENSION__ ::= "__extension__"
T_PRIVATE ::= "private"
T___ATTRIBUTE__ ::= "__attribute__"
T_ALIGNAS ::= "allignas"
T_DOT_DOT_DOT ::= "..."
T_VIRTUAL ::= "virtual"
T_CASE ::= "case"
T_DEFAULT ::= "default"
T_WHILE ::= "while"
T_IF ::= "if"
T_ELSE ::= "else"
T_CONSTEVAL ::= "consteval"
T_SWITCH ::= "switch"
T_BREAK ::= "break"
T_RETURN ::= "return"
T_CO_RETURN ::= "co_return"
T_TRY ::= "try"
T_CATCH ::= "catch"
T_FOR ::= "for"
T_CLASS ::= "class"
T_STRUCT ::= "struct"
T_UNION ::= "union"
T_DELETE ::= "delete"
T_DO ::= "do"
T_CONSTEXPR ::= "constexpr"
T_CONTINUE ::= "continue"


T_STRING_LITERAL ::= '"' ('\' . | [^"\\n\\r\\])* '"'
T_IDENTIFIER ::= [A-Za-z_][A-Za-z0-9_]*

@mingodad
Copy link
Author

I figured out that the content on specs/grammar.txt come from https://github.com/cplusplus/draft so I made a script to scrap/convert it to an EBNF understood by https://www.bottlecaps.de/rr/ui see the result here cplusplus/draft#6742 .

@robertoraggi
Copy link
Owner

Thanks for your suggestion but I'm not sure it is a good idea to diverge too much from the official C++ grammar, the C++ language is still evolving. In the past I had a C++ grammar in BNF for pgen, a simple generalized parser generator that I wrote, but it was way too much work to maintain.

https://github.com/robertoraggi/pgen
https://github.com/robertoraggi/cplusplus/blob/554e41b4c07b88f7cf51787e37d6b21dcf7481ef/src/cxx/parser.pgen

@mingodad
Copy link
Author

Not at all !
This one is mechanically extracted from the files at https://github.com/cplusplus/draft/

@mingodad
Copy link
Author

I've just added the C++11, C++14, C++117, C++20, C++23-draft converted to the EBNF understood by https://www.bottlecaps.de/rr/ui and the navigable railroad diagrams read to view here https://mingodad.github.io/cpp-grammars/ .

@mingodad
Copy link
Author

Maybe you'll also be interested in https://github.com/thradams/cake and it's playground http://thradams.com/cake/playground.html it has an interesting borrow checker extension.

@robertoraggi
Copy link
Owner

@mingodad Thanks for the suggestion, it looks like an interesting project to follow.
Once I’m done with core language, I plan to implement a few extensions for C++, with reflection and memory safety being on top of my list.

@mingodad
Copy link
Author

Today I found this project https://github.com/srcML/srcML and they have a wasm playground here http://www.srcml.org/doc/playground.html that is very interesting and I think that it can be interesting to you too.

@mingodad
Copy link
Author

Playing at https://aistudio.google.com/prompts/new_chat with this prompt:

Looking at https://github.com/robertoraggi/cplusplus and https://github.com/robertoraggi/cplusplus/blob/main/src/parser/cxx/parser.cc that is a C++ parser  can you extract an ebnf to create railroad diagram ?

I've got (after small manual fixes):

translation_unit ::= ( declaration )*

declaration ::=
    block_declaration
  | function_definition
  | template_declaration
  | explicit_instantiation
  | explicit_specialization
  | linkage_specification
  | namespace_definition
  | using_directive
  | using_declaration
  | static_assert_declaration
  | asm_definition
  | alias_declaration // using IDENTIFIER = type_id;
  | opaque_enum_declaration // enum (class|struct)? IDENTIFIER (: type_specifier_seq] SEMICOLON
  // ... other top-level declarations

// Simplified from parseSimpleDeclaration and related functions
block_declaration ::=
    decl_specifier_seq ( init_declarator_list )? SEMICOLON

decl_specifier_seq ::=
    decl_specifier ( decl_specifier )*

decl_specifier ::=
    storage_class_specifier
  | type_specifier
  | function_specifier // e.g., inline, virtual, explicit
  | KW_FRIEND
  | KW_TYPEDEF
  | KW_CONSTEXPR
  | KW_CONSTEVAL
  | KW_CONSTINIT
  // ... other specifiers like attributes

storage_class_specifier ::=
    KW_STATIC | KW_EXTERN | KW_REGISTER | KW_MUTABLE | KW_THREAD_LOCAL

type_specifier ::=
    simple_type_specifier
  | class_specifier
  | enum_specifier
  | elaborated_type_specifier
  | typename_specifier // KW_TYPENAME nested_name_specifier IDENTIFIER
  | cv_qualifier

cv_qualifier ::= KW_CONST | KW_VOLATILE

simple_type_specifier ::=
    nested_name_specifier_opt IDENTIFIER // for user-defined types
  | nested_name_specifier KW_TEMPLATE template_id // template type
  | KW_CHAR | KW_CHAR8_T | KW_CHAR16_T | KW_CHAR32_T | KW_WCHAR_T
  | KW_BOOL | KW_SHORT | KW_INT | KW_LONG | KW_SIGNED | KW_UNSIGNED
  | KW_FLOAT | KW_DOUBLE | KW_VOID
  | KW_AUTO
  | decltype_specifier

elaborated_type_specifier ::=
    (KW_CLASS | KW_STRUCT | KW_UNION) (nested_name_specifier_opt)? IDENTIFIER
  | (KW_CLASS | KW_STRUCT | KW_UNION) nested_name_specifier KW_TEMPLATE template_id
  | KW_ENUM (nested_name_specifier_opt)? IDENTIFIER

init_declarator_list ::=
    init_declarator ( COMMA init_declarator )*

init_declarator ::=
    declarator ( initializer )?

declarator ::=
    ptr_operator_seq direct_declarator

ptr_operator_seq ::= ( ptr_operator )*

ptr_operator ::=
    STAR (cv_qualifier_seq)?
  | AMP (cv_qualifier_seq)?              // Lvalue ref
  | AMP_AMP (cv_qualifier_seq)?          // Rvalue ref
  | nested_name_specifier_opt STAR (cv_qualifier_seq)? // Pointer to member

direct_declarator ::=
    ( declarator_id | LPAREN declarator RPAREN )
    ( declarator_suffix )*

declarator_id ::= nested_name_specifier_opt unqualified_id

unqualified_id ::= IDENTIFIER | operator_function_id | conversion_function_id | literal_operator_id | TILDE IDENTIFIER /*destructor*/

declarator_suffix ::=
    LPAREN parameter_declaration_clause RPAREN (cv_qualifier_seq)? (ref_qualifier)? (noexcept_specifier)? (attribute_specifier_seq)? (trailing_return_type)?
  | LSQUARE (expression_opt)? RSQUARE (attribute_specifier_seq)?

parameter_declaration_clause ::= ( parameter_declaration_list )? (COMMA ELLIPSIS)? | ELLIPSIS

parameter_declaration_list ::= parameter_declaration ( COMMA parameter_declaration )*

parameter_declaration ::= (attribute_specifier_seq)? decl_specifier_seq declarator (ASSIGNMENT expression)?
                        | (attribute_specifier_seq)? decl_specifier_seq (abstract_declarator)? (ASSIGNMENT expression)?

initializer ::=
    ASSIGNMENT initializer_clause
  | LPAREN expression_list RPAREN
  | LBRACE initializer_list (COMMA)? RBRACE

initializer_clause ::= assignment_expression | LBRACE initializer_list (COMMA)? RBRACE

initializer_list ::= designated_initializer_clause ( COMMA designated_initializer_clause )*
                  | initializer_clause ( COMMA initializer_clause )*

// --- Statements (Simplified from parseStatement and its callees) ---
statement ::=
    labeled_statement
  | attribute_specifier_seq_opt (
        expression_statement
      | compound_statement
      | selection_statement
      | iteration_statement
      | jump_statement
      | try_block
      | declaration_statement // block_declaration
    )

expression_statement ::= (expression)? SEMICOLON

compound_statement ::= LBRACE ( statement )* RBRACE

selection_statement ::=
    KW_IF (KW_CONSTEXPR)? LPAREN condition RPAREN statement (KW_ELSE statement)?
  | KW_SWITCH (KW_CONSTEXPR)? LPAREN condition RPAREN statement

iteration_statement ::=
    KW_WHILE LPAREN condition RPAREN statement
  | KW_DO statement KW_WHILE LPAREN expression RPAREN SEMICOLON
  | KW_FOR LPAREN for_init_statement (condition)? SEMICOLON (expression)? RPAREN statement
  | KW_FOR LPAREN for_range_declaration COLON for_range_initializer RPAREN statement

jump_statement ::=
    KW_BREAK SEMICOLON
  | KW_CONTINUE SEMICOLON
  | KW_RETURN (expression)? SEMICOLON
  | KW_GOTO IDENTIFIER SEMICOLON
  | KW_CO_RETURN (expression)? SEMICOLON
  | KW_CO_YIELD expression SEMICOLON
  | KW_CO_AWAIT expression SEMICOLON


// --- Expressions (VERY simplified, not showing full precedence) ---
// The parser implements precedence by a cascade of functions
// e.g., parseAssignmentExpression calls parseConditionalExpression, etc.
// This EBNF just shows the general structure.

expression_list ::= assignment_expression ( COMMA assignment_expression )*

expression ::= assignment_expression ( COMMA assignment_expression )* // As in expression_list

// A typical way to represent precedence in EBNF (simplified):
primary_expression ::=
    literal
  | KW_THIS
  | LPAREN expression RPAREN
  | id_expression
  | lambda_expression

postfix_expression ::=
    primary_expression
  | postfix_expression LSQUARE expression RSQUARE
  | postfix_expression LPAREN (expression_list)? RPAREN
  | postfix_expression DOT (KW_TEMPLATE_OPT unqualified_id | pseudo_destructor_name)
  | postfix_expression ARROW (KW_TEMPLATE_OPT unqualified_id | pseudo_destructor_name)
  | postfix_expression PLUS_PLUS
  | postfix_expression MINUS_MINUS
  // | simple_type_specifier LPAREN (expression_list)? RPAREN // functional cast
  // | typename_specifier LPAREN (expression_list)? RPAREN
  // | KW_DYNAMIC_CAST LT type_id GT LPAREN expression RPAREN
  // ... other casts, typeid

unary_expression ::=
    postfix_expression
  | (PLUS_PLUS | MINUS_MINUS) unary_expression
  | unary_operator cast_expression
  | KW_SIZEOF ( unary_expression | LPAREN type_id RPAREN )
  | KW_ALIGNOF LPAREN type_id RPAREN
  | noexcept_expression // KW_NOEXCEPT LPAREN expression RPAREN
  | new_expression
  | delete_expression
  | co_await_expression

unary_operator ::= PLUS | MINUS | STAR | AMP | EXCLAIM | TILDE

cast_expression ::= unary_expression | LPAREN type_id RPAREN cast_expression

pm_expression ::= cast_expression ( (DOT_STAR | ARROW_STAR) cast_expression )* // Pointer-to-member

multiplicative_expression ::= pm_expression ( (STAR | SLASH | PERCENT) pm_expression )*

additive_expression ::= multiplicative_expression ( (PLUS | MINUS) multiplicative_expression )*

shift_expression ::= additive_expression ( (LSHIFT | RSHIFT) additive_expression )*

compare_expression ::= shift_expression ( (LESS | GREATER | LESS_EQUAL | GREATER_EQUAL | SPACESHIP) shift_expression )* // C++20 spaceship

equality_expression ::= compare_expression ( (EQUAL_EQUAL | NOT_EQUAL) compare_expression )*

and_expression ::= equality_expression ( AMP equality_expression )*

exclusive_or_expression ::= and_expression ( CARET and_expression )*

inclusive_or_expression ::= exclusive_or_expression ( PIPE exclusive_or_expression )*

logical_and_expression ::= inclusive_or_expression ( AMP_AMP inclusive_or_expression )*

logical_or_expression ::= logical_and_expression ( PIPE_PIPE logical_and_expression )*

conditional_expression ::= logical_or_expression (QUESTION expression COLON assignment_expression)?

assignment_expression ::=
    conditional_expression
  | logical_or_expression assignment_operator initializer_clause
  | throw_expression
  | yield_expression // co_yield

assignment_operator ::=
    ASSIGNMENT | STAR_ASSIGNMENT | SLASH_ASSIGNMENT | PERCENT_ASSIGNMENT | PLUS_ASSIGNMENT |
    MINUS_ASSIGNMENT | RSHIFT_ASSIGNMENT | LSHIFT_ASSIGNMENT | AMP_ASSIGNMENT |
    CARET_ASSIGNMENT | PIPE_ASSIGNMENT

// --- Class Specifier ---
class_specifier ::=
    class_head LBRACE (member_specification)? RBRACE

class_head ::=
    class_key (attribute_specifier_seq)? (class_head_name)? (class_virt_specifier_seq)? (base_clause)?
  | class_key (attribute_specifier_seq)? base_clause

class_key ::= KW_CLASS | KW_STRUCT | KW_UNION

class_head_name ::= (nested_name_specifier)? IDENTIFIER

base_clause ::= COLON base_specifier_list

base_specifier_list ::= base_specifier ( COMMA base_specifier )*

base_specifier ::=
    (attribute_specifier_seq)? (KW_VIRTUAL)? (access_specifier)? (KW_VIRTUAL)? class_or_decltype
  | (attribute_specifier_seq)? KW_VIRTUAL (access_specifier)? (KW_VIRTUAL)? class_or_decltype
  | (attribute_specifier_seq)? access_specifier (KW_VIRTUAL)? class_or_decltype
  // ... and ELLIPSIS for pack expansion

access_specifier ::= KW_PRIVATE | KW_PROTECTED | KW_PUBLIC

member_specification ::= ( member_declaration )* ( access_specifier COLON ( member_declaration )* )*

member_declaration ::=
    (attribute_specifier_seq)? (decl_specifier_seq)? (member_declarator_list)? SEMICOLON
  | function_definition (SEMICOLON_OPT)?
  | using_declaration
  | static_assert_declaration
  | template_declaration
  | alias_declaration
  // ... constructor, destructor, conversion_function_id, etc.

// --- Templates ---
template_declaration ::=
    KW_EXPORT_OPT KW_TEMPLATE LESS template_parameter_list GREATER declaration

template_parameter_list ::= template_parameter ( COMMA template_parameter )*

template_parameter ::=
    type_parameter
  | parameter_declaration // non-type template parameter

type_parameter ::=
    (KW_CLASS | KW_TYPENAME) (IDENTIFIER)? (ASSIGNMENT type_id)?
  | KW_TEMPLATE LESS template_parameter_list GREATER (KW_CLASS | KW_TYPENAME) (IDENTIFIER)? (ASSIGNMENT id_expression)?
  // ... constrained type parameter (concepts)

// --- Namespaces ---
namespace_definition ::=
    KW_INLINE_OPT KW_NAMESPACE (IDENTIFIER)? LBRACE ( declaration )* RBRACE
  | KW_INLINE_OPT KW_NAMESPACE IDENTIFIER ASSIGNMENT nested_name_specifier IDENTIFIER SEMICOLON // namespace alias

// --- Utilities ---
nested_name_specifier_opt ::= (nested_name_specifier)?
nested_name_specifier ::= (IDENTIFIER | template_id) COLON_COLON ( (IDENTIFIER | template_id) COLON_COLON )*

template_id ::= IDENTIFIER LESS (template_argument_list)? GREATER

template_argument_list ::= template_argument ( COMMA template_argument )*

template_argument ::= type_id | expression | id_expression // simplified

type_id ::= type_specifier_seq (abstract_declarator)?

abstract_declarator ::= ptr_operator_seq (direct_abstract_declarator)?
                      | direct_abstract_declarator // when no ptr_operator

// ... many other rules would be needed for a full grammar.
// For example, literal, id_expression, lambda_expression, attributes, concepts, etc.
// are non-terminals that would need further definition.

@mingodad
Copy link
Author

And for comparison here is what copilot gave me after two prompts and manual fixing the EBNF:
First prompt:

Extract an EBNF to generate railroad diagram from this file/repository that is a C++ parser

Second prompt:

Give me an EBNF for the entire parser with as much as possible details and in one file

EBNF manually fixed:

/* Top-level entry points */
translation_unit ::=
    module_unit
  | top_level_declaration_seq


module_unit ::=
    module_head module_declaration declaration_seq private_module_fragment? EOF_SYMBOL


top_level_declaration_seq ::=
    ( declaration )*


/* Declarations */
declaration ::=
    empty_declaration
  | explicit_instantiation
  | template_declaration
  | linkage_specification
  | namespace_definition
  | deduction_guide
  | export_declaration
  | module_import_declaration
  | attribute_declaration
  | block_declaration


block_declaration ::=
    asm_declaration
  | namespace_alias_definition
  | static_assert_declaration
  | opaque_enum_declaration
  | using_enum_declaration
  | using_directive
  | alias_declaration
  | using_declaration
  | simple_declaration


simple_declaration ::=
    attribute_declaration
  | notypespec_function_definition
  | type_or_forward_declaration
  | structured_binding
  | full_simple_declaration


full_simple_declaration ::=
    decl_specifier_seq init_declarator_list? ";"

init_declarator_list ::=
    init_declarator ( "," init_declarator )*


init_declarator ::=
    declarator ( requires_clause? initializer? )


empty_declaration ::= ";"

attribute_declaration ::=
    attribute_specifier_seq ";"


/* Statements */
statement ::=
    case_statement
  | default_statement
  | while_statement
  | do_statement
  | for_statement
  | if_statement
  | switch_statement
  | break_statement
  | continue_statement
  | return_statement
  | goto_statement
  | coroutine_return_statement
  | try_block
  | compound_statement
  | labeled_statement
  | declaration_statement
  | expression_statement


compound_statement ::=
    "{" ( statement )* "}"


expression_statement ::=
    ( expression )? ";"


declaration_statement ::=
    block_declaration


/* Expressions */
expression ::=
    maybe_expression


maybe_expression ::=
    maybe_assignment_expression ( "," maybe_assignment_expression )*


maybe_assignment_expression ::=
    yield_expression
  | throw_expression
  | conditional_expression assignment_operator initializer_clause?
  | conditional_expression


conditional_expression ::=
    logical_or_expression
    ( "?" expression ":" assignment_expression )?


assignment_operator ::=
    "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | "&=" | "^=" | "|=" | ">>="

initializer_clause ::=
    braced_init_list
  | assignment_expression


assignment_expression ::=
    conditional_expression


logical_or_expression ::=
    logical_and_expression ( "||" logical_and_expression )*


logical_and_expression ::=
    inclusive_or_expression ( "&&" inclusive_or_expression )*


inclusive_or_expression ::=
    exclusive_or_expression ( "|" exclusive_or_expression )*


exclusive_or_expression ::=
    and_expression ( "^" and_expression )*


and_expression ::=
    equality_expression ( "&" equality_expression )*


equality_expression ::=
    relational_expression ( ("==" | "!=") relational_expression )*


relational_expression ::=
    shift_expression ( ("<" | ">" | "<=" | ">=") shift_expression )*


shift_expression ::=
    additive_expression ( ("<<" | ">>") additive_expression )*


additive_expression ::=
    multiplicative_expression ( ("+" | "-") multiplicative_expression )*


multiplicative_expression ::=
    pm_expression ( ("*" | "/" | "%") pm_expression )*


pm_expression ::=
    cast_expression ( (".*" | "->*") cast_expression )*


cast_expression ::=
    unary_expression
  | "(" type_id ")" cast_expression


unary_expression ::=
    postfix_expression
  | unary_operator cast_expression


unary_operator ::=
    "*" | "&" | "+" | "-" | "!" | "~" | "++" | "--"


postfix_expression ::=
    primary_expression
    (   "[" expression "]"
      | "(" expression_list? ")"
      | "." id_expression
      | "->" id_expression
      | "++" | "--"
    )*


primary_expression ::=
    literal
  | "this"
  | "(" expression ")"
  | id_expression
  | lambda_expression
  | requires_expression
  | fold_expression
  | splicer_expression
  | reflect_expression


literal ::=
    integer_literal
  | character_literal
  | floating_point_literal
  | string_literal
  | boolean_literal
  | nullptr


id_expression ::=
    ( nested_name_specifier )? ( "template" )? unqualified_id


unqualified_id ::=
    identifier
  | operator_function_id
  | conversion_function_id
  | literal_operator_id
  | template_id
  | destructor_id


nested_name_specifier ::=
    ("::" | (type_name | template_id) "::") ( (type_name | template_id) "::" )*


type_name ::=
    identifier
  | simple_template_id


template_id ::=
    identifier "<" template_argument_list ">"


template_argument_list ::=
    template_argument ( "," template_argument )*


template_argument ::=
    type_id
  | constant_expression


type_id ::=
    type_specifier_seq declarator?


type_specifier_seq ::=
    type_specifier ( type_specifier )*


type_specifier ::=
    simple_type_specifier
  | elaborated_type_specifier
  | typename_specifier
  | cv_qualifier
  | splicer_specifier


cv_qualifier ::= "const" | "volatile" | "__restrict__"

simple_type_specifier ::=
    "char" | "char8_t" | "char16_t" | "char32_t" | "wchar_t" | "bool"
  | "int" | "__int64" | "__int128"
  | "float" | "double" | "__float80" | "__float128"
  | "void"
  | named_type_specifier
  | decltype_specifier_type_specifier


named_type_specifier ::=
    ( nested_name_specifier )? ( "template" )? type_name


decltype_specifier_type_specifier ::=
    "decltype" "(" expression ")"


elaborated_type_specifier ::=
    ( "class" | "struct" | "union" | "enum" ) ( nested_name_specifier )? identifier


typename_specifier ::=
    "typename" nested_name_specifier ( "template" )? identifier


splicer_specifier ::=
    /* reflection-specific extension */


/* Template declarations, parameters, concepts */
template_declaration ::=
    "template" "<" template_parameter_list ">" requires_clause? declaration


template_parameter_list ::=
    template_parameter ( "," template_parameter )*


template_parameter ::=
    type_parameter
  | non_type_template_parameter
  | constraint_type_parameter


type_parameter ::=
    ( "class" | "typename" ) ( "..." )? ( identifier ( "=" type_id )? )?
  | template_type_parameter


template_type_parameter ::=
    "template" "<" template_parameter_list ">" requires_clause? type_parameter


non_type_template_parameter ::=
    parameter_declaration


constraint_type_parameter ::=
    type_constraint ( "..." )? ( identifier ( "=" type_id )? )?


type_constraint ::=
    ( nested_name_specifier )? identifier ( "<" template_argument_list ">" )?


requires_clause ::=
    "requires" constraint_expression


constraint_expression ::=
    logical_or_expression


concept_definition ::=
    "concept" identifier "=" constraint_expression ";"


/* Lambda expressions */
lambda_expression ::=
    "[" lambda_capture? "]" lambda_declarator? compound_statement


lambda_capture ::=
    capture_default ( "," capture_list )? | capture_list


capture_default ::= "&" | "="

capture_list ::=
    capture ( "," capture )*


capture ::=
    simple_capture
  | init_capture


simple_capture ::=
    identifier ( "..." )?
  | "&" identifier ( "..." )?
  | "this"
  | "*" "this"


init_capture ::=
    ( "&" )? ( "..." )? identifier initializer


lambda_declarator ::=
    "(" parameter_declaration_clause? ")" attribute_specifier_seq? lambda_specifier_seq? noexcept_specifier? trailing_return_type? attribute_specifier_seq? requires_clause?


lambda_specifier_seq ::=
    lambda_specifier ( lambda_specifier )*


lambda_specifier ::=
    "mutable" | "constexpr" | "consteval" | "static"


/* Attributes */
attribute_specifier_seq ::=
    attribute_specifier ( attribute_specifier )*


attribute_specifier ::=
    cxx_attribute_specifier
  | gcc_attribute
  | alignment_specifier
  | asm_specifier


cxx_attribute_specifier ::=
    "[[" attribute_using_prefix? attribute_list "]]"


attribute_using_prefix ::=
    "using" attribute_namespace ":"


attribute_namespace ::= identifier

attribute_list ::=
    attribute ( "," attribute )*


attribute ::=
    attribute_token attribute_argument_clause?


attribute_token ::=
    simple_attribute_token
  | scoped_attribute_token


simple_attribute_token ::=
    identifier


scoped_attribute_token ::=
    attribute_namespace "::" identifier


attribute_argument_clause ::=
    "(" ... ")" /* Balanced parens, possibly skipping for brevity */


gcc_attribute ::=
    "__attribute__" "((" ... "))"


alignment_specifier ::=
    "alignas" "(" ( type_id | constant_expression ) ( "..." )? ")"


asm_specifier ::=
    "asm" "(" string_literal ")"


/* Namespaces */
namespace_definition ::=
    ( "inline" )? "namespace" identifier? attribute_specifier_seq? "{" namespace_body "}"


namespace_body ::=
    ( declaration )*


namespace_alias_definition ::=
    "namespace" identifier "=" qualified_namespace_specifier ";"


qualified_namespace_specifier ::=
    ( nested_name_specifier )? identifier


using_directive ::=
    ( attribute_specifier_seq )? "using" "namespace" nested_name_specifier identifier ";"


using_declaration ::=
    "using" using_declarator_list ";"


using_declarator_list ::=
    using_declarator ( "," using_declarator )*


using_declarator ::=
    ( "typename" )? nested_name_specifier unqualified_id ( "..." )?


/* Classes */
class_specifier ::=
    class_key ( attribute_specifier_seq )? ( nested_name_specifier )? ( identifier | simple_template_id ) class_virt_specifier? base_clause? "{" class_body "}"


class_key ::= "class" | "struct" | "union"

class_virt_specifier ::= final

final ::= "final"

base_clause ::=
    ":" base_specifier_list


base_specifier_list ::=
    base_specifier ( "," base_specifier )*


base_specifier ::=
    ( attribute_specifier_seq )? ( "virtual" )? ( access_specifier )? ( "template" )? nested_name_specifier? unqualified_id ( "..." )?


access_specifier ::= "private" | "protected" | "public"

class_body ::=
    ( member_declaration )*


member_declaration ::=
    access_specifier ":"
  | empty_declaration
  | using_enum_declaration
  | alias_declaration
  | using_declaration
  | static_assert_declaration
  | deduction_guide
  | opaque_enum_declaration
  | template_declaration
  | member_declaration_helper


member_declaration_helper ::=
    attribute_specifier_seq? decl_specifier_seq? member_declarator_list? ";"

member_declarator_list ::=
    member_declarator ( "," member_declarator )*


member_declarator ::=
    bitfield_declarator
  | declarator ( requires_clause? initializer? )


bitfield_declarator ::=
    ( identifier )? ( attribute_specifier_seq )? ":" constant_expression


/* Enums */
enum_specifier ::=
    enum_key ( attribute_specifier_seq )? ( nested_name_specifier )? identifier? enum_base? "{" enumerator_list? "}"


enum_key ::= "enum" ( "class" | "struct" )?

enum_base ::=
    ":" type_specifier_seq


enumerator_list ::=
    enumerator ( "," enumerator )*


enumerator ::=
    identifier ( attribute_specifier_seq )? ( "=" constant_expression )?


/* Templates, concepts, requires, deduction guides, modules, etc. */
/* See earlier rules; add more as needed */

/* Others */
asm_declaration ::=
    ( attribute_specifier_seq )? "asm" "(" string_literal ")" qualifier_list? ";"

qualifier_list ::=
    ( "inline" | "volatile" | "goto" )*


static_assert_declaration ::=
    "static_assert" "(" constant_expression ( "," string_literal )? ")" ";"


deduction_guide ::=
    ( explicit_specifier )? identifier "(" parameter_declaration_clause? ")" "->" simple_template_id ";"


opaque_enum_declaration ::=
    ( attribute_specifier_seq )? enum_key nested_name_specifier identifier enum_base? ";"


export_declaration ::=
    "export" ( export_compound_declaration | module_import_declaration | declaration )


export_compound_declaration ::=
    "{" declaration_seq "}"


module_import_declaration ::=
    import_keyword import_name attribute_specifier_seq? ";"


import_keyword ::= "import"

import_name ::=
    header_name
  | module_partition
  | module_name


header_name ::= string_literal
module_partition ::= ":" module_name
module_name ::= identifier ( "." identifier )*

private_module_fragment ::=
    module_keyword ":" "private" ";" declaration_seq


module_head ::=
    ( "export" )? module_keyword


module_keyword ::= "module"

/* Placeholders for other rules, see parser.cc for full elaboration */

/* --- End of Grammar --- */

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants