pascalabcnet/Utils/NodesGeneratorNew/CSharpGrammar.cs
Бондарев Иван d423b906ac added missing copyrights
2017-05-27 20:06:12 +02:00

885 lines
52 KiB
C#
Raw Permalink Blame History

// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Irony.Parsing;
using System.Globalization;
namespace Irony.Samples.CSharp {
//Full c# 3.0 grammar; all but 2 features are not implemented:
// - preprocessor directives (currently treated as comment lines)
// - LINQ query expressions.
#region current conflicts explanations
/*
Shift-reduce conflict in state S88, reduce production: using_directives_opt -> on inputs: extern
- because of use of "extern" two places: in "extern alias someName;" and as modifier of class members;
this conflict is not in original c# grammar, it is a result of grammar tweaking (merging modifiers definitions)
prefering shift is correct behavior
Shift-reduce conflict in state S518, reduce production: else_clause_opt -> on inputs: else
- "dangling ELSE conflict" well described in textbooks; preferring shift is a correct behavior
*/
#endregion
[Language("c#", "3.5", "Sample c# grammar")]
public class CSharpGrammar : Grammar {
TerminalSet _skipTokensInPreview = new TerminalSet(); //used in token preview for conflict resolution
public CSharpGrammar() {
this.GrammarComments = "NOTE: This grammar is just a demo, and it is a broken demo.\r\n" +
"Demonstrates token preview technique to help parser resolve conflicts.\r\n";
#region Lexical structure
StringLiteral StringLiteral = TerminalFactory.CreateCSharpString("StringLiteral");
StringLiteral CharLiteral = TerminalFactory.CreateCSharpChar("CharLiteral");
NumberLiteral Number = TerminalFactory.CreateCSharpNumber("Number");
IdentifierTerminal identifier = TerminalFactory.CreateCSharpIdentifier("Identifier");
CommentTerminal SingleLineComment = new CommentTerminal("SingleLineComment", "//", "\r", "\n", "\u2085", "\u2028", "\u2029");
CommentTerminal DelimitedComment = new CommentTerminal("DelimitedComment", "/*", "*/");
NonGrammarTerminals.Add(SingleLineComment);
NonGrammarTerminals.Add(DelimitedComment);
//Temporarily, treat preprocessor instructions like comments
CommentTerminal ppInstruction = new CommentTerminal("ppInstruction", "#", "\n");
NonGrammarTerminals.Add(ppInstruction);
//Symbols
KeyTerm colon = ToTerm(":", "colon");
KeyTerm semi = ToTerm(";", "semi");
NonTerminal semi_opt = new NonTerminal("semi?");
semi_opt.Rule = Empty | semi;
KeyTerm dot = ToTerm(".", "dot");
KeyTerm comma = ToTerm(",", "comma");
NonTerminal comma_opt = new NonTerminal("comma_opt", Empty | comma);
NonTerminal commas_opt = new NonTerminal("commas_opt");
commas_opt.Rule = MakeStarRule(commas_opt, null, comma);
KeyTerm qmark = ToTerm("?", "qmark");
NonTerminal qmark_opt = new NonTerminal("qmark_opt", Empty | qmark);
KeyTerm Lbr = ToTerm("{");
KeyTerm Rbr = ToTerm("}");
KeyTerm Lpar = ToTerm("(");
KeyTerm Rpar = ToTerm(")");
KeyTerm tgoto = ToTerm("goto");
KeyTerm yld = ToTerm("yield");
KeyTerm Lparx = ToTerm("(*");
#endregion
#region NonTerminals
//B.2.1. Basic concepts
var qual_name_with_targs = new NonTerminal("qual_name_with_targs");
var base_type_list = new NonTerminal("base_type_list");
var generic_dimension_specifier = new NonTerminal("generic_dimension_specifier");
var qual_name_segment = new NonTerminal("qual_name_segment");
var qual_name_segments_opt = new NonTerminal("qual_name_segments_opt");
var type_or_void = new NonTerminal("type_or_void", "type or void");
var builtin_type = new NonTerminal("builtin_type", "built-in type");
var type_ref_list = new NonTerminal("type_ref_list");
var identifier_ext = new NonTerminal("identifier_ext");
var identifier_or_builtin = new NonTerminal("identifier_or_builtin");
//B.2.2. Types
var type_ref = new NonTerminal("type_ref");
var new_type_ref = new NonTerminal("new_type_ref");
var type_argument_list = new NonTerminal("type_argument_list");
var typearg_or_gendimspec_list = new NonTerminal("typearg_or_gendimspec_list");
var type_argument_list_opt = new NonTerminal("type_argument_list_opt");
var integral_type = new NonTerminal("integral_type");
//B.2.4. Expressions
var argument = new NonTerminal("argument");
var argument_list = new NonTerminal("argument_list");
var argument_list_opt = new NonTerminal("argument_list_opt");
var expression = new NonTerminal("expression", "expression");
var expression_list = new NonTerminal("expression_list");
var expression_opt = new NonTerminal("expression_opt");
var conditional_expression = new NonTerminal("conditional_expression");
var lambda_expression = new NonTerminal("lambda_expression");
var query_expression = new NonTerminal("query_expression");
var unary_operator = new NonTerminal("unary_operator");
var assignment_operator = new NonTerminal("assignment_operator");
var primary_expression = new NonTerminal("primary_expression");
var unary_expression = new NonTerminal("unary_expression");
var pre_incr_decr_expression = new NonTerminal("pre_incr_decr_expression");
var post_incr_decr_expression = new NonTerminal("post_incr_decr_expression");
var primary_no_array_creation_expression = new NonTerminal("primary_no_array_creation_expression");
var literal = new NonTerminal("literal");
var parenthesized_expression = new NonTerminal("parenthesized_expression");
var member_access = new NonTerminal("member_access");
var member_access_segment = new NonTerminal("member_access_segment");
var member_access_segments_opt = new NonTerminal("member_access_segments_opt");
var array_indexer = new NonTerminal("array_indexer");
var argument_list_par = new NonTerminal("argument_list_par");
var argument_list_par_opt = new NonTerminal("argument_list_par_opt");
var incr_or_decr = new NonTerminal("incr_or_decr");
var incr_or_decr_opt = new NonTerminal("incr_or_decr_opt");
var creation_args = new NonTerminal("creation_args");
var object_creation_expression = new NonTerminal("object_creation_expression");
// delegate creation is syntactically equiv to object creation
//var delegate_creation_expression = new NonTerminal("delegate_creation_expression");
var anonymous_object_creation_expression = new NonTerminal("anonymous_object_creation_expression");
var typeof_expression = new NonTerminal("typeof_expression");
var checked_expression = new NonTerminal("checked_expression");
var unchecked_expression = new NonTerminal("unchecked_expression");
var default_value_expression = new NonTerminal("default_value_expression");
var anonymous_method_expression = new NonTerminal("anonymous_method_expression");
var elem_initializer = new NonTerminal("elem_initializer");
var elem_initializer_list = new NonTerminal("elem_initializer_list");
var elem_initializer_list_ext = new NonTerminal("elem_initializer_list_ext");
var initializer_value = new NonTerminal("initializer_value");
var anonymous_object_initializer = new NonTerminal("anonymous_object_initializer");
var member_declarator = new NonTerminal("member_declarator");
var member_declarator_list = new NonTerminal("member_declarator_list");
var unbound_type_name = new NonTerminal("unbound_type_name");
var generic_dimension_specifier_opt = new NonTerminal("generic_dimension_specifier_opt");
var anonymous_function_signature = new NonTerminal("anonymous_function_signature");
var anonymous_function_signature_opt = new NonTerminal("anonymous_function_signature_opt");
var anonymous_function_parameter = new NonTerminal("anonymous_function_parameter");
var anonymous_function_parameter_decl = new NonTerminal("anonymous_function_parameter_decl");
var anonymous_function_parameter_list_opt = new NonTerminal("anonymous_function_parameter_list_opt");
var anonymous_function_parameter_modifier_opt = new NonTerminal("anonymous_function_parameter_modifier_opt");
var anonymous_function_body = new NonTerminal("anonymous_function_body");
var lambda_function_signature = new NonTerminal("lambda_function_signature");
var bin_op_expression = new NonTerminal("bin_op_expression");
var typecast_expression = new NonTerminal("typecast_expression");
var bin_op = new NonTerminal("bin_op", "operator symbol");
//B.2.5. Statements
var statement = new NonTerminal("statement", "statement");
var statement_list = new NonTerminal("statement_list");
var statement_list_opt = new NonTerminal("statement_list_opt");
var labeled_statement = new NonTerminal("labeled_statement");
var declaration_statement = new NonTerminal("declaration_statement");
var embedded_statement = new NonTerminal("embedded_statement");
var selection_statement = new NonTerminal("selection_statement");
var iteration_statement = new NonTerminal("iteration_statement");
var jump_statement = new NonTerminal("jump_statement");
var try_statement = new NonTerminal("try_statement");
var checked_statement = new NonTerminal("checked_statement");
var unchecked_statement = new NonTerminal("unchecked_statement");
var lock_statement = new NonTerminal("lock_statement");
var using_statement = new NonTerminal("using_statement");
var yield_statement = new NonTerminal("yield_statement");
var block = new NonTerminal("block");
var statement_expression = new NonTerminal("statement_expression");
var statement_expression_list = new NonTerminal("statement_expression_list");
var local_variable_declaration = new NonTerminal("local_variable_declaration");
var local_constant_declaration = new NonTerminal("local_constant_declaration");
var local_variable_type = new NonTerminal("local_variable_type");
var local_variable_declarator = new NonTerminal("local_variable_declarator");
var local_variable_declarators = new NonTerminal("local_variable_declarators");
var if_statement = new NonTerminal("if_statement");
var switch_statement = new NonTerminal("switch_statement");
var else_clause_opt = new NonTerminal("else_clause_opt");
var switch_section = new NonTerminal("switch_section");
var switch_sections_opt = new NonTerminal("switch_sections_opt");
var switch_label = new NonTerminal("switch_label");
var switch_labels = new NonTerminal("switch_labels");
var while_statement = new NonTerminal("while_statement");
var do_statement = new NonTerminal("do_statement");
var for_statement = new NonTerminal("for_statement");
var foreach_statement = new NonTerminal("foreach_statement");
var for_initializer_opt = new NonTerminal("for_initializer_opt");
var for_condition_opt = new NonTerminal("for_condition_opt");
var for_iterator_opt = new NonTerminal("for_iterator_opt");
var break_statement = new NonTerminal("break_statement");
var continue_statement = new NonTerminal("continue_statement");
var goto_statement = new NonTerminal("goto_statement");
var return_statement = new NonTerminal("return_statement");
var throw_statement = new NonTerminal("throw_statement");
var try_clause = new NonTerminal("try_clause");
var try_clauses = new NonTerminal("try_clauses");
var catch_clause = new NonTerminal("catch_clause");
var finally_clause = new NonTerminal("finally_clause");
var catch_specifier_opt = new NonTerminal("catch_specifier_opt");
var identifier_opt = new NonTerminal("identifier_opt");
var resource_acquisition = new NonTerminal("resource_acquisition");
//namespaces, compilation units
var compilation_unit = new NonTerminal("compilation_unit");
var extern_alias_directive = new NonTerminal("extern_alias_directive");
var extern_alias_directives_opt = new NonTerminal("extern_alias_directives_opt");
var using_directive = new NonTerminal("using_directive");
var using_directives = new NonTerminal("using_directives");
var using_directives_opt = new NonTerminal("using_directives_opt");
var namespace_declaration = new NonTerminal("namespace_declaration");
var namespace_declarations_opt = new NonTerminal("namespace_declarations_opt");
var qualified_identifier = new NonTerminal("qualified_identifier");
var namespace_body = new NonTerminal("namespace_body");
var namespace_member_declaration = new NonTerminal("namespace_member_declaration");
var namespace_member_declarations = new NonTerminal("namespace_member_declarations");
var using_alias_directive = new NonTerminal("using_alias_directive");
var using_ns_directive = new NonTerminal("using_ns_directive");
var type_declaration = new NonTerminal("type_declaration");
var class_declaration = new NonTerminal("class_declaration");
var delegate_declaration = new NonTerminal("delegate_declaration");
var qualified_alias_member = new NonTerminal("qualified_alias_member");
var class_body = new NonTerminal("class_body");
//B.2.7 Classes
Terminal partial = ToTerm("partial");
var type_parameter_list_opt = new NonTerminal("type_parameter_list_opt");
var type_parameter = new NonTerminal("type_parameter");
var type_parameters = new NonTerminal("type_parameters");
var bases_opt = new NonTerminal("bases_opt");
var type_parameter_constraints_clause = new NonTerminal("type_parameter_constraints_clause");
var type_parameter_constraints_clauses_opt = new NonTerminal("type_parameter_constraints_clauses");
var type_parameter_constraint = new NonTerminal("type_parameter_constraint");
var type_parameter_constraints = new NonTerminal("type_parameter_constraints");
var member_declaration = new NonTerminal("member_declaration");
var member_declarations_opt = new NonTerminal("member_declarations_opt");
var constant_declaration = new NonTerminal("constant_declaration");
var field_declaration = new NonTerminal("field_declaration");
var method_declaration = new NonTerminal("method_declaration");
var property_declaration = new NonTerminal("property_declaration");
var event_declaration = new NonTerminal("event_declaration");
var indexer_declaration = new NonTerminal("indexer_declaration");
var constructor_declaration = new NonTerminal("constructor_declaration");
var destructor_declaration = new NonTerminal("destructor_declaration");
var constant_declarator = new NonTerminal("constant_declarator");
var constant_declarators = new NonTerminal("constant_declarators");
var modifier = new NonTerminal("modifier");
var modifiers_opt = new NonTerminal("modifiers_opt");
var member_header = new NonTerminal("member_header");
var accessor_name = new NonTerminal("accessor_name");
var accessor_declaration = new NonTerminal("accessor_declaration");
var accessor_declarations = new NonTerminal("accessor_declarations");
var accessor_modifier_opt = new NonTerminal("accessor_modifier_opt");
var event_body = new NonTerminal("event_body");
var event_accessor_declarations = new NonTerminal("event_accessor_declarations");
var add_accessor_declaration = new NonTerminal("add_accessor_declaration");
var remove_accessor_declaration = new NonTerminal("remove_accessor_declaration");
var indexer_name = new NonTerminal("indexer_name");
var operator_declaration = new NonTerminal("operator_declaration");
var conversion_operator_declaration = new NonTerminal("conversion_operator_declaration");
var overloadable_operator = new NonTerminal("overloadable_operator");
var operator_parameter = new NonTerminal("operator_parameter");
var operator_parameters = new NonTerminal("operator_parameters");
var conversion_operator_kind = new NonTerminal("conversion_operator_kind");
var constructor_initializer_opt = new NonTerminal("constructor_initializer_opt");
var constructor_base = new NonTerminal("constructor_base");
var variable_declarator = new NonTerminal("variable_declarator");
var variable_declarators = new NonTerminal("variable_declarators");
var method_body = new NonTerminal("method_body");
var formal_parameter_list = new NonTerminal("formal_parameter_list");
var formal_parameter_list_par = new NonTerminal("formal_parameter_list_par");
var fixed_parameter = new NonTerminal("fixed_parameter");
var fixed_parameters = new NonTerminal("fixed_parameters");
var parameter_modifier_opt = new NonTerminal("parameter_modifier_opt");
var parameter_array = new NonTerminal("parameter_array");
//B.2.8 struct
var struct_declaration = new NonTerminal("struct_declaration");
var struct_body = new NonTerminal("struct_body");
//B.2.9. Arrays
var rank_specifier = new NonTerminal("rank_specifier");
var rank_specifiers = new NonTerminal("rank_specifiers");
var rank_specifiers_opt = new NonTerminal("rank_specifiers_opt");
var dim_specifier = new NonTerminal("dim_specifier");
var dim_specifier_opt = new NonTerminal("dim_specifier_opt");
var list_initializer = new NonTerminal("array_initializer");
var list_initializer_opt = new NonTerminal("array_initializer_opt");
//B.2.10 Interfaces
var interface_declaration = new NonTerminal("interface_declaration");
var interface_body = new NonTerminal("interface_body");
var interface_member_declaration = new NonTerminal("interface_member_declaration");
var interface_member_declarations = new NonTerminal("interface_member_declarations");
var interface_method_declaration = new NonTerminal("interface_method_declaration");
var interface_property_declaration = new NonTerminal("interface_property_declaration");
var interface_event_declaration = new NonTerminal("interface_event_declaration");
var interface_indexer_declaration = new NonTerminal("interface_indexer_declaration");
var new_opt = new NonTerminal("new_opt");
var interface_accessor = new NonTerminal("interface_get_accessor");
var interface_accessors = new NonTerminal("interface_accessors");
//B.2.11 Enums
var enum_declaration = new NonTerminal("enum_declaration");
var enum_base_opt = new NonTerminal("enum_base_opt");
var enum_member_declaration = new NonTerminal("enum_member_declaration");
var enum_member_declarations = new NonTerminal("enum_member_declarations");
//B.2.13 Attributes
var attribute_section = new NonTerminal("attribute_section");
var attributes_opt = new NonTerminal("attributes_opt");
var attribute_target_specifier_opt = new NonTerminal("attribute_target_specifier_opt");
var attribute_target = new NonTerminal("attribute_target");
var attribute = new NonTerminal("attribute");
var attribute_list = new NonTerminal("attribute_list");
var attribute_arguments_opt = new NonTerminal("attribute_arguments");
var named_argument = new NonTerminal("named_argument");
var attr_arg = new NonTerminal("attr_arg");
var attribute_arguments_par_opt = new NonTerminal("attribute_arguments_par_opt");
#endregion
#region operators, punctuation and delimiters
RegisterOperators(1, "||");
RegisterOperators(2, "&&");
RegisterOperators(3, "|");
RegisterOperators(4, "^");
RegisterOperators(5, "&");
RegisterOperators(6, "==", "!=");
RegisterOperators(7, "<", ">", "<=", ">=", "is", "as");
RegisterOperators(8, "<<", ">>");
RegisterOperators(9, "+", "-");
RegisterOperators(10, "*", "/", "%");
//RegisterOperators(11, ".");
// RegisterOperators(12, "++", "--");
#region comments
//The following makes sense, if you think about "?" in context of operator precedence.
// What we say here is that "?" has the lowest priority among arithm operators.
// Therefore, the parser should prefer reduce over shift when input symbol is "?".
// For ex., when seeing ? in expression "a + b?...", the parser will perform Reduce:
// (a + b)->expr
// and not shift the "?" symbol.
// Same goes for ?? symbol
#endregion
RegisterOperators(-3, "=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=");
RegisterOperators(-2, "?");
RegisterOperators(-1, "??");
this.Delimiters = "{}[](),:;+-*/%&|^!~<>=";
this.MarkPunctuation(";", ",", "(", ")", "{", "}", "[", "]", ":");
this.MarkTransient(namespace_member_declaration, member_declaration, type_declaration, statement, embedded_statement, expression,
literal, bin_op, primary_expression, expression);
this.AddTermsReportGroup("assignment", "=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=");
this.AddTermsReportGroup("typename", "bool", "decimal", "float", "double", "string", "object",
"sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "char");
this.AddTermsReportGroup("statement", "if", "switch", "do", "while", "for", "foreach", "continue", "goto", "return", "try", "yield",
"break", "throw", "unchecked", "using");
this.AddTermsReportGroup("type declaration", "public", "private", "protected", "static", "internal", "sealed", "abstract", "partial",
"class", "struct", "delegate", "interface", "enum");
this.AddTermsReportGroup("member declaration", "virtual", "override", "readonly", "volatile", "extern");
this.AddTermsReportGroup("constant", Number, StringLiteral, CharLiteral);
this.AddTermsReportGroup("constant", "true", "false", "null");
this.AddTermsReportGroup("unary operator", "+", "-", "!", "~");
this.AddToNoReportGroup(comma, semi);
this.AddToNoReportGroup("var", "const", "new", "++", "--", "this", "base", "checked", "lock", "typeof", "default",
"{", "}", "[");
//
#endregion
#region "<" conflict resolution
var gen_lt = new NonTerminal("gen_lt");
gen_lt.Rule = CustomActionHere(this.ResolveLessThanConflict) + "<";
#endregion
/*
#region Keywords
string strKeywords =
"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";
AddKeywordList(strKeywords);
#endregion
*/
// RULES
//B.2.1. Basic concepts
//qual_name_with_targs is an alias for namespace-name, namespace-or-type-name, type-name,
generic_dimension_specifier.Rule = gen_lt + commas_opt + ">";
qual_name_segments_opt.Rule = MakeStarRule(qual_name_segments_opt, null, qual_name_segment);
identifier_or_builtin.Rule = identifier | builtin_type;
identifier_ext.Rule = identifier_or_builtin | "this" | "base";
qual_name_segment.Rule = dot + identifier
| "::" + identifier
| type_argument_list;
//generic_dimension_specifier.Rule = lt + commas_opt + ">";
generic_dimension_specifier.Rule = gen_lt + commas_opt + ">";
qual_name_with_targs.Rule = identifier_or_builtin + qual_name_segments_opt;
type_argument_list.Rule = gen_lt + type_ref_list + ">";
type_argument_list_opt.Rule = Empty | type_argument_list;
typearg_or_gendimspec_list.Rule = type_argument_list | generic_dimension_specifier_opt;
//B.2.2. Types
type_or_void.Rule = qual_name_with_targs | "void";
builtin_type.Rule = integral_type | "bool" | "decimal" | "float" | "double" | "string" | "object";
type_ref.Rule = type_or_void + qmark_opt + rank_specifiers_opt + typearg_or_gendimspec_list;
type_ref_list.Rule = MakePlusRule(type_ref_list, comma, type_ref);
var comma_list_opt = new NonTerminal("comma_list_opt");
comma_list_opt.Rule = MakeStarRule(comma_list_opt, comma);
rank_specifier.Rule = "[" + comma_list_opt + "]";
rank_specifiers.Rule = MakePlusRule(rank_specifiers, null, rank_specifier);
rank_specifiers_opt.Rule = rank_specifiers.Q();
integral_type.Rule = ToTerm("sbyte") | "byte" | "short" | "ushort" | "int" | "uint" | "long" | "ulong" | "char";
//B.2.4. Variables
//Quite strange in specs -
// variable-reference:
// expression
// Is that case it would be possible to do the following:
// GetMyStuff(out (a+b));
// but MS c# rejects it
//B.2.4. Expressions
argument.Rule = expression | "ref" + identifier | "out" + identifier;
argument_list.Rule = MakePlusRule(argument_list, comma, argument);
argument_list_opt.Rule = Empty | argument_list;
expression.Rule = conditional_expression
| bin_op_expression
| typecast_expression
| primary_expression;
expression_opt.Rule = Empty | expression;
expression_list.Rule = MakePlusRule(expression_list, comma, expression);
unary_operator.Rule = ToTerm("+") | "-" | "!" | "~" | "*";
assignment_operator.Rule = ToTerm("=") | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=";
conditional_expression.Rule = expression + PreferShiftHere() + qmark + expression + colon + expression;// + ReduceThis();
bin_op_expression.Rule = expression + bin_op + expression;
typecast_expression.Rule = parenthesized_expression + primary_expression;
primary_expression.Rule =
literal
| unary_expression
| parenthesized_expression
| member_access
| pre_incr_decr_expression
| post_incr_decr_expression
| object_creation_expression
| anonymous_object_creation_expression
| typeof_expression
| checked_expression
| unchecked_expression
| default_value_expression
| anonymous_method_expression;
unary_expression.Rule = unary_operator + primary_expression;
dim_specifier.Rule = "[" + expression_list + "]";
dim_specifier_opt.Rule = dim_specifier.Q();
literal.Rule = Number | StringLiteral | CharLiteral | "true" | "false" | "null";
parenthesized_expression.Rule = Lpar + expression + Rpar;
pre_incr_decr_expression.Rule = incr_or_decr + member_access;
post_incr_decr_expression.Rule = member_access + incr_or_decr;
//joined invocation_expr and member_access; for member access left the most general variant
member_access.Rule = identifier_ext + member_access_segments_opt;
member_access_segments_opt.Rule = MakeStarRule(member_access_segments_opt, null, member_access_segment);
member_access_segment.Rule = dot + identifier
| array_indexer
| argument_list_par
| type_argument_list;
array_indexer.Rule = "[" + expression_list + "]";
argument_list_par.Rule = Lpar + argument_list_opt + Rpar;
argument_list_par_opt.Rule = Empty | argument_list_par;
list_initializer.Rule = Lbr + elem_initializer_list_ext + Rbr;
list_initializer_opt.Rule = list_initializer.Q();
elem_initializer.Rule = initializer_value | identifier + "=" + initializer_value;
elem_initializer_list.Rule = MakePlusRule(elem_initializer_list, comma, elem_initializer);
elem_initializer_list_ext.Rule = Empty | elem_initializer_list + comma_opt;
initializer_value.Rule = expression | list_initializer;
//delegate, anon-object, object
object_creation_expression.Rule = "new" + qual_name_with_targs + qmark_opt + creation_args + list_initializer_opt;
creation_args.Rule = dim_specifier | rank_specifier | argument_list_par;
anonymous_object_creation_expression.Rule = "new" + anonymous_object_initializer;
anonymous_object_initializer.Rule = Lbr + Rbr | Lbr + member_declarator_list + comma_opt + Rbr;
member_declarator.Rule = expression | identifier + "=" + expression;
member_declarator_list.Rule = MakePlusRule(member_declarator_list, comma, member_declarator);
//typeof
typeof_expression.Rule = "typeof" + Lpar + type_ref + Rpar;
generic_dimension_specifier_opt.Rule = Empty | gen_lt + commas_opt + ">";
//checked, unchecked
checked_expression.Rule = "checked" + parenthesized_expression;
unchecked_expression.Rule = "unchecked" + parenthesized_expression;
//default-value
default_value_expression.Rule = "default" + Lpar + type_ref + Rpar;
//note: we treat ?? as bin-operation, so null-coalesce-expr used in spec as first (condition) component is replaced with expression
// we resolve all this expr hierarchies of binary expressions using precedence
//anonymous method and lambda - we join explicit and implicit param definitions, making 'type' element optional
// TODO: add after-parse check for this
anonymous_method_expression.Rule = "delegate" + anonymous_function_signature_opt + block;
lambda_expression.Rule = lambda_function_signature + "=>" + anonymous_function_body;
lambda_function_signature.Rule = anonymous_function_signature | identifier;
anonymous_function_signature.Rule = Lpar + anonymous_function_parameter_list_opt + Rpar;
anonymous_function_signature_opt.Rule = anonymous_function_signature.Q();
anonymous_function_parameter_modifier_opt.Rule = Empty | "ref" | "out";
anonymous_function_parameter.Rule = anonymous_function_parameter_modifier_opt + anonymous_function_parameter_decl;
anonymous_function_parameter_decl.Rule = identifier | type_ref + identifier;
anonymous_function_parameter_list_opt.Rule = MakeStarRule(anonymous_function_parameter_list_opt, comma, anonymous_function_parameter_decl);
anonymous_function_body.Rule = expression | block;
//we don't use grammar expressions to specify operator precedence, so we combine all these grammar elements together
// and define just bin_op_expression. Where to put it?
// In spec: non_assignment_expression.Rule = conditional_expression | lambda_expression | query_expression;
//I think it's a mistake; there must be additional entry here for arithm expressions, so we put them here.
// We also have to add "is" and "as" expressions here, as we don't build entire hierarchy of elements for expressing
// precedence (where they appear in original spec); so we put them here
bin_op.Rule = ToTerm("<")
| "||" | "&&" | "|" | "^" | "&" | "==" | "!=" | ">" | "<=" | ">=" | "<<" | ">>" | "+" | "-" | "*" | "/" | "%"
| "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>="
| "is" | "as" | "??";
//type_check_expression.Rule = expression + "is" + type_ref | expression + "as" + type_ref;
//Queries
query_expression.Rule = "from";
//B.2.5. Statements
statement.Rule = labeled_statement | declaration_statement | embedded_statement;
statement.ErrorRule = SyntaxError + semi; //skip all until semicolon
statement_list.Rule = MakePlusRule(statement_list, null, statement);
statement_list_opt.Rule = Empty | statement_list;
//labeled_statement
labeled_statement.Rule = identifier + colon + embedded_statement;
//declaration_statement
declaration_statement.Rule = local_variable_declaration + semi | local_constant_declaration + semi;
local_variable_declaration.Rule = local_variable_type + local_variable_declarators; //!!!
local_variable_type.Rule = member_access | "var"; // | builtin_type; //to fix the conflict, changing to member-access here
local_variable_declarator.Rule = identifier | identifier + "=" + initializer_value;
local_variable_declarators.Rule = MakePlusRule(local_variable_declarators, comma, local_variable_declarator);
local_constant_declaration.Rule = "const" + type_ref + constant_declarators;
//embedded_statement
embedded_statement.Rule = block | semi /*empty_statement*/ | statement_expression + semi | selection_statement
| iteration_statement | jump_statement | try_statement | checked_statement | unchecked_statement
| lock_statement | using_statement | yield_statement;
block.Rule = Lbr + statement_list_opt + Rbr;
//selection (if and switch)
selection_statement.Rule = if_statement | switch_statement;
if_statement.Rule = ToTerm("if") + Lpar + expression + Rpar + embedded_statement + else_clause_opt;
else_clause_opt.Rule = Empty | PreferShiftHere() + "else" + embedded_statement;
switch_statement.Rule = "switch" + parenthesized_expression + Lbr + switch_sections_opt + Rbr;
switch_section.Rule = switch_labels + statement_list;
switch_sections_opt.Rule = MakeStarRule(switch_sections_opt, null, switch_section);
switch_label.Rule = "case" + expression + colon | "default" + colon;
switch_labels.Rule = MakePlusRule(switch_labels, null, switch_label);
//iteration statements
iteration_statement.Rule = while_statement | do_statement | for_statement | foreach_statement;
while_statement.Rule = "while" + parenthesized_expression + embedded_statement;
do_statement.Rule = "do" + embedded_statement + "while" + parenthesized_expression + semi;
for_statement.Rule = "for" + Lpar + for_initializer_opt + semi + for_condition_opt + semi + for_iterator_opt + Rpar + embedded_statement;
for_initializer_opt.Rule = Empty | local_variable_declaration | statement_expression_list;
for_condition_opt.Rule = Empty | expression;
for_iterator_opt.Rule = Empty | statement_expression_list;
foreach_statement.Rule = "foreach" + Lpar + local_variable_type + identifier + "in" + expression + Rpar + embedded_statement;
//jump-statement
jump_statement.Rule = break_statement | continue_statement | goto_statement | return_statement | throw_statement;
break_statement.Rule = "break" + semi;
continue_statement.Rule = "continue" + semi;
goto_statement.Rule = tgoto + identifier + semi | tgoto + "case" + expression + semi | tgoto + "default" + semi;
return_statement.Rule = "return" + expression_opt + semi;
throw_statement.Rule = "throw" + expression_opt + semi;
//try-statement
//changed to avoid conflicts; need to check correct ordering of catch/finally clause in after-parse validation
try_statement.Rule = "try" + block + try_clauses;
try_clause.Rule = catch_clause | finally_clause;
try_clauses.Rule = MakePlusRule(try_clauses, null, try_clause);
catch_clause.Rule = "catch" + catch_specifier_opt + block;
finally_clause.Rule = "finally" + block;
catch_specifier_opt.Rule = Empty | Lpar + qual_name_with_targs + identifier_opt + Rpar;
identifier_opt.Rule = Empty | identifier;
//checked, unchecked, locked, using
checked_statement.Rule = "checked" + block;
unchecked_statement.Rule = "unchecked" + block;
lock_statement.Rule = "lock" + parenthesized_expression + embedded_statement;
using_statement.Rule = "using" + Lpar + resource_acquisition + Rpar + embedded_statement;
resource_acquisition.Rule = local_variable_declaration | expression;
//yield statement
yield_statement.Rule = yld + "return" + expression + semi | yld + "break" + semi;
//expression statement
// expression_statement.Rule = statement_expression + semi;
statement_expression.Rule = object_creation_expression
| member_access | member_access + assignment_operator + expression
| pre_incr_decr_expression | post_incr_decr_expression
;
statement_expression_list.Rule = MakePlusRule(statement_expression_list, comma, statement_expression);
incr_or_decr_opt.Rule = Empty | ToTerm("++") | "--";
incr_or_decr.Rule = ToTerm("++") | "--";
//B.2.6. Namespaces
this.Root = compilation_unit;
compilation_unit.Rule = extern_alias_directives_opt
+ using_directives_opt
+ attributes_opt + namespace_declarations_opt;
extern_alias_directive.Rule = PreferShiftHere() + ToTerm("extern") + "alias" + identifier + semi;
extern_alias_directives_opt.Rule = MakeStarRule(extern_alias_directives_opt, null, extern_alias_directive);
namespace_declaration.Rule = "namespace" + qualified_identifier + namespace_body + semi_opt;
namespace_declarations_opt.Rule = MakeStarRule(namespace_declarations_opt, null, namespace_declaration);
qualified_identifier.Rule = MakePlusRule(qualified_identifier, dot, identifier);
namespace_body.Rule = "{" + extern_alias_directives_opt + using_directives_opt + namespace_member_declarations + "}";
using_directive.Rule = using_alias_directive | using_ns_directive;
using_directives.Rule = MakePlusRule(using_directives, null, using_directive);
using_directives_opt.Rule = Empty | using_directives;
using_alias_directive.Rule = "using" + identifier + "=" + qual_name_with_targs + semi;
using_ns_directive.Rule = "using" + qual_name_with_targs + semi;
namespace_member_declaration.Rule = namespace_declaration | type_declaration;
namespace_member_declarations.Rule = MakePlusRule(namespace_member_declarations, null, namespace_member_declaration);
type_declaration.Rule = class_declaration | struct_declaration | interface_declaration | enum_declaration | delegate_declaration;
//B.2.7. Classes
class_declaration.Rule = member_header + "class" + identifier + type_parameter_list_opt +
bases_opt + type_parameter_constraints_clauses_opt + class_body;
class_body.Rule = Lbr + member_declarations_opt + Rbr;
bases_opt.Rule = Empty | colon + base_type_list;
base_type_list.Rule = MakePlusRule(base_type_list, comma, qual_name_with_targs);
//Type parameters
type_parameter.Rule = attributes_opt + identifier;
type_parameters.Rule = MakePlusRule(type_parameters, comma, type_parameter);
type_parameter_list_opt.Rule = Empty | gen_lt + type_parameters + ">";
type_parameter_constraints_clause.Rule = "where" + type_parameter + colon + type_parameter_constraints;
type_parameter_constraints.Rule = MakePlusRule(type_parameter_constraints, comma, type_parameter_constraint);
type_parameter_constraints_clauses_opt.Rule = MakeStarRule(type_parameter_constraints_clauses_opt, null, type_parameter_constraints_clause);
//Note for post-processing - make sure the order is correct: new() is always last, etc. See p.503 of the spec
type_parameter_constraint.Rule = qual_name_with_targs | "class" | "struct" | ToTerm("new") + Lpar + Rpar;
//Class members
//Note: we split operator-declaration into two separate operator elements: bin/unary and conversion operators
// to avoid possible ambiguities and conflicts
member_declaration.Rule = constant_declaration | field_declaration | method_declaration
| property_declaration | event_declaration | indexer_declaration
| operator_declaration | conversion_operator_declaration
| constructor_declaration | destructor_declaration | type_declaration;
member_declaration.ErrorRule = SyntaxError + ";" | SyntaxError + "}" ;
member_declarations_opt.Rule = MakeStarRule(member_declarations_opt, null, member_declaration);
//Modifiers - see note #1 in Notes.txt file
modifier.Rule = ToTerm("new") | "public" | "protected" | "internal" | "private" | "static" | "virtual" | "sealed" |
"override" | "abstract" | "readonly" | "volatile" | "partial" | "extern"; //!!!
modifiers_opt.Rule = MakeStarRule(modifiers_opt, null, modifier);
//Joined member header - see note #2
member_header.Rule = attributes_opt + modifiers_opt;
constant_declaration.Rule = member_header + "const" + type_ref + constant_declarators + semi;
constant_declarator.Rule = identifier + "=" + expression;
constant_declarators.Rule = MakePlusRule(constant_declarators, comma, constant_declarator);
field_declaration.Rule = member_header + type_ref + variable_declarators + semi;
variable_declarator.Rule = identifier | identifier + "=" + elem_initializer;
variable_declarators.Rule = MakePlusRule(variable_declarators, comma, variable_declarator);
//See note #3 about merging type_parameter_list into type_arguments of the preceding qual_name.
method_declaration.Rule = member_header + type_ref + qual_name_with_targs // + type_parameter_list.Q()
+ formal_parameter_list_par + type_parameter_constraints_clauses_opt + method_body;
formal_parameter_list.Rule = fixed_parameters | fixed_parameters + comma + parameter_array | parameter_array;
formal_parameter_list_par.Rule = Lpar + Rpar | Lpar + formal_parameter_list + Rpar;
fixed_parameter.Rule = attributes_opt + parameter_modifier_opt + type_ref + identifier;
fixed_parameters.Rule = MakePlusRule(fixed_parameters, comma, fixed_parameter);
parameter_modifier_opt.Rule = Empty | "ref" | "out" | "this";
parameter_array.Rule = attributes_opt + "params" + type_ref + /*"[" + "]" + */ identifier;
method_body.Rule = block | semi;
// See note #4 about member-name
//TODO: add after-parse validation that no more than one accessor of each type is there.
property_declaration.Rule = member_header + type_ref + qual_name_with_targs/*member-name*/ + Lbr + accessor_declarations + Rbr;
accessor_declaration.Rule = attributes_opt + accessor_modifier_opt + accessor_name + block;
accessor_declarations.Rule = MakePlusRule(accessor_declarations, null, accessor_declaration);
accessor_name.Rule = ToTerm("get") | "set";
accessor_modifier_opt.Rule = Empty | "protected" | "internal" | "private" |
ToTerm("protected") + "internal" | ToTerm("internal") + "protected";
event_declaration.Rule = member_header + "event" + type_ref + event_body;
event_body.Rule = variable_declarators + semi | qual_name_with_targs + Lbr + event_accessor_declarations + Rbr;
event_accessor_declarations.Rule = add_accessor_declaration + remove_accessor_declaration |
remove_accessor_declaration + add_accessor_declaration;
add_accessor_declaration.Rule = attributes_opt + "add" + block;
remove_accessor_declaration.Rule = attributes_opt + "remove" + block;
//indexer
indexer_declaration.Rule = member_header + type_ref + indexer_name + "[" + formal_parameter_list + "]" +
Lbr + accessor_declarations + Rbr;
indexer_name.Rule = "this" | qual_name_with_targs + dot + "this";
//operator
// note: difference with specs - we separate unary/binary operators from conversion operator,
// and join binary and unary operator definitions, see note #5
operator_declaration.Rule = member_header + type_ref + "operator" + overloadable_operator + Lpar + operator_parameters + Rpar + block;
overloadable_operator.Rule = ToTerm("+") | "-" | "!" | "~" | "++" | "--" | "true" | "false" //unary operators
| "*" | "/" | "%" | "&" | "|" | "^" | "<<" | ">>" | "==" | "!=" | ">" | "<" | ">=" | "<=";
operator_parameters.Rule = operator_parameter | operator_parameter + comma + operator_parameter;
operator_parameter.Rule = type_ref + identifier;
conversion_operator_declaration.Rule = member_header + conversion_operator_kind +
"operator" + type_ref + Lpar + operator_parameter + Rpar + block;
conversion_operator_kind.Rule = ToTerm("implicit") | "explicit";
//constructor - also covers static constructor; the only difference is the word static
constructor_declaration.Rule = member_header + identifier + formal_parameter_list_par +
constructor_initializer_opt + block;
constructor_initializer_opt.Rule = Empty | colon + constructor_base + argument_list_par;
constructor_base.Rule = ToTerm("this") | "base";
destructor_declaration.Rule = member_header + // changed from Symbol("extern").Q()
"~" + identifier + Lpar + Rpar + block;
//B.2.8
struct_declaration.Rule = member_header + "struct" + identifier + type_parameter_list_opt + bases_opt
+ type_parameter_constraints_clauses_opt + struct_body;
struct_body.Rule = Lbr + member_declarations_opt + Rbr;
//B.2.9. Arrays
//B.2.10 Interface
interface_declaration.Rule = member_header + "interface" + identifier + type_parameter_list_opt + bases_opt
+ type_parameter_constraints_clauses_opt + interface_body;
interface_body.Rule = Lbr + interface_member_declarations + Rbr;
interface_member_declaration.Rule = interface_method_declaration | interface_property_declaration
| interface_event_declaration | interface_indexer_declaration;
interface_member_declarations.Rule = MakePlusRule(interface_member_declarations, null, interface_member_declaration);
interface_method_declaration.Rule = attributes_opt + new_opt + type_ref + identifier + type_parameter_list_opt +
formal_parameter_list_par + type_parameter_constraints_clauses_opt + semi;
//NOte: changing type to type_ref to fix the conflict
//Note: add after-parse validation that no more than one accessor of each type is there.
interface_property_declaration.Rule = attributes_opt + new_opt + type_ref + identifier + Lbr + interface_accessors + Rbr;
interface_accessor.Rule = attributes_opt + accessor_name + semi;
interface_accessors.Rule = MakePlusRule(interface_accessors, null, interface_accessor);
interface_event_declaration.Rule = attributes_opt + new_opt + "event" + type_ref + identifier;
interface_indexer_declaration.Rule = attributes_opt + new_opt + type_ref + "this" +
"[" + formal_parameter_list + "]" + Lbr + interface_accessors + Rbr;
new_opt.Rule = Empty | "new";
//B.2.11 Enums
enum_declaration.Rule = member_header + "enum" + identifier + enum_base_opt + Lbr + enum_member_declarations + Rbr + semi_opt;
enum_base_opt.Rule = Empty | colon + integral_type;
enum_member_declaration.Rule = attributes_opt + identifier | attributes_opt + identifier + "=" + expression;
enum_member_declarations.Rule = MakeListRule(enum_member_declarations, comma, enum_member_declaration, TermListOptions.PlusList | TermListOptions.AllowTrailingDelimiter);
//B.2.12 Delegates
delegate_declaration.Rule = member_header + "delegate" + type_ref + identifier +
type_parameter_list_opt + formal_parameter_list_par + type_parameter_constraints_clauses_opt + semi;
//B.2.13. Attributes
attributes_opt.Rule = MakeStarRule(attributes_opt, null, attribute_section);
attribute_section.Rule = "[" + attribute_target_specifier_opt + attribute_list + comma_opt + "]";
attribute_list.Rule = MakePlusRule(attribute_list, comma, attribute);
attribute.Rule = qual_name_with_targs + attribute_arguments_par_opt;
attribute_target_specifier_opt.Rule = Empty | attribute_target + colon;
attribute_target.Rule = ToTerm("field") | "event" | "method" | "param" | "property" | "return" | "type";
attribute_arguments_par_opt.Rule = Empty | Lpar + attribute_arguments_opt + Rpar;
attribute_arguments_opt.Rule = MakeStarRule(attribute_arguments_opt, comma, attr_arg);
attr_arg.Rule = identifier + "=" + expression | expression;
//Prepare term set for conflict resolution
_skipTokensInPreview.UnionWith(new Terminal[] { dot, identifier, comma, ToTerm("::"), comma, ToTerm("["), ToTerm("]") });
}
#region conflict resolution for "<"
/* The shift-reduce conflict for "<" symbol is the problem of deciding what is "<" symbol in the input - is it
* opening brace for generic reference, or logical operator. The following is a printout of parser state that has a conflict
* The handling code needs to run ahead and decide a proper action: if we see ">", then it is a generic bracket and we do shift;
* otherwise, it is an operator and we make Reduce
*
State S188 (Inadequate)
Shift items:
member_access_segments_opt -> member_access_segments_opt <20>member_access_segment
member_access_segment -> <20>. Identifier
member_access_segment -> <20>array_indexer
array_indexer -> <20>[ expression_list ]
member_access_segment -> <20>argument_list_par
argument_list_par -> <20>( argument_list_opt )
member_access_segment -> <20>type_argument_list
type_argument_list -> <20>_<_ type_ref_list >
_<_ -> <20><
Reduce items:
member_access -> identifier_ext member_access_segments_opt <20> [? , ) : ; } ] Identifier ++ -- || && | ^ & == != > <= >= << >> + - * / % = += -= *= /= %= &= |= ^= <<= >>= is as ?? <]
Shifts: member_access_segment->S220, .->S221, array_indexer->S222, [->S223, argument_list_par->S224, (->S225, type_argument_list->S226, _<_->S59,
*/
//Here is an elaborate generic declaration which can be used as a good test. Perfectly legal, uncomment it to check that c#
// accepts it:
// List<Dictionary<string, object[,]>> genericVar;
private void ResolveLessThanConflict(ParsingContext context, CustomParserAction customAction) {
var scanner = context.Parser.Scanner;
string previewSym = null;
if (context.CurrentParserInput.Term.Name == "<") {
scanner.BeginPreview();
int ltCount = 0;
while(true) {
//Find first token ahead (using preview mode) that is either end of generic parameter (">") or something else
Token preview;
do {
preview = scanner.GetToken();
} while (_skipTokensInPreview.Contains(preview.Terminal) && preview.Terminal != base.Eof);
//See what did we find
previewSym = preview.Terminal.Name;
if (previewSym == "<")
ltCount++;
else if (previewSym == ">" && ltCount > 0) {
ltCount--;
continue;
} else
break;
}
scanner.EndPreview(true); //keep previewed tokens; important to keep ">>" matched to two ">" symbols, not one combined symbol (see method below)
}//if
//if we see ">", then it is type argument, not operator
ParserAction action;
if (previewSym == ">")
action = customAction.ShiftActions.First(a => a.Term.Name == "<");
else
action = customAction.ReduceActions.First();
// Actually execute action
action.Execute(context);
}
//In preview, we may run into combination '>>' which is a comletion of nested generic parameters.
// It should be recognized as two ">" symbols, not a single ">>" operator
// By default, the ">>" has higher priority over single ">" symbol because it is longer.
// When this method is called we force the selection to a single ">"
public override void OnScannerSelectTerminal(ParsingContext context) {
if (context.Source.PreviewChar == '>' && context.Status == ParserStatus.Previewing) {
context.CurrentTerminals.Clear();
context.CurrentTerminals.Add(ToTerm(">")); //select the ">" terminal
}
base.OnScannerSelectTerminal(context);
}
#endregion
// See http://www.jaggersoft.com/csharp_standard/9.3.3.htm
public override void SkipWhitespace(ISourceStream source) {
while (!source.EOF()) {
var ch = source.PreviewChar;
switch (ch) {
case ' ':
case '\t':
case '\r':
case '\n':
case '\v':
case '\u2085':
case '\u2028':
case '\u2029':
source.PreviewPosition++;
break;
default:
//Check unicode class Zs
UnicodeCategory chCat = char.GetUnicodeCategory(ch);
if (chCat == UnicodeCategory.SpaceSeparator) //it is whitespace, continue moving
continue;//while loop
//Otherwize return
return;
}//switch
}//while
}
}//class
}//namespace