Anglr Syntax Rules for C# Language


Introduction

This paragraph introduces complete set of Anglr syntax rules for C# 8 programming language. C# parser, which is made using these rules, can be used to produce concrete syntax tree for any C# source code file. C# program following these syntax rules, should be used to parse single C# source file or the whole directory of C# source code files. The result is a list of concrete syntax trees. For every source file parsed without syntax errors there is exactly one syntax tree in the list.

[ Description
    Text='In this file are represented Anglr declarations for C# programming language.'
    Text='All grammar and lexical definitions are actually copied from the Microsoft'
    Text='specifications of C# programming language defined in'
    Text='https://learn.microsoft.com/en-us/dotnet/csharp/specification/overview'
    Text='The notations of some syntax rules are slightly modified, however, because'
    Text='they can be written more compactly in Anglr. For example: syntax rule'
    Text='        expression ( "," expression ) *        '
    Text='can be writen like'
    Text='        expression + [ "," ]                   '
    Text='which means: positive number of expressions separated with commas.'
]

[ CompilationInfo ClassName='CsharpDeclarations' NameSpace='Csharp.Declarations' Access='public' TokenPrefix='token_' Hover='true' ]
%declarations csharpDecls
%{

    [ Description
        Text='character representation of an identifier as returned by the lexical analyzer'
    ]
    %terminal
    {
        raw-identifier
    }

    [ Description
        Text='terminal symbols associated with C# keywords'
    ]
    %terminal
    {
        abstract add   alias  as   ascending
        async  await  base  bool  break
        by   byte  case  catch  char
        checked  class  const  continue decimal
        default  delegate descending do   double
        dynamic  else  enum  equals  event
        explicit extern  false  finally  fixed
        float  for   foreach  from  get
        global  using  goto  group  if
        implicit in   int   interface internal
        into  is   join  let   lock
        long  nameof  namespace new   null
        object  on   operator orderby  out
        override params  partial  private  protected
        public  readonly ref   remove  return
        sbyte  sealed  select  set   short
        sizeof  stackalloc static  string  struct
        switch  this  throw  true  try
        typeof  uint  ulong  unchecked unmanaged
        unsafe  ushort  var   virtual  void
        volatile when  where  while  yield
    }

    [ Description
        Text='terminal symbols representing C# literals'
    ]
    %terminal
    {
        keyword
        boolean-literal
        integer-literal
        real-literal
        character-literal
        string-literal
        null-literal
    }

    [ Description
        Text='Terminal symbols representing C# arithmetic operators.'
        Text='They are listed with their textual representations.'
        Text='But be carefull: exact textual representations are defined'
        Text='with regular expression cs-ops and should differ from the'
        Text='textual representations stated in the following %terminal block.'
    ]
    %terminal
    {
        lshequ-op '<<='
        nullc-op '??'
        member-op '::'
        uinc-op '++'
        udec-op '--'
        land-op '&&'
        lor-op '||'
        ptr-op '->'
        eq-op '=='
        neq-op '!='
        lteq-op '<='
        gteq-op '>='
        adde-op '+='
        sube-op '-='
        mule-op '*='
        dive-op '/='
        mode-op '%='
        ande-op '&='
        ore-op '|='
        xore-op '^='
        lsh-op '<<'
        lambda-op '=>'
        lcb '{'
        rcb '}'
        lab '['
        rab ']'
        lrb '('
        rrb ')'
        dot '.'
        comma ','
        colon ':'
        semicolon ';'
        add-op '+'
        sub-op '-'
        mul-op '*'
        div-op '/'
        mod-op '%'
        and-op '&'
        or-op '|'
        xor-op '^'
        not-op '!'
        inv-op '~'
        equ-op '='
        lt-op '<'
        gt-op '>'
        aif-op '?'
    }

    [ Description
        Text='terminal symbols associated with interpolated strings'
    ]
    %terminal
    {
        interpolated-regular-string-elements
        interpolated-verbatim-string-elements
        irss '$"'
        ivss '$@"'
        ise  '"'
    }

    [ Description
        Text='regular expressions associated with c# arithmetic operators'
    ]
    %regex
    {
        lshequ-op \<\<\=
        nullc-op \?\?
        member-op \:\:
        uinc-op \+\+
        udec-op \-\-
        land-op \&\&
        lor-op \|\|
        ptr-op \-\>
        eq-op \=\=
        neq-op \!\=
        lteq-op \<\=
        gteq-op \>\=
        adde-op \+\=
        sube-op \-\=
        mule-op \*\=
        dive-op \/\=
        mode-op \%\=
        ande-op \&\=
        ore-op \|\=
        xore-op \^\=
        lsh-op \<\<
        lambda-op \=\>
        lcb \{
        rcb \}
        lab \[
        rab \]
        lrb \(
        rrb \)
        dot \.
        comma \,
        colon \:
        semicolon \;
        add-op \+
        sub-op \-
        mul-op \*
        div-op \/
        mod-op \%
        and-op \&
        or-op \|
        xor-op \^
        not-op \!
        inv-op \~
        equ-op \=
        lt-op \<
        gt-op \>
        aif-op \?

        cs-ops ({lshequ-op}|{nullc-op}|{member-op}|{uinc-op}|{udec-op}|{land-op}|{lor-op}|{ptr-op}|{eq-op}|{neq-op}|{lteq-op}|{gteq-op}|{adde-op}|{sube-op}|{mule-op}|{dive-op}|{mode-op}|{ande-op}|{ore-op}|{xore-op}|{lsh-op}|{lambda-op}|{lcb}|{rcb}|{lab}|{rab}|{lrb}|{rrb}|{dot}|{comma}|{colon}|{semicolon}|{add-op}|{sub-op}|{mul-op}|{div-op}|{mod-op}|{and-op}|{or-op}|{xor-op}|{not-op}|{inv-op}|{equ-op}|{lt-op}|{gt-op}|{aif-op})
    }

    [ Description
        Text='regular expressions associated with beginning of interpolated strings'
    ]
    %regex
    {
        irss \$\"
        ivss \$\@\"|\@\$\"
    }

    [ Description Text='Lexical grammar' Hover='true' ]
    %regex
    {
        input    ({input-section})?
        input-section  ({input-section-part})+
        input-section-part ({input-elements})?({new-line})|({pp-directive})
        input-elements  ({input-element})+
        input-element  ({whitespace})|({comment})|({token})
    }

    [ Description Text='Line terminators' Hover='true' ]
    %regex
    {

        new-line \u000D|\u000A|\u000D\u000A|\u0085|\u2028|\u2029
    }

    [ Description Text='White space' Hover='true' ]
    %regex
    {
        whitespace    ({whitespace-character})+
        whitespace-character \p{Zs}|\u0009|\u000B|\u000C
    }

    [ Description Text='Comments' Hover='true' ]
    %regex
    {
        comment      ({single-line-comment})|({delimited-comment})
        single-line-comment   \/\/({input-characters})?
        input-characters   ({input-character})+
        input-character    [^{new-line-character}]
        new-line-character   \u000D\u000A\u0085\u2028\u2029
        delimited-comment   \/\*({delimited-comment-text})?({asterisks})\/
        delimited-comment-text  ({delimited-comment-section})+
        delimited-comment-section \/|({asterisks})?({not-slash-or-asterisk})
        asterisks     \*+
        not-slash-or-asterisk  [^\/\*]
    }

    [ Description Text='Tokens' Hover='true' ]
    %regex
    {
        token ({identifier})|({keyword})|({integer-literal})|({real-literal})|({character-literal})|({string-literal})|({operator-or-punctuator})
    }

    [ Description Text='Unicode character escape sequences' Hover='true' ]
    %regex
    {
        unicode-escape-sequence \\u({hex-digit}){4}|\\u({hex-digit}){8}
    }

    [ Description Text='Identifiers' Hover='true' ]
    %regex
    {
        identifier     ({available-identifier})|\@({identifier-or-keyword})
        available-identifier  {identifier-or-keyword}
        identifier-or-keyword  ({identifier-start-character})({identifier-part-characters})?
        identifier-start-character ({letter-character})|({underscore-character})
        underscore-character  _|\u005F
        identifier-part-characters ({identifier-part-character})+
        identifier-part-character ({letter-character})|({decimal-digit-character})|({connecting-character})|({combining-character})|({formatting-character})
        letter-character   \p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}
        combining-character   \p{Mn}|\p{Mc}
        decimal-digit-character  \p{Nd}
        connecting-character  \p{Pc}
        formatting-character  \p{Cf}
    }

    [ Description Text='Keywords' Hover='true' ]
    %regex
    {
        keyword abstract|as|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while
    }

    [ Description Text='Literals' Hover='true' ]
    %regex
    {
        literal          ({boolean-literal})|({integer-literal})|({real-literal})|({character-literal})|({string-literal})|({null-literal})
        boolean-literal        true|false
        integer-literal        ({hexadecimal-integer-literal})|{decimal-integer-literal}
        decimal-integer-literal      ({decimal-digits})({integer-type-suffix})?
        decimal-digits        ({decimal-digit})+
        decimal-digit        [0-9]
        integer-type-suffix       [uUlL]+
        hexadecimal-integer-literal     (0(x|X)({hex-digits})({integer-type-suffix})?)|((x|X)0({hex-digits})({integer-type-suffix})?)
        hex-digits         ({hex-digit})+
        hex-digit         [0-9A-Fa-f]
        real-literal        ({decimal-digits})\.({decimal-digits})({exponent-part})?({real-type-suffix})?|\.({decimal-digits})({exponent-part})?({real-type-suffix})?|({decimal-digits})({exponent-part})({real-type-suffix})?|({decimal-digits})({real-type-suffix})
        exponent-part        (e|E)({sign})?({decimal-digits})
        sign          \+|\-
        real-type-suffix       F|f|D|d|M|m
        character-literal       '({character})'
        character         ({single-character})|({simple-escape-sequence})|({hexadecimal-escape-sequence})|({unicode-escape-sequence})
        single-character       [^'\\{new-line-character}]
        simple-escape-sequence      \\\'|\\\"|\\\\|\\0|\\a|\\b|\\f|\\n|\\r|\\t|\\v
        hexadecimal-escape-sequence     \\x({hex-digit}){1,4}
        string-literal        ({regular-string-literal})|({verbatim-string-literal})
        regular-string-literal      "({regular-string-literal-characters})?"
        regular-string-literal-characters   ({regular-string-literal-character})+
        regular-string-literal-character   ({single-regular-string-literal-character})|({simple-escape-sequence})|({hexadecimal-escape-sequence})|({unicode-escape-sequence})
        single-regular-string-literal-character  [^"\\{new-line-character}]
        verbatim-string-literal      @"({verbatim-string-literal-characters})?"
        verbatim-string-literal-characters   ({verbatim-string-literal-character})+
        verbatim-string-literal-character   ({single-verbatim-string-literal-character})|({quote-escape-sequence})
        single-verbatim-string-literal-character [^"]
        quote-escape-sequence      ""
        null-literal        null
        interpolated-regular-string-elements  ({interpolated-regular-string-element})+
        interpolated-regular-string-element   {interpolated-regular-string-character}|{simple-escape-sequence}|{hexadecimal-escape-sequence}|{unicode-escape-sequence}|{open-brace-escape-sequence}|{close-brace-escape-sequence}
        interpolated-regular-string-character  [^"\\{}\u000D\u000A\u0085\u2028\u2029]
        open-brace-escape-sequence     \u007b\u007b
        close-brace-escape-sequence     \u007d\u007d
        interpolated-verbatim-string-elements  ({interpolated-verbatim-string-element})+
        interpolated-verbatim-string-element  {interpolated-verbatim-string-character}|{quote-escape-sequence}|{open-brace-escape-sequence}|{close-brace-escape-sequence}
        interpolated-verbatim-string-character  [^"{}]
    }

    [ Description Text='Operators and punctuators' Hover='true' ]
    %regex
    {
        operator-or-punctuator \{|\}|\[|\]|\(|\)|\.|\,|\:|\;|\+|\-|\*|\/|\%|\&|\||\^|\!|\~|\=|\<|\>|\?|\?\?|\:\:|\+\+|\-\-|\&\&|\|\||\-\>|\=\=|\!\=|\<\=|\>\=|\+\=|\-\=|\*\=|\/\=|\%\=|\&\=|\|\=|\^\=|\<\<|\<\<\=
        right-shift    \>\>
        right-shift-assignment \>\>\=
    }

    [ Description
        Text='Pre-processing directives. They are not handled by lexical analyzer. Instead they'
        Text='are handled by event pp-directive. See csharpScanner %scanner section for details'
        Text='and https://angstlr.com for additional information about Anglr events.'

        Text='%regex'
        Text='{'
        Text='	pp-directive::'
        Text='		pp-declaration'
        Text='		pp-conditional'
        Text='		pp-line '
        Text='		pp-diagnostic'
        Text='		pp-region'
        Text='		pp-pragma'
        Text='	conditional-symbol::'
        Text='		Any identifier-or-keyword except true or false'
        Text='	pp-expression::'
        Text='		whitespace ? pp-or-expression whitespace ?'
        Text='	pp-or-expression::'
        Text='		pp-and-expression'
        Text='		pp-or-expression whitespace ? || whitespace ? pp-and-expression'
        Text='	pp-and-expression::'
        Text='		pp-equality-expression'
        Text='		pp-and-expression whitespace ? && whitespace ? pp-equality-expression'
        Text='	pp-equality-expression::'
        Text='		pp-unary-expression'
        Text='		pp-equality-expression whitespace ? == whitespace ? pp-unary-expression'
        Text='		pp-equality-expression whitespace ? != whitespace ? pp-unary-expression'
        Text='	pp-unary-expression::'
        Text='		pp-primary-expression'
        Text='		! whitespace ? pp-unary-expression'
        Text='	pp-primary-expression::'
        Text='		true'
        Text='		false'
        Text='		conditional-symbol'
        Text='		( whitespace ? pp-expression whitespace ? )'
        Text='	pp-declaration::'
        Text='		whitespace ? # whitespace ? define whitespace conditional-symbol pp-new-line'
        Text='		whitespace ? # whitespace ? undef whitespace conditional-symbol pp-new-line'
        Text='	pp-new-line::'
        Text='		whitespace ? single-line-comment ? new-line'
        Text='	pp-conditional::'
        Text='		pp-if-section pp-elif-sections ? pp-else-section ? pp-endif'
        Text='	pp-if-section::'
        Text='		whitespace ? # whitespace ? if whitespace pp-expression pp-new-line conditional-section ?'
        Text='	pp-elif-sections::'
        Text='		pp-elif-section'
        Text='		pp-elif-sections pp-elif-section'
        Text='	pp-elif-section::'
        Text='		whitespace ? # whitespace ? elif whitespace pp-expression pp-new-line conditional-section ?'
        Text='	pp-else-section::'
        Text='		whitespace ? # whitespace ? else pp-new-line conditional-section ?'
        Text='	pp-endif::'
        Text='		whitespace ? # whitespace ? endif pp-new-line'
        Text='	conditional-section::'
        Text='		input-section'
        Text='		skipped-section'
        Text='	skipped-section::'
        Text='		skipped-section-part +'
        Text='	skipped-section-part::'
        Text='		skipped-characters ? new-line'
        Text='		pp-directive'
        Text='	skipped-characters::'
        Text='		whitespace ? not-number-sign input-characters ?'
        Text='	not-number-sign::'
        Text='		Any input-character except #'
        Text='	pp-line::'
        Text='		whitespace ? # whitespace ? line whitespace line-indicator pp-new-line'
        Text='	line-indicator::'
        Text='		decimal-digits whitespace file-name'
        Text='		decimal-digits'
        Text='		default'
        Text='		hidden'
        Text='	file-name::'
        Text='		" file-name-characters "'
        Text='	file-name-characters::'
        Text='		file-name-character +'
        Text='	file-name-character::'
        Text='		Any input-character except " (U+0022), and new-line-character'
        Text='	pp-diagnostic::'
        Text='		whitespace ? # whitespace ? error pp-message'
        Text='		whitespace ? # whitespace ? warning pp-message'
        Text='	pp-message::'
        Text='		new-line'
        Text='		whitespace input-characters ? new-line'
        Text='	pp-region::'
        Text='		pp-start-region conditional-section ? pp-end-region'
        Text='	pp-start-region::'
        Text='		whitespace ? # whitespace ? region pp-message'
        Text='	pp-end-region::'
        Text='		whitespace ? # whitespace ? endregion pp-message'
        Text='	pp-pragma::'
        Text='		whitespace ? # whitespace ? pragma pp-pragma-text'
        Text='	pp-pragma-text::'
        Text='		new-line'
        Text='		whitespace input-characters ? new-line'
        Text='}'
    ]
    %regex
    {
        pp-directive ({whitespace})?#({whitespace})?({identifier}).*
    }
%}

[ Declarations Id='csharpDecls' Hover='true' ]
[ CompilationInfo ClassName='CommentRegex' NameSpace='Csharp.RegexLib' Access='public' Hover='true' ]
%scanner commentScanner
%{
\*+/
    pop
{delimited-comment-section}
    skip
{new-line}
    skip
%}

[ Declarations Id='csharpDecls' Hover='true' ]
[ CompilationInfo ClassName='InterpolatedRegularStringRegex' NameSpace='Csharp.RegexLib' Access='public' Hover='true' ]
%scanner interpolatedRegularStringScanner
%{
\"
    pop
    terminal ise
{interpolated-regular-string-elements}
    terminal interpolated-regular-string-elements
{lcb}
    push interpolatedScanner
    terminal lcb
%}

[ Declarations Id='csharpDecls' Hover='true' ]
[ CompilationInfo ClassName='InterpolatedVerbatimStringRegex' NameSpace='Csharp.RegexLib' Access='public' Hover='true' ]
%scanner interpolatedVerbatimStringScanner
%{
\"
    pop
    terminal ise
{interpolated-verbatim-string-elements}
    terminal interpolated-verbatim-string-elements
{lcb}
    push interpolatedScanner
    terminal lcb
%}

[
    Description Hover='true'
    Text='In the definition of the following scanner there are two lexical rules'
    Text='which are correlated in some way, namely:'
    Text='- {rcb}'
    Text='- {cs-ops}'
    Text='Lexical rule {cs-ops} must be preceeded by lexical rule {rcb} since it'
    Text='contains its definition. Otherwise the lexical rule {rcb} will have no'
    Text='effect since its definition would be hidden by the lexical rule {cs-ops}.'
    Text='Otherwise (if the lexical rule {rcb} follows the definition of the lexical'
    Text='rule {cs-ops} or if the lexical rule {rcb} would be omited), the event'
    Text='handler for the lexical rule {cs-ops} should implement the funcionality'
    Text='of the lexical rule {rcb}. It should invoke pop action and return terminal'
    Text='symbol rcb. But such implementation is not clean since some push and/or pop'
    Text='actions are executed by lexical analyzer itself and the other with event'
    Text='handlers and is hard to identify their pairing.'
    Text=''
    Text='Also, there is another event handler: event identifier. This event handler'
    Text='should distinguish between keywords and other identifiers found in C# source'
    Text='code. Since it is important for a lexical analyzer to contain as few items as'
    Text='possible, all identifiers are treated in the source code, which separates'
    Text='them into names of the variables and keywords. There are other aspects that'
    Text='need to be taken into account, e.g. the use of keywords instead of'
    Text='variable names. All this can only be done in the source code and that is what'
    Text='this event handler should do: it should take into account the duality of'
    Text='keywords. Some keywords should be treated as keywords and variable names at'
    Text='the same time. Syntax analyzer should later decide what is right depending'
    Text='of the context in which this identifier is found.'
    Text=''
    Text='The same arguments apply to the definition of the next scanner, except that'
    Text='there is no need to handle the lexical rule {rcb} separately from the'
    Text='lexical rule {cs-ops} since {rcb} need not to pop the scanner but just'
    Text='return the token code which is returned by {cs-ops} too.'
]
[ Declarations Id='csharpDecls' Hover='true' ]
[ CompilationInfo ClassName='InterpolatedScannerRegex' NameSpace='Csharp.RegexLib' Access='public' Hover='true' ]
%scanner interpolatedScanner
%{
\/\/.*
    skip
\/\*
    push commentScanner
{integer-literal}
    terminal integer-literal
{real-literal}
    terminal real-literal
{character-literal}
    terminal character-literal
{string-literal}
    terminal string-literal
{irss}
    push interpolatedRegularStringScanner
    terminal irss
{ivss}
    push interpolatedVerbatimStringScanner
    terminal ivss
{identifier}
    event identifier
{rcb}
    pop
    terminal rcb
{cs-ops}
    event cs-ops
{whitespace}
    skip
[\n\f\r\v]
    pop
.
    pop
%}

[ Declarations Id='csharpDecls' Hover='true' ]
[ CompilationInfo ClassName='ScannerRegex' NameSpace='Csharp.RegexLib' Access='public' Hover='true' ]
%scanner csharpScanner
%{
\/\/.*
    skip
\/\*
    push commentScanner
{integer-literal}
    terminal integer-literal
{real-literal}
    terminal real-literal
{character-literal}
    terminal character-literal
{string-literal}
    terminal string-literal
{irss}
    push interpolatedRegularStringScanner
    terminal irss
{ivss}
    push interpolatedVerbatimStringScanner
    terminal ivss
{identifier}
    event identifier
{cs-ops}
    event cs-ops
{pp-directive}
    event pp-directive
{whitespace}
    skip
[\n\f\r\v]
    skip
.
    skip
%}

[ Description Text='Lexer for c# file' Hover='true' ]
[
    UseScanner
        ScannerId='commentScanner'
        ScannerId='interpolatedRegularStringScanner'
        ScannerId='interpolatedVerbatimStringScanner'
        ScannerId='interpolatedScanner'
        InitialScanner='csharpScanner'
        Hover='true'
]
[ CompilationInfo ClassName='CsharpLexer' NameSpace='Csharp.Lexer' Access='public' Hover='true' ]
%lexer csharpLexer
%{
%}

[ Declarations Id='csharpDecls' Hover='true' ]
[ Lexer Id='csharpLexer' Hover='true' ]
[ CompilationInfo ClassName='CsharpParser' NameSpace='Csharp.Parser' Access='public' Hover='true' ]
%parser csharpParser
%{

[ Description Text='Helpers' ]
[ Description Text='The following syntax rules are introduced only to prevent creation' ]
[ Description Text='of generated rules of the form <generated rule n>' ]
Helpers
{

identifier
    : raw-identifier
    ;

coma-sign
    : ','
    ;

semicolon-sign
    : ';'
    ;

aif-op-sign
    : '?'
    ;

ref-readonly
    : ref readonly ?
    ;

right-shift
    : '>' '>'
    ;

right-shift-assignment
    : '>' '>' '='
    ;
}

[ Description Text='A.3 Syntactic grammar' ]
[ Description Text='A.3.1 Basic concepts' ]
Basic-concepts
{

namespace-name
    : namespace-or-type-name
    ;

type-name
    : namespace-or-type-name
    ;

[ Iterator
    Text='This attribute is processed by Anglr compiler.'
    Text='Therefore, the transition of the node belonging'
    Text='to the syntax rule namespace-or-type-name turns'
    Text='into an iteration. You can also remove this'
    Text='attribute because namespace names are usually not'
    Text='long. Therefore, recursive node transitions cannot'
    Text='be a problem either.'
]
namespace-or-type-name
    : simple-name
    | namespace-or-type-name '.' simple-name
    | qualified-alias-member
    ;

}

[ Description Text='A.3.2 Types' ]
Types
{

type
    : reference-type
    | value-type
    | type-parameter
    | nullable-type
    | pointer-type
    ;

reference-type
    : class-type
    | interface-type
    | array-type
    | delegate-type
    | dynamic
    ;

class-type
    : type-name
    | object
    | string
    ;

interface-type
    : type-name
    ;

array-type
    : non-array-type rank-specifiers
    ;

non-array-type
    : value-type
    | class-type
    | interface-type
    | delegate-type
    | dynamic
    | type-parameter
    | pointer-type
    ;

rank-specifiers
    : rank-specifier +
    ;

rank-specifier
    : '[' dim-separators ? ']'
    ;

dim-separators
    : ',' +
    ;

delegate-type
    : type-name
    ;

value-type
    : non-nullable-value-type
    | nullable-value-type
    ;

non-nullable-value-type
    : struct-type
    | enum-type
    ;

struct-type
    : type-name
    | simple-type
    | tuple-type
    ;

simple-type
    : numeric-type
    | bool
    ;

numeric-type
    : integral-type
    | floating-point-type
    | decimal
    ;

integral-type
    : sbyte
    | byte
    | short
    | ushort
    | int
    | uint
    | long
    | ulong
    | char
    ;

nullable-type
    : non-nullable-value-type '?'
    ;

floating-point-type
    : float
    | double
    ;

tuple-type
    : '(' tuple-type-element { 2, } [ ',' ] ')'
    ;

tuple-type-element
    : type identifier ?
    ;

enum-type
    : type-name
    ;

nullable-value-type
    : non-nullable-value-type '?'
    ;

type-argument-list
    : '<' type-arguments '>'
    ;

type-arguments
    : type-argument + [ ',' ]
    ;

type-argument
    : type
    ;

type-parameter
    : identifier
    ;

unmanaged-type
    : value-type
    ;

}

[ Description Text='A.3.3 Variables' ]
Variables
{

variable-reference
    : expression
    ;

}

[ Description Text='Source: ?11.2 Pattern Forms' ]
Patterns
{
pattern
    : declaration-pattern
    | constant-pattern
    | var-pattern
    ;

[ Description Text='Source: ?11.2.1 Declaration pattern' ]
declaration-pattern
    : type simple-designation
    ;

simple-designation
    : single-variable-designation
    ;

single-variable-designation
    : identifier
    ;

[ Description Text='Source: ?11.2.2 Constant pattern' ]
constant-pattern
    : constant-expression
    ;

[ Description Text='Source: ?11.2.3 Var pattern' ]
var-pattern
    : var designation
    ;

designation
    : simple-designation
    ;

}

[ Description Text='A.3.4 Expressions' ]
Expressions
{

argument-list
    : argument + [ ',' ]
    ;

argument
    : argument-name ? argument-value
    ;

argument-name
    : identifier ':'
    ;

argument-value
    : expression
    | in variable-reference
    | ref variable-reference
    | out variable-reference
    ;

primary-expression
    : primary-no-array-creation-expression
    | array-creation-expression
    ;

primary-no-array-creation-expression
    : literal
    | interpolated-string-expression
    | simple-name
    | parenthesized-expression
    | tuple-expression
    | member-access
    | null-conditional-member-access
    | invocation-expression
    | element-access
    | null-conditional-element-access
    | this-access
    | base-access
    | post-increment-expression
    | post-decrement-expression
    | object-creation-expression
    | delegate-creation-expression
    | anonymous-object-creation-expression
    | typeof-expression
    | sizeof-expression
    | checked-expression
    | unchecked-expression
    | default-value-expression
    | nameof-expression
    | anonymous-method-expression
    | pointer-member-access
    | pointer-element-access
    | stackalloc-expression
    ;

interpolated-string-expression
    : interpolated-regular-string-expression
    | interpolated-verbatim-string-expression
    ;

interpolated-regular-string-expression
    : Interpolated-Regular-String-Start Interpolated-Regular-String-Mid ? + [ '{' regular-interpolation '}' ] Interpolated_Regular_String_End
    ;

interpolation-minimum-width
    : ',' constant-expression
    ;

regular-interpolation
    : expression interpolation-minimum-width ? Regular-Interpolation-Format ?
    ;

Interpolated-Regular-String-Start
    : '$"'
    ;

Interpolated-Regular-String-Mid
    : interpolated-regular-string-elements
    ;

Regular-Interpolation-Format
    : ':' ( :Regular-Interpolation-Format-body: interpolated-regular-string-elements | literal | identifier )
    ;

Interpolated_Regular_String_End
    : '"'
    ;

interpolated-verbatim-string-expression
    : Interpolated-Verbatim-String-Start Interpolated-Verbatim-String-Mid ? + [ '{' verbatim_interpolation '}' ] Interpolated-Verbatim-String-End
    ;

verbatim_interpolation
    : expression interpolation-minimum-width ? Verbatim-Interpolation-Format ?
    ;

Interpolated-Verbatim-String-Start
    : '$@"'
    ;

Interpolated-Verbatim-String-Mid
    : interpolated-verbatim-string-elements
    ;

Verbatim-Interpolation-Format
    : ':' ( :Verbatim-Interpolation-Format-body: interpolated-verbatim-string-elements | literal | identifier )
    ;

Interpolated-Verbatim-String-End
    : '"'
    ;

literal
    : boolean-literal
    | integer-literal
    | real-literal
    | character-literal
    | string-literal
    | null-literal
    ;

simple-name
    : identifier type-argument-list ?
    ;

parenthesized-expression
    : '(' expression ')'
    ;

tuple-expression
    : '(' tuple-element { 2, } [ ',' ] ')'
    | deconstruction-expression
    ;

tuple-element
    : ( :tuple-element-ref: identifier ':' ) ? expression
    ;

deconstruction-expression
    : var deconstruction-tuple
    ;

deconstruction-tuple
    : '(' deconstruction-element { 2, } [ ',' ] ')'
    ;

deconstruction-element
    : deconstruction-tuple
    | identifier
    ;

member-access
    : ( :member-access-head: primary-expression | predefined-type  | qualified-alias-member ) aif-op-sign ? '.' simple-name
    ;

predefined-type
    : bool
    | byte
    | char
    | decimal
    | double
    | float
    | int
    | long
    | object
    | sbyte
    | short
    | string
    | uint
    | ulong
    | ushort
    ;

[ Description Text = "?12.8.8 Null Conditional Member Access" ]
null-conditional-member-access
    : primary-expression '?' '.' simple-name dependent-access-list ?
    ;

dependent-access-list
    : dependent-access +
    ;

dependent-access
    : '.' simple-name
    | '[' argument-list ']'
    | '(' argument-list ? ')'
    ;

null-conditional-projection-initializer
    : primary-expression '?' '.' simple-name
    ;

invocation-expression
    : primary-expression '(' argument-list ? ')'
    ;

null-conditional-invocation-expression
    : null-conditional-member-access '(' argument-list ? ')'
    | null-conditional-element-access '(' argument-list ? ')'
    ;

element-access
    : primary-no-array-creation-expression '[' argument-list ']'
    ;

null-conditional-element-access
    : primary-no-array-creation-expression '?' '[' argument-list ']' dependent-access-list ?
    ;

expression-list
    : expression + [ ',' ]
    ;

this-access
    : this
    ;

base-access
    : base '.' simple-name
    | base '[' argument-list ']'
    ;

post-increment-expression
    : primary-expression '++'
    ;

post-decrement-expression
    : primary-expression '--'
    ;

object-creation-expression
    : new type '(' argument-list ? ')' object-or-collection-initializer ?
    | new type object-or-collection-initializer
    ;

object-or-collection-initializer
    : object-initializer
    | collection-initializer
    ;

object-initializer
    : '{' member-initializer-list ? coma-sign ? '}'
    ;

member-initializer-list
    : member-initializer + [ ',' ]
    ;

member-initializer
    : initializer-target '=' initializer-value
    ;

initializer-target
    : identifier
    | '[' argument-list ']'
    ;

initializer-value
    : expression
    | object-or-collection-initializer
    ;

collection-initializer
    : '{' element-initializer-list ? coma-sign ? '}'
    ;

element-initializer-list
    : element-initializer + [ ',' ]
    ;

element-initializer
    : non-assignment-expression
    | '{' expression-list '}'
    ;

array-creation-expression
    : new non-array-type '[' expression-list ']' rank-specifiers ? array-initializer ?
    | new array-type array-initializer
    | new rank-specifier array-initializer
    ;

delegate-creation-expression
    : new delegate-type '(' expression ')'
    ;

anonymous-object-creation-expression
    : new anonymous-object-initializer
    ;

anonymous-object-initializer
    : '{' member-declarator-list ? coma-sign ? '}'
    ;

member-declarator-list
    : member-declarator + [ ',' ]
    ;

member-declarator
    : simple-name
    | member-access
    | null-conditional-projection-initializer
    | base-access
    | identifier '=' expression
    ;

typeof-expression
    : typeof '(' type ')'
    | typeof '(' unbound-type-name ')'
    | typeof '(' void ')'
    ;

unbound-type-name
    : ( :unbound-type-name-head: identifier | identifier '::' identifier | unbound-type-name '.' identifier ) generic-dimension-specifier ?
    ;

generic-dimension-specifier
    : '<' commas ? '>'
    ;

commas
    : ',' +
    ;

sizeof-expression
    : sizeof '(' unmanaged-type ')'
    ;

checked-expression
    : checked '(' expression ')'
    ;

unchecked-expression
    : unchecked '(' expression ')'
    ;

default-value-expression
    : default ( :default-value-expression-body: '(' type ')' ) ?
    ;

stackalloc-expression
    : stackalloc unmanaged-type '[' expression ']'
    | stackalloc unmanaged-type ? '[' expression ? ']' stackalloc-initializer
    ;

stackalloc-initializer
    : '{' stackalloc-initializer-element-list '}'
    ;

stackalloc-initializer-element-list
    : stackalloc-element-initializer + [ ',' ] coma-sign ?
    ;

stackalloc-element-initializer
    : expression
    ;

nameof-expression
    : nameof '(' named-entity ')'
    ;

named-entity
    : named-entity-target named-entity-part-list ?
    ;

named-entity-part-list
    : '.' simple-name + [ '.' ]
    ;

named-entity-target
    : simple-name
    | this
    | base
    | predefined-type
    | qualified-alias-member
    ;

unary-expression
    : primary-expression
    | '+' unary-expression
    | '-' unary-expression
    | '!' unary-expression
    | '~' unary-expression
    | pre-increment-expression
    | pre-decrement-expression
    | cast-expression
    | await-expression
    | pointer-indirection-expression
    | addressof-expression
    ;

pre-increment-expression
    : '++' unary-expression
    ;

pre-decrement-expression
    : '--' unary-expression
    ;

cast-expression
    : '(' type ')' unary-expression
    ;

await-expression
    : await unary-expression
    ;

multiplicative-expression
    : unary-expression
    | multiplicative-expression '*' unary-expression
    | multiplicative-expression '/' unary-expression
    | multiplicative-expression '%' unary-expression
    ;

additive-expression
    : multiplicative-expression
    | additive-expression '+' multiplicative-expression
    | additive-expression '-' multiplicative-expression
    ;

shift-expression
    : additive-expression
    | shift-expression '<<' additive-expression
    | shift-expression right-shift additive-expression
    ;

relational-expression
    : shift-expression
    | relational-expression '<' shift-expression
    | relational-expression '>' shift-expression
    | relational-expression '<=' shift-expression
    | relational-expression '>=' shift-expression
    | relational-expression is type
    | relational-expression is pattern
    | relational-expression is null-literal
    | relational-expression as type
    ;

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
    ;

conditional-and-expression
    : inclusive-or-expression
    | conditional-and-expression '&&' inclusive-or-expression
    ;

conditional-or-expression
    : conditional-and-expression
    | conditional-or-expression '||' conditional-and-expression
    ;

null-coalescing-expression
    : conditional-or-expression
    | conditional-or-expression '??' null-coalescing-expression
    | throw-expression
    ;

throw-expression
    : throw null-coalescing-expression
    ;

declaration-expression
    : local-variable-type identifier
    ;

conditional-expression
    : null-coalescing-expression
    | null-coalescing-expression '?' expression ':' expression
    | null-coalescing-expression '?' ref variable-reference ':' ref variable-reference
    ;

lambda-expression
    : async ? anonymous-function-signature '=>' anonymous-function-body
    ;

anonymous-method-expression
    : async ? delegate explicit-anonymous-function-signature ? block
    ;

anonymous-function-signature
    : explicit-anonymous-function-signature
    | implicit-anonymous-function-signature
    ;

explicit-anonymous-function-signature
    : '(' explicit-anonymous-function-parameter-list ? ')'
    ;

explicit-anonymous-function-parameter-list
    : explicit-anonymous-function-parameter + [ ',' ]
    ;

explicit-anonymous-function-parameter
    : anonymous-function-parameter-modifier ? type identifier
    ;

anonymous-function-parameter-modifier
    : ref
    | out
    | in
    ;

implicit-anonymous-function-signature
    : '(' implicit-anonymous-function-parameter-list ? ')'
    | implicit-anonymous-function-parameter
    ;

implicit-anonymous-function-parameter-list
    : implicit-anonymous-function-parameter + [ ',' ]
    ;

implicit-anonymous-function-parameter
    : identifier
    ;

anonymous-function-body
    : null-conditional-invocation-expression
    | expression
    | ref variable-reference
    | block
    ;

query-expression
    : from-clause query-body
    ;

from-clause
    : from type ? identifier in expression
    ;

query-body
    : query-body-clauses ? select-or-group-clause query-continuation ?
    ;

query-body-clauses
    : query-body-clause +
    ;

query-body-clause
    : from-clause
    | let-clause
    | where-clause
    | join-clause
    | join-into-clause
    | orderby-clause
    ;

let-clause
    : let identifier '=' expression
    ;

where-clause
    : where boolean-expression
    ;

join-clause
    : join type ? identifier in expression on expression equals expression
    ;

join-into-clause
    : join type ? identifier in expression on expression equals expression into identifier
    ;

orderby-clause
    : orderby orderings
    ;

orderings
    : ordering + [ ',' ]
    ;

ordering
    : expression ordering-direction ?
    ;

ordering-direction
    : ascending
    | descending
    ;

select-or-group-clause
    : select-clause
    | group-clause
    ;

select-clause
    : select expression
    ;

group-clause
    : group expression by expression
    ;

query-continuation
    : into identifier query-body
    ;

assignment
    : unary-expression assignment-operator expression
    ;

assignment-operator
    : '='
    | '+='
    | '-='
    | '*='
    | '/='
    | '%='
    | '&='
    | '|='
    | '^='
    | '<<='
    | right-shift-assignment
    ;

expression
    : non-assignment-expression
    | assignment
    ;

non-assignment-expression
    : declaration-expression
    | conditional-expression
    | lambda-expression
    | query-expression
    ;

constant-expression
    : expression
    ;

boolean-expression
    : expression
    ;

}

[ Description Text='A.3.5 Statements' ]
Statements
{

statement
    : labeled-statement
    | declaration-statement
    | embedded-statement
    ;

embedded-statement
    : block
    | empty-statement
    | expression-statement
    | selection-statement
    | iteration-statement
    | jump-statement
    | try-statement
    | checked-statement
    | unchecked-statement
    | lock-statement
    | using-statement
    | yield-statement
    | unsafe-statement
    | fixed-statement
    ;

block
    : '{' statement-list ? '}'
    ;

statement-list
    : statement +
    ;

empty-statement
    : ';'
    ;

labeled-statement
    : identifier ':' statement
    ;

declaration-statement
    : local-variable-declaration ';'
    | local-constant-declaration ';'
    | local-function-declaration
    ;

local-variable-declaration
    : ref-readonly ? local-variable-type local-variable-declarators
    ;

local-variable-type
    : type
    | var
    ;

local-variable-declarators
    : local-variable-declarator + [ ',' ]
    ;

local-variable-declarator
    : identifier
    | identifier '=' local-variable-initializer
    ;

local-variable-initializer
    : expression
    | ref variable-reference
    | array-initializer
    ;

local-constant-declaration
    : const type constant-declarators
    ;

constant-declarators
    : constant-declarator + [ ',' ]
    ;

constant-declarator
    : identifier '=' constant-expression
    ;

local-function-declaration
    : local-function-header local-function-body
    ;

local-function-header
    : local-function-modifiers ? ref-readonly ? return-type identifier type-parameter-list ? '(' formal-parameter-list ? ')' type-parameter-constraints-clauses ?
    ;

local-function-modifiers
    : local-function-modifier +
    ;

local-function-modifier
    : async
    | unsafe
    ;

local-function-body
    : block
    | '=>' null-conditional-invocation-expression ';'
    | '=>' expression ';'
    ;

expression-statement
    : statement-expression ';'
    ;

statement-expression
    : null-conditional-invocation-expression
    | invocation-expression
    | object-creation-expression
    | assignment
    | post-increment-expression
    | post-decrement-expression
    | pre-increment-expression
    | pre-decrement-expression
    | await-expression
    ;

selection-statement
    : if-statement
    | switch-statement
    ;

if-statement
    : if '(' boolean-expression ')' embedded-statement
    | if '(' boolean-expression ')' embedded-statement else embedded-statement
    ;

switch-statement
    : switch '(' expression ')' switch-block
    ;

switch-block
    : '{' switch-sections ? '}'
    ;

switch-sections
    : switch-section +
    ;

switch-section
    : switch-labels statement-list
    ;

switch-labels
    : switch-label +
    ;

switch-label
    : case pattern case-guard ? ':'
    | default ':'
    ;

case-guard
    : when expression
    ;

iteration-statement
    : while-statement
    | do-statement
    | for-statement
    | foreach-statement
    ;

while-statement
    : while '(' boolean-expression ')' embedded-statement
    ;

do-statement
    : do embedded-statement while '(' boolean-expression ')' ';'
    ;

for-statement
    : for '(' for-initializer ? ';' for-condition ? ';' for-iterator ? ')' embedded-statement
    ;

for-initializer
    : local-variable-declaration
    | statement-expression-list
    ;

for-condition
    : boolean-expression
    ;

for-iterator
    : statement-expression-list
    ;

statement-expression-list
    : statement-expression + [ ',' ]
    ;

foreach-statement
    : foreach '(' ref-readonly ? local-variable-type identifier ? in expression ')' embedded-statement
    ;

jump-statement
    : break-statement
    | continue-statement
    | goto-statement
    | return-statement
    | throw-statement
    ;

break-statement
    : break ';'
    ;

continue-statement
    : continue ';'
    ;

goto-statement
    : goto identifier ';'
    | goto case constant-expression ';'
    | goto default ';'
    ;

return-statement
    : return ';'
    | return expression ';'
    | return ref variable-reference ';'
    ;

throw-statement
    : throw expression ? ';'
    ;

try-statement
    : try block catch-clauses
    | try block catch-clauses ? finally-clause
    ;

catch-clauses
    : specific-catch-clauses
    | specific-catch-clauses ? general-catch-clause
    ;

specific-catch-clauses
    : specific-catch-clause +
    ;

specific-catch-clause
    : catch exception-specifier exception-filter ? block
    | catch exception-filter block
    ;

exception-specifier
    : '(' type identifier ? ')'
    ;

exception-filter
    : when '(' boolean-expression ')'
    ;

general-catch-clause
    : catch block
    ;

finally-clause
    : finally block
    ;

checked-statement
    : checked block
    ;

unchecked-statement
    : unchecked block
    ;

lock-statement
    : lock '(' expression ')' embedded-statement
    ;

using-statement
    : using '(' resource-acquisition ')' embedded-statement
    ;

resource-acquisition
    : local-variable-declaration
    | expression
    ;

yield-statement
    : yield return expression ';'
    | yield break ';'
    ;

}

[ Description Text='A.3.6 Namespaces' ]
Namespaces
{

[ Start ]
compilation-unit
    : extern-alias-directives ? global-using-directives ? using-directives ? global-attributes ? namespace-member-declarations ?
    ;

global-using-directives
    : global-using-directive +
    ;
global-using-directive
                : global-using-alias-directive
                | global-using-namespace-directive
                | global-using-static-directive
                ;

global-using-alias-directive
                : global using identifier '=' namespace-or-type-name ';'
                ;

global-using-namespace-directive
                : global using namespace-name ';'
                ;

global-using-static-directive
    : global using static type-name ';'
    ;

namespace-declaration
    : namespace qualified-identifier namespace-body semicolon-sign ?
    ;

qualified-identifier
    : identifier + [ '.' ]
    ;

namespace-body
    : '{' extern-alias-directives ? using-directives ? namespace-member-declarations ? '}'
    ;

extern-alias-directives
    : extern-alias-directive +
    ;

extern-alias-directive
    : extern alias identifier ';'
    ;

using-directives
    : using-directive +
    ;

using-directive
    : using-alias-directive
    | using-namespace-directive
    | using-static-directive
    ;

using-alias-directive
    : using identifier '=' namespace-or-type-name ';'
    ;

using-namespace-directive
    : using namespace-name ';'
    ;

using-static-directive
    : using static type-name ';'
    ;

namespace-member-declarations
    : namespace-member-declaration +
    ;

namespace-member-declaration
    : namespace-declaration
    | type-declaration
    ;

type-declaration
    : class-declaration
    | struct-declaration
    | interface-declaration
    | enum-declaration
    | delegate-declaration
    ;

qualified-alias-member
    : identifier '::' simple-name
    ;

}

[ Description Text='A.3.7 Classes' ]
Classes
{

class-declaration
    : attributes ? class-modifiers ? partial ? class identifier type-parameter-list ? class-base ? type-parameter-constraints-clauses ? class-body semicolon-sign ?
    ;

class-modifiers
    : class-modifier +
    ;

class-modifier
    : new
    | public
    | protected
    | internal
    | private
    | abstract
    | sealed
    | static
    | unsafe-modifier
    ;

type-parameter-list
    : '<' type-parameters '>'
    ;

type-parameters
    : ( :type-parameters-body: attributes ? type-parameter ) + [ ',' ]
    ;

class-base
    : ':' class-type
    | ':' interface-type-list
    | ':' class-type ',' interface-type-list
    ;

interface-type-list
    : interface-type + [ ',' ]
    ;

type-parameter-constraints-clauses
    : type-parameter-constraints-clause +
    ;

type-parameter-constraints-clause
    : where type-parameter ':' type-parameter-constraints
    ;

type-parameter-constraints
    : primary-constraint
    | secondary-constraints
    | constructor-constraint
    | primary-constraint ',' secondary-constraints
    | primary-constraint ',' constructor-constraint
    | secondary-constraints ',' constructor-constraint
    | primary-constraint ',' secondary-constraints ',' constructor-constraint
    ;

primary-constraint
    : class-type
    | class
    | struct
    | unmanaged
    ;

secondary-constraints
    : ( :secondary-constraints-body: interface-type | type-parameter ) + [ ',' ]
    ;

constructor-constraint
    : new '(' ')'
    ;

class-body
    : '{' class-member-declarations ? '}'
    ;

class-member-declarations
    : class-member-declaration +
    ;

class-member-declaration
    : constant-declaration
    | field-declaration
    | method-declaration
    | property-declaration
    | event-declaration
    | indexer-declaration
    | operator-declaration
    | constructor-declaration
    | finalizer-declaration
    | static-constructor-declaration
    | type-declaration
    ;

constant-declaration
    : attributes ? constant-modifiers ? const type constant-declarators ';'
    ;

constant-modifiers
    : constant-modifier +
    ;

constant-modifier
    : new
    | public
    | protected
    | internal
    | private
    ;

field-declaration
    : attributes ? field-modifiers ? type variable-declarators ';'
    ;

field-modifiers
    : field-modifier +
    ;

field-modifier
    : new
    | public
    | protected
    | internal
    | private
    | static
    | readonly
    | volatile
    | unsafe-modifier
    ;

variable-declarators
    : variable-declarator + [ ',' ]
    ;

variable-declarator
    : identifier
    | identifier '=' variable-initializer
    ;

method-declaration
    : method-header method-body
    ;

method-header
    : attributes ? method-modifiers ? partial ? ref-readonly ? return-type member-name type-parameter-list ? '(' formal-parameter-list ? ')' type-parameter-constraints-clauses ?
    ;

method-modifiers
    : method-modifier +
    ;

method-modifier
    : new
    | public
    | protected
    | internal
    | private
    | static
    | virtual
    | sealed
    | override
    | abstract
    | extern
    | async
    | unsafe-modifier
    ;

return-type
    : type
    | void
    ;

member-name
    : identifier
    | interface-type '.' identifier
    ;

method-body
    : block
    | '=>' null-conditional-invocation-expression ';'
    | '=>' expression ';'
    | ';'
    ;

formal-parameter-list
    : fixed-parameters
    | fixed-parameters ',' parameter-array
    | parameter-array
    ;

fixed-parameters
    : fixed-parameter + [ ',' ]
    ;

fixed-parameter
    : attributes ? parameter-modifier ? type identifier default-argument ?
    ;

default-argument
    : '=' expression
    ;

parameter-modifier
    : parameter-mode-modifier
    | this
    ;

parameter-mode-modifier
    : ref
    | out
    | in
    ;

parameter-array
    : attributes ? params array-type identifier
    ;

property-declaration
    : attributes ? property-modifiers ? ref-readonly ? type member-name property-body
    ;

property-modifiers
    : property-modifier +
    ;

property-modifier
    : new
    | public
    | protected
    | internal
    | private
    | static
    | virtual
    | sealed
    | override
    | abstract
    | extern
    | unsafe-modifier
    ;

property-body
    : '{' accessor-declarations '}' property-initializer ?
    | '=>' expression ';'
    ;

property-initializer
    : '=' variable-initializer ';'
    ;

accessor-declarations
    : get-accessor-declaration set-accessor-declaration ?
    | set-accessor-declaration get-accessor-declaration ?
    ;

get-accessor-declaration
    : attributes ? accessor-modifier ? get accessor-body
    ;

set-accessor-declaration
    : attributes ? accessor-modifier ? set accessor-body
    ;

accessor-modifier
    : protected
    | internal
    | private
    | protected internal
    | internal protected
    | protected private
    | private protected
    ;

accessor-body
    : block
    | '=>' expression ';'
    | ';'
    ;

event-declaration
    : attributes ? event-modifiers ? event type variable-declarators ';'
    | attributes ? event-modifiers ? event type member-name '{' event-accessor-declarations '}'
    ;

event-modifiers
    : event-modifier +
    ;

event-modifier
    : new
    | public
    | protected
    | internal
    | private
    | static
    | virtual
    | sealed
    | override
    | abstract
    | extern
    | unsafe-modifier
    ;

event-accessor-declarations
    : add-accessor-declaration remove-accessor-declaration
    | remove-accessor-declaration add-accessor-declaration
    ;

add-accessor-declaration
    : attributes ? add block
    | attributes ? add '=>' expression ';'
    ;

remove-accessor-declaration
    : attributes ? remove block
    | attributes ? remove '=>' expression ';'
    ;

indexer-declaration
    : attributes ? indexer-modifiers ? indexer-declarator indexer-body
    ;

indexer-modifiers
    : indexer-modifier +
    ;

indexer-modifier
    : new
    | public
    | protected
    | internal
    | private
    | virtual
    | sealed
    | override
    | abstract
    | extern
    | unsafe-modifier
    ;

indexer-declarator
    : ref-readonly ? type this '[' formal-parameter-list ']'
    | ref-readonly ? type interface-type '.' this '[' formal-parameter-list ']'
    ;

indexer-body
    : '{' accessor-declarations '}'
    | '=>' expression ';'
    ;

operator-declaration
    : attributes ? operator-modifiers operator-declarator operator-body
    ;

operator-modifiers
    : operator-modifier +
    ;

operator-modifier
    : public
    | static
    | extern
    | unsafe-modifier
    ;

operator-declarator
    : unary-operator-declarator
    | binary-operator-declarator
    | conversion-operator-declarator
    ;

unary-operator-declarator
    : type operator overloadable-unary-operator '(' fixed-parameter ')'
    ;

overloadable-unary-operator
    : '+'
    | '-'
    | '!'
    | '~'
    | '++'
    | '--'
    | true
    | false
    ;

binary-operator-declarator
    : type operator overloadable-binary-operator '(' fixed-parameter ',' fixed-parameter ')'
    ;

overloadable-binary-operator
    : '+'
    | '-'
    | '*'
    | '/'
    | '%'
    | '&'
    | '|'
    | '^'
    | '<<'
    | right-shift
    | '=='
    | '!='
    | '>'
    | '<'
    | '>='
    | '<='
    ;

conversion-operator-declarator
    : implicit operator type '(' fixed-parameter ')'
    | explicit operator type '(' fixed-parameter ')'
    ;

operator-body
    : block
    | '=>' expression ';'
    | ';'
    ;

constructor-declaration
    : attributes ? constructor-modifiers ? constructor-declarator constructor-body
    ;

constructor-modifiers
    : constructor-modifier +
    ;

constructor-modifier
    : public
    | protected
    | internal
    | private
    | extern
    | unsafe-modifier
    ;

constructor-declarator
    : identifier '(' formal-parameter-list ? ')' constructor-initializer ?
    ;

constructor-initializer
    : ':' base '(' argument-list ? ')'
    | ':' this '(' argument-list ? ')'
    ;

constructor-body
    : block
    | '=>' expression ';'
    | ';'
    ;

static-constructor-declaration
    : attributes ? static-constructor-modifiers identifier '(' ')' static-constructor-body
    ;

static-constructor-modifiers
    : static
    | static extern unsafe-modifier ?
    | static unsafe-modifier extern ?
    | extern static unsafe-modifier ?
    | extern unsafe-modifier static
    | unsafe-modifier static extern ?
    | unsafe-modifier extern static
    ;

static-constructor-body
    : block
    | '=>' expression ';'
    | ';'
    ;

finalizer-declaration
    : attributes ? '~' identifier '(' ')' finalizer-body
    | attributes ? extern unsafe-modifier ? '~' identifier '(' ')' finalizer-body
    | attributes ? unsafe-modifier extern ? '~' identifier '(' ')' finalizer-body
    ;

finalizer-body
    : block
    | '=>' expression ';'
    | ';'
    ;

}

[ Description Text='A.3.8 Structs' ]
Structs
{

struct-declaration
    : attributes ? struct-modifiers ? ref ? partial ? struct identifier type-parameter-list ? struct-interfaces ? type-parameter-constraints-clauses ? struct-body semicolon-sign ?
    ;

struct-modifiers
    : struct-modifier +
    ;

struct-modifier
    : new
    | public
    | protected
    | internal
    | private
    | readonly
    | unsafe-modifier
    ;

struct-interfaces
    : ':' interface-type-list
    ;

struct-body
    : '{' struct-member-declarations ? '}'
    ;

struct-member-declarations
    : struct-member-declaration +
    ;

struct-member-declaration
    : constant-declaration
    | field-declaration
    | method-declaration
    | property-declaration
    | event-declaration
    | indexer-declaration
    | operator-declaration
    | constructor-declaration
    | static-constructor-declaration
    | type-declaration
    | fixed-size-buffer-declaration
    ;

}

[ Description Text='A.3.9 Arrays' ]
Arrays
{

array-initializer
    : '{' variable-initializer-list ? coma-sign ? '}'
    ;

variable-initializer-list
    : variable-initializer + [ ',' ]
    ;

variable-initializer
    : expression
    | array-initializer
    ;

}

[ Description Text='A.3.10 Interfaces' ]
Interfaces
{

interface-declaration
    : attributes ? interface-modifiers ? partial ? interface identifier variant-type-parameter-list ? interface-base ? type-parameter-constraints-clauses ? interface-body semicolon-sign ?
    ;

interface-modifiers
    : interface-modifier +
    ;

interface-modifier
    : new
    | public
    | protected
    | internal
    | private
    | unsafe-modifier
    ;

variant-type-parameter-list
    : '<' variant-type-parameters '>'
    ;

variant-type-parameters
    : ( :variant-type-parameter: attributes ? variance-annotation ? type-parameter ) + [ ',' ]
    ;

variance-annotation
    : in
    | out
    ;

interface-base
    : ':' interface-type-list
    ;

interface-body
    : '{' interface-member-declarations ? '}'
    ;

interface-member-declarations
    : interface-member-declaration +
    ;

interface-member-declaration
    : interface-method-declaration
    | interface-property-declaration
    | interface-event-declaration
    | interface-indexer-declaration
    ;

interface-method-declaration
    : attributes ? new ? return-type identifier type-parameter-list ? '(' formal-parameter-list ? ')' type-parameter-constraints-clauses ? ';'
    ;

interface-property-declaration
    : attributes ? new ? type identifier '{' interface-accessors '}'
    ;

interface-accessors
    : attributes ? get ';'
    | attributes ? set ';'
    | attributes ? get ';' attributes ? set ';'
    | attributes ? set ';' attributes ? get ';'
    ;

interface-event-declaration
    : attributes ? new ? event type identifier ';'
    ;

interface-indexer-declaration
    : attributes ? new ? type this '[' formal-parameter-list ']' '{' interface-accessors '}'
    ;

}

[ Description Text='A.3.11 Enums' ]
Enums
{

enum-declaration
    : attributes ? enum-modifiers ? enum identifier enum-base ? enum-body semicolon-sign ?
    ;

enum-base
    : ':' integral-type
    | ':' integral-type-name
    ;

integral-type-name
    : type-name
    ;

enum-body
    : '{' enum-member-declarations ? coma-sign ? '}'
    ;

enum-modifiers
    : enum-modifier +
    ;

enum-modifier
    : new
    | public
    | protected
    | internal
    | private
    ;

enum-member-declarations
    : enum-member-declaration + [ ',' ]
    ;

enum-member-declaration
    : attributes ? identifier
    | attributes ? identifier '=' constant-expression
    ;

}

[ Description Text='A.3.12 Delegates' ]
Delegates
{

delegate-declaration
    : attributes ? delegate-modifiers ? delegate ref-readonly ? return-type identifier variant-type-parameter-list ? '(' formal-parameter-list ? ')' type-parameter-constraints-clauses ? ';'
    ;

delegate-modifiers
    : delegate-modifier +
    ;

delegate-modifier
    : new
    | public
    | protected
    | internal
    | private
    | unsafe-modifier
    ;

}

[ Description Text='A.3.13 Attributes' ]
Attributes
{

global-attributes
    : global-attribute-sections
    ;

global-attribute-sections
    : global-attribute-section +
    ;

global-attribute-section
    : '[' global-attribute-target-specifier attribute-list coma-sign ? ']'
    ;

global-attribute-target-specifier
    : global-attribute-target ':'
    ;

global-attribute-target
    : identifier
    ;

attributes
    : attribute-sections
    ;

attribute-sections
    : attribute-section +
    ;

attribute-section
    : '[' attribute-target-specifier ? attribute-list coma-sign ? ']'
    ;

attribute-target-specifier
    : attribute-target ':'
    ;

attribute-target
    : identifier
    | keyword
    ;

attribute-list
    : attribute + [ ',' ]
    ;

attribute
    : attribute-name attribute-arguments ?
    ;

attribute-name
    : type-name
    ;

attribute-arguments
    : '(' positional-argument-list ? ')'
    | '(' positional-argument-list ',' named-argument-list ')'
    | '(' named-argument-list ')'
    ;

positional-argument-list
    : positional-argument + [ ',' ]
    ;

positional-argument
    : argument-name ? attribute-argument-expression
    ;

named-argument-list
    : named-argument + [ ',' ]
    ;

named-argument
    : identifier '=' attribute-argument-expression
    ;

attribute-argument-expression
    : expression
    ;

}

[ Description Text='A.4 Grammar extensions for unsafe code' ]
Grammar-extensions-for-unsafe-code
{

unsafe-modifier
    : unsafe
    ;

unsafe-statement
    : unsafe block
    ;

pointer-type
    : unmanaged-type '*'
    | void '*'
    ;

pointer-indirection-expression
    : '*' unary-expression
    ;

pointer-member-access
    : primary-expression '->' simple-name
    ;

pointer-element-access
    : primary-no-array-creation-expression '[' expression ']'
    ;

addressof-expression
    : '&' unary-expression
    ;

fixed-statement
    : fixed '(' pointer-type fixed-pointer-declarators ')' embedded-statement
    ;

fixed-pointer-declarators
    : fixed-pointer-declarator + [ ',' ]
    ;

fixed-pointer-declarator
    : identifier '=' fixed-pointer-initializer
    ;

fixed-pointer-initializer
    : '&' variable-reference
    | expression
    ;

fixed-size-buffer-declaration
    : attributes ? fixed-size-buffer-modifiers ? fixed buffer-element-type fixed-size-buffer-declarators ';'
    ;

[ Description Text='ATTENTION: right recursion' ]
fixed-size-buffer-modifiers
    : fixed-size-buffer-modifier -
    ;

fixed-size-buffer-modifier
    : new
    | public
    | protected
    | internal
    | private
    | unsafe
    ;

buffer-element-type
    : type
    ;

[ Description Text='ATTENTION: right recursion' ]
fixed-size-buffer-declarators
    : fixed-size-buffer-declarator - [ ',' ]
    ;

fixed-size-buffer-declarator
    : identifier '[' constant-expression ']'
    ;

}

%}