[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

C# grammar for SableCC



Hi,

Attached you will find a grammar for the ECMA C# language. I am sure it
contains bugs, but I was able to parse the class library and the C#
compiler of Mono (www.go-mono.com) with it. I plan to introduce AST
transformations for the expressions and the statements. In order to
resolve conflicts the grammar accepts some invalid statements too. These
need to be sorted out during processing.

Let me know, what You think,
Gergely

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Copyright 2003, Kis Gergely

Package recoder.csharp.ast;

// NOTE: The following should be identical to the lexer in csharp-pp.sablecc

Helpers

// Generic helpers

// Any input character

all = [ 0 .. 65535 ];

// 9.3.1 Line terminators
// NOTE: We do not need line terminator tokens
// TODO: Unicode support.

cr = 13;
lf = 10;
next_line = 0x85;
line_separator = 0x2028;
paragraph_separator = 0x2029;
newline = cr | lf | cr lf | next_line | line_separator | paragraph_separator;

// 9.3.2 Comments

// Any input character except the newline character
// TODO: Unicode support
newline_character = [[[[ cr + lf ] + next_line ] + line_separator ] + paragraph_separator ];

input_character = [ all - newline_character ];

input_characters = input_character+;

not_star = [ all - '*' ];
not_star_slash = [ not_star - '/' ];

not_slash_input_character = [ input_character - '/' ];

// 9.3.3 White space
// TODO: Unicode support

horizontal_tab = 9;
vertical_tab = 0x0b;
form_feed = 0x0c;

whitespace = [[[ horizontal_tab + ' ' ] + vertical_tab ] +  form_feed ];

// 9.4 Tokens

// 9.4.1 Unicode escape sequence
// NOTE: Moved here because 9.4.1 depends on this
hex_digit = [ [ 'A' .. 'F' ] + [ [ 'a' .. 'f' ] + [ '0' .. '9'] ] ];


unicode_escape_sequence = '\u' hex_digit hex_digit hex_digit hex_digit |
                            '\U' hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit;

// NOTE: More concrete versions have to be created for the particular character classes.


// 9.4.2 Identifiers
// TODO: Unicode support

letter_character = [[ 'a' .. 'z' ] + [ 'A' .. 'Z' ]];
underscore = '_';
identifier_start_character = [ letter_character + underscore ];
connecting_character = underscore;

// TODO: Dummy definition;
combining_character = connecting_character;

decimal_digit_character = [ '0' .. '9' ];

identifier_part_character = [[[ letter_character + decimal_digit_character ] + combining_character ] + connecting_character ];

identifier_or_keyword = identifier_start_character identifier_part_character*;


// 9.4.3 Keywords

// 9.4.4 Literals

// 9.4.4.1 Boolean literals
// true or false

// 9.4.4.2 Integer literals
integer_type_suffix = 'U' | 'u' | 'L' | 'l' | 'UL' | 'Ul' | 'uL' | 'ul' | 'LU' | 'Lu' | 'lU' | 'lu';
decimal_digit = [ '0' .. '9' ];

decimal_integer_literal = decimal_digit+ integer_type_suffix?;

hexadecimal_integer_literal = ('0x' | '0X') hex_digit+ integer_type_suffix?;

// 9.4.4.3 Real literals

sign = '+' | '-';

exponent_part = ('e' | 'E') sign? decimal_digit+;

real_type_suffix = 'F' | 'f' | 'D' | 'd' | 'M' | 'm';

// 9.4.4.4 Character literals

single_character = [ all - ''' ];

simple_escape_sequence = '\' ( ''' | '"'  | '\' | '0' | 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v' );


hexadecimal_escape_sequence = '\x' hex_digit hex_digit? hex_digit? hex_digit?;

character = single_character | simple_escape_sequence | hexadecimal_escape_sequence | unicode_escape_sequence;

// 9.4.4.5 String literals

single_regular_string_literal_character = [[[ all - '"' ] - '\' ] - newline_character ] ;
regular_string_literal_character = single_regular_string_literal_character | simple_escape_sequence
                                   | hexadecimal_escape_sequence | unicode_escape_sequence;

regular_string_literal = '"' regular_string_literal_character* '"';

single_verbatim_string_literal_character = [ all - '"' ];
verbatim_string_literal_character = single_verbatim_string_literal_character | '""';

verbatim_string_literal = '@"' verbatim_string_literal_character* '"';

// 9.4.4.6 Null literal

// 9.4.5 Operators and punctuators

// 9.5 Preprocessing directives

pp_file_name_character = [[ all - '"' ] - newline_character ];


States
default, pp, pp_msg;

Tokens

// 9.3.1 Line terminators
// NOTE: No tokens required

// 9.3.2 Comments
single_line_comment = '//' (not_slash_input_character input_characters?)?;
delimited_comment = '/*' not_star* '*'+ (not_star_slash not_star* '*'+)* '/';
csharp_doc_comment = '///' input_characters? (newline '///' input_characters?)*;

// 9.3.3 White space

// 9.4 Tokens

// 9.4.1 Unicode escape sequence

// 9.4.3 Keywords

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

// 9.4.2 Identifiers

{default} identifier = '@'? identifier_or_keyword;

// 9.4.4 Literals

// 9.4.4.1 Boolean literals
// true or false

// 9.4.4.2 Integer literals

{default} integer_literal = decimal_integer_literal | hexadecimal_integer_literal;

// 9.4.4.3 Real literals

{default} real_literal = decimal_digit+ '.' decimal_digit+ exponent_part? real_type_suffix? |
			   '.' decimal_digit+ exponent_part? real_type_suffix? |
			   decimal_digit+ exponent_part real_type_suffix? |
			   decimal_digit+ real_type_suffix;
			
			

// 9.4.4.4 Character literals

{default} character_literal = ''' character ''';

// 9.4.4.5 String literals
{default} string_literal = regular_string_literal | verbatim_string_literal;

// 9.4.4.6 Null literal

// 9.4.5 Operators and punctuators

// A.1.7 Punctuators

     l_brace = '{';
     r_brace = '}';
     l_bracket = '[';
     r_bracket = ']';
     l_par = '(';
     r_par = ')';
     dot = '.';
     comma = ',';
     colon = ':';
     semicolon = ';';

     plus = '+';
     minus = '-';
	star = '*';
     div = '/';
     mod = '%';
     ampersand = '&';
     bar = '|';
     caret = '^';
     excl_mark = '!';
	tilde = '~';
     equal = '=';
     lt = '<';
     gt = '>';
     quest_mark = '?';
     plus_plus = '++';
     minus_minus = '--';
     ampersand_ampersand = '&&';
     bar_bar = '||';
     shl = '<<';
     shr = '>>';
     equal_equal = '==';
     excl_mark_equal = '!=';
     lt_equal = '<=';
     gt_equal = '>=';
     plus_equal = '+=';
     minus_equal = '-=';
     star_equal = '*=';
     div_equal = '/=';
     mod_equal = '%=';
     ampersand_equal = '&=';
     bar_equal = '|=';
     caret_equal = '^=';
     shl_equal = '<<=';
     shr_equal = '>>=';
     arrow = '->';

// 9.5 Preprocessing directives


{pp -> default, pp_msg -> default} pp_newline = newline;

{default -> pp} pp_if = '#' whitespace* 'if';
{default -> pp} pp_elif = '#' whitespace* 'elif';
{default -> pp} pp_else = '#' whitespace* 'else';
{default -> pp} pp_endif = '#' whitespace* 'endif';

{pp} pp_whitespace = whitespace+;

{default -> pp_msg} pp_region = '#' whitespace* 'region';
{default -> pp_msg} pp_endregion = '#' whitespace* 'endregion';
{default -> pp_msg} pp_error = '#' whitespace* 'error';
{default -> pp_msg} pp_warning = '#' whitespace* 'warning';

{default ->pp} pp_line = '#' whitespace* 'line';

{pp_msg -> pp} pp_message = input_character*;

{default ->pp} pp_define = '#' whitespace* 'define';
{default ->pp} pp_undef = '#' whitespace* 'undef';

{pp} pp_line_indicator = decimal_digit+ whitespace+ ('"' pp_file_name_character+ '"')?;
{pp} pp_conditional_symbol = identifier_or_keyword;

// Additional Tokens
{default} blank_newline = newline+;
{default} blank_whitespace = whitespace+;


// NOTE: End part from csharp-pp.sablecc

Ignored Tokens
blank_whitespace, blank_newline, single_line_comment, delimited_comment, csharp_doc_comment;

Productions

// A.2.1 Basic Concepts

// NOTE: This is the production from the standard. We had to declare it differently.
// compilation_unit = using_directive* global_attribute_section* namespace_member_declaration*;

// NOTE: the attribute sections correctness need to be checked. Only global_attribute_section may be used here.
// NOTE: if the source contains a namespace_member_declaration, the global attributes are attached to the first one.
compilation_unit =
{no_namespace_member} using_directive* attribute_section* |
{namespace_member}    using_directive* namespace_member_declaration+;


// Names and Identifiers

name = {simple} identifier |
{qualified} name dot identifier;

// NOTE: This production is needed to support the unsafe extensions
name_star = name star;

name_list = name name_list_tail*;

name_list_tail = comma name;

// A.1.8 Literals

literal =
{true}      true              |
{false}     false             |
{integer}   integer_literal   |
{real}      real_literal      |
{string}    string_literal    |
{character} character_literal |
{null}      null;


// A.2.2 Types

type =
{predefined} predefined_type |
{reference}  reference_type ;


predefined_type =
{simple} simple_type           |
{class}  predefined_class_type;

simple_type =
{numeric} numeric_type |
{bool}    bool;

numeric_type =
{integral}            integral_type       |
{floating_point_type} floating_point_type |
{decimal}             decimal;

integral_type =
{sbyte}  sbyte  |
{byte}   byte   |
{short}  short  |
{ushort} ushort |
{int}    int    |
{uint}   uint   |
{long}   long   |
{ulong}  ulong  |
{char}   char;

floating_point_type =
{float}  float  |
{double} double;


predefined_class_type =
{object} object |
{string} string;

reference_type =
{simple}  name         |
{array}   array_type   |
{pointer} pointer_type; // NOTE: Unsafe extension


array_type =
{predefined_array}          predefined_array_type          |
{name_array}                name_array_type                |
{pointer_array}             pointer_array_type             |
{compound_predefined_array} compound_predefined_array_type |
{compound_name_array}       compound_name_array_type       |
{compound_pointer_array}    compound_pointer_array_type;

predefined_array_type =          predefined_type l_bracket comma* r_bracket;
compound_predefined_array_type = predefined_array_type l_bracket comma* r_bracket;
name_array_type =                name l_bracket comma* r_bracket;
compound_name_array_type =       name_array_type l_bracket comma* r_bracket;
pointer_array_type =             pointer_type l_bracket comma* r_bracket;
compound_pointer_array_type =    pointer_array_type l_bracket comma* r_bracket;

// NOTE: Unsafe extension
pointer_type =
            name_pointer_type |
{not_name} not_name_pointer_type;

name_pointer_type = name_star star*;

not_name_pointer_type =
{predefined} predefined_type star       |
{void}       void star                  |
{compound}   not_name_pointer_type star;

// A.2.3 Variables

// NOTE: Just for Reference
// variable_reference = expression;

// A.2.4 Expressions

argument =
       expression     |
{ref} ref expression |
{out} out expression ;

argument_list = argument argument_list_tail*;

argument_list_tail = comma argument;

primary_expression =
{no_array} primary_no_array_expression |
{array}    array_creation_expression ;


// NOTE: simple name is not included.

primary_no_array_expression =
{literal}           literal                          |
{parenthesized}     l_par expression r_par           |
{member_access}     member_access                    |
{invocation}        invocation_expression            |
{this}              this                             |
{element_access}    element_access                   |
{base_access}       base_access                      |
{instance_creation} instance_creation_expression     |
{typeof}            typeof_expression                |
{checked}           checked l_par expression r_par   |
{unchecked}         unchecked l_par expression r_par |
{sizeof}            sizeof l_par type r_par;

member_access =
{primary}         primary_expression dot identifier |
{predefined}      predefined_type dot identifier |
{pointer_primary} primary_expression arrow identifier | // NOTE: Unsafe extensions
{pointer_name}    name arrow identifier; // NOTE: Unsafe extensions

invocation_expression =
{name}       name l_par argument_list? r_par                              |
{primary}    primary_expression dot identifier l_par argument_list? r_par |
{base}       base dot identifier l_par argument_list? r_par               |
{predefined} predefined_type dot identifier l_par argument_list? r_par;

base_access =
{field}      base dot identifier |
{element}    base l_bracket expression_list? r_bracket;

element_access =
{name}       name l_bracket expression_list r_bracket |
{primary}    primary_no_array_expression l_bracket expression_list r_bracket ;

expression_list = expression expression_list_tail*;

expression_list_tail = comma expression;

// NOTE: May be delegate or object instance
instance_creation_expression =
{predefined} new predefined_type l_par argument_list? r_par |
{name}       new name l_par argument_list? r_par ;

typeof_expression =
        typeof l_par type r_par |
{void} typeof l_par void r_par ;

array_creation_expression =
{expr_predefined} new predefined_type dim_expr+ dim* array_initializer? |
{expr_name}       new name dim_expr+ dim* array_initializer? |
{predefined}      new predefined_type dim+ array_initializer |
{name}            new name dim+ array_initializer ;

dim_expr = l_bracket expression_list r_bracket;

dim = l_bracket comma* r_bracket;

postfix_expression =
{name}     name                        |
{not_name} postfix_expression_not_name;

// NOTE: This production is here to make the "name* id" type expressions work with the unsafe extensions
postfix_expression_not_name =
{primary}        primary_expression        |
{post_increment} post_increment_expression |
{post_decrement} post_decrement_expression;


post_increment_expression = postfix_expression plus_plus;
post_decrement_expression = postfix_expression minus_minus;

unary_expression =
{pointer_indirection} star unary_expression      | // NOTE: Unsafe extensions
{not_star}            unary_expression_not_star;

unary_expression_not_ampersand =
{pointer_indirection} star unary_expression                   | // NOTE: Unsafe extensions
{not_star}            unary_expression_not_star_not_ampersand;


// NOTE: This production exist to allow the usage of pointer indirections. (Unsafe extension)
unary_expression_not_star =
{plus}           plus  unary_expression          |
{minus}          minus unary_expression          |
{pre_increment}  pre_increment_expression        |
{pre_decrement}  pre_decrement_expression        |
{not_plus_minus} unary_expression_not_plus_minus;

unary_expression_not_star_not_ampersand =
{plus}           plus  unary_expression                        |
{minus}          minus unary_expression                        |
{pre_increment}  pre_increment_expression                      |
{pre_decrement}  pre_decrement_expression                      |
{not_plus_minus} unary_expression_not_plus_minus_not_ampersand;


pre_increment_expression = plus_plus   unary_expression;
pre_decrement_expression = minus_minus unary_expression;

// NOTE: This production is here to make the "name* id" type expressions work with the unsafe extensions
unary_expression_not_name =
{plus}                plus unary_expression                    |
{minus}               minus unary_expression                   |
{pointer_indirection} star unary_expression                    | // NOTE: Unsafe extensions
{pre_increment}       pre_increment_expression                 |
{pre_decrement}       pre_decrement_expression                 |
{not_plus_minus}      unary_expression_not_plus_minus_not_name;

unary_expression_not_name_not_ampersand =
{plus}                plus unary_expression                                  |
{minus}               minus unary_expression                                 |
{pointer_indirection} star unary_expression                                  | // NOTE: Unsafe extensions
{pre_increment}       pre_increment_expression                               |
{pre_decrement}       pre_decrement_expression                               |
{not_plus_minus}      unary_expression_not_plus_minus_not_name_not_ampersand;

unary_expression_not_plus_minus =
{postfix}    postfix_expression         |
{not}        excl_mark unary_expression |
{binary_not} tilde unary_expression     |
{addressof}  ampersand unary_expression | // NOTE: Unsafe extensions
{cast}       cast_expression;

unary_expression_not_plus_minus_not_ampersand =
{postfix}    postfix_expression         |
{not}        excl_mark unary_expression |
{binary_not} tilde unary_expression     |
{cast}       cast_expression;


cast_expression =
{predefined}   l_par predefined_type dim* r_par unary_expression                              |
{expression}   l_par expression           r_par unary_expression_not_plus_minus_not_ampersand | // NOTE: The "(expression) & expression" case is parsed as an and_expression, we need to check it later
{name_array}   l_par name dim+            r_par unary_expression_not_plus_minus               |
{pointer_type} l_par pointer_type dim*    r_par unary_expression_not_plus_minus ;

// NOTE: This production is here to make the "name* id" type expressions work with the unsafe extensions
unary_expression_not_plus_minus_not_name =
{postfix}    postfix_expression_not_name |
{not}        excl_mark unary_expression  |
{binary_not} tilde unary_expression      |
{addressof}  ampersand unary_expression  | // NOTE: Unsafe extensions
{cast}       cast_expression;

unary_expression_not_plus_minus_not_name_not_ampersand =
{postfix}    postfix_expression_not_name |
{not}        excl_mark unary_expression  |
{binary_not} tilde unary_expression      |
{cast}       cast_expression;

// NOTE: This production is here to make the "name* id" type expressions work with the unsafe extensions
multiplicative_expression_not_name =
{unary}     unary_expression_not_name                                          |
{mult_name} name_star                          star* unary_expression_not_star |
{mult}      multiplicative_expression_not_name star  unary_expression          |
{div} multiplicative_expression                div   unary_expression          |
{mod} multiplicative_expression                mod   unary_expression;

multiplicative_expression_not_name_not_ampersand =
{unary}     unary_expression_not_name_not_ampersand                                          |
{mult_name} name_star                                        star* unary_expression_not_star |
{mult}      multiplicative_expression_not_name_not_ampersand star  unary_expression          |
{div}       multiplicative_expression_not_ampersand          div   unary_expression          |
{mod}       multiplicative_expression_not_ampersand          mod   unary_expression;


multiplicative_expression =
{unary}     unary_expression                                                   |
{mult_name} name_star                          star* unary_expression_not_star |
{mult}      multiplicative_expression_not_name star  unary_expression          |
{div}       multiplicative_expression          div   unary_expression          |
{mod}       multiplicative_expression          mod   unary_expression;

multiplicative_expression_not_ampersand =
{unary}     unary_expression_not_ampersand                                                   |
{mult_name} name_star                                        star* unary_expression_not_star |
{mult}      multiplicative_expression_not_name_not_ampersand star  unary_expression          |
{div}       multiplicative_expression_not_ampersand          div   unary_expression          |
{mod}       multiplicative_expression_not_ampersand          mod   unary_expression;


additive_expression =
{multiplicative} multiplicative_expression                           |
{add}            additive_expression plus  multiplicative_expression |
{sub}            additive_expression minus multiplicative_expression;

additive_expression_not_ampersand =
{multiplicative} multiplicative_expression_not_ampersand                           |
{add}            additive_expression_not_ampersand plus  multiplicative_expression |
{sub}            additive_expression_not_ampersand minus multiplicative_expression;


shift_expression =
{additive}    additive_expression                      |
{shift_left}  shift_expression shl additive_expression |
{shift_right} shift_expression shr additive_expression;

shift_expression_not_ampersand =
{additive}    additive_expression_not_ampersand                      |
{shift_left}  shift_expression_not_ampersand shl additive_expression |
{shift_right} shift_expression_not_ampersand shr additive_expression ;



relational_expression =
{shift} shift_expression                                     |
{lt}         relational_expression lt shift_expression       |
{gt}         relational_expression gt shift_expression       |
{lt_equal}   relational_expression lt_equal shift_expression |
{gt_equal}   relational_expression gt_equal shift_expression |
{is}         relational_expression is predefined_type dim*   |
{is_name}    relational_expression is name dim*              |
{is_pointer} relational_expression is pointer_type dim*      |
{as}         relational_expression as predefined_type dim*   |
{as_name}    relational_expression as name dim*              |
{as_pointer} relational_expression as pointer_type dim*;

relational_expression_not_ampersand =
{shift}      shift_expression_not_ampersand                                    |
{lt}         relational_expression_not_ampersand lt       shift_expression     |
{gt}         relational_expression_not_ampersand gt       shift_expression     |
{lt_equal}   relational_expression_not_ampersand lt_equal shift_expression     |
{gt_equal}   relational_expression_not_ampersand gt_equal shift_expression     |
{is}         relational_expression_not_ampersand is       predefined_type dim* |
{is_name}    relational_expression_not_ampersand is       name dim*            |
{is_pointer} relational_expression_not_ampersand is       pointer_type dim*    |
{as}         relational_expression_not_ampersand as       predefined_type dim* |
{as_name}    relational_expression_not_ampersand as       name dim*            |
{as_pointer} relational_expression_not_ampersand as       pointer_type dim*;



equality_expression =
               relational_expression                                     |
{equal_equal} equality_expression equal_equal     relational_expression |
{not_equal}   equality_expression excl_mark_equal relational_expression;

equality_expression_not_ampersand =
               relational_expression_not_ampersand                                     |
{equal_equal} equality_expression_not_ampersand equal_equal     relational_expression |
{not_equal}   equality_expression_not_ampersand excl_mark_equal relational_expression;


and_expression =
       equality_expression                                          |
{and} and_expression ampersand+ equality_expression_not_ampersand; // NOTE: Need to check later, whether this is a cast expression with an addressof operator...valid only in unsafe context.

exclusive_or_expression =
       and_expression                                |
{xor} exclusive_or_expression caret and_expression;

inclusive_or_expression =
      exclusive_or_expression                              |
{or} inclusive_or_expression bar exclusive_or_expression;

conditional_and_expression =
inclusive_or_expression                                                                  |
{conditional_and} conditional_and_expression ampersand_ampersand inclusive_or_expression;

conditional_or_expression =
                  conditional_and_expression                                    |
{conditional_or} conditional_or_expression bar_bar conditional_and_expression ;

conditional_expression =
             conditional_or_expression                                                         |
{cond_expr} conditional_or_expression quest_mark [true]: expression colon [false]: expression;

assignment = unary_expression assignment_operator expression;

assignment_operator =
{equal}           equal           |
{plus_equal}      plus_equal      |
{minus_equal}     minus_equal     |
{star_equal}      star_equal      |
{div_equal}       div_equal       |
{mod_equal}       mod_equal       |
{ampersand_equal} ampersand_equal |
{bar_equal}       bar_equal       |
{caret_equal}     caret_equal     |
{shl_equal}       shl_equal       |
{shr_equal}       shr_equal;

expression =
{conditional_expression} conditional_expression |
{assignment}             assignment;

// A.2.5 Statements

statement =
{labeled}     identifier            colon statement |
{declaration} declaration_statement                 |
{embedded}    embedded_statement;

embedded_statement =
{no_substatement} embedded_statement_without_trailing_substatement |
{if}              if_statement                                     |
{if_else}         if_else_statement                                |
{while}           while_statement                                  |
{for}             for_statement                                    |
{foreach}         foreach_statement                                |
{lock}            lock_statement                                   |
{using}           using_statement                                  |
{fixed}           fixed_statement;

embedded_statement_no_short_if =
{no_substatement} embedded_statement_without_trailing_substatement |
{if_else}         if_else_statement_no_short_if                    |
{while}           while_statement_no_short_if                      |
{for}             for_statement_no_short_if                        |
{foreach}         foreach_statement_no_short_if                    |
{lock}            lock_statement_no_short_if                       |
{using}           using_statement_no_short_if                      |
{fixed}           fixed_statement_no_short_if;

embedded_statement_without_trailing_substatement =
{block}      block                                                                                         |
{empty}      semicolon                                                                                     |
{expression} expression_statement                                                                          |
{switch}     switch               l_par              expression r_par l_brace    switch_section+ r_brace   |
{do}         do                   embedded_statement while      l_par expression r_par           semicolon |
{break}      break                semicolon                                                                |
{continue}   continue             semicolon                                                                |
{goto}       goto_statement                                                                                |
{return}     return               expression?        semicolon                                             |
{throw}      throw                expression?        semicolon                                             |
{try}        try_statement                                                                                 |
{checked}    checked              block                                                                    |
{unchecked}  unchecked            block                                                                    |
{unsafe}     unsafe               block; // NOTE: Unsafe extension


block = l_brace statement* r_brace;

declaration_statement =
{local_variable}           local_variable_declaration semicolon                      |
{local_variable_name_star} name_pointer_type          variable_declarators semicolon | // NOTE: this alternative is included to support the unsafe name* i structure
{local_constant}           local_constant_declaration semicolon;

// TODO: support for name_star identifier
local_variable_declaration =
{predefined}       predefined_type       variable_declarators |
{name}             name                  variable_declarators |
{array}            array_type            variable_declarators |
{not_name_pointer} not_name_pointer_type variable_declarators;

variable_declarators = variable_declarator variable_declarators_tail*;

variable_declarators_tail = comma variable_declarator;

variable_declarator =
               identifier                            |
{initialized} identifier equal variable_initializer;

local_constant_declaration = const type constant_declarators;

constant_declarator = identifier equal expression;

constant_declarators = constant_declarator constant_declarators_tail*;

constant_declarators_tail = comma constant_declarator;

expression_statement = statement_expression semicolon;

statement_expression =
{invocation}        invocation_expression |
{post_increment}    post_increment_expression |
{pre_increment}     pre_increment_expression |
{post_decrement}    post_decrement_expression |
{pre_decrement}     pre_decrement_expression |
{instance_creation} instance_creation_expression |
{assignment}        assignment;

if_statement =                  if l_par expression r_par              embedded_statement;

if_else_statement =             if l_par expression r_par              embedded_statement_no_short_if else               embedded_statement;

if_else_statement_no_short_if = if l_par expression r_par [expr_true]: embedded_statement_no_short_if else [expr_false]: embedded_statement_no_short_if;

switch_section = switch_label+ statement+;

switch_label =
{case}    case    expression colon |
{default} default colon;

while_statement =             while l_par expression r_par embedded_statement;

while_statement_no_short_if = while l_par expression r_par embedded_statement_no_short_if;


for_statement =             for l_par for_initializer? [sep1]: semicolon expression? [sep2]: semicolon statement_expression_list? r_par embedded_statement;

for_statement_no_short_if = for l_par for_initializer? [sep1]: semicolon expression? [sep2]: semicolon statement_expression_list? r_par embedded_statement_no_short_if;

for_initializer =
{variable}                  local_variable_declaration                      |
{variable_name_star}        name_pointer_type          variable_declarators | // NOTE: this alternative is included to support the unsafe name* i structure
{statement_expression_list} statement_expression_list;

statement_expression_list = statement_expression statement_expression_list_tail*;
statement_expression_list_tail = comma statement_expression;


foreach_statement =             foreach l_par type identifier in expression r_par embedded_statement;

foreach_statement_no_short_if = foreach l_par type identifier in expression r_par embedded_statement_no_short_if;

goto_statement =
{identifier} goto identifier semicolon            |
{case}       goto case       expression semicolon |
{default}    goto default    semicolon ;


try_statement =
{catch}   try block catch_clause+                 |
{finally} try block catch_clause* finally_clause;

// NOTE: Need to be checked later, that only the last catch clause may be general.
catch_clause =
{predefined_specific} catch l_par predefined_class_type identifier? r_par block |
{name_specific}       catch l_par name identifier? r_par block |
{general}             catch block;

finally_clause = finally block;

lock_statement =             lock l_par expression r_par embedded_statement;

lock_statement_no_short_if = lock l_par expression r_par embedded_statement_no_short_if;

using_statement =             using l_par resource_aquisition r_par embedded_statement;

using_statement_no_short_if = using l_par resource_aquisition r_par embedded_statement_no_short_if;

// NOTE: The expression needs to be checked for "name* identifier" type expressions, as they are actually pointer
// declarations inside an unsafe block.
resource_aquisition =
{conditional_expression}     conditional_expression                                   |
{assignment}                 multiplicative_expression assignment_operator expression |
{local_variable_declaration} local_variable_declaration;


// NOTE: Unsafe extensions
fixed_statement =             fixed l_par pointer_type variable_declarators r_par embedded_statement;

// NOTE: Unsafe extensions
fixed_statement_no_short_if = fixed l_par pointer_type variable_declarators r_par embedded_statement_no_short_if;


// Namespaces

// NOTE: for explanation see the compilation_unit production
namespace_declaration = attribute_section* namespace name l_brace using_directive* namespace_member_declaration* r_brace ;

using_directive =
{namespace} using name       semicolon                |
{alias}     using identifier equal     name semicolon ;


// NOTE: The usage of semicolons needs to be checked later.
namespace_member_declaration =
{namespace} namespace_declaration |
{type}      type_declaration      |
{semicolon} semicolon; // NOTE: The usage of semicolons needs to be checked later.

type_declaration =
{class}     class_declaration     |
{struct}    struct_declaration    |
{interface} interface_declaration |
{enum}      enum_declaration      |
{delegate}  delegate_declaration;

// Modifiers for general use

// NOTE: The valid usage scenarios need to be checked later
modifier =
{new}       new       |
{public}    public    |
{protected} protected |
{internal}  internal  |
{private}   private   |
{static}    static    |
{virtual}   virtual   |
{abstract}  abstract  |
{sealed}    sealed    |
{override}  override  |
{readonly}  readonly  |
{volatile}  volatile  |
{extern}    extern    |
{unsafe}    unsafe ;// NOTE: Unsafe extensions;

// A.2.6 Classes

class_declaration = attribute_section* modifier* [keyword]: class identifier class_base? l_brace class_member_declaration* r_brace;

class_base =
{predefined}                 colon predefined_class_type                 |
{names}                      colon name_list                             | // NOTE: This alternative matches both interface_type_list and class_type comma interface_type_list
{predefined_with_interfaces} colon predefined_class_type comma name_list;

class_member_declaration =
{constant}    constant_declaration    |
{field}       field_declaration       |
{method}      method_declaration      |
{property}    property_declaration    |
{event}       event_declaration       |
{indexer}     indexer_declaration     |
{operator}    operator_declaration    |
// NOTE: The constructor_declaration also matches the static constructor declaration
{constructor} constructor_declaration |
{destructor}  destructor_declaration  |
{type}        type_declaration        |
{semicolon}   semicolon; // NOTE: The usage of semicolons needs to be checked later.

constant_declaration = attribute_section* modifier* const type constant_declarators semicolon ;

field_declaration = attribute_section* modifier* type variable_declarators semicolon;

method_declaration =
        attribute_section* modifier* type name l_par formal_parameter_list? r_par method_body |
{void} attribute_section* modifier* void name l_par formal_parameter_list? r_par method_body;

method_body =
{block} block     |
{empty} semicolon;

formal_parameter_list =
{fixed}       fixed_parameters                       |
{fixed_array} fixed_parameters comma parameter_array |
{array}       parameter_array;

fixed_parameters =
            fixed_parameter                        |
{multiple} fixed_parameters comma fixed_parameter;

// NOTE: These would result in a shift / reduce conflict. We would only need them, if we wanted to transform the fixed_parameters list.
// If I find time, maybe I will come up with a solution.
// fixed_parameters_for_param_array = fixed_parameter fixed_parameters_tail* comma;
// fixed_parameters = fixed_parameter fixed_parameters_tail*;
// fixed_parameters_tail = comma fixed_parameter;

fixed_parameter = attribute_section* parameter_modifier? type identifier;

parameter_modifier =
{ref} ref |
{out} out;

parameter_array = attribute_section* params array_type identifier;

property_declaration = attribute_section* modifier* type name l_brace accessor_declarations r_brace ;

accessor_declarations = [mandatory]: accessor_declaration [optional]: accessor_declaration?;

// NOTE: The identifier is either "get" or "set"
accessor_declaration = attribute_section* identifier accessor_body;

// NOTE: These match with the method_body production
accessor_body =
{block} block      |
{empty} semicolon;

event_declaration =
{variable} attribute_section* modifier* event type variable_declarators semicolon                                     |
{accessor} attribute_section* modifier* event type name                 l_brace   event_accessor_declarations r_brace;

event_accessor_declarations = [first]: event_accessor_declaration [second]: event_accessor_declaration;

// NOTE: The identifier is either "add" or "remove"
event_accessor_declaration = attribute_section* identifier block ;

indexer_declaration = attribute_section* modifier* indexer_declarator l_brace accessor_declarations r_brace;

indexer_declarator =
{simple}   type this          l_bracket formal_parameter_list r_bracket |
{compound} type name dot this l_bracket formal_parameter_list r_bracket;

operator_declaration =
{unary}               attribute_section* modifier* [return_type]: type operator overloadable_operator l_par [param_type]: type identifier r_par operator_body |
{binary}              attribute_section* modifier* [return_type]: type operator overloadable_operator l_par [param_type1]:type [param_id1]: identifier comma [param_type2]: type [param_id2]: identifier r_par operator_body |
{implicit_conversion} attribute_section* modifier* implicit operator [return_type]: type l_par [param_type]: type identifier r_par operator_body |
{explicit_conversion} attribute_section* modifier* explicit operator [return_type]: type l_par [param_type]: type identifier r_par operator_body;

// NOTE: Need to check later, whether the operator is valid for the particular declaration.
overloadable_operator =
{plus}        plus            |
{minus}       minus           |
{not}         excl_mark       |
{binary_not}  tilde           |
{plus_plus}   plus_plus       |
{minus_minus} minus_minus     |
{true}        true            |
{false}       false           |
{mult}        star            |
{div}         div             |
{mod}         mod             |
{binary_and}  ampersand       |
{binary_or}   bar             |
{caret}       caret           | // TODO: What is the function of this operator???
{shl}         shl             |
{shr}         shr             |
{equal_equal} equal_equal     |
{not_equal}   excl_mark_equal |
{gt}          gt              |
{lt}          lt              |
{gt_equal}    gt_equal        |
{lt_equal}    lt_equal;

// NOTE: These match with the method_body production
operator_body =
{block} block     |
{empty} semicolon;

// NOTE: this rule matches the static_constructor_declaration too
constructor_declaration = attribute_section* modifier* identifier l_par formal_parameter_list? r_par constructor_initializer? constructor_body ;

constructor_initializer =
{base} colon base l_par argument_list? r_par |
{this} colon this l_par argument_list? r_par ;

// NOTE: These match with the method_body production
constructor_body =
{block} block     |
{empty} semicolon;

destructor_declaration = attribute_section* modifier* tilde identifier l_par r_par destructor_body;

// NOTE: These match with the method_body production
destructor_body =
{block} block     |
{empty} semicolon;

// A.2.7 Structs

struct_declaration = attribute_section* modifier* struct identifier struct_interfaces? l_brace struct_member_declaration* r_brace;

struct_interfaces = colon name_list;

struct_member_declaration =
{constant}    constant_declaration |
{field}       field_declaration |
{method}      method_declaration |
{property}    property_declaration |
{event}       event_declaration |
{indexer}     indexer_declaration |
{operator}    operator_declaration |
// NOTE: The constructor_declaration also matches the static constructor declaration
{constructor} constructor_declaration |
{destructor}  destructor_declaration |
{type}        type_declaration |
{semicolon}   semicolon; // NOTE: The usage of semicolons needs to be checked later.

// A.2.8 Arrays

array_initializer = l_brace variable_initializer_list? r_brace; // NOTE: trailing comma in list production


variable_initializer_list =      variable_initializer variable_initializer_list_tail* comma?;
variable_initializer_list_tail = comma variable_initializer;

variable_initializer =
{expression} expression              |
{array}      array_initializer       |
{stackalloc} stackalloc_initializer;

// NOTE: Unsafe extension
stackalloc_initializer =
{predefined}                stackalloc predefined_type                l_bracket expression r_bracket |
{pointer}                   stackalloc pointer_type                   l_bracket expression r_bracket |
{predefined_array}          stackalloc predefined_array_type          l_bracket expression r_bracket |
{predefined_compound_array} stackalloc compound_predefined_array_type l_bracket expression r_bracket |
{pointer_array}             stackalloc pointer_array_type             l_bracket expression r_bracket |
{pointer_compound_array}    stackalloc compound_pointer_array_type    l_bracket expression r_bracket |
{name}                      stackalloc name rank_specifier*           l_bracket expression r_bracket;

rank_specifier = l_bracket comma* r_bracket;

// A.2.9 Interfaces

interface_declaration = attribute_section* modifier* interface identifier interface_base? l_brace interface_member_declaration* r_brace;

interface_base = colon name_list;

interface_member_declaration =
{method}   interface_method_declaration   |
{property} interface_property_declaration |
{event}    interface_event_declaration    |
{indexer}  interface_indexer_declaration;

interface_method_declaration =
        attribute_section* modifier* type identifier l_par formal_parameter_list? r_par semicolon |
{void} attribute_section* modifier* void identifier l_par formal_parameter_list? r_par semicolon;

interface_property_declaration = attribute_section* modifier* type identifier l_brace interface_accessors r_brace;

// NOTE: The only valid identifiers are "get" and "set"
interface_accessors =
{single} attribute_section* identifier semicolon |
{double} [first_attributes]: attribute_section* [first_id]: identifier [sc1]: semicolon [second_attributes]: attribute_section* [second_id]: identifier [sc2]: semicolon ;

interface_event_declaration = attribute_section* modifier* event type identifier semicolon ;

interface_indexer_declaration = attribute_section* modifier* type this l_bracket formal_parameter_list r_bracket l_brace interface_accessors r_brace;


// A.2.10 Enums

enum_declaration = attribute_section* modifier* enum identifier enum_base? enum_body ;

enum_base = colon integral_type;

enum_body = l_brace enum_member_declarations? r_brace; // NOTE: the trailing comma is in the list production

enum_member_declarations = enum_member_declaration enum_member_declarations_tail* comma?;
enum_member_declarations_tail = comma enum_member_declaration;


enum_member_declaration =
               attribute_section* identifier |
{initialized} attribute_section* identifier equal expression ;


// A.2.11 Delegates

delegate_declaration =
        attribute_section* modifier* delegate type identifier l_par formal_parameter_list? r_par semicolon |
{void} attribute_section* modifier* delegate void identifier l_par formal_parameter_list? r_par semicolon;

// A.2.12 Attributes

// NOTE: the only valid global_attribute_target is "assembly";
// We do not introduce a separate rule for global attribute  sections. The correct semantic meaning needs to be checked later.
// global_attribute_section = l_bracket assembly colon attribute_list r_bracket;


  attribute_section = l_bracket attribute_target_specifier? attribute_list r_bracket; // NOTE: trailing comma in attribute_list


// NOTE: Currently valid targets are: "field", "event", "method", "param", "property", "return", "type" for regular attributes
// and "assembly" for global attributes.
attribute_target_specifier = attribute_target colon;

attribute_target =
{basic} identifier |
{event} event |
{return} return;


attribute_list = attribute attribute_list_tail* comma?;
attribute_list_tail = comma attribute ;



// NOTE: special handling of expressions "identifier = expression" is required.
attribute = name attribute_argument?;

attribute_argument = l_par expression_list? r_par;