%{ // // cs-parser.jay: The Parser for the C# compiler // // Authors: Miguel de Icaza (miguel@gnu.org) // Ravi Pratap (ravi@ximian.com) // Marek Safar (marek.safar@gmail.com) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) // (C) 2004 Novell, Inc // // TODO: // (1) Figure out why error productions dont work. `type-declaration' is a // great spot to put an `error' because you can reproduce it with this input: // "public X { }" // // Possible optimization: // Run memory profiler with parsing only, and consider dropping // arraylists where not needed. Some pieces can use linked lists. // using System.Text; using System.IO; using System; namespace Mono.CSharp { using System.Collections; /// /// The C# Parser /// public class CSharpParser { NamespaceEntry current_namespace; TypeContainer current_container; DeclSpace current_class; IAnonymousHost anonymous_host; /// /// Current block is used to add statements as we find /// them. /// Block current_block; Delegate current_delegate; GenericMethod current_generic_method; AnonymousMethodExpression current_anonymous_method; /// /// This is used by the unary_expression code to resolve /// a name against a parameter. /// // FIXME: This is very ugly and it's very hard to reset it correctly // on all places, especially when some parameters are autogenerated. Parameters current_local_parameters; /// /// Using during property parsing to describe the implicit /// value parameter that is passed to the "set" and "get"accesor /// methods (properties and indexers). /// FullNamedExpression implicit_value_parameter_type; Parameters indexer_parameters; /// /// Hack to help create non-typed array initializer /// public static FullNamedExpression current_array_type; FullNamedExpression pushed_current_array_type; /// /// Used to determine if we are parsing the get/set pair /// of an indexer or a property /// bool parsing_indexer; bool parsing_anonymous_method; /// /// An out-of-band stack. /// static Stack oob_stack; /// /// Switch stack. /// Stack switch_stack; static public int yacc_verbose_flag; /// /// The current file. /// CompilationUnit file; /// /// Temporary Xml documentation cache. /// For enum types, we need one more temporary store. /// string tmpComment; string enumTypeComment; /// Current attribute target string current_attr_target; /// assembly and module attribute definitions are enabled bool global_attrs_enabled = true; bool has_get, has_set; bool parameter_modifiers_not_allowed; bool params_modifiers_not_allowed; bool arglist_allowed; %} %token EOF %token NONE /* This token is never returned by our lexer */ %token ERROR // This is used not by the parser, but by the tokenizer. // do not remove. /* *These are the C# keywords */ %token FIRST_KEYWORD %token ABSTRACT %token AS %token ADD %token ASSEMBLY %token BASE %token BOOL %token BREAK %token BYTE %token CASE %token CATCH %token CHAR %token CHECKED %token CLASS %token CONST %token CONTINUE %token DECIMAL %token DEFAULT %token DELEGATE %token DO %token DOUBLE %token ELSE %token ENUM %token EVENT %token EXPLICIT %token EXTERN %token FALSE %token FINALLY %token FIXED %token FLOAT %token FOR %token FOREACH %token GOTO %token IF %token IMPLICIT %token IN %token INT %token INTERFACE %token INTERNAL %token IS %token LOCK %token LONG %token NAMESPACE %token NEW %token NULL %token OBJECT %token OPERATOR %token OUT %token OVERRIDE %token PARAMS %token PRIVATE %token PROTECTED %token PUBLIC %token READONLY %token REF %token RETURN %token REMOVE %token SBYTE %token SEALED %token SHORT %token SIZEOF %token STACKALLOC %token STATIC %token STRING %token STRUCT %token SWITCH %token THIS %token THROW %token TRUE %token TRY %token TYPEOF %token UINT %token ULONG %token UNCHECKED %token UNSAFE %token USHORT %token USING %token VIRTUAL %token VOID %token VOLATILE %token WHERE %token WHILE %token ARGLIST %token PARTIAL %token ARROW %token QUERY_FIRST_TOKEN %token FROM %token JOIN %token ON %token EQUALS %token SELECT %token GROUP %token BY %token LET %token ORDERBY %token ASCENDING %token DESCENDING %token INTO %token QUERY_LAST_TOKEN /* C# keywords which are not really keywords */ %token GET "get" %token SET "set" %left LAST_KEYWORD /* C# single character operators/punctuation. */ %token OPEN_BRACE "{" %token CLOSE_BRACE "}" %token OPEN_BRACKET "[" %token CLOSE_BRACKET "]" %token OPEN_PARENS "(" %token CLOSE_PARENS ")" %token DOT "." %token COMMA "," %token COLON ":" %token SEMICOLON ";" %token TILDE "~" %token PLUS "+" %token MINUS "-" %token BANG "!" %token ASSIGN "=" %token OP_LT "<" %token OP_GENERICS_LT "<" %token OP_GT ">" %token OP_GENERICS_GT ">" %token BITWISE_AND "&" %token BITWISE_OR "|" %token STAR "*" %token PERCENT "%" %token DIV "/" %token CARRET "^" %token INTERR "?" /* C# multi-character operators. */ %token DOUBLE_COLON "::" %token OP_INC "++" %token OP_DEC "--" %token OP_SHIFT_LEFT "<<" %token OP_SHIFT_RIGHT ">>" %token OP_LE "<=" %token OP_GE ">=" %token OP_EQ "==" %token OP_NE "!=" %token OP_AND "&&" %token OP_OR "||" %token OP_MULT_ASSIGN "*=" %token OP_DIV_ASSIGN "/=" %token OP_MOD_ASSIGN "%=" %token OP_ADD_ASSIGN "+=" %token OP_SUB_ASSIGN "-=" %token OP_SHIFT_LEFT_ASSIGN "<<=" %token OP_SHIFT_RIGHT_ASSIGN ">>=" %token OP_AND_ASSIGN "&=" %token OP_XOR_ASSIGN "^=" %token OP_OR_ASSIGN "|=" %token OP_PTR "->" %token OP_COALESCING "??" /* Numbers */ %token LITERAL_INTEGER "int literal" %token LITERAL_FLOAT "float literal" %token LITERAL_DOUBLE "double literal" %token LITERAL_DECIMAL "decimal literal" %token LITERAL_CHARACTER "character literal" %token LITERAL_STRING "string literal" %token IDENTIFIER %token OPEN_PARENS_LAMBDA %token CLOSE_PARENS_CAST %token CLOSE_PARENS_NO_CAST %token CLOSE_PARENS_OPEN_PARENS %token CLOSE_PARENS_MINUS %token DEFAULT_OPEN_PARENS %token GENERIC_DIMENSION %token DEFAULT_COLON /* Add precedence rules to solve dangling else s/r conflict */ %nonassoc LOWPREC %nonassoc IF %nonassoc ELSE %right ASSIGN %left OP_OR %left OP_AND %left BITWISE_OR %left BITWISE_AND %left OP_SHIFT_LEFT OP_SHIFT_RIGHT %left PLUS MINUS %left STAR DIV PERCENT %right BANG CARRET UMINUS %nonassoc OP_INC OP_DEC %left OPEN_PARENS %left OPEN_BRACKET OPEN_BRACE %left DOT %nonassoc HIGHPREC %start compilation_unit %% compilation_unit : outer_declarations opt_EOF | outer_declarations global_attributes opt_EOF | global_attributes opt_EOF | opt_EOF /* allow empty files */ ; opt_EOF : /* empty */ { Lexer.check_incorrect_doc_comment (); } | EOF { Lexer.check_incorrect_doc_comment (); } ; outer_declarations : outer_declaration | outer_declarations outer_declaration ; outer_declaration : extern_alias_directive | using_directive | namespace_member_declaration ; extern_alias_directives : extern_alias_directive | extern_alias_directives extern_alias_directive; extern_alias_directive : EXTERN IDENTIFIER IDENTIFIER SEMICOLON { LocatedToken lt = (LocatedToken) $2; string s = lt.Value; if (s != "alias"){ Report.Error (1003, lt.Location, "'alias' expected"); } else if (RootContext.Version == LanguageVersion.ISO_1) { Report.FeatureIsNotAvailable (lt.Location, "external alias"); } else { lt = (LocatedToken) $3; current_namespace.AddUsingExternalAlias (lt.Value, lt.Location); } } ; using_directives : using_directive | using_directives using_directive ; using_directive : using_alias_directive { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } | using_namespace_directive { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } ; using_alias_directive : USING IDENTIFIER ASSIGN namespace_or_type_name SEMICOLON { LocatedToken lt = (LocatedToken) $2; current_namespace.AddUsingAlias (lt.Value, (MemberName) $4, (Location) $1); } | USING error { CheckIdentifierToken (yyToken, GetLocation ($2)); } ; using_namespace_directive : USING namespace_name SEMICOLON { current_namespace.AddUsing ((MemberName) $2, (Location) $1); } ; // // Strictly speaking, namespaces don't have attributes but // we parse global attributes along with namespace declarations and then // detach them // namespace_declaration : opt_attributes NAMESPACE qualified_identifier { MemberName name = (MemberName) $3; if ($1 != null) { Report.Error(1671, name.Location, "A namespace declaration cannot have modifiers or attributes"); } current_namespace = new NamespaceEntry ( current_namespace, file, name.GetName ()); current_class = current_namespace.SlaveDeclSpace; current_container = current_class.PartialContainer; } namespace_body opt_semicolon { current_namespace = current_namespace.Parent; current_class = current_namespace.SlaveDeclSpace; current_container = current_class.PartialContainer; } ; qualified_identifier : IDENTIFIER { LocatedToken lt = (LocatedToken) $1; $$ = new MemberName (lt.Value, lt.Location); } | qualified_identifier DOT IDENTIFIER { LocatedToken lt = (LocatedToken) $3; $$ = new MemberName ((MemberName) $1, lt.Value, lt.Location); } | error { syntax_error (lexer.Location, "`.' expected"); } ; opt_semicolon : /* empty */ | SEMICOLON ; opt_comma : /* empty */ | COMMA ; namespace_name : namespace_or_type_name { MemberName name = (MemberName) $1; if (name.TypeArguments != null) syntax_error (lexer.Location, "namespace name expected"); $$ = name; } ; namespace_body : OPEN_BRACE { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } namespace_body_body ; namespace_body_body : opt_extern_alias_directives opt_using_directives opt_namespace_member_declarations CLOSE_BRACE | error { Report.Error (1518, lexer.Location, "Expected `class', `delegate', `enum', `interface', or `struct'"); } CLOSE_BRACE | opt_extern_alias_directives opt_using_directives opt_namespace_member_declarations EOF { Report.Error (1513, lexer.Location, "} expected"); } ; opt_using_directives : /* empty */ | using_directives ; opt_extern_alias_directives : /* empty */ | extern_alias_directives ; opt_namespace_member_declarations : /* empty */ | namespace_member_declarations ; namespace_member_declarations : namespace_member_declaration | namespace_member_declarations namespace_member_declaration ; namespace_member_declaration : type_declaration { if ($1 != null) { DeclSpace ds = (DeclSpace)$1; if ((ds.ModFlags & (Modifiers.PRIVATE|Modifiers.PROTECTED)) != 0){ Report.Error (1527, ds.Location, "Namespace elements cannot be explicitly declared as private, protected or protected internal"); } } current_namespace.DeclarationFound = true; } | namespace_declaration { current_namespace.DeclarationFound = true; } | field_declaration { Report.Error (116, ((MemberCore) $1).Location, "A namespace can only contain types and namespace declarations"); } | method_declaration { Report.Error (116, ((MemberCore) $1).Location, "A namespace can only contain types and namespace declarations"); } ; type_declaration : class_declaration | struct_declaration | interface_declaration | enum_declaration | delegate_declaration // // Enable this when we have handled all errors, because this acts as a generic fallback // // | error { // Console.WriteLine ("Token=" + yyToken); // Report.Error (1518, GetLocation ($1), "Expected class, struct, interface, enum or delegate"); // } ; // // Attributes 17.2 // global_attributes : attribute_sections { if ($1 != null) { Attributes attrs = (Attributes)$1; if (global_attrs_enabled) { CodeGen.Assembly.AddAttributes (attrs.Attrs); } else { foreach (Attribute a in attrs.Attrs) { Report.Error (1730, a.Location, "Assembly and module attributes must precede all other elements except using clauses and extern alias declarations"); } } } $$ = $1; } opt_attributes : /* empty */ { global_attrs_enabled = false; $$ = null; } | attribute_sections { global_attrs_enabled = false; $$ = $1; } ; attribute_sections : attribute_section { if (current_attr_target != String.Empty) { ArrayList sect = (ArrayList) $1; if (global_attrs_enabled) { if (current_attr_target == "module") { CodeGen.Module.AddAttributes (sect); $$ = null; } else if (current_attr_target != null && current_attr_target.Length > 0) { CodeGen.Assembly.AddAttributes (sect); $$ = null; } else { $$ = new Attributes (sect); } if ($$ == null) { if (RootContext.Documentation != null) { Lexer.check_incorrect_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } } } else { $$ = new Attributes (sect); } } else $$ = null; current_attr_target = null; } | attribute_sections attribute_section { if (current_attr_target != String.Empty) { Attributes attrs = $1 as Attributes; ArrayList sect = (ArrayList) $2; if (global_attrs_enabled) { if (current_attr_target == "module") { CodeGen.Module.AddAttributes (sect); $$ = null; } else if (current_attr_target == "assembly") { CodeGen.Assembly.AddAttributes (sect); $$ = null; } else { if (attrs == null) attrs = new Attributes (sect); else attrs.AddAttributes (sect); } } else { if (attrs == null) attrs = new Attributes (sect); else attrs.AddAttributes (sect); } $$ = attrs; } else $$ = null; current_attr_target = null; } ; attribute_section : OPEN_BRACKET attribute_target_specifier attribute_list opt_comma CLOSE_BRACKET { $$ = $3; } | OPEN_BRACKET attribute_list opt_comma CLOSE_BRACKET { $$ = $2; } ; attribute_target_specifier : attribute_target COLON { current_attr_target = (string)$1; $$ = $1; } ; attribute_target : IDENTIFIER { LocatedToken lt = (LocatedToken) $1; $$ = CheckAttributeTarget (lt.Value, lt.Location); } | EVENT { $$ = "event"; } | RETURN { $$ = "return"; } | error { string name = yyNames [yyToken].ToLower (); $$ = CheckAttributeTarget (name, GetLocation ($1)); } ; attribute_list : attribute { ArrayList attrs = new ArrayList (4); attrs.Add ($1); $$ = attrs; } | attribute_list COMMA attribute { ArrayList attrs = (ArrayList) $1; attrs.Add ($3); $$ = attrs; } ; attribute : attribute_name opt_attribute_arguments { MemberName mname = (MemberName) $1; if (mname.IsGeneric) { Report.Error (404, lexer.Location, "'<' unexpected: attributes cannot be generic"); } object [] arguments = (object []) $2; MemberName left = mname.Left; string identifier = mname.Name; Expression left_expr = left == null ? null : left.GetTypeExpression (); if (current_attr_target == String.Empty) $$ = null; else if (global_attrs_enabled && (current_attr_target == "assembly" || current_attr_target == "module")) // FIXME: supply "nameEscaped" parameter here. $$ = new GlobalAttribute (current_namespace, current_attr_target, left_expr, identifier, arguments, mname.Location, lexer.IsEscapedIdentifier (mname.Location)); else $$ = new Attribute (current_attr_target, left_expr, identifier, arguments, mname.Location, lexer.IsEscapedIdentifier (mname.Location)); } ; attribute_name : namespace_or_type_name { /* reserved attribute name or identifier: 17.4 */ } ; opt_attribute_arguments : /* empty */ { $$ = null; } | OPEN_PARENS attribute_arguments CLOSE_PARENS { $$ = $2; } ; attribute_arguments : opt_positional_argument_list { if ($1 == null) $$ = null; else { $$ = new object [] { $1, null }; } } | positional_argument_list COMMA named_argument_list { $$ = new object[] { $1, $3 }; } | named_argument_list { $$ = new object [] { null, $1 }; } ; opt_positional_argument_list : /* empty */ { $$ = null; } | positional_argument_list ; positional_argument_list : expression { ArrayList args = new ArrayList (4); args.Add (new Argument ((Expression) $1, Argument.AType.Expression)); $$ = args; } | positional_argument_list COMMA expression { ArrayList args = (ArrayList) $1; args.Add (new Argument ((Expression) $3, Argument.AType.Expression)); $$ = args; } ; named_argument_list : named_argument { ArrayList args = new ArrayList (4); args.Add ($1); $$ = args; } | named_argument_list COMMA named_argument { ArrayList args = (ArrayList) $1; args.Add ($3); $$ = args; } | named_argument_list COMMA expression { Report.Error (1016, ((Expression) $3).Location, "Named attribute argument expected"); $$ = null; } ; named_argument : IDENTIFIER ASSIGN expression { // FIXME: keep location $$ = new DictionaryEntry ( ((LocatedToken) $1).Value, new Argument ((Expression) $3, Argument.AType.Expression)); } ; class_body : OPEN_BRACE opt_class_member_declarations CLOSE_BRACE ; opt_class_member_declarations : /* empty */ | class_member_declarations ; class_member_declarations : class_member_declaration | class_member_declarations class_member_declaration ; class_member_declaration : constant_declaration // done | field_declaration // done | method_declaration // done | property_declaration // done | event_declaration // done | indexer_declaration // done | operator_declaration // done | constructor_declaration // done | destructor_declaration // done | type_declaration ; struct_declaration : opt_attributes opt_modifiers opt_partial STRUCT { lexer.ConstraintsParsing = true; } type_name { MemberName name = MakeName ((MemberName) $6); push_current_class (new Struct (current_namespace, current_class, name, (int) $2, (Attributes) $1), $3); } opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; current_class.SetParameterInfo ((ArrayList) $9); if (RootContext.Documentation != null) current_container.DocComment = Lexer.consume_doc_comment (); } struct_body { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } opt_semicolon { $$ = pop_current_class (); } | opt_attributes opt_modifiers opt_partial STRUCT error { CheckIdentifierToken (yyToken, GetLocation ($5)); } ; struct_body : OPEN_BRACE { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } opt_struct_member_declarations CLOSE_BRACE ; opt_struct_member_declarations : /* empty */ | struct_member_declarations ; struct_member_declarations : struct_member_declaration | struct_member_declarations struct_member_declaration ; struct_member_declaration : constant_declaration | field_declaration | method_declaration | property_declaration | event_declaration | indexer_declaration | operator_declaration | constructor_declaration | type_declaration /* * This is only included so we can flag error 575: * destructors only allowed on class types */ | destructor_declaration ; constant_declaration : opt_attributes opt_modifiers CONST type constant_declarators SEMICOLON { int modflags = (int) $2; foreach (VariableDeclaration constant in (ArrayList) $5){ Location l = constant.Location; if ((modflags & Modifiers.STATIC) != 0) { Report.Error (504, l, "The constant `{0}' cannot be marked static", current_container.GetSignatureForError () + '.' + (string) constant.identifier); continue; } Const c = new Const ( current_class, (FullNamedExpression) $4, (string) constant.identifier, (Expression) constant.expression_or_array_initializer, modflags, (Attributes) $1, l); if (RootContext.Documentation != null) { c.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } current_container.AddConstant (c); } } ; constant_declarators : constant_declarator { ArrayList constants = new ArrayList (4); if ($1 != null) constants.Add ($1); $$ = constants; } | constant_declarators COMMA constant_declarator { if ($3 != null) { ArrayList constants = (ArrayList) $1; constants.Add ($3); } } ; constant_declarator : IDENTIFIER ASSIGN constant_expression { $$ = new VariableDeclaration ((LocatedToken) $1, $3); } | IDENTIFIER { // A const field requires a value to be provided Report.Error (145, ((LocatedToken) $1).Location, "A const field requires a value to be provided"); $$ = null; } ; field_declaration : opt_attributes opt_modifiers type variable_declarators SEMICOLON { FullNamedExpression type = (FullNamedExpression) $3; int mod = (int) $2; current_array_type = null; foreach (VariableDeclaration var in (ArrayList) $4){ Field field = new Field (current_class, type, mod, var.identifier, (Attributes) $1, var.Location); field.Initializer = var.expression_or_array_initializer; if (RootContext.Documentation != null) { field.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } current_container.AddField (field); $$ = field; // FIXME: might be better if it points to the top item } } | opt_attributes opt_modifiers FIXED type fixed_variable_declarators SEMICOLON { FullNamedExpression type = (FullNamedExpression) $4; int mod = (int) $2; current_array_type = null; foreach (VariableDeclaration var in (ArrayList) $5) { FixedField field = new FixedField (current_class, type, mod, var.identifier, (Expression)var.expression_or_array_initializer, (Attributes) $1, var.Location); if (RootContext.Documentation != null) { field.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } current_container.AddField (field); $$ = field; // FIXME: might be better if it points to the top item } } | opt_attributes opt_modifiers FIXED type error { Report.Error (1641, GetLocation ($4), "A fixed size buffer field must have the array size specifier after the field name"); } | opt_attributes opt_modifiers VOID variable_declarators SEMICOLON { current_array_type = null; Report.Error (670, (Location) $3, "Fields cannot have void type"); } ; fixed_variable_declarators : fixed_variable_declarator { ArrayList decl = new ArrayList (2); decl.Add ($1); $$ = decl; } | fixed_variable_declarators COMMA fixed_variable_declarator { ArrayList decls = (ArrayList) $1; decls.Add ($3); $$ = $1; } ; fixed_variable_declarator : IDENTIFIER OPEN_BRACKET expression CLOSE_BRACKET { $$ = new VariableDeclaration ((LocatedToken) $1, $3); } | IDENTIFIER OPEN_BRACKET CLOSE_BRACKET { Report.Error (443, lexer.Location, "Value or constant expected"); $$ = new VariableDeclaration ((LocatedToken) $1, null); } ; variable_declarators : variable_declarator { ArrayList decl = new ArrayList (4); if ($1 != null) decl.Add ($1); $$ = decl; } | variable_declarators COMMA variable_declarator { ArrayList decls = (ArrayList) $1; decls.Add ($3); $$ = $1; } ; variable_declarator : IDENTIFIER ASSIGN variable_initializer { $$ = new VariableDeclaration ((LocatedToken) $1, $3); } | IDENTIFIER { $$ = new VariableDeclaration ((LocatedToken) $1, null); } | IDENTIFIER OPEN_BRACKET opt_expression CLOSE_BRACKET { Report.Error (650, ((LocatedToken) $1).Location, "Syntax error, bad array declarator. To declare a managed array the rank specifier precedes the variable's identifier. " + "To declare a fixed size buffer field, use the fixed keyword before the field type"); $$ = null; } ; variable_initializer : expression { $$ = $1; } | array_initializer { $$ = $1; } | STACKALLOC type OPEN_BRACKET expression CLOSE_BRACKET { $$ = new StackAlloc ((Expression) $2, (Expression) $4, (Location) $1); } | ARGLIST { $$ = new ArglistAccess ((Location) $1); } | STACKALLOC type { Report.Error (1575, (Location) $1, "A stackalloc expression requires [] after type"); $$ = null; } ; method_declaration : method_header { anonymous_host = (IAnonymousHost) $1; if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.NotAllowed; } method_body { Method method = (Method) $1; method.Block = (ToplevelBlock) $3; current_container.AddMethod (method); anonymous_host = null; current_generic_method = null; current_local_parameters = null; if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } ; opt_error_modifier : /* empty */ | modifiers { int m = (int) $1; int i = 1; while (m != 0){ if ((i & m) != 0){ Report.Error (1585, lexer.Location, "Member modifier `{0}' must precede the member type and name", Modifiers.Name (i)); } m &= ~i; i = i << 1; } } ; // // This rule is used to handle the cases where OPEN_PARENS_LAMBDA // is returned (type followed by an identifier), these are the // declarations (methods, overloads, constructors, etc) and a handful // of expressions ("using", "fixed") or "catch". // open_parens : OPEN_PARENS | OPEN_PARENS_LAMBDA ; method_header : opt_attributes opt_modifiers type member_name open_parens { arglist_allowed = true; } opt_formal_parameter_list CLOSE_PARENS { lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; arglist_allowed = false; MemberName name = (MemberName) $4; current_local_parameters = (Parameters) $7; if ($10 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Constraints are not allowed on non-generic declarations"); Method method; GenericMethod generic = null; if (name.TypeArguments != null) { generic = new GenericMethod (current_namespace, current_class, name, (FullNamedExpression) $3, current_local_parameters); generic.SetParameterInfo ((ArrayList) $10); } method = new Method (current_class, generic, (FullNamedExpression) $3, (int) $2, false, name, current_local_parameters, (Attributes) $1); anonymous_host = method; current_generic_method = generic; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); $$ = method; } | opt_attributes opt_modifiers VOID member_name open_parens { arglist_allowed = true; } opt_formal_parameter_list CLOSE_PARENS { lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; arglist_allowed = false; MemberName name = (MemberName) $4; current_local_parameters = (Parameters) $7; if ($10 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Constraints are not allowed on non-generic declarations"); Method method; GenericMethod generic = null; if (name.TypeArguments != null) { generic = new GenericMethod (current_namespace, current_class, name, TypeManager.system_void_expr, current_local_parameters); generic.SetParameterInfo ((ArrayList) $10); } method = new Method (current_class, generic, TypeManager.system_void_expr, (int) $2, false, name, current_local_parameters, (Attributes) $1); anonymous_host = method; current_generic_method = generic; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); $$ = method; } | opt_attributes opt_modifiers PARTIAL VOID member_name open_parens opt_formal_parameter_list CLOSE_PARENS { lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; MemberName name = (MemberName) $5; current_local_parameters = (Parameters) $7; if ($9 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Constraints are not allowed on non-generic declarations"); Method method; GenericMethod generic = null; if (name.TypeArguments != null) { generic = new GenericMethod (current_namespace, current_class, name, TypeManager.system_void_expr, current_local_parameters); generic.SetParameterInfo ((ArrayList) $10); } int modifiers = (int) $2; const int invalid_partial_mod = Modifiers.Accessibility | Modifiers.ABSTRACT | Modifiers.EXTERN | Modifiers.NEW | Modifiers.OVERRIDE | Modifiers.SEALED | Modifiers.VIRTUAL; if ((modifiers & invalid_partial_mod) != 0) { Report.Error (750, name.Location, "A partial method cannot define access modifier or " + "any of abstract, extern, new, override, sealed, or virtual modifiers"); modifiers &= ~invalid_partial_mod; } if ((current_class.ModFlags & Modifiers.PARTIAL) == 0) { Report.Error (751, name.Location, "A partial method must be declared within a " + "partial class or partial struct"); } modifiers |= Modifiers.PARTIAL | Modifiers.PRIVATE; method = new Method (current_class, generic, TypeManager.system_void_expr, modifiers, false, name, current_local_parameters, (Attributes) $1); anonymous_host = method; current_generic_method = generic; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); $$ = method; } | opt_attributes opt_modifiers type modifiers member_name open_parens opt_formal_parameter_list CLOSE_PARENS { MemberName name = (MemberName) $5; Report.Error (1585, name.Location, "Member modifier `{0}' must precede the member type and name", Modifiers.Name ((int) $4)); Method method = new Method (current_class, null, TypeManager.system_void_expr, 0, false, name, (Parameters) $7, (Attributes) $1); current_local_parameters = (Parameters) $7; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); $$ = null; } ; method_body : block | SEMICOLON { $$ = null; } ; opt_formal_parameter_list : /* empty */ { $$ = Parameters.EmptyReadOnlyParameters; } | formal_parameter_list ; opt_parameter_list_no_mod : /* empty */ { $$ = Parameters.EmptyReadOnlyParameters; } | { parameter_modifiers_not_allowed = true; } formal_parameter_list { parameter_modifiers_not_allowed = false; $$ = $2; } ; formal_parameter_list : fixed_parameters { ArrayList pars_list = (ArrayList) $1; Parameter [] pars = new Parameter [pars_list.Count]; pars_list.CopyTo (pars); $$ = new Parameters (pars); } | fixed_parameters COMMA parameter_array { ArrayList pars_list = (ArrayList) $1; pars_list.Add ($3); Parameter [] pars = new Parameter [pars_list.Count]; pars_list.CopyTo (pars); $$ = new Parameters (pars); } | fixed_parameters COMMA arglist_modifier { ArrayList pars_list = (ArrayList) $1; //pars_list.Add (new ArglistParameter (GetLocation ($3))); Parameter [] pars = new Parameter [pars_list.Count]; pars_list.CopyTo (pars); $$ = new Parameters (pars, true); } | parameter_array COMMA error { if ($1 != null) Report.Error (231, ((Parameter) $1).Location, "A params parameter must be the last parameter in a formal parameter list"); $$ = null; } | fixed_parameters COMMA parameter_array COMMA error { if ($3 != null) Report.Error (231, ((Parameter) $3).Location, "A params parameter must be the last parameter in a formal parameter list"); $$ = null; } | arglist_modifier COMMA error { Report.Error (257, (Location) $1, "An __arglist parameter must be the last parameter in a formal parameter list"); $$ = null; } | fixed_parameters COMMA ARGLIST COMMA error { Report.Error (257, (Location) $3, "An __arglist parameter must be the last parameter in a formal parameter list"); $$ = null; } | parameter_array { $$ = new Parameters (new Parameter[] { (Parameter) $1 } ); } | arglist_modifier { $$ = new Parameters (new Parameter[0], true); } ; fixed_parameters : fixed_parameter { ArrayList pars = new ArrayList (4); pars.Add ($1); $$ = pars; } | fixed_parameters COMMA fixed_parameter { ArrayList pars = (ArrayList) $1; Parameter p = (Parameter)$3; if (p != null) { if (p.HasExtensionMethodModifier) Report.Error (1100, p.Location, "The parameter modifier `this' can only be used on the first parameter"); pars.Add (p); } $$ = $1; } ; fixed_parameter : opt_attributes opt_parameter_modifier type IDENTIFIER { LocatedToken lt = (LocatedToken) $4; $$ = new Parameter ((FullNamedExpression) $3, lt.Value, (Parameter.Modifier) $2, (Attributes) $1, lt.Location); } | opt_attributes opt_parameter_modifier type IDENTIFIER OPEN_BRACKET CLOSE_BRACKET { LocatedToken lt = (LocatedToken) $4; Report.Error (1552, lt.Location, "Array type specifier, [], must appear before parameter name"); $$ = null; } | opt_attributes opt_parameter_modifier type { Report.Error (1001, GetLocation ($3), "Identifier expected"); $$ = null; } | opt_attributes opt_parameter_modifier type error { CheckIdentifierToken (yyToken, GetLocation ($4)); $$ = null; } | opt_attributes opt_parameter_modifier type IDENTIFIER ASSIGN constant_expression { LocatedToken lt = (LocatedToken) $4; Report.Error (241, lt.Location, "Default parameter specifiers are not permitted"); $$ = null; } ; opt_parameter_modifier : /* empty */ { $$ = Parameter.Modifier.NONE; } | parameter_modifiers ; parameter_modifiers : parameter_modifier { $$ = $1; } | parameter_modifiers parameter_modifier { Parameter.Modifier p2 = (Parameter.Modifier)$2; Parameter.Modifier mod = (Parameter.Modifier)$1 | p2; if (((Parameter.Modifier)$1 & p2) == p2) { Error_DuplicateParameterModifier (lexer.Location, p2); } else { switch (mod & ~Parameter.Modifier.This) { case Parameter.Modifier.REF: Report.Error (1101, lexer.Location, "The parameter modifiers `this' and `ref' cannot be used altogether"); break; case Parameter.Modifier.OUT: Report.Error (1102, lexer.Location, "The parameter modifiers `this' and `out' cannot be used altogether"); break; default: Report.Error (1108, lexer.Location, "A parameter cannot have specified more than one modifier"); break; } } $$ = mod; } ; parameter_modifier : REF { if (parameter_modifiers_not_allowed) Error_ParameterModifierNotValid ("ref", (Location)$1); $$ = Parameter.Modifier.REF; } | OUT { if (parameter_modifiers_not_allowed) Error_ParameterModifierNotValid ("out", (Location)$1); $$ = Parameter.Modifier.OUT; } | THIS { if (parameter_modifiers_not_allowed) Error_ParameterModifierNotValid ("this", (Location)$1); if (RootContext.Version <= LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (GetLocation ($1), "extension methods"); $$ = Parameter.Modifier.This; } ; parameter_array : opt_attributes params_modifier type IDENTIFIER { LocatedToken lt = (LocatedToken) $4; $$ = new ParamsParameter ((FullNamedExpression) $3, lt.Value, (Attributes) $1, lt.Location); } | opt_attributes params_modifier type error { CheckIdentifierToken (yyToken, GetLocation ($4)); $$ = null; } ; params_modifier : PARAMS { if (params_modifiers_not_allowed) Report.Error (1670, ((Location) $1), "The `params' modifier is not allowed in current context"); } | PARAMS parameter_modifier { Parameter.Modifier mod = (Parameter.Modifier)$2; if ((mod & Parameter.Modifier.This) != 0) { Report.Error (1104, (Location)$1, "The parameter modifiers `this' and `params' cannot be used altogether"); } else { Report.Error (1611, (Location)$1, "The params parameter cannot be declared as ref or out"); } } | PARAMS params_modifier { Error_DuplicateParameterModifier ((Location)$1, Parameter.Modifier.PARAMS); } ; arglist_modifier : ARGLIST { if (!arglist_allowed) Report.Error (1669, (Location) $1, "__arglist is not valid in this context"); } ; property_declaration : opt_attributes opt_modifiers type namespace_or_type_name { if (RootContext.Documentation != null) tmpComment = Lexer.consume_doc_comment (); } OPEN_BRACE { implicit_value_parameter_type = (FullNamedExpression) $3; lexer.PropertyParsing = true; } accessor_declarations { lexer.PropertyParsing = false; has_get = has_set = false; } CLOSE_BRACE { if ($8 == null) break; Property prop; Accessors accessors = (Accessors) $8; Accessor get_block = accessors.get_or_add; Accessor set_block = accessors.set_or_remove; MemberName name = (MemberName) $4; if (name.TypeArguments != null) syntax_error (lexer.Location, "a property can't have type arguments"); prop = new Property (current_class, (FullNamedExpression) $3, (int) $2, false, name, (Attributes) $1, get_block, set_block, accessors.declared_in_reverse, current_block); current_container.AddProperty (prop); implicit_value_parameter_type = null; if (RootContext.Documentation != null) prop.DocComment = ConsumeStoredComment (); } ; accessor_declarations : get_accessor_declaration { $$ = new Accessors ((Accessor) $1, null); } | get_accessor_declaration accessor_declarations { Accessors accessors = (Accessors) $2; accessors.get_or_add = (Accessor) $1; $$ = accessors; } | set_accessor_declaration { $$ = new Accessors (null, (Accessor) $1); } | set_accessor_declaration accessor_declarations { Accessors accessors = (Accessors) $2; accessors.set_or_remove = (Accessor) $1; accessors.declared_in_reverse = true; $$ = accessors; } | error { Report.Error (1014, GetLocation ($1), "A get or set accessor expected"); $$ = null; } ; get_accessor_declaration : opt_attributes opt_modifiers GET { // If this is not the case, then current_local_parameters has already // been set in indexer_declaration if (parsing_indexer == false) current_local_parameters = null; else current_local_parameters = indexer_parameters; lexer.PropertyParsing = false; anonymous_host = SimpleAnonymousHost.GetSimple (); } accessor_body { if (has_get) { Report.Error (1007, (Location) $3, "Property accessor already defined"); break; } Accessor accessor = new Accessor ((ToplevelBlock) $5, (int) $2, (Attributes) $1, (Location) $3); has_get = true; current_local_parameters = null; lexer.PropertyParsing = true; SimpleAnonymousHost.Simple.Propagate (accessor); anonymous_host = null; if (RootContext.Documentation != null) if (Lexer.doc_state == XmlCommentState.Error) Lexer.doc_state = XmlCommentState.NotAllowed; $$ = accessor; } ; set_accessor_declaration : opt_attributes opt_modifiers SET { Parameter [] args; Parameter implicit_value_parameter = new Parameter ( implicit_value_parameter_type, "value", Parameter.Modifier.NONE, null, (Location) $3); if (parsing_indexer == false) { args = new Parameter [1]; args [0] = implicit_value_parameter; current_local_parameters = new Parameters (args); } else { Parameter [] fpars = indexer_parameters.FixedParameters; if (fpars != null){ int count = fpars.Length; args = new Parameter [count + 1]; fpars.CopyTo (args, 0); args [count] = implicit_value_parameter; } else args = null; current_local_parameters = new Parameters ( args); } lexer.PropertyParsing = false; anonymous_host = SimpleAnonymousHost.GetSimple (); } accessor_body { if (has_set) { Report.Error (1007, ((LocatedToken) $3).Location, "Property accessor already defined"); break; } Accessor accessor = new Accessor ((ToplevelBlock) $5, (int) $2, (Attributes) $1, (Location) $3); has_set = true; current_local_parameters = null; lexer.PropertyParsing = true; SimpleAnonymousHost.Simple.Propagate (accessor); anonymous_host = null; if (RootContext.Documentation != null && Lexer.doc_state == XmlCommentState.Error) Lexer.doc_state = XmlCommentState.NotAllowed; $$ = accessor; } ; accessor_body : block | SEMICOLON { $$ = null; } ; interface_declaration : opt_attributes opt_modifiers opt_partial INTERFACE { lexer.ConstraintsParsing = true; } type_name { MemberName name = MakeName ((MemberName) $6); push_current_class (new Interface (current_namespace, current_class, name, (int) $2, (Attributes) $1), $3); } opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; current_class.SetParameterInfo ((ArrayList) $9); if (RootContext.Documentation != null) { current_container.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } } interface_body { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } opt_semicolon { $$ = pop_current_class (); } | opt_attributes opt_modifiers opt_partial INTERFACE error { CheckIdentifierToken (yyToken, GetLocation ($5)); } ; interface_body : OPEN_BRACE opt_interface_member_declarations CLOSE_BRACE ; opt_interface_member_declarations : /* empty */ | interface_member_declarations ; interface_member_declarations : interface_member_declaration | interface_member_declarations interface_member_declaration ; interface_member_declaration : interface_method_declaration { if ($1 == null) break; Method m = (Method) $1; if (m.IsExplicitImpl) Report.Error (541, m.Location, "`{0}': explicit interface declaration can only be declared in a class or struct", m.GetSignatureForError ()); current_container.AddMethod (m); if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } | interface_property_declaration { if ($1 == null) break; Property p = (Property) $1; if (p.IsExplicitImpl) Report.Error (541, p.Location, "`{0}': explicit interface declaration can only be declared in a class or struct", p.GetSignatureForError ()); current_container.AddProperty (p); if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } | interface_event_declaration { if ($1 != null){ Event e = (Event) $1; if (e.IsExplicitImpl) Report.Error (541, e.Location, "`{0}': explicit interface declaration can only be declared in a class or struct", e.GetSignatureForError ()); current_container.AddEvent (e); } if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } | interface_indexer_declaration { if ($1 == null) break; Indexer i = (Indexer) $1; if (i.IsExplicitImpl) Report.Error (541, i.Location, "`{0}': explicit interface declaration can only be declared in a class or struct", i.GetSignatureForError ()); current_container.AddIndexer (i); if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } | delegate_declaration { if ($1 != null) { Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants", ((MemberCore)$1).GetSignatureForError ()); } } | class_declaration { if ($1 != null) { Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants", ((MemberCore)$1).GetSignatureForError ()); } } | struct_declaration { if ($1 != null) { Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants", ((MemberCore)$1).GetSignatureForError ()); } } | enum_declaration { if ($1 != null) { Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants", ((MemberCore)$1).GetSignatureForError ()); } } | interface_declaration { if ($1 != null) { Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants", ((MemberCore)$1).GetSignatureForError ()); } } | constant_declaration { Report.Error (525, GetLocation ($1), "Interfaces cannot contain fields or constants"); } ; opt_new : opt_modifiers { int val = (int) $1; val = Modifiers.Check (Modifiers.NEW | Modifiers.UNSAFE, val, 0, GetLocation ($1)); $$ = val; } ; interface_method_declaration_body : OPEN_BRACE { Report.Error (531, (Location)$1, "`{0}.{1}{2}': interface members cannot have a definition", current_class.GetSignatureForError (), ((MemberName) $-0).GetSignatureForError (), ((Parameters)$-4).GetSignatureForError ()); lexer.ConstraintsParsing = false; } opt_statement_list CLOSE_BRACE { $$ = null; } | SEMICOLON ; interface_method_declaration : opt_attributes opt_new type namespace_or_type_name open_parens opt_formal_parameter_list CLOSE_PARENS { lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { // Refer to the name as $-1 in interface_method_declaration_body $$ = $4; } interface_method_declaration_body { lexer.ConstraintsParsing = false; MemberName name = (MemberName) $4; if ($9 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Constraints are not allowed on non-generic declarations"); GenericMethod generic = null; if (name.TypeArguments != null) { generic = new GenericMethod (current_namespace, current_class, name, (FullNamedExpression) $3, (Parameters) $6); generic.SetParameterInfo ((ArrayList) $9); } $$ = new Method (current_class, generic, (FullNamedExpression) $3, (int) $2, true, name, (Parameters) $6, (Attributes) $1); if (RootContext.Documentation != null) ((Method) $$).DocComment = Lexer.consume_doc_comment (); } | opt_attributes opt_new VOID namespace_or_type_name open_parens opt_formal_parameter_list CLOSE_PARENS { lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { $$ = $4; } interface_method_declaration_body { lexer.ConstraintsParsing = false; MemberName name = (MemberName) $4; if ($9 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Constraints are not allowed on non-generic declarations"); GenericMethod generic = null; if (name.TypeArguments != null) { generic = new GenericMethod (current_namespace, current_class, name, TypeManager.system_void_expr, (Parameters) $6); generic.SetParameterInfo ((ArrayList) $9); } $$ = new Method (current_class, generic, TypeManager.system_void_expr, (int) $2, true, name, (Parameters) $6, (Attributes) $1); if (RootContext.Documentation != null) ((Method) $$).DocComment = Lexer.consume_doc_comment (); } ; interface_property_declaration : opt_attributes opt_new type IDENTIFIER OPEN_BRACE { lexer.PropertyParsing = true; implicit_value_parameter_type = (FullNamedExpression)$3; } accessor_declarations { has_get = has_set = false; lexer.PropertyParsing = false; implicit_value_parameter_type = null; } CLOSE_BRACE { LocatedToken lt = (LocatedToken) $4; MemberName name = new MemberName (lt.Value, lt.Location); if ($3 == TypeManager.system_void_expr) { Report.Error (547, lt.Location, "`{0}': property or indexer cannot have void type", lt.Value); break; } Property p = null; if ($7 == null) { p = new Property (current_class, (FullNamedExpression) $3, (int) $2, true, name, (Attributes) $1, null, null, false); Report.Error (548, p.Location, "`{0}': property or indexer must have at least one accessor", p.GetSignatureForError ()); break; } Accessors accessor = (Accessors) $7; p = new Property (current_class, (FullNamedExpression) $3, (int) $2, true, name, (Attributes) $1, accessor.get_or_add, accessor.set_or_remove, accessor.declared_in_reverse); if (accessor.get_or_add != null && accessor.get_or_add.Block != null) { Report.Error (531, p.Location, "`{0}.get': interface members cannot have a definition", p.GetSignatureForError ()); $$ = null; break; } if (accessor.set_or_remove != null && accessor.set_or_remove.Block != null) { Report.Error (531, p.Location, "`{0}.set': interface members cannot have a definition", p.GetSignatureForError ()); $$ = null; break; } if (RootContext.Documentation != null) p.DocComment = Lexer.consume_doc_comment (); $$ = p; } | opt_attributes opt_new type error { CheckIdentifierToken (yyToken, GetLocation ($4)); $$ = null; } ; interface_event_declaration : opt_attributes opt_new EVENT type IDENTIFIER SEMICOLON { LocatedToken lt = (LocatedToken) $5; $$ = new EventField (current_class, (FullNamedExpression) $4, (int) $2, true, new MemberName (lt.Value, lt.Location), (Attributes) $1); if (RootContext.Documentation != null) ((EventField) $$).DocComment = Lexer.consume_doc_comment (); } | opt_attributes opt_new EVENT type error { CheckIdentifierToken (yyToken, GetLocation ($5)); $$ = null; } | opt_attributes opt_new EVENT type IDENTIFIER ASSIGN { LocatedToken lt = (LocatedToken) $5; Report.Error (68, lt.Location, "`{0}.{1}': event in interface cannot have initializer", current_container.Name, lt.Value); $$ = null; } | opt_attributes opt_new EVENT type IDENTIFIER OPEN_BRACE { implicit_value_parameter_type = (FullNamedExpression) $4; lexer.EventParsing = true; } event_accessor_declarations { lexer.EventParsing = false; implicit_value_parameter_type = null; } CLOSE_BRACE { Report.Error (69, (Location) $3, "Event in interface cannot have add or remove accessors"); $$ = null; } ; interface_indexer_declaration : opt_attributes opt_new type THIS OPEN_BRACKET opt_parameter_list_no_mod CLOSE_BRACKET OPEN_BRACE { lexer.PropertyParsing = true; implicit_value_parameter_type = (FullNamedExpression)$3; } accessor_declarations { has_get = has_set = false; lexer.PropertyParsing = false; implicit_value_parameter_type = null; } CLOSE_BRACE { Indexer i = null; if ($10 == null) { i = new Indexer (current_class, (FullNamedExpression) $3, new MemberName (TypeContainer.DefaultIndexerName, (Location) $4), (int) $2, true, (Parameters) $6, (Attributes) $1, null, null, false); Report.Error (548, i.Location, "`{0}': property or indexer must have at least one accessor", i.GetSignatureForError ()); break; } Accessors accessors = (Accessors) $10; i = new Indexer (current_class, (FullNamedExpression) $3, new MemberName (TypeContainer.DefaultIndexerName, (Location) $4), (int) $2, true, (Parameters) $6, (Attributes) $1, accessors.get_or_add, accessors.set_or_remove, accessors.declared_in_reverse); if (accessors.get_or_add != null && accessors.get_or_add.Block != null) { Report.Error (531, i.Location, "`{0}.get': interface members cannot have a definition", i.GetSignatureForError ()); $$ = null; break; } if (accessors.set_or_remove != null && accessors.set_or_remove.Block != null) { Report.Error (531, i.Location, "`{0}.set': interface members cannot have a definition", i.GetSignatureForError ()); $$ = null; break; } if (RootContext.Documentation != null) i.DocComment = ConsumeStoredComment (); $$ = i; } ; operator_declaration : opt_attributes opt_modifiers operator_declarator { anonymous_host = SimpleAnonymousHost.GetSimple (); } operator_body { if ($3 == null) break; OperatorDeclaration decl = (OperatorDeclaration) $3; Operator op = new Operator ( current_class, decl.optype, decl.ret_type, (int) $2, current_local_parameters, (ToplevelBlock) $5, (Attributes) $1, decl.location); if (RootContext.Documentation != null) { op.DocComment = tmpComment; Lexer.doc_state = XmlCommentState.Allowed; } SimpleAnonymousHost.Simple.Propagate (op); anonymous_host = null; // Note again, checking is done in semantic analysis current_container.AddOperator (op); current_local_parameters = null; } ; operator_body : block | SEMICOLON { $$ = null; } ; operator_declarator : type OPERATOR overloadable_operator open_parens { params_modifiers_not_allowed = true; } opt_parameter_list_no_mod CLOSE_PARENS { params_modifiers_not_allowed = false; Location loc = (Location) $2; Operator.OpType op = (Operator.OpType) $3; current_local_parameters = (Parameters)$6; int p_count = current_local_parameters.Count; if (p_count == 1) { if (op == Operator.OpType.Addition) op = Operator.OpType.UnaryPlus; else if (op == Operator.OpType.Subtraction) op = Operator.OpType.UnaryNegation; } if (IsUnaryOperator (op)) { if (p_count == 2) { Report.Error (1020, loc, "Overloadable binary operator expected"); } else if (p_count != 1) { Report.Error (1535, loc, "Overloaded unary operator `{0}' takes one parameter", Operator.GetName (op)); } } else { if (p_count > 2) { Report.Error (1534, loc, "Overloaded binary operator `{0}' takes two parameters", Operator.GetName (op)); } else if (p_count != 2) { Report.Error (1019, loc, "Overloadable unary operator expected"); } } if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } $$ = new OperatorDeclaration (op, (FullNamedExpression) $1, loc); } | conversion_operator_declarator ; overloadable_operator // Unary operators: : BANG { $$ = Operator.OpType.LogicalNot; } | TILDE { $$ = Operator.OpType.OnesComplement; } | OP_INC { $$ = Operator.OpType.Increment; } | OP_DEC { $$ = Operator.OpType.Decrement; } | TRUE { $$ = Operator.OpType.True; } | FALSE { $$ = Operator.OpType.False; } // Unary and binary: | PLUS { $$ = Operator.OpType.Addition; } | MINUS { $$ = Operator.OpType.Subtraction; } // Binary: | STAR { $$ = Operator.OpType.Multiply; } | DIV { $$ = Operator.OpType.Division; } | PERCENT { $$ = Operator.OpType.Modulus; } | BITWISE_AND { $$ = Operator.OpType.BitwiseAnd; } | BITWISE_OR { $$ = Operator.OpType.BitwiseOr; } | CARRET { $$ = Operator.OpType.ExclusiveOr; } | OP_SHIFT_LEFT { $$ = Operator.OpType.LeftShift; } | OP_SHIFT_RIGHT { $$ = Operator.OpType.RightShift; } | OP_EQ { $$ = Operator.OpType.Equality; } | OP_NE { $$ = Operator.OpType.Inequality; } | OP_GT { $$ = Operator.OpType.GreaterThan; } | OP_LT { $$ = Operator.OpType.LessThan; } | OP_GE { $$ = Operator.OpType.GreaterThanOrEqual; } | OP_LE { $$ = Operator.OpType.LessThanOrEqual; } ; conversion_operator_declarator : IMPLICIT OPERATOR type open_parens { params_modifiers_not_allowed = true; } opt_parameter_list_no_mod CLOSE_PARENS { params_modifiers_not_allowed = false; Location loc = (Location) $2; current_local_parameters = (Parameters)$6; if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } $$ = new OperatorDeclaration (Operator.OpType.Implicit, (FullNamedExpression) $3, loc); } | EXPLICIT OPERATOR type open_parens { params_modifiers_not_allowed = true; } opt_parameter_list_no_mod CLOSE_PARENS { params_modifiers_not_allowed = false; Location loc = (Location) $2; current_local_parameters = (Parameters)$6; if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } $$ = new OperatorDeclaration (Operator.OpType.Explicit, (FullNamedExpression) $3, loc); } | IMPLICIT error { syntax_error ((Location) $1, "'operator' expected"); } | EXPLICIT error { syntax_error ((Location) $1, "'operator' expected"); } ; constructor_declaration : opt_attributes opt_modifiers constructor_declarator constructor_body { Constructor c = (Constructor) $3; c.Block = (ToplevelBlock) $4; c.OptAttributes = (Attributes) $1; int yield_method = c.ModFlags & Modifiers.METHOD_YIELDS; int mods = (int) $2; if (RootContext.Documentation != null) c.DocComment = ConsumeStoredComment (); if ((mods & Modifiers.STATIC) != 0 && c.Name == current_container.Basename) { if ((mods & Modifiers.Accessibility) != 0){ Report.Error (515, c.Location, "`{0}': access modifiers are not allowed on static constructors", c.GetSignatureForError ()); } if (c.Initializer != null){ Report.Error (514, c.Location, "`{0}': static constructor cannot have an explicit `this' or `base' constructor call", c.GetSignatureForError ()); } } c.ModFlags = Modifiers.Check (Constructor.AllowedModifiers, mods, Modifiers.PRIVATE, c.Location) | yield_method; current_container.AddConstructor (c); current_local_parameters = null; if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } ; constructor_declarator : constructor_header { $$ = $1; } | constructor_header constructor_initializer { ((Constructor)$1).Initializer = (ConstructorInitializer) $2; $$ = $1; } ; constructor_header : IDENTIFIER { if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } } open_parens opt_formal_parameter_list CLOSE_PARENS { LocatedToken lt = (LocatedToken) $1; current_local_parameters = (Parameters) $4; current_block = new ToplevelBlock (null, current_local_parameters, null, lt.Location); $$ = new Constructor (current_class, lt.Value, 0, current_local_parameters, null, lt.Location); anonymous_host = (IAnonymousHost) $$; } ; constructor_body : block_prepared | SEMICOLON { current_block = null; $$ = null; } ; constructor_initializer : COLON BASE open_parens opt_argument_list CLOSE_PARENS { $$ = new ConstructorBaseInitializer ((ArrayList) $4, (Location) $2); } | COLON THIS open_parens opt_argument_list CLOSE_PARENS { $$ = new ConstructorThisInitializer ((ArrayList) $4, (Location) $2); } | COLON error { Report.Error (1018, (Location) $1, "Keyword this or base expected"); $$ = null; } ; opt_finalizer : /* EMPTY */ { $$ = 0; } | UNSAFE { $$ = Modifiers.UNSAFE; } | EXTERN { $$ = Modifiers.EXTERN; } ; destructor_declaration : opt_attributes opt_finalizer TILDE { if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } } IDENTIFIER OPEN_PARENS CLOSE_PARENS block { LocatedToken lt = (LocatedToken) $5; if (lt.Value != current_container.MemberName.Name){ Report.Error (574, lt.Location, "Name of destructor must match name of class"); } else if (current_container.Kind != Kind.Class){ Report.Error (575, lt.Location, "Only class types can contain destructor"); } else { Location l = lt.Location; int m = (int) $2; if (!RootContext.StdLib && current_container.Name == "System.Object") m |= Modifiers.PROTECTED | Modifiers.VIRTUAL; else m |= Modifiers.PROTECTED | Modifiers.OVERRIDE; Method d = new Destructor ( current_class, TypeManager.system_void_expr, m, "Finalize", Parameters.EmptyReadOnlyParameters, (Attributes) $1, l); if (RootContext.Documentation != null) d.DocComment = ConsumeStoredComment (); d.Block = (ToplevelBlock) $8; current_container.AddMethod (d); } } ; event_declaration : opt_attributes opt_modifiers EVENT type variable_declarators SEMICOLON { current_array_type = null; foreach (VariableDeclaration var in (ArrayList) $5) { MemberName name = new MemberName (var.identifier, var.Location); EventField e = new EventField ( current_class, (FullNamedExpression) $4, (int) $2, false, name, (Attributes) $1); e.Initializer = var.expression_or_array_initializer; current_container.AddEvent (e); if (RootContext.Documentation != null) { e.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } } } | opt_attributes opt_modifiers EVENT type namespace_or_type_name OPEN_BRACE { implicit_value_parameter_type = (FullNamedExpression) $4; lexer.EventParsing = true; } event_accessor_declarations { lexer.EventParsing = false; } CLOSE_BRACE { MemberName name = (MemberName) $5; if ($8 == null){ Report.Error (65, (Location) $3, "`{0}.{1}': event property must have both add and remove accessors", current_container.Name, name.GetSignatureForError ()); $$ = null; } else { Accessors accessors = (Accessors) $8; if (name.TypeArguments != null) syntax_error (lexer.Location, "an event can't have type arguments"); if (accessors.get_or_add == null || accessors.set_or_remove == null) // CS0073 is already reported, so no CS0065 here. $$ = null; else { Event e = new EventProperty ( current_class, (FullNamedExpression) $4, (int) $2, false, name, (Attributes) $1, accessors.get_or_add, accessors.set_or_remove); if (RootContext.Documentation != null) { e.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } current_container.AddEvent (e); implicit_value_parameter_type = null; } } } | opt_attributes opt_modifiers EVENT type namespace_or_type_name error { MemberName mn = (MemberName) $5; if (mn.Left != null) Report.Error (71, mn.Location, "An explicit interface implementation of an event must use property syntax"); else Report.Error (71, mn.Location, "Event declaration should use property syntax"); if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } ; event_accessor_declarations : add_accessor_declaration remove_accessor_declaration { $$ = new Accessors ((Accessor) $1, (Accessor) $2); } | remove_accessor_declaration add_accessor_declaration { Accessors accessors = new Accessors ((Accessor) $2, (Accessor) $1); accessors.declared_in_reverse = true; $$ = accessors; } | add_accessor_declaration { $$ = null; } | remove_accessor_declaration { $$ = null; } | error { Report.Error (1055, GetLocation ($1), "An add or remove accessor expected"); $$ = null; } | { $$ = null; } ; add_accessor_declaration : opt_attributes ADD { Parameter [] args = new Parameter [1]; Parameter implicit_value_parameter = new Parameter ( implicit_value_parameter_type, "value", Parameter.Modifier.NONE, null, (Location) $2); args [0] = implicit_value_parameter; current_local_parameters = new Parameters (args); lexer.EventParsing = false; anonymous_host = SimpleAnonymousHost.GetSimple (); } block { Accessor accessor = new Accessor ((ToplevelBlock) $4, 0, (Attributes) $1, (Location) $2); lexer.EventParsing = true; current_local_parameters = null; SimpleAnonymousHost.Simple.Propagate (accessor); anonymous_host = null; $$ = accessor; } | opt_attributes ADD error { Report.Error (73, (Location) $2, "An add or remove accessor must have a body"); $$ = null; } | opt_attributes modifiers ADD { Report.Error (1609, (Location) $3, "Modifiers cannot be placed on event accessor declarations"); $$ = null; } ; remove_accessor_declaration : opt_attributes REMOVE { Parameter [] args = new Parameter [1]; Parameter implicit_value_parameter = new Parameter ( implicit_value_parameter_type, "value", Parameter.Modifier.NONE, null, (Location) $2); args [0] = implicit_value_parameter; current_local_parameters = new Parameters (args); lexer.EventParsing = false; } block { $$ = new Accessor ((ToplevelBlock) $4, 0, (Attributes) $1, (Location) $2); lexer.EventParsing = true; current_local_parameters = null; } | opt_attributes REMOVE error { Report.Error (73, (Location) $2, "An add or remove accessor must have a body"); $$ = null; } | opt_attributes modifiers REMOVE { Report.Error (1609, (Location) $3, "Modifiers cannot be placed on event accessor declarations"); $$ = null; } ; indexer_declaration : opt_attributes opt_modifiers indexer_declarator OPEN_BRACE { IndexerDeclaration decl = (IndexerDeclaration) $3; implicit_value_parameter_type = decl.type; lexer.PropertyParsing = true; parsing_indexer = true; indexer_parameters = decl.param_list; anonymous_host = SimpleAnonymousHost.GetSimple (); } accessor_declarations { lexer.PropertyParsing = false; has_get = has_set = false; parsing_indexer = false; } CLOSE_BRACE { if ($6 == null) break; // The signature is computed from the signature of the indexer. Look // at section 3.6 on the spec Indexer indexer; IndexerDeclaration decl = (IndexerDeclaration) $3; Location loc = decl.location; Accessors accessors = (Accessors) $6; Accessor get_block = accessors.get_or_add; Accessor set_block = accessors.set_or_remove; MemberName name; if (decl.interface_type != null) name = new MemberName (decl.interface_type, TypeContainer.DefaultIndexerName, loc); else name = new MemberName (TypeContainer.DefaultIndexerName, loc); indexer = new Indexer (current_class, decl.type, name, (int) $2, false, decl.param_list, (Attributes) $1, get_block, set_block, accessors.declared_in_reverse); if (RootContext.Documentation != null) indexer.DocComment = ConsumeStoredComment (); current_container.AddIndexer (indexer); current_local_parameters = null; implicit_value_parameter_type = null; indexer_parameters = null; } ; indexer_declarator : type THIS OPEN_BRACKET opt_parameter_list_no_mod CLOSE_BRACKET { Parameters pars = (Parameters) $4; if (pars.Empty){ Report.Error (1551, (Location) $2, "Indexers must have at least one parameter"); } if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } $$ = new IndexerDeclaration ((FullNamedExpression) $1, null, pars, (Location) $2); } | type namespace_or_type_name DOT THIS OPEN_BRACKET opt_formal_parameter_list CLOSE_BRACKET { Parameters pars = (Parameters) $6; if (pars.Empty){ Report.Error (1551, (Location) $4, "Indexers must have at least one parameter"); } MemberName name = (MemberName) $2; $$ = new IndexerDeclaration ((FullNamedExpression) $1, name, pars, (Location) $4); if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } } ; enum_declaration : opt_attributes opt_modifiers ENUM IDENTIFIER opt_enum_base { if (RootContext.Documentation != null) enumTypeComment = Lexer.consume_doc_comment (); } enum_body opt_semicolon { LocatedToken lt = (LocatedToken) $4; Location enum_location = lt.Location; MemberName name = MakeName (new MemberName (lt.Value, enum_location)); Enum e = new Enum (current_namespace, current_class, (FullNamedExpression) $5, (int) $2, name, (Attributes) $1); if (RootContext.Documentation != null) e.DocComment = enumTypeComment; EnumMember em = null; foreach (VariableDeclaration ev in (ArrayList) $7) { em = new EnumMember ( e, em, ev.identifier, (Expression) ev.expression_or_array_initializer, ev.OptAttributes, ev.Location); // if (RootContext.Documentation != null) em.DocComment = ev.DocComment; e.AddEnumMember (em); } current_container.AddTypeContainer (e); $$ = e; } ; opt_enum_base : /* empty */ { $$ = TypeManager.system_int32_expr; } | COLON type { $$ = $2; } ; enum_body : OPEN_BRACE { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } opt_enum_member_declarations { // here will be evaluated after CLOSE_BLACE is consumed. if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } CLOSE_BRACE { $$ = $3; } ; opt_enum_member_declarations : /* empty */ { $$ = new ArrayList (4); } | enum_member_declarations opt_comma { $$ = $1; } ; enum_member_declarations : enum_member_declaration { ArrayList l = new ArrayList (4); l.Add ($1); $$ = l; } | enum_member_declarations COMMA enum_member_declaration { ArrayList l = (ArrayList) $1; l.Add ($3); $$ = l; } ; enum_member_declaration : opt_attributes IDENTIFIER { VariableDeclaration vd = new VariableDeclaration ( (LocatedToken) $2, null, (Attributes) $1); if (RootContext.Documentation != null) { vd.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } $$ = vd; } | opt_attributes IDENTIFIER { if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } } ASSIGN expression { VariableDeclaration vd = new VariableDeclaration ( (LocatedToken) $2, $5, (Attributes) $1); if (RootContext.Documentation != null) vd.DocComment = ConsumeStoredComment (); $$ = vd; } ; delegate_declaration : opt_attributes opt_modifiers DELEGATE type type_name open_parens opt_formal_parameter_list CLOSE_PARENS { MemberName name = MakeName ((MemberName) $5); Parameters p = (Parameters) $7; Delegate del = new Delegate (current_namespace, current_class, (FullNamedExpression) $4, (int) $2, name, p, (Attributes) $1); if (RootContext.Documentation != null) { del.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } current_container.AddDelegate (del); current_delegate = del; lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; } SEMICOLON { current_delegate.SetParameterInfo ((ArrayList) $10); $$ = current_delegate; current_delegate = null; } ; opt_nullable : /* empty */ { lexer.CheckNullable (false); $$ = false; } | INTERR { // FIXME: A hack with parsing conditional operator as nullable type //if (RootContext.Version < LanguageVersion.ISO_2) // Report.FeatureIsNotAvailable (lexer.Location, "nullable types"); lexer.CheckNullable (true); $$ = true; } ; namespace_or_type_name : IDENTIFIER opt_type_argument_list { LocatedToken lt = (LocatedToken) $1; $$ = new MemberName (lt.Value, (TypeArguments) $2, lt.Location); } | IDENTIFIER DOUBLE_COLON IDENTIFIER opt_type_argument_list { LocatedToken lt1 = (LocatedToken) $1; LocatedToken lt2 = (LocatedToken) $3; if (RootContext.Version == LanguageVersion.ISO_1) Report.FeatureIsNotAvailable (lt1.Location, "namespace alias qualifier"); $$ = new MemberName (lt1.Value, lt2.Value, (TypeArguments) $4, lt1.Location); } | namespace_or_type_name DOT IDENTIFIER opt_type_argument_list { LocatedToken lt = (LocatedToken) $3; $$ = new MemberName ((MemberName) $1, lt.Value, (TypeArguments) $4, lt.Location); } ; member_name : IDENTIFIER opt_type_parameter_list { LocatedToken lt = (LocatedToken) $1; $$ = new MemberName (lt.Value, (TypeArguments) $2, lt.Location); } | namespace_or_type_name DOT IDENTIFIER opt_type_parameter_list { LocatedToken lt = (LocatedToken) $3; $$ = new MemberName ((MemberName) $1, lt.Value, (TypeArguments) $4, lt.Location); } ; type_name : IDENTIFIER opt_type_parameter_list { LocatedToken lt = (LocatedToken) $1; $$ = new MemberName (lt.Value, (TypeArguments)$2, lt.Location); } ; // // Generics arguments (any type, without attributes) // opt_type_argument_list : /* empty */ { $$ = null; } | OP_GENERICS_LT type_arguments OP_GENERICS_GT { if (RootContext.Version < LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (GetLocation ($1), "generics"); $$ = $2; } ; // // Generics parameters (identifiers only, with attributes), used in type, method declarations // opt_type_parameter_list : /* empty */ { $$ = null; } | OP_GENERICS_LT type_arguments OP_GENERICS_GT { if (RootContext.Version < LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (GetLocation ($1), "generics"); $$ = $2; } ; type_arguments : type_argument { TypeArguments type_args = new TypeArguments (lexer.Location); type_args.Add ((Expression) $1); $$ = type_args; } | type_arguments COMMA type_argument { TypeArguments type_args = (TypeArguments) $1; type_args.Add ((Expression) $3); $$ = type_args; } ; type_argument : type { $$ = $1; } | attribute_sections type { SimpleName sn = $2 as SimpleName; if (sn == null) Error_TypeExpected (GetLocation ($2)); else $2 = new TypeParameterName (sn.Name, (Attributes) $1, lexer.Location); $$ = $2; } ; /* * Before you think of adding a return_type, notice that we have been * using two rules in the places where it matters (one rule using type * and another identical one that uses VOID as the return type). This * gets rid of a shift/reduce couple */ type : namespace_or_type_name opt_nullable { MemberName name = (MemberName) $1; if ((bool) $2) { $$ = new ComposedCast (name.GetTypeExpression (), "?", lexer.Location); } else { if (RootContext.Version > LanguageVersion.ISO_2 && name.Left == null && name.Name == "var") $$ = new VarExpr (name.Location); else $$ = name.GetTypeExpression (); } } | builtin_types opt_nullable { if ((bool) $2) $$ = new ComposedCast ((FullNamedExpression) $1, "?", lexer.Location); } | array_type | pointer_type ; pointer_type : type STAR { // // Note that here only unmanaged types are allowed but we // can't perform checks during this phase - we do it during // semantic analysis. // $$ = new ComposedCast ((FullNamedExpression) $1, "*", Lexer.Location); } | VOID STAR { $$ = new ComposedCast (TypeManager.system_void_expr, "*", (Location) $1); } ; non_expression_type : builtin_types opt_nullable { if ((bool) $2) $$ = new ComposedCast ((FullNamedExpression) $1, "?", lexer.Location); } | non_expression_type rank_specifier { Location loc = GetLocation ($1); if (loc.IsNull) loc = lexer.Location; $$ = new ComposedCast ((FullNamedExpression) $1, (string) $2, loc); } | non_expression_type STAR { Location loc = GetLocation ($1); if (loc.IsNull) loc = lexer.Location; $$ = new ComposedCast ((FullNamedExpression) $1, "*", loc); } // // We need this because the parser will happily go and reduce IDENTIFIER STAR // through this different path // | multiplicative_expression STAR { FullNamedExpression e = $1 as FullNamedExpression; if (e != null) $$ = new ComposedCast (e, "*"); else Error_TypeExpected (GetLocation ($1)); } ; type_list : base_type_name { ArrayList types = new ArrayList (2); types.Add ($1); $$ = types; } | type_list COMMA base_type_name { ArrayList types = (ArrayList) $1; types.Add ($3); $$ = types; } ; base_type_name : type { if ($1 is ComposedCast) Report.Error (1521, GetLocation ($1), "Invalid base type `{0}'", ((ComposedCast)$1).GetSignatureForError ()); $$ = $1; } ; /* * replaces all the productions for isolating the various * simple types, but we need this to reuse it easily in local_variable_type */ builtin_types : OBJECT { $$ = TypeManager.system_object_expr; } | STRING { $$ = TypeManager.system_string_expr; } | BOOL { $$ = TypeManager.system_boolean_expr; } | DECIMAL { $$ = TypeManager.system_decimal_expr; } | FLOAT { $$ = TypeManager.system_single_expr; } | DOUBLE { $$ = TypeManager.system_double_expr; } | integral_type ; integral_type : SBYTE { $$ = TypeManager.system_sbyte_expr; } | BYTE { $$ = TypeManager.system_byte_expr; } | SHORT { $$ = TypeManager.system_int16_expr; } | USHORT { $$ = TypeManager.system_uint16_expr; } | INT { $$ = TypeManager.system_int32_expr; } | UINT { $$ = TypeManager.system_uint32_expr; } | LONG { $$ = TypeManager.system_int64_expr; } | ULONG { $$ = TypeManager.system_uint64_expr; } | CHAR { $$ = TypeManager.system_char_expr; } | VOID { $$ = TypeManager.system_void_expr; } ; array_type : type rank_specifiers { string rank_specifiers = (string) $2; $$ = current_array_type = new ComposedCast ((FullNamedExpression) $1, rank_specifiers); } ; // // Expressions, section 7.5 // primary_expression : literal { // 7.5.1: Literals } | type_name { MemberName mn = (MemberName) $1; $$ = mn.GetTypeExpression (); } | IDENTIFIER DOUBLE_COLON IDENTIFIER opt_type_argument_list { LocatedToken lt1 = (LocatedToken) $1; LocatedToken lt2 = (LocatedToken) $3; if (RootContext.Version == LanguageVersion.ISO_1) Report.FeatureIsNotAvailable (lt1.Location, "namespace alias qualifier"); $$ = new QualifiedAliasMember (lt1.Value, lt2.Value, (TypeArguments) $4, lt1.Location); } | parenthesized_expression | default_value_expression | member_access | invocation_expression | element_access | this_access | base_access | post_increment_expression | post_decrement_expression | new_expression | typeof_expression | sizeof_expression | checked_expression | unchecked_expression | pointer_member_access | anonymous_method_expression ; literal : boolean_literal | integer_literal | real_literal | LITERAL_CHARACTER { $$ = new CharLiteral ((char) lexer.Value, lexer.Location); } | LITERAL_STRING { $$ = new StringLiteral ((string) lexer.Value, lexer.Location); } | NULL { $$ = new NullLiteral (lexer.Location); } ; real_literal : LITERAL_FLOAT { $$ = new FloatLiteral ((float) lexer.Value, lexer.Location); } | LITERAL_DOUBLE { $$ = new DoubleLiteral ((double) lexer.Value, lexer.Location); } | LITERAL_DECIMAL { $$ = new DecimalLiteral ((decimal) lexer.Value, lexer.Location); } ; integer_literal : LITERAL_INTEGER { object v = lexer.Value; if (v is int){ $$ = new IntLiteral ((int) v, lexer.Location); } else if (v is uint) $$ = new UIntLiteral ((UInt32) v, lexer.Location); else if (v is long) $$ = new LongLiteral ((Int64) v, lexer.Location); else if (v is ulong) $$ = new ULongLiteral ((UInt64) v, lexer.Location); else Console.WriteLine ("OOPS. Unexpected result from scanner"); } ; boolean_literal : TRUE { $$ = new BoolLiteral (true, lexer.Location); } | FALSE { $$ = new BoolLiteral (false, lexer.Location); } ; parenthesized_expression_0 : OPEN_PARENS expression CLOSE_PARENS { $$ = $2; lexer.Deambiguate_CloseParens ($$); // After this, the next token returned is one of // CLOSE_PARENS_CAST, CLOSE_PARENS_NO_CAST (CLOSE_PARENS), CLOSE_PARENS_OPEN_PARENS // or CLOSE_PARENS_MINUS. } | OPEN_PARENS expression error { CheckToken (1026, yyToken, "Expecting ')'", lexer.Location); } ; parenthesized_expression : parenthesized_expression_0 CLOSE_PARENS_NO_CAST { $$ = $1; } | parenthesized_expression_0 CLOSE_PARENS { $$ = $1; } | parenthesized_expression_0 CLOSE_PARENS_MINUS { // If a parenthesized expression is followed by a minus, we need to wrap // the expression inside a ParenthesizedExpression for the CS0075 check // in Binary.DoResolve(). $$ = new ParenthesizedExpression ((Expression) $1); } ; member_access : primary_expression DOT IDENTIFIER opt_type_argument_list { LocatedToken lt = (LocatedToken) $3; $$ = new MemberAccess ((Expression) $1, lt.Value, (TypeArguments) $4, lt.Location); } | predefined_type DOT IDENTIFIER opt_type_argument_list { LocatedToken lt = (LocatedToken) $3; // TODO: Location is wrong as some predefined types doesn't hold a location $$ = new MemberAccess ((Expression) $1, lt.Value, (TypeArguments) $4, lt.Location); } ; predefined_type : builtin_types ; invocation_expression : primary_expression OPEN_PARENS opt_argument_list CLOSE_PARENS { if ($1 == null) Report.Error (1, (Location) $2, "Parse error"); else $$ = new Invocation ((Expression) $1, (ArrayList) $3); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS CLOSE_PARENS { $$ = new Invocation ((Expression) $1, new ArrayList ()); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS primary_expression { $$ = new InvocationOrCast ((Expression) $1, (Expression) $3); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS non_simple_argument CLOSE_PARENS { ArrayList args = new ArrayList (1); args.Add ($4); $$ = new Invocation ((Expression) $1, args); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS argument_list COMMA argument CLOSE_PARENS { ArrayList args = ((ArrayList) $4); args.Add ($6); $$ = new Invocation ((Expression) $1, args); } ; opt_object_or_collection_initializer : /* empty */ { $$ = null; } | object_or_collection_initializer ; object_or_collection_initializer : OPEN_BRACE opt_member_initializer_list CLOSE_BRACE { if ($2 == null) $$ = CollectionOrObjectInitializers.Empty; else $$ = new CollectionOrObjectInitializers ((ArrayList) $2, GetLocation ($1)); } | OPEN_BRACE member_initializer_list COMMA CLOSE_BRACE { $$ = new CollectionOrObjectInitializers ((ArrayList) $2, GetLocation ($1)); } ; opt_member_initializer_list : /* empty */ { $$ = null; } | member_initializer_list { $$ = $1; } ; member_initializer_list : member_initializer { ArrayList a = new ArrayList (); a.Add ($1); $$ = a; } | member_initializer_list COMMA member_initializer { ArrayList a = (ArrayList)$1; a.Add ($3); $$ = a; } ; member_initializer : IDENTIFIER ASSIGN initializer_value { LocatedToken lt = $1 as LocatedToken; $$ = new ElementInitializer (lt.Value, (Expression)$3, lt.Location); } | non_assignment_expression { $$ = new CollectionElementInitializer ((Expression)$1); } | OPEN_BRACE expression_list CLOSE_BRACE { $$ = new CollectionElementInitializer ((ArrayList)$2, GetLocation ($1)); } | OPEN_BRACE CLOSE_BRACE { Report.Error (1920, GetLocation ($1), "An element initializer cannot be empty"); } ; initializer_value : expression | object_or_collection_initializer ; opt_argument_list : /* empty */ { $$ = null; } | argument_list ; argument_list : argument { ArrayList list = new ArrayList (4); list.Add ($1); $$ = list; } | argument_list COMMA argument { ArrayList list = (ArrayList) $1; list.Add ($3); $$ = list; } | argument_list error { CheckToken (1026, yyToken, "Expected `,' or `)'", GetLocation ($2)); $$ = null; } ; argument : expression { $$ = new Argument ((Expression) $1, Argument.AType.Expression); } | non_simple_argument { $$ = $1; } ; non_simple_argument : REF variable_reference { $$ = new Argument ((Expression) $2, Argument.AType.Ref); } | OUT variable_reference { $$ = new Argument ((Expression) $2, Argument.AType.Out); } | ARGLIST OPEN_PARENS argument_list CLOSE_PARENS { ArrayList list = (ArrayList) $3; Argument[] args = new Argument [list.Count]; list.CopyTo (args, 0); Expression expr = new Arglist (args, (Location) $1); $$ = new Argument (expr, Argument.AType.Expression); } | ARGLIST OPEN_PARENS CLOSE_PARENS { $$ = new Argument (new Arglist ((Location) $1), Argument.AType.Expression); } | ARGLIST { $$ = new Argument (new ArglistAccess ((Location) $1), Argument.AType.ArgList); } ; variable_reference : expression { note ("section 5.4"); $$ = $1; } ; element_access : primary_expression OPEN_BRACKET expression_list CLOSE_BRACKET { $$ = new ElementAccess ((Expression) $1, (ArrayList) $3); } | primary_expression rank_specifiers { // So the super-trick is that primary_expression // can only be either a SimpleName or a MemberAccess. // The MemberAccess case arises when you have a fully qualified type-name like : // Foo.Bar.Blah i; // SimpleName is when you have // Blah i; Expression expr = (Expression) $1; if (expr is ComposedCast){ $$ = new ComposedCast ((ComposedCast)expr, (string) $2); } else if (expr is ATypeNameExpression){ // // So we extract the string corresponding to the SimpleName // or MemberAccess // $$ = new ComposedCast ((ATypeNameExpression)expr, (string) $2); } else { Error_ExpectingTypeName (expr); $$ = TypeManager.system_object_expr; } current_array_type = (FullNamedExpression)$$; } ; expression_list : expression { ArrayList list = new ArrayList (4); list.Add ($1); $$ = list; } | expression_list COMMA expression { ArrayList list = (ArrayList) $1; list.Add ($3); $$ = list; } ; this_access : THIS { $$ = new This (current_block, (Location) $1); } ; base_access : BASE DOT IDENTIFIER opt_type_argument_list { LocatedToken lt = (LocatedToken) $3; $$ = new BaseAccess (lt.Value, (TypeArguments) $4, lt.Location); } | BASE OPEN_BRACKET expression_list CLOSE_BRACKET { $$ = new BaseIndexerAccess ((ArrayList) $3, (Location) $1); } | BASE error { Report.Error (175, (Location) $1, "Use of keyword `base' is not valid in this context"); $$ = null; } ; post_increment_expression : primary_expression OP_INC { $$ = new UnaryMutator (UnaryMutator.Mode.PostIncrement, (Expression) $1, (Location) $2); } ; post_decrement_expression : primary_expression OP_DEC { $$ = new UnaryMutator (UnaryMutator.Mode.PostDecrement, (Expression) $1, (Location) $2); } ; new_expression : object_or_delegate_creation_expression | array_creation_expression | anonymous_type_expression ; object_or_delegate_creation_expression : NEW type OPEN_PARENS opt_argument_list CLOSE_PARENS opt_object_or_collection_initializer { if ($6 != null) { if (RootContext.Version <= LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (GetLocation ($1), "object initializers"); $$ = new NewInitialize ((Expression) $2, (ArrayList) $4, (CollectionOrObjectInitializers) $6, (Location) $1); } else $$ = new New ((Expression) $2, (ArrayList) $4, (Location) $1); } | NEW type object_or_collection_initializer { if (RootContext.Version <= LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (GetLocation ($1), "collection initializers"); $$ = new NewInitialize ((Expression) $2, null, (CollectionOrObjectInitializers) $3, (Location) $1); } ; array_creation_expression : NEW type OPEN_BRACKET expression_list CLOSE_BRACKET opt_rank_specifier opt_array_initializer { $$ = new ArrayCreation ((FullNamedExpression) $2, (ArrayList) $4, (string) $6, (ArrayList) $7, (Location) $1); } | NEW type rank_specifiers array_initializer { $$ = new ArrayCreation ((FullNamedExpression) $2, (string) $3, (ArrayList) $4, (Location) $1); } | NEW rank_specifiers array_initializer { $$ = new ImplicitlyTypedArrayCreation ((string) $2, (ArrayList) $3, (Location) $1); } | NEW error { Report.Error (1031, (Location) $1, "Type expected"); $$ = null; } | NEW type error { Report.Error (1526, (Location) $1, "A new expression requires () or [] after type"); $$ = null; } ; anonymous_type_expression : NEW OPEN_BRACE anonymous_type_parameters_opt_comma CLOSE_BRACE { if (RootContext.Version <= LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (GetLocation ($1), "anonymous types"); $$ = new AnonymousTypeDeclaration ((ArrayList) $3, current_container, GetLocation ($1)); } ; anonymous_type_parameters_opt_comma : anonymous_type_parameters_opt | anonymous_type_parameters COMMA ; anonymous_type_parameters_opt : { $$ = null; } | anonymous_type_parameters ; anonymous_type_parameters : anonymous_type_parameter { ArrayList a = new ArrayList (4); a.Add ($1); $$ = a; } | anonymous_type_parameters COMMA anonymous_type_parameter { ArrayList a = (ArrayList) $1; a.Add ($3); $$ = a; } ; anonymous_type_parameter : IDENTIFIER ASSIGN variable_initializer { LocatedToken lt = (LocatedToken)$1; $$ = new AnonymousTypeParameter ((Expression)$3, lt.Value, lt.Location); } | IDENTIFIER { LocatedToken lt = (LocatedToken)$1; $$ = new AnonymousTypeParameter (new SimpleName (lt.Value, lt.Location), lt.Value, lt.Location); } | BASE DOT IDENTIFIER opt_type_argument_list { LocatedToken lt = (LocatedToken) $3; BaseAccess ba = new BaseAccess (lt.Value, (TypeArguments) $4, lt.Location); $$ = new AnonymousTypeParameter (ba, lt.Value, lt.Location); } | member_access { MemberAccess ma = (MemberAccess) $1; $$ = new AnonymousTypeParameter (ma, ma.Name, ma.Location); } | error { Report.Error (746, lexer.Location, "Invalid anonymous type member declarator. " + "Anonymous type members must be a member assignment, simple name or member access expression"); } ; opt_rank_specifier : /* empty */ { $$ = ""; } | rank_specifiers { $$ = $1; } ; opt_rank_specifier_or_nullable : /* empty */ { $$ = string.Empty; } | INTERR { if (RootContext.Version < LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (lexer.Location, "nullable types"); $$ = "?"; } | opt_nullable rank_specifiers { if ((bool) $1) $$ = "?" + $2; else $$ = $2; } ; rank_specifiers : rank_specifier opt_rank_specifier { $$ = (string) $2 + (string) $1; } ; rank_specifier : OPEN_BRACKET opt_dim_separators CLOSE_BRACKET { $$ = "[" + (string) $2 + "]"; } ; opt_dim_separators : /* empty */ { $$ = ""; } | dim_separators { $$ = $1; } ; dim_separators : COMMA { $$ = ","; } | dim_separators COMMA { $$ = (string) $1 + ","; } ; opt_array_initializer : /* empty */ { $$ = null; } | array_initializer { $$ = $1; } ; array_initializer : OPEN_BRACE CLOSE_BRACE { ArrayList list = new ArrayList (4); $$ = list; } | OPEN_BRACE variable_initializer_list opt_comma CLOSE_BRACE { $$ = (ArrayList) $2; } ; variable_initializer_list : variable_initializer { ArrayList list = new ArrayList (4); list.Add ($1); $$ = list; } | variable_initializer_list COMMA variable_initializer { ArrayList list = (ArrayList) $1; list.Add ($3); $$ = list; } ; typeof_expression : TYPEOF { pushed_current_array_type = current_array_type; lexer.TypeOfParsing = true; } OPEN_PARENS typeof_type_expression CLOSE_PARENS { lexer.TypeOfParsing = false; Expression type = (Expression)$4; if (type == TypeManager.system_void_expr) $$ = new TypeOfVoid ((Location) $1); else $$ = new TypeOf (type, (Location) $1); current_array_type = pushed_current_array_type; } ; typeof_type_expression : type { $$ = $1; } | unbound_type_name { $$ = new UnboundTypeExpression ((MemberName)$1, lexer.Location); } ; unbound_type_name : IDENTIFIER GENERIC_DIMENSION { if (RootContext.Version < LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (lexer.Location, "generics"); LocatedToken lt = (LocatedToken) $1; TypeArguments ta = new TypeArguments ((int)$2, lt.Location); $$ = new MemberName (lt.Value, ta, lt.Location); } | IDENTIFIER DOUBLE_COLON IDENTIFIER GENERIC_DIMENSION { LocatedToken lt = (LocatedToken) $1; MemberName left = new MemberName (lt.Value, lt.Location); lt = (LocatedToken) $3; TypeArguments ta = new TypeArguments ((int)$4, lt.Location); if (RootContext.Version == LanguageVersion.ISO_1) Report.FeatureIsNotAvailable (lt.Location, "namespace alias qualifier"); $$ = new MemberName (left, lt.Value, ta, lt.Location); } | unbound_type_name DOT IDENTIFIER GENERIC_DIMENSION { LocatedToken lt = (LocatedToken) $3; TypeArguments ta = new TypeArguments ((int)$4, lt.Location); $$ = new MemberName ((MemberName)$1, lt.Value, ta, lt.Location); } | namespace_or_type_name DOT IDENTIFIER GENERIC_DIMENSION { LocatedToken lt = (LocatedToken) $3; TypeArguments ta = new TypeArguments ((int)$4, lt.Location); $$ = new MemberName ((MemberName)$1, lt.Value, ta, lt.Location); } ; sizeof_expression : SIZEOF OPEN_PARENS type CLOSE_PARENS { $$ = new SizeOf ((Expression) $3, (Location) $1); } ; checked_expression : CHECKED OPEN_PARENS expression CLOSE_PARENS { $$ = new CheckedExpr ((Expression) $3, (Location) $1); } ; unchecked_expression : UNCHECKED OPEN_PARENS expression CLOSE_PARENS { $$ = new UnCheckedExpr ((Expression) $3, (Location) $1); } ; pointer_member_access : primary_expression OP_PTR IDENTIFIER { Expression deref; LocatedToken lt = (LocatedToken) $3; deref = new Indirection ((Expression) $1, lt.Location); $$ = new MemberAccess (deref, lt.Value); } ; anonymous_method_expression : DELEGATE opt_anonymous_method_signature { start_anonymous (false, (Parameters) $2, (Location) $1); } block { $$ = end_anonymous ((ToplevelBlock) $4, (Location) $1); } ; opt_anonymous_method_signature : /* empty */ { $$ = null; } | anonymous_method_signature ; anonymous_method_signature : open_parens { params_modifiers_not_allowed = true; } opt_formal_parameter_list CLOSE_PARENS { params_modifiers_not_allowed = false; $$ = $3; } ; default_value_expression : DEFAULT_OPEN_PARENS type CLOSE_PARENS { if (RootContext.Version < LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (lexer.Location, "default value expression"); $$ = new DefaultValueExpression ((Expression) $2, lexer.Location); } ; unary_expression : primary_expression | BANG prefixed_unary_expression { $$ = new Unary (Unary.Operator.LogicalNot, (Expression) $2, (Location) $1); } | TILDE prefixed_unary_expression { $$ = new Unary (Unary.Operator.OnesComplement, (Expression) $2, (Location) $1); } | cast_expression ; cast_list : parenthesized_expression_0 CLOSE_PARENS_CAST unary_expression { $$ = new Cast ((Expression) $1, (Expression) $3); } | parenthesized_expression_0 CLOSE_PARENS_NO_CAST default_value_expression { $$ = new Cast ((Expression) $1, (Expression) $3); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS cast_expression { $$ = new Cast ((Expression) $1, (Expression) $3); } ; cast_expression : cast_list | OPEN_PARENS non_expression_type CLOSE_PARENS prefixed_unary_expression { // TODO: wrong location $$ = new Cast ((Expression) $2, (Expression) $4, lexer.Location); } ; // // The idea to split this out is from Rhys' grammar // to solve the problem with casts. // prefixed_unary_expression : unary_expression | PLUS prefixed_unary_expression { $$ = new Unary (Unary.Operator.UnaryPlus, (Expression) $2, (Location) $1); } | MINUS prefixed_unary_expression { $$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, (Location) $1); } | OP_INC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement, (Expression) $2, (Location) $1); } | OP_DEC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement, (Expression) $2, (Location) $1); } | STAR prefixed_unary_expression { $$ = new Indirection ((Expression) $2, (Location) $1); } | BITWISE_AND prefixed_unary_expression { $$ = new Unary (Unary.Operator.AddressOf, (Expression) $2, (Location) $1); } ; multiplicative_expression : prefixed_unary_expression | multiplicative_expression STAR prefixed_unary_expression { $$ = new Binary (Binary.Operator.Multiply, (Expression) $1, (Expression) $3); } | multiplicative_expression DIV prefixed_unary_expression { $$ = new Binary (Binary.Operator.Division, (Expression) $1, (Expression) $3); } | multiplicative_expression PERCENT prefixed_unary_expression { $$ = new Binary (Binary.Operator.Modulus, (Expression) $1, (Expression) $3); } ; additive_expression : multiplicative_expression | additive_expression PLUS multiplicative_expression { $$ = new Binary (Binary.Operator.Addition, (Expression) $1, (Expression) $3); } | additive_expression MINUS multiplicative_expression { $$ = new Binary (Binary.Operator.Subtraction, (Expression) $1, (Expression) $3); } ; shift_expression : additive_expression | shift_expression OP_SHIFT_LEFT additive_expression { $$ = new Binary (Binary.Operator.LeftShift, (Expression) $1, (Expression) $3); } | shift_expression OP_SHIFT_RIGHT additive_expression { $$ = new Binary (Binary.Operator.RightShift, (Expression) $1, (Expression) $3); } ; opt_error : /* empty */ { $$ = false; } | error { lexer.PutbackNullable (); $$ = true; } ; nullable_type_or_conditional : type opt_error { if (((bool) $2) && ($1 is ComposedCast)) $$ = ((ComposedCast) $1).RemoveNullable (); else $$ = $1; } ; relational_expression : shift_expression | relational_expression OP_LT shift_expression { $$ = new Binary (Binary.Operator.LessThan, (Expression) $1, (Expression) $3); } | relational_expression OP_GT shift_expression { $$ = new Binary (Binary.Operator.GreaterThan, (Expression) $1, (Expression) $3); } | relational_expression OP_LE shift_expression { $$ = new Binary (Binary.Operator.LessThanOrEqual, (Expression) $1, (Expression) $3); } | relational_expression OP_GE shift_expression { $$ = new Binary (Binary.Operator.GreaterThanOrEqual, (Expression) $1, (Expression) $3); } | relational_expression IS { yyErrorFlag = 3; } nullable_type_or_conditional { $$ = new Is ((Expression) $1, (Expression) $4, (Location) $2); } | relational_expression AS { yyErrorFlag = 3; } nullable_type_or_conditional { $$ = new As ((Expression) $1, (Expression) $4, (Location) $2); } ; equality_expression : relational_expression | equality_expression OP_EQ relational_expression { $$ = new Binary (Binary.Operator.Equality, (Expression) $1, (Expression) $3); } | equality_expression OP_NE relational_expression { $$ = new Binary (Binary.Operator.Inequality, (Expression) $1, (Expression) $3); } ; and_expression : equality_expression | and_expression BITWISE_AND equality_expression { $$ = new Binary (Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3); } ; exclusive_or_expression : and_expression | exclusive_or_expression CARRET and_expression { $$ = new Binary (Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3); } ; inclusive_or_expression : exclusive_or_expression | inclusive_or_expression BITWISE_OR exclusive_or_expression { $$ = new Binary (Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3); } ; conditional_and_expression : inclusive_or_expression | conditional_and_expression OP_AND inclusive_or_expression { $$ = new Binary (Binary.Operator.LogicalAnd, (Expression) $1, (Expression) $3); } ; conditional_or_expression : conditional_and_expression | conditional_or_expression OP_OR conditional_and_expression { $$ = new Binary (Binary.Operator.LogicalOr, (Expression) $1, (Expression) $3); } ; conditional_expression : conditional_or_expression | conditional_or_expression INTERR expression COLON expression { $$ = new Conditional ((Expression) $1, (Expression) $3, (Expression) $5); } | conditional_or_expression OP_COALESCING expression { if (RootContext.Version < LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (GetLocation ($2), "null coalescing operator"); $$ = new Nullable.NullCoalescingOperator ((Expression) $1, (Expression) $3, lexer.Location); } // We'll be resolved into a `parenthesized_expression_0' later on. | conditional_or_expression INTERR CLOSE_PARENS { $$ = new ComposedCast ((FullNamedExpression) $1, "?", lexer.Location); lexer.PutbackCloseParens (); } ; assignment_expression : prefixed_unary_expression ASSIGN expression { $$ = new SimpleAssign ((Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_MULT_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.Multiply, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_DIV_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.Division, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_MOD_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.Modulus, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_ADD_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.Addition, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_SUB_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.Subtraction, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_SHIFT_LEFT_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.LeftShift, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_SHIFT_RIGHT_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.RightShift, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_AND_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_OR_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3); } | prefixed_unary_expression OP_XOR_ASSIGN expression { $$ = new CompoundAssign ( Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3); } ; lambda_parameter_list : lambda_parameter { ArrayList pars = new ArrayList (4); pars.Add ($1); $$ = pars; } | lambda_parameter_list COMMA lambda_parameter { ArrayList pars = (ArrayList) $1; Parameter p = (Parameter)$3; if (pars[0].GetType () != p.GetType ()) { Report.Error (748, p.Location, "All lambda parameters must be typed either explicitly or implicitly"); } pars.Add (p); $$ = pars; } ; lambda_parameter : parameter_modifier type IDENTIFIER { LocatedToken lt = (LocatedToken) $3; $$ = new Parameter ((FullNamedExpression) $2, lt.Value, (Parameter.Modifier) $1, null, lt.Location); } | type IDENTIFIER { LocatedToken lt = (LocatedToken) $2; $$ = new Parameter ((FullNamedExpression) $1, lt.Value, Parameter.Modifier.NONE, null, lt.Location); } | IDENTIFIER { LocatedToken lt = (LocatedToken) $1; $$ = new ImplicitLambdaParameter (lt.Value, lt.Location); } ; opt_lambda_parameter_list : /* empty */ { $$ = Parameters.EmptyReadOnlyParameters; } | lambda_parameter_list { ArrayList pars_list = (ArrayList) $1; $$ = new Parameters ((Parameter[])pars_list.ToArray (typeof (Parameter))); } ; lambda_expression_body : { start_block (lexer.Location); } expression { Block b = end_block (lexer.Location); b.AddStatement (new ContextualReturn ((Expression) $2)); $$ = b; } | block { $$ = $1; } ; lambda_expression : IDENTIFIER ARROW { LocatedToken lt = (LocatedToken) $1; Parameter p = new ImplicitLambdaParameter (lt.Value, lt.Location); start_anonymous (true, new Parameters (p), (Location) $2); } lambda_expression_body { $$ = end_anonymous ((ToplevelBlock) $4, (Location) $2); } | OPEN_PARENS_LAMBDA opt_lambda_parameter_list CLOSE_PARENS ARROW { start_anonymous (true, (Parameters) $2, (Location) $4); } lambda_expression_body { $$ = end_anonymous ((ToplevelBlock) $6, (Location) $4); } ; expression : assignment_expression | non_assignment_expression ; non_assignment_expression : conditional_expression | lambda_expression | query_expression ; constant_expression : expression ; boolean_expression : expression ; // // 10 classes // class_declaration : opt_attributes opt_modifiers opt_partial CLASS { lexer.ConstraintsParsing = true; } type_name { MemberName name = MakeName ((MemberName) $6); push_current_class (new Class (current_namespace, current_class, name, (int) $2, (Attributes) $1), $3); } opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; current_class.SetParameterInfo ((ArrayList) $9); if (RootContext.Documentation != null) { current_container.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } } class_body { if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } opt_semicolon { $$ = pop_current_class (); } ; opt_partial : /* empty */ { $$ = null; } | PARTIAL { $$ = $1; } // location ; opt_modifiers : /* empty */ { $$ = (int) 0; } | modifiers ; modifiers : modifier | modifiers modifier { int m1 = (int) $1; int m2 = (int) $2; if ((m1 & m2) != 0) { Location l = lexer.Location; Report.Error (1004, l, "Duplicate `{0}' modifier", Modifiers.Name (m2)); } $$ = (int) (m1 | m2); } ; modifier : NEW { $$ = Modifiers.NEW; } | PUBLIC { $$ = Modifiers.PUBLIC; } | PROTECTED { $$ = Modifiers.PROTECTED; } | INTERNAL { $$ = Modifiers.INTERNAL; } | PRIVATE { $$ = Modifiers.PRIVATE; } | ABSTRACT { $$ = Modifiers.ABSTRACT; } | SEALED { $$ = Modifiers.SEALED; } | STATIC { $$ = Modifiers.STATIC; } | READONLY { $$ = Modifiers.READONLY; } | VIRTUAL { $$ = Modifiers.VIRTUAL; } | OVERRIDE { $$ = Modifiers.OVERRIDE; } | EXTERN { $$ = Modifiers.EXTERN; } | VOLATILE { $$ = Modifiers.VOLATILE; } | UNSAFE { $$ = Modifiers.UNSAFE; } ; opt_class_base : /* empty */ | class_base ; class_base : COLON type_list { current_container.AddBasesForPart (current_class, (ArrayList) $2); } ; opt_type_parameter_constraints_clauses : /* empty */ { $$ = null; } | type_parameter_constraints_clauses { $$ = $1; } ; type_parameter_constraints_clauses : type_parameter_constraints_clause { ArrayList constraints = new ArrayList (1); constraints.Add ($1); $$ = constraints; } | type_parameter_constraints_clauses type_parameter_constraints_clause { ArrayList constraints = (ArrayList) $1; Constraints new_constraint = (Constraints)$2; foreach (Constraints c in constraints) { if (new_constraint.TypeParameter == c.TypeParameter) { Report.Error (409, new_constraint.Location, "A constraint clause has already been specified for type parameter `{0}'", new_constraint.TypeParameter); } } constraints.Add (new_constraint); $$ = constraints; } ; type_parameter_constraints_clause : WHERE IDENTIFIER COLON type_parameter_constraints { LocatedToken lt = (LocatedToken) $2; $$ = new Constraints (lt.Value, (ArrayList) $4, lt.Location); } ; type_parameter_constraints : type_parameter_constraint { ArrayList constraints = new ArrayList (1); constraints.Add ($1); $$ = constraints; } | type_parameter_constraints COMMA type_parameter_constraint { ArrayList constraints = (ArrayList) $1; constraints.Add ($3); $$ = constraints; } ; type_parameter_constraint : type | NEW OPEN_PARENS CLOSE_PARENS { $$ = SpecialConstraint.Constructor; } | CLASS { $$ = SpecialConstraint.ReferenceType; } | STRUCT { $$ = SpecialConstraint.ValueType; } ; // // Statements (8.2) // // // A block is "contained" on the following places: // method_body // property_declaration as part of the accessor body (get/set) // operator_declaration // constructor_declaration // destructor_declaration // event_declaration as part of add_accessor_declaration or remove_accessor_declaration // block : OPEN_BRACE { ++lexer.parsing_block; start_block ((Location) $1); } opt_statement_list CLOSE_BRACE { --lexer.parsing_block; $$ = end_block ((Location) $4); } ; block_prepared : OPEN_BRACE { ++lexer.parsing_block; } opt_statement_list CLOSE_BRACE { --lexer.parsing_block; $$ = end_block ((Location) $4); } ; opt_statement_list : /* empty */ | statement_list ; statement_list : statement | statement_list statement ; statement : declaration_statement { if ($1 != null && (Block) $1 != current_block){ current_block.AddStatement ((Statement) $1); current_block = (Block) $1; } } | valid_declaration_statement { current_block.AddStatement ((Statement) $1); } | labeled_statement ; valid_declaration_statement : block | empty_statement | expression_statement | selection_statement | iteration_statement | jump_statement | try_statement | checked_statement | unchecked_statement | lock_statement | using_statement | unsafe_statement | fixed_statement ; embedded_statement : valid_declaration_statement | declaration_statement { Report.Error (1023, GetLocation ($1), "An embedded statement may not be a declaration or labeled statement"); $$ = null; } | labeled_statement { Report.Error (1023, GetLocation ($1), "An embedded statement may not be a declaration or labeled statement"); $$ = null; } ; empty_statement : SEMICOLON { $$ = EmptyStatement.Value; } ; labeled_statement : IDENTIFIER COLON { LocatedToken lt = (LocatedToken) $1; LabeledStatement labeled = new LabeledStatement (lt.Value, lt.Location); if (current_block.AddLabel (labeled)) current_block.AddStatement (labeled); } statement ; declaration_statement : local_variable_declaration SEMICOLON { current_array_type = null; if ($1 != null){ DictionaryEntry de = (DictionaryEntry) $1; Expression e = (Expression) de.Key; $$ = declare_local_variables (e, (ArrayList) de.Value, e.Location); } } | local_constant_declaration SEMICOLON { current_array_type = null; if ($1 != null){ DictionaryEntry de = (DictionaryEntry) $1; $$ = declare_local_constants ((Expression) de.Key, (ArrayList) de.Value); } } ; /* * The following is from Rhys' grammar: * > Types in local variable declarations must be recognized as * > expressions to prevent reduce/reduce errors in the grammar. * > The expressions are converted into types during semantic analysis. */ local_variable_type : primary_expression opt_rank_specifier_or_nullable { // FIXME: Do something smart here regarding the composition of the type. // Ok, the above "primary_expression" is there to get rid of // both reduce/reduce and shift/reduces in the grammar, it should // really just be "type_name". If you use type_name, a reduce/reduce // creeps up. If you use namespace_or_type_name (which is all we need // really) two shift/reduces appear. // // So the super-trick is that primary_expression // can only be either a SimpleName or a MemberAccess. // The MemberAccess case arises when you have a fully qualified type-name like : // Foo.Bar.Blah i; // SimpleName is when you have // Blah i; Expression expr = (Expression) $1; string rank_or_nullable = (string) $2; if (expr is ComposedCast){ $$ = new ComposedCast ((ComposedCast)expr, rank_or_nullable); } else if (expr is ATypeNameExpression){ // // So we extract the string corresponding to the SimpleName // or MemberAccess // if (rank_or_nullable.Length == 0) { SimpleName sn = expr as SimpleName; if (sn != null && RootContext.Version > LanguageVersion.ISO_2 && sn.Name == "var") $$ = new VarExpr (sn.Location); else $$ = $1; } else { $$ = new ComposedCast ((ATypeNameExpression)expr, rank_or_nullable); } } else { Error_ExpectingTypeName (expr); $$ = TypeManager.system_object_expr; } } | builtin_types opt_rank_specifier_or_nullable { if ((string) $2 == "") $$ = $1; else $$ = current_array_type = new ComposedCast ((FullNamedExpression) $1, (string) $2, lexer.Location); } ; local_variable_pointer_type : primary_expression STAR { ATypeNameExpression expr = $1 as ATypeNameExpression; if (expr != null) { $$ = new ComposedCast (expr, "*"); } else { Error_ExpectingTypeName ((Expression)$1); $$ = expr; } } | builtin_types STAR { $$ = new ComposedCast ((FullNamedExpression) $1, "*", lexer.Location); } | VOID STAR { $$ = new ComposedCast (TypeManager.system_void_expr, "*", (Location) $1); } | local_variable_pointer_type STAR { $$ = new ComposedCast ((FullNamedExpression) $1, "*"); } ; local_variable_declaration : local_variable_type variable_declarators { if ($1 != null) { VarExpr ve = $1 as VarExpr; if (ve != null) ve.VariableInitializer = (ArrayList)$2; $$ = new DictionaryEntry ($1, $2); } else $$ = null; } | local_variable_pointer_type opt_rank_specifier_or_nullable variable_declarators { if ($1 != null){ Expression t; if ((string) $2 == "") t = (Expression) $1; else t = new ComposedCast ((FullNamedExpression) $1, (string) $2); $$ = new DictionaryEntry (t, $3); } else $$ = null; } ; local_constant_declaration : CONST local_variable_type constant_declarators { if ($2 != null) $$ = new DictionaryEntry ($2, $3); else $$ = null; } ; expression_statement : statement_expression SEMICOLON { $$ = $1; } ; // // We have to do the wrapping here and not in the case above, // because statement_expression is used for example in for_statement // statement_expression : expression { Expression expr = (Expression) $1; ExpressionStatement s = expr as ExpressionStatement; if (s == null) { expr.Error_InvalidExpressionStatement (); $$ = null; } $$ = new StatementExpression (s); } | error { Report.Error (1002, GetLocation ($1), "Expecting `;'"); $$ = null; } ; selection_statement : if_statement | switch_statement ; if_statement : IF OPEN_PARENS boolean_expression CLOSE_PARENS embedded_statement { Location l = (Location) $1; $$ = new If ((Expression) $3, (Statement) $5, l); // FIXME: location for warning should be loc property of $5. if ($5 == EmptyStatement.Value) Report.Warning (642, 3, l, "Possible mistaken empty statement"); } | IF OPEN_PARENS boolean_expression CLOSE_PARENS embedded_statement ELSE embedded_statement { Location l = (Location) $1; $$ = new If ((Expression) $3, (Statement) $5, (Statement) $7, l); // FIXME: location for warning should be loc property of $5 and $7. if ($5 == EmptyStatement.Value) Report.Warning (642, 3, l, "Possible mistaken empty statement"); if ($7 == EmptyStatement.Value) Report.Warning (642, 3, l, "Possible mistaken empty statement"); } ; switch_statement : SWITCH OPEN_PARENS { if (switch_stack == null) switch_stack = new Stack (2); switch_stack.Push (current_block); } expression CLOSE_PARENS switch_block { $$ = new Switch ((Expression) $4, (ArrayList) $6, (Location) $1); current_block = (Block) switch_stack.Pop (); } ; switch_block : OPEN_BRACE opt_switch_sections CLOSE_BRACE { $$ = $2; } ; opt_switch_sections : /* empty */ { Report.Warning (1522, 1, lexer.Location, "Empty switch block"); $$ = new ArrayList (); } | switch_sections ; switch_sections : switch_section { ArrayList sections = new ArrayList (4); sections.Add ($1); $$ = sections; } | switch_sections switch_section { ArrayList sections = (ArrayList) $1; sections.Add ($2); $$ = sections; } ; switch_section : switch_labels { current_block = current_block.CreateSwitchBlock (lexer.Location); } statement_list { $$ = new SwitchSection ((ArrayList) $1, current_block.Explicit); } ; switch_labels : switch_label { ArrayList labels = new ArrayList (4); labels.Add ($1); $$ = labels; } | switch_labels switch_label { ArrayList labels = (ArrayList) ($1); labels.Add ($2); $$ = labels; } ; switch_label : CASE constant_expression COLON { $$ = new SwitchLabel ((Expression) $2, (Location) $1); } | DEFAULT_COLON { $$ = new SwitchLabel (null, (Location) $1); } | error { Report.Error ( 1523, GetLocation ($1), "The keyword case or default must precede code in switch block"); } ; iteration_statement : while_statement | do_statement | for_statement | foreach_statement ; while_statement : WHILE OPEN_PARENS boolean_expression CLOSE_PARENS embedded_statement { Location l = (Location) $1; $$ = new While ((Expression) $3, (Statement) $5, l); } ; do_statement : DO embedded_statement WHILE OPEN_PARENS boolean_expression CLOSE_PARENS SEMICOLON { Location l = (Location) $1; $$ = new Do ((Statement) $2, (Expression) $5, l); } ; for_statement : FOR open_parens opt_for_initializer SEMICOLON { Location l = lexer.Location; start_block (l); Block assign_block = current_block; if ($3 is DictionaryEntry){ DictionaryEntry de = (DictionaryEntry) $3; Expression type = (Expression) de.Key; ArrayList var_declarators = (ArrayList) de.Value; foreach (VariableDeclaration decl in var_declarators){ LocalInfo vi; vi = current_block.AddVariable (type, decl.identifier, decl.Location); if (vi == null) continue; Expression expr = decl.expression_or_array_initializer; LocalVariableReference var; var = new LocalVariableReference (assign_block, decl.identifier, l); if (expr != null) { Assign a = new SimpleAssign (var, expr, decl.Location); assign_block.AddStatement (new StatementExpression (a)); } } // Note: the $$ below refers to the value of this code block, not of the LHS non-terminal. // This can be referred to as $5 below. $$ = null; } else { $$ = $3; } } opt_for_condition SEMICOLON opt_for_iterator CLOSE_PARENS embedded_statement { Location l = (Location) $1; For f = new For ((Statement) $5, (Expression) $6, (Statement) $8, (Statement) $10, l); current_block.AddStatement (f); $$ = end_block (lexer.Location); } ; opt_for_initializer : /* empty */ { $$ = EmptyStatement.Value; } | for_initializer ; for_initializer : local_variable_declaration | statement_expression_list ; opt_for_condition : /* empty */ { $$ = null; } | boolean_expression ; opt_for_iterator : /* empty */ { $$ = EmptyStatement.Value; } | for_iterator ; for_iterator : statement_expression_list ; statement_expression_list : statement_expression { // CHANGE: was `null' Statement s = (Statement) $1; Block b = new Block (current_block, s.loc, lexer.Location); b.AddStatement (s); $$ = b; } | statement_expression_list COMMA statement_expression { Block b = (Block) $1; b.AddStatement ((Statement) $3); $$ = $1; } ; foreach_statement : FOREACH open_parens type IN expression CLOSE_PARENS { Report.Error (230, (Location) $1, "Type and identifier are both required in a foreach statement"); $$ = null; } | FOREACH open_parens type IDENTIFIER IN expression CLOSE_PARENS { start_block (lexer.Location); Block foreach_block = current_block; LocatedToken lt = (LocatedToken) $4; Location l = lt.Location; LocalInfo vi = foreach_block.AddVariable ((Expression) $3, lt.Value, l); if (vi != null) { vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Foreach); // Get a writable reference to this read-only variable. // // Note that the $$ here refers to the value of _this_ code block, // not the value of the LHS non-terminal. This can be referred to as $8 below. $$ = new LocalVariableReference (foreach_block, lt.Value, l, vi, false); } else { $$ = null; } } embedded_statement { LocalVariableReference v = (LocalVariableReference) $8; Location l = (Location) $1; if (v != null) { Foreach f = new Foreach ((Expression) $3, v, (Expression) $6, (Statement) $9, l); current_block.AddStatement (f); } $$ = end_block (lexer.Location); } ; jump_statement : break_statement | continue_statement | goto_statement | return_statement | throw_statement | yield_statement ; break_statement : BREAK SEMICOLON { $$ = new Break ((Location) $1); } ; continue_statement : CONTINUE SEMICOLON { $$ = new Continue ((Location) $1); } ; goto_statement : GOTO IDENTIFIER SEMICOLON { LocatedToken lt = (LocatedToken) $2; $$ = new Goto (lt.Value, lt.Location); } | GOTO CASE constant_expression SEMICOLON { $$ = new GotoCase ((Expression) $3, (Location) $1); } | GOTO DEFAULT SEMICOLON { $$ = new GotoDefault ((Location) $1); } ; return_statement : RETURN opt_expression SEMICOLON { $$ = new Return ((Expression) $2, (Location) $1); } ; throw_statement : THROW opt_expression SEMICOLON { $$ = new Throw ((Expression) $2, (Location) $1); } ; yield_statement : IDENTIFIER RETURN expression SEMICOLON { LocatedToken lt = (LocatedToken) $1; string s = lt.Value; if (s != "yield"){ Report.Error (1003, lt.Location, "; expected"); $$ = null; } if (RootContext.Version == LanguageVersion.ISO_1){ Report.FeatureIsNotAvailable (lt.Location, "yield statement"); $$ = null; } if (anonymous_host == null){ Report.Error (204, lt.Location, "yield statement can only be used within a method, operator or property"); $$ = null; } else { anonymous_host.SetYields (); $$ = new Yield ((Expression) $3, lt.Location); } } | IDENTIFIER RETURN SEMICOLON { Report.Error (1627, (Location) $2, "Expression expected after yield return"); $$ = null; } | IDENTIFIER BREAK SEMICOLON { LocatedToken lt = (LocatedToken) $1; string s = lt.Value; if (s != "yield"){ Report.Error (1003, lt.Location, "; expected"); $$ = null; } if (RootContext.Version == LanguageVersion.ISO_1){ Report.FeatureIsNotAvailable (lt.Location, "yield statement"); $$ = null; } if (anonymous_host == null){ Report.Error (204, lt.Location, "yield statement can only be used within a method, operator or property"); $$ = null; } else { anonymous_host.SetYields (); $$ = new YieldBreak (lt.Location); } } ; opt_expression : /* empty */ | expression ; try_statement : TRY block catch_clauses { $$ = new TryCatch ((Block) $2, (ArrayList) $3, (Location) $1, false); } | TRY block FINALLY block { $$ = new TryFinally ((Statement) $2, (Block) $4, (Location) $1); } | TRY block catch_clauses FINALLY block { $$ = new TryFinally (new TryCatch ((Block) $2, (ArrayList) $3, (Location) $1, true), (Block) $5, (Location) $1); } | TRY block error { Report.Error (1524, (Location) $1, "Expected catch or finally"); $$ = null; } ; catch_clauses : catch_clause { ArrayList l = new ArrayList (4); l.Add ($1); $$ = l; } | catch_clauses catch_clause { ArrayList l = (ArrayList) $1; l.Add ($2); $$ = l; } ; opt_identifier : /* empty */ { $$ = null; } | IDENTIFIER ; catch_clause : CATCH opt_catch_args { Expression type = null; if ($2 != null) { DictionaryEntry cc = (DictionaryEntry) $2; type = (Expression) cc.Key; LocatedToken lt = (LocatedToken) cc.Value; if (lt != null){ ArrayList one = new ArrayList (4); one.Add (new VariableDeclaration (lt, null)); start_block (lexer.Location); current_block = declare_local_variables (type, one, lt.Location); } } } block { Expression type = null; string id = null; Block var_block = null; if ($2 != null){ DictionaryEntry cc = (DictionaryEntry) $2; type = (Expression) cc.Key; LocatedToken lt = (LocatedToken) cc.Value; if (lt != null){ id = lt.Value; var_block = end_block (lexer.Location); } } $$ = new Catch (type, id, (Block) $4, var_block, ((Block) $4).loc); } ; opt_catch_args : /* empty */ { $$ = null; } | catch_args ; catch_args : OPEN_PARENS type opt_identifier CLOSE_PARENS { $$ = new DictionaryEntry ($2, $3); } | OPEN_PARENS CLOSE_PARENS { Report.Error (1015, GetLocation ($1), "A type that derives from `System.Exception', `object', or `string' expected"); } ; checked_statement : CHECKED block { $$ = new Checked ((Block) $2); } ; unchecked_statement : UNCHECKED block { $$ = new Unchecked ((Block) $2); } ; unsafe_statement : UNSAFE { RootContext.CheckUnsafeOption ((Location) $1); } block { $$ = new Unsafe ((Block) $3); } ; fixed_statement : FIXED open_parens type fixed_pointer_declarators CLOSE_PARENS { ArrayList list = (ArrayList) $4; Expression type = (Expression) $3; Location l = (Location) $1; int top = list.Count; start_block (lexer.Location); for (int i = 0; i < top; i++){ Pair p = (Pair) list [i]; LocalInfo v; v = current_block.AddVariable (type, (string) p.First, l); if (v == null) continue; v.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed); v.Pinned = true; p.First = v; list [i] = p; } } embedded_statement { Location l = (Location) $1; Fixed f = new Fixed ((Expression) $3, (ArrayList) $4, (Statement) $7, l); current_block.AddStatement (f); $$ = end_block (lexer.Location); } ; fixed_pointer_declarators : fixed_pointer_declarator { ArrayList declarators = new ArrayList (4); if ($1 != null) declarators.Add ($1); $$ = declarators; } | fixed_pointer_declarators COMMA fixed_pointer_declarator { ArrayList declarators = (ArrayList) $1; if ($3 != null) declarators.Add ($3); $$ = declarators; } ; fixed_pointer_declarator : IDENTIFIER ASSIGN expression { LocatedToken lt = (LocatedToken) $1; // FIXME: keep location $$ = new Pair (lt.Value, $3); } | IDENTIFIER { Report.Error (210, ((LocatedToken) $1).Location, "You must provide an initializer in a fixed or using statement declaration"); $$ = null; } ; lock_statement : LOCK OPEN_PARENS expression CLOSE_PARENS { // } embedded_statement { $$ = new Lock ((Expression) $3, (Statement) $6, (Location) $1); } ; using_statement : USING open_parens local_variable_declaration CLOSE_PARENS { start_block (lexer.Location); Block assign_block = current_block; DictionaryEntry de = (DictionaryEntry) $3; Location l = (Location) $1; Expression type = (Expression) de.Key; ArrayList var_declarators = (ArrayList) de.Value; Stack vars = new Stack (); foreach (VariableDeclaration decl in var_declarators) { LocalInfo vi = current_block.AddVariable (type, decl.identifier, decl.Location); if (vi == null) continue; vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Using); Expression expr = decl.expression_or_array_initializer; if (expr == null) { Report.Error (210, l, "You must provide an initializer in a fixed or using statement declaration"); continue; } LocalVariableReference var; // Get a writable reference to this read-only variable. var = new LocalVariableReference (assign_block, decl.identifier, l, vi, false); // This is so that it is not a warning on using variables vi.Used = true; vars.Push (new DictionaryEntry (var, expr)); // Assign a = new SimpleAssign (var, expr, decl.Location); // assign_block.AddStatement (new StatementExpression (a)); } // Note: the $$ here refers to the value of this code block and not of the LHS non-terminal. // It can be referred to as $5 below. $$ = vars; } embedded_statement { Statement stmt = (Statement) $6; Stack vars = (Stack) $5; Location l = (Location) $1; while (vars.Count > 0) { DictionaryEntry de = (DictionaryEntry) vars.Pop (); stmt = new Using ((Expression) de.Key, (Expression) de.Value, stmt, l); } current_block.AddStatement (stmt); $$ = end_block (lexer.Location); } | USING open_parens expression CLOSE_PARENS { start_block (lexer.Location); } embedded_statement { current_block.AddStatement (new UsingTemporary ((Expression) $3, (Statement) $6, (Location) $1)); $$ = end_block (lexer.Location); } ; // LINQ query_expression : first_from_clause { ++lexer.query_parsing; } query_body { if (--lexer.query_parsing == 1) lexer.query_parsing = 0; Linq.AQueryClause from = $1 as Linq.AQueryClause; from.Tail.Next = (Linq.AQueryClause)$3; $$ = from; current_block.SetEndLocation (lexer.Location); current_block = current_block.Parent; } ; first_from_clause : FROM IDENTIFIER IN expression { current_block = new Linq.QueryBlock (current_block, GetLocation ($1)); LocatedToken lt = (LocatedToken) $2; current_block.AddVariable (Linq.ImplicitQueryParameter.ImplicitType.Instance, lt.Value, lt.Location); $$ = new Linq.QueryExpression (lt, new Linq.QueryStartClause ((Expression)$4)); } | FROM type IDENTIFIER IN expression { current_block = new Linq.QueryBlock (current_block, GetLocation ($1)); LocatedToken lt = (LocatedToken) $3; Expression type = (Expression)$2; current_block.AddVariable (type, lt.Value, lt.Location); $$ = new Linq.QueryExpression (lt, new Linq.Cast (type, (Expression)$5)); } ; from_clause : FROM IDENTIFIER IN expression { LocatedToken lt = (LocatedToken) $2; current_block.AddVariable (Linq.ImplicitQueryParameter.ImplicitType.Instance, lt.Value, lt.Location); $$ = new Linq.SelectMany (lt, (Expression)$4); } | FROM type IDENTIFIER IN expression { LocatedToken lt = (LocatedToken) $3; Expression type = (Expression)$2; current_block.AddVariable (type, lt.Value, lt.Location); $$ = new Linq.SelectMany (lt, new Linq.Cast (type, (Expression)$5)); } ; query_body : opt_query_body_clauses select_or_group_clause opt_query_continuation { Linq.AQueryClause head = (Linq.AQueryClause)$2; if ($3 != null) head.Next = (Linq.AQueryClause)$3; if ($1 != null) { Linq.AQueryClause clause = (Linq.AQueryClause)$1; clause.Tail.Next = head; head = clause; } $$ = head; } ; select_or_group_clause : SELECT expression { $$ = new Linq.Select ((Expression)$2, GetLocation ($1)); } | GROUP expression BY expression { $$ = new Linq.GroupBy ((Expression)$2, (Expression)$4, GetLocation ($1)); } ; opt_query_body_clauses : /* empty */ | query_body_clauses ; query_body_clauses : query_body_clause | query_body_clauses query_body_clause { ((Linq.AQueryClause)$1).Tail.Next = (Linq.AQueryClause)$2; $$ = $1; } ; query_body_clause : from_clause | let_clause | where_clause | join_clause | orderby_clause ; let_clause : LET IDENTIFIER ASSIGN expression { LocatedToken lt = (LocatedToken) $2; current_block.AddVariable (Linq.ImplicitQueryParameter.ImplicitType.Instance, lt.Value, lt.Location); $$ = new Linq.Let (lt, (Expression)$4, GetLocation ($1)); } ; where_clause : WHERE boolean_expression { $$ = new Linq.Where ((Expression)$2, GetLocation ($1)); } ; join_clause : JOIN IDENTIFIER IN expression ON expression EQUALS expression opt_join_into { Location loc = GetLocation ($1); LocatedToken lt = (LocatedToken) $2; current_block.AddVariable (Linq.ImplicitQueryParameter.ImplicitType.Instance, lt.Value, lt.Location); if ($9 == null) { $$ = new Linq.Join (lt, (Expression)$4, (Expression)$6, (Expression)$8, loc); } else { LocatedToken lt_into = (LocatedToken) $9; $$ = new Linq.GroupJoin (lt, (Expression)$4, (Expression)$6, (Expression)$8, lt_into, loc); } } | JOIN type IDENTIFIER IN expression ON expression EQUALS expression opt_join_into { Location loc = GetLocation ($1); LocatedToken lt = (LocatedToken) $3; current_block.AddVariable ((Expression)$2, lt.Value, lt.Location); Linq.Cast cast = new Linq.Cast ((Expression)$2, (Expression)$5); if ($10 == null) { $$ = new Linq.Join (lt, cast, (Expression)$7, (Expression)$9, loc); } else { LocatedToken lt_into = (LocatedToken) $10; $$ = new Linq.GroupJoin (lt, cast, (Expression)$7, (Expression)$9, lt_into, loc); } } ; opt_join_into : /* empty */ | INTO IDENTIFIER { $$ = $2; } ; orderby_clause : ORDERBY orderings { $$ = $2; } ; orderings : order_by | order_by COMMA orderings_then_by { ((Linq.AQueryClause)$1).Next = (Linq.AQueryClause)$3; $$ = $1; } ; orderings_then_by : then_by { $$ = $1; } | orderings_then_by COMMA then_by { ((Linq.AQueryClause)$1).Tail.Next = (Linq.AQueryClause)$3; $$ = $1; } ; order_by : expression { $$ = new Linq.OrderByAscending ((Expression)$1); } | expression ASCENDING { $$ = new Linq.OrderByAscending ((Expression)$1); } | expression DESCENDING { $$ = new Linq.OrderByDescending ((Expression)$1); } ; then_by : expression { $$ = new Linq.ThenByAscending ((Expression)$1); } | expression ASCENDING { $$ = new Linq.ThenByAscending ((Expression)$1); } | expression DESCENDING { $$ = new Linq.ThenByDescending ((Expression)$1); } ; opt_query_continuation : /* empty */ | INTO IDENTIFIER { // query continuation block is not linked with query block but with block // before. This means each query can use same range variable names for // different identifiers. current_block.SetEndLocation (GetLocation ($1)); current_block = current_block.Parent; current_block = new Linq.QueryBlock (current_block, GetLocation ($1)); LocatedToken lt = (LocatedToken) $2; current_block.AddVariable (Linq.ImplicitQueryParameter.ImplicitType.Instance, lt.Value, lt.Location); } query_body { $$ = new Linq.QueryExpression ((LocatedToken) $2, (Linq.AQueryClause)$4); } ; %% // // A class used to pass around variable declarations and constants // public class VariableDeclaration { public string identifier; public Expression expression_or_array_initializer; public Location Location; public Attributes OptAttributes; public string DocComment; public VariableDeclaration (LocatedToken lt, object eoai, Attributes opt_attrs) { this.identifier = lt.Value; if (eoai is ArrayList) { this.expression_or_array_initializer = new ArrayCreation (CSharpParser.current_array_type, "", (ArrayList)eoai, lt.Location); } else { this.expression_or_array_initializer = (Expression)eoai; } this.Location = lt.Location; this.OptAttributes = opt_attrs; } public VariableDeclaration (LocatedToken lt, object eoai) : this (lt, eoai, null) { } } // // A class used to hold info about an indexer declarator // public class IndexerDeclaration { public FullNamedExpression type; public MemberName interface_type; public Parameters param_list; public Location location; public IndexerDeclaration (FullNamedExpression type, MemberName interface_type, Parameters param_list, Location loc) { this.type = type; this.interface_type = interface_type; this.param_list = param_list; this.location = loc; } } // // We use this when we do not have an object in advance that is an IAnonymousHost // public class SimpleAnonymousHost : IAnonymousHost { public static readonly SimpleAnonymousHost Simple = new SimpleAnonymousHost (); bool yields; public static SimpleAnonymousHost GetSimple () { Simple.yields = false; return Simple; } public void SetYields () { yields = true; } public void Propagate (IAnonymousHost real_host) { if (yields) real_host.SetYields (); } } // // A class used to hold info about an operator declarator // struct OperatorDeclaration { public readonly Operator.OpType optype; public readonly FullNamedExpression ret_type; public readonly Location location; public OperatorDeclaration (Operator.OpType op, FullNamedExpression ret_type, Location location) { optype = op; this.ret_type = ret_type; this.location = location; } } void Error_ExpectingTypeName (Expression expr) { if (expr is Invocation){ Report.Error (1002, expr.Location, "Expecting `;'"); } else { expr.Error_InvalidExpressionStatement (); } } static void Error_ParameterModifierNotValid (string modifier, Location loc) { Report.Error (631, loc, "The parameter modifier `{0}' is not valid in this context", modifier); } static void Error_DuplicateParameterModifier (Location loc, Parameter.Modifier mod) { Report.Error (1107, loc, "Duplicate parameter modifier `{0}'", Parameter.GetModifierSignature (mod)); } static void Error_TypeExpected (Location loc) { Report.Error (1031, loc, "Type expected"); } void push_current_class (TypeContainer tc, object partial_token) { if (partial_token != null) current_container = current_container.AddPartial (tc); else current_container = current_container.AddTypeContainer (tc); current_class = tc; } DeclSpace pop_current_class () { DeclSpace retval = current_class; current_class = current_class.Parent; current_container = current_class.PartialContainer; return retval; } // // Given the @class_name name, it creates a fully qualified name // based on the containing declaration space // MemberName MakeName (MemberName class_name) { Namespace ns = current_namespace.NS; if (current_container.Name.Length == 0){ if (ns.Name.Length != 0) return new MemberName (ns.MemberName, class_name); else return class_name; } else { return new MemberName (current_container.MemberName, class_name); } } Block declare_local_variables (Expression type, ArrayList variable_declarators, Location loc) { Block implicit_block; ArrayList inits = null; // // We use the `Used' property to check whether statements // have been added to the current block. If so, we need // to create another block to contain the new declaration // otherwise, as an optimization, we use the same block to // add the declaration. // // FIXME: A further optimization is to check if the statements // that were added were added as part of the initialization // below. In which case, no other statements have been executed // and we might be able to reduce the number of blocks for // situations like this: // // int j = 1; int k = j + 1; // if (current_block.Used) implicit_block = new Block (current_block, loc, Location.Null); else implicit_block = current_block; foreach (VariableDeclaration decl in variable_declarators){ if (implicit_block.AddVariable (type, decl.identifier, decl.Location) != null) { if (decl.expression_or_array_initializer != null){ if (inits == null) inits = new ArrayList (4); inits.Add (decl); } } } if (inits == null) return implicit_block; foreach (VariableDeclaration decl in inits){ Assign assign; Expression expr = decl.expression_or_array_initializer; LocalVariableReference var; var = new LocalVariableReference (implicit_block, decl.identifier, loc); assign = new SimpleAssign (var, expr, decl.Location); implicit_block.AddStatement (new StatementExpression (assign)); } return implicit_block; } Block declare_local_constants (Expression type, ArrayList declarators) { Block implicit_block; if (current_block.Used) implicit_block = new Block (current_block); else implicit_block = current_block; foreach (VariableDeclaration decl in declarators){ implicit_block.AddConstant (type, decl.identifier, (Expression) decl.expression_or_array_initializer, decl.Location); } return implicit_block; } string CheckAttributeTarget (string a, Location l) { switch (a) { case "assembly" : case "module" : case "field" : case "method" : case "param" : case "property" : case "type" : return a; } Report.Warning (658, 1, l, "`{0}' is invalid attribute target. All attributes in this attribute section will be ignored", a); return string.Empty; } static bool IsUnaryOperator (Operator.OpType op) { switch (op) { case Operator.OpType.LogicalNot: case Operator.OpType.OnesComplement: case Operator.OpType.Increment: case Operator.OpType.Decrement: case Operator.OpType.True: case Operator.OpType.False: case Operator.OpType.UnaryPlus: case Operator.OpType.UnaryNegation: return true; } return false; } void syntax_error (Location l, string msg) { Report.Error (1003, l, "Syntax error, " + msg); } void note (string s) { // Used to put annotations } Tokenizer lexer; public Tokenizer Lexer { get { return lexer; } } static CSharpParser () { oob_stack = new Stack (); } public CSharpParser (SeekableStreamReader reader, CompilationUnit file, ArrayList defines) { this.file = file; current_namespace = new NamespaceEntry (null, file, null); current_class = current_namespace.SlaveDeclSpace; current_container = current_class.PartialContainer; // == RootContest.ToplevelTypes oob_stack.Clear (); lexer = new Tokenizer (reader, file, defines); } public void parse () { int errors = Report.Errors; try { if (yacc_verbose_flag > 1) yyparse (lexer, new yydebug.yyDebugSimple ()); else yyparse (lexer); Tokenizer tokenizer = lexer as Tokenizer; tokenizer.cleanup (); } catch (Exception e){ // // Removed for production use, use parser verbose to get the output. // // Console.WriteLine (e); if (Report.Errors == errors) Report.Error (-25, lexer.Location, "Parsing error"); if (yacc_verbose_flag > 0) Console.WriteLine (e); } if (RootContext.ToplevelTypes.NamespaceEntry != null) throw new InternalErrorException ("who set it?"); } static void CheckToken (int error, int yyToken, string msg, Location loc) { if (yyToken >= Token.FIRST_KEYWORD && yyToken <= Token.LAST_KEYWORD) Report.Error (error, loc, "{0}: `{1}' is a keyword", msg, yyNames [yyToken].ToLower ()); else Report.Error (error, loc, msg); } void CheckIdentifierToken (int yyToken, Location loc) { CheckToken (1041, yyToken, "Identifier expected", loc); } string ConsumeStoredComment () { string s = tmpComment; tmpComment = null; Lexer.doc_state = XmlCommentState.Allowed; return s; } Location GetLocation (object obj) { if (obj is MemberCore) return ((MemberCore) obj).Location; if (obj is MemberName) return ((MemberName) obj).Location; if (obj is LocatedToken) return ((LocatedToken) obj).Location; if (obj is Location) return (Location) obj; return lexer.Location; } void start_block (Location loc) { if (current_block == null || parsing_anonymous_method) { current_block = new ToplevelBlock (current_block, current_local_parameters, current_generic_method, loc); parsing_anonymous_method = false; } else { current_block = new ExplicitBlock (current_block, loc, Location.Null); } } Block end_block (Location loc) { Block retval = current_block.Explicit; retval.SetEndLocation (loc); current_block = retval.Parent; return retval; } void start_anonymous (bool lambda, Parameters parameters, Location loc) { oob_stack.Push (current_anonymous_method); oob_stack.Push (current_local_parameters); current_local_parameters = parameters; current_anonymous_method = lambda ? new LambdaExpression (current_container, parameters, loc) : new AnonymousMethodExpression (current_container, parameters, loc); // Force the next block to be created as a ToplevelBlock parsing_anonymous_method = true; } /* * Completes the anonymous method processing, if lambda_expr is null, this * means that we have a Statement instead of an Expression embedded */ AnonymousMethodExpression end_anonymous (ToplevelBlock anon_block, Location loc) { AnonymousMethodExpression retval; if (RootContext.Version == LanguageVersion.ISO_1){ Report.FeatureIsNotAvailable (loc, "anonymous methods"); retval = null; } else { current_anonymous_method.Block = anon_block; retval = current_anonymous_method; } current_local_parameters = (Parameters) oob_stack.Pop (); current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop (); return retval; } /* end end end */ }