%{ // // cs-parser.jay: The Parser for the C# compiler // // Authors: Miguel de Icaza (miguel@gnu.org) // Ravi Pratap (ravi@ximian.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; TypeContainer current_class; IIteratorContainer iterator_container; /// /// Current block is used to add statements as we find /// them. /// Block current_block, top_current_block; Delegate current_delegate; /// /// This is used by the unary_expression code to resolve /// a name against a parameter. /// 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). /// Expression implicit_value_parameter_type; Parameters indexer_parameters; /// /// Used to determine if we are parsing the get/set pair /// of an indexer or a property /// bool parsing_indexer; /// /// An out-of-band stack. /// Stack oob_stack; /// /// Switch stack. /// Stack switch_stack; static public int yacc_verbose_flag; // Name of the file we are parsing public string name; /// /// The current file. /// SourceFile 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; %} %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 /* 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 "->" /* 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 CLOSE_PARENS_CAST %token CLOSE_PARENS_NO_CAST %token CLOSE_PARENS_OPEN_PARENS %token CLOSE_PARENS_MINUS %token DEFAULT_OPEN_PARENS %token GENERIC_DIMENSION /* 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.FeatureIsNotStandardized (lt.Location, "external alias"); } else { lt = (LocatedToken) $3; current_namespace.UsingExternalAlias (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.UsingAlias (lt.Value, (MemberName) $4, (Location) $1); current_namespace.UsingFound = true; } | USING error { CheckIdentifierToken (yyToken, GetLocation ($2)); } ; using_namespace_directive : USING namespace_name SEMICOLON { current_namespace.Using ((MemberName) $2, (Location) $1); current_namespace.UsingFound = true; } ; // // 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 namespace_or_type_name { MemberName name = (MemberName) $3; if ($1 != null) { Report.Error(1671, name.Location, "A namespace declaration cannot have modifiers or attributes"); } if (name.TypeArguments != null) syntax_error (lexer.Location, "namespace name expected"); current_namespace = new NamespaceEntry ( current_namespace, file, name.GetName (), name.Location); } namespace_body opt_semicolon { current_namespace = current_namespace.Parent; } ; 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; } opt_extern_alias_directives opt_using_directives opt_namespace_member_declarations CLOSE_BRACE ; 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) CodeGen.Assembly.AddAttributes (((Attributes)$1).Attrs); $$ = $1; } opt_attributes : /* empty */ { global_attrs_enabled = false; $$ = null; } | attribute_sections { global_attrs_enabled = false; $$ = $1; } ; attribute_sections : attribute_section { 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); } current_attr_target = null; } | attribute_sections attribute_section { 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; 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); $$ = lt.Value; // Location won't be required anymore. } | EVENT { $$ = "event"; } | RETURN { $$ = "return"; } ; 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"); } ArrayList arguments = (ArrayList) $2; MemberName left = mname.Left; string identifier = mname.Name; Expression left_expr = left == null ? null : left.GetTypeExpression (); if (current_attr_target == "assembly" || current_attr_target == "module") // FIXME: supply "nameEscaped" parameter here. $$ = new GlobalAttribute (current_class, 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 { ArrayList args = new ArrayList (4); args.Add ($1); $$ = args; } } | positional_argument_list COMMA named_argument_list { ArrayList args = new ArrayList (4); args.Add ($1); args.Add ($3); $$ = args; } | named_argument_list { ArrayList args = new ArrayList (4); args.Add (null); args.Add ($1); $$ = args; } ; 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; } member_name { MemberName name = MakeName ((MemberName) $6); if ($3 != null) { ClassPart part = PartialContainer.CreatePart ( current_namespace, current_class, name, (int) $2, (Attributes) $1, Kind.Struct, (Location) $3); current_container = part.PartialContainer; current_class = part; } else { current_class = new Struct ( current_namespace, current_class, name, (int) $2, (Attributes) $1); current_container.AddClassOrStruct (current_class); current_container = current_class; RootContext.Tree.RecordDecl (current_namespace.NS, name, current_class); } } opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; if ($8 != null) current_class.Bases = (ArrayList) $8; current_class.SetParameterInfo ((ArrayList) $9); if (RootContext.Documentation != null) current_class.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, (Expression) $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 { Expression type = (Expression) $3; int mod = (int) $2; foreach (VariableDeclaration var in (ArrayList) $4){ Field field = new Field (current_class, type, mod, var.identifier, 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 fixed_variable_declarators SEMICOLON { Expression type = (Expression) $4; int mod = (int) $2; 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 VOID variable_declarators SEMICOLON { 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); } | STACKALLOC type { Report.Error (1575, (Location) $1, "A stackalloc expression requires [] after type"); $$ = null; } ; method_declaration : method_header { iterator_container = (IIteratorContainer) $1; if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.NotAllowed; } method_body { Method method = (Method) $1; method.Block = (ToplevelBlock) $3; current_container.AddMethod (method); current_local_parameters = null; iterator_container = 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; } } ; method_header : opt_attributes opt_modifiers type namespace_or_type_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; MemberName name = (MemberName) $4; if ($9 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); Method method; GenericMethod generic = null; if (name.TypeArguments != null) { generic = new GenericMethod (current_namespace, current_class, name, (Expression) $3, (Parameters) $6); generic.SetParameterInfo ((ArrayList) $9); } method = new Method (current_class, generic, (Expression) $3, (int) $2, false, name, (Parameters) $6, (Attributes) $1); current_local_parameters = (Parameters) $6; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); $$ = method; } | opt_attributes opt_modifiers VOID namespace_or_type_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; MemberName name = (MemberName) $4; if ($9 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Contraints 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, (Parameters) $6); generic.SetParameterInfo ((ArrayList) $9); } method = new Method (current_class, generic, TypeManager.system_void_expr, (int) $2, false, name, (Parameters) $6, (Attributes) $1); current_local_parameters = (Parameters) $6; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); $$ = method; } | opt_attributes opt_modifiers type modifiers namespace_or_type_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) $6, (Attributes) $1); current_local_parameters = (Parameters) $6; 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 ; formal_parameter_list : fixed_parameters { ArrayList pars_list = (ArrayList) $1; Parameter [] pars = new Parameter [pars_list.Count]; pars_list.CopyTo (pars); $$ = new Parameters (pars, null); } | fixed_parameters COMMA parameter_array { ArrayList pars_list = (ArrayList) $1; Parameter [] pars = new Parameter [pars_list.Count]; pars_list.CopyTo (pars); $$ = new Parameters (pars, (Parameter) $3); } | fixed_parameters COMMA ARGLIST { ArrayList pars_list = (ArrayList) $1; Parameter [] pars = new Parameter [pars_list.Count]; pars_list.CopyTo (pars); $$ = new Parameters (pars, true); } | parameter_array COMMA fixed_parameters { if ($1 != null) Report.Error (231, ((Parameter) $1).Location, "A params parameter must be the last parameter in a formal parameter list"); $$ = null; } | ARGLIST COMMA fixed_parameters { Report.Error (257, (Location) $1, "An __arglist parameter must be the last parameter in a formal parameter list"); $$ = null; } | parameter_array { $$ = new Parameters (null, (Parameter) $1); } | ARGLIST { $$ = new Parameters (null, true); } ; fixed_parameters : fixed_parameter { ArrayList pars = new ArrayList (4); pars.Add ($1); $$ = pars; } | fixed_parameters COMMA fixed_parameter { ArrayList pars = (ArrayList) $1; pars.Add ($3); $$ = $1; } ; fixed_parameter : opt_attributes opt_parameter_modifier type IDENTIFIER { LocatedToken lt = (LocatedToken) $4; $$ = new Parameter ((Expression) $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_modifier ; parameter_modifier : REF { $$ = Parameter.Modifier.REF | Parameter.Modifier.ISBYREF; } | OUT { $$ = Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF; } ; parameter_array : opt_attributes PARAMS type IDENTIFIER { LocatedToken lt = (LocatedToken) $4; $$ = new Parameter ((Expression) $3, lt.Value, Parameter.Modifier.PARAMS, (Attributes) $1, lt.Location); note ("type must be a single-dimension array type"); } | opt_attributes PARAMS parameter_modifier type IDENTIFIER { Report.Error (1611, (Location) $2, "The params parameter cannot be declared as ref or out"); $$ = null; } | opt_attributes PARAMS type error { CheckIdentifierToken (yyToken, GetLocation ($4)); $$ = null; } ; 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 = (Expression) $3; lexer.PropertyParsing = true; } accessor_declarations { lexer.PropertyParsing = false; has_get = has_set = false; } CLOSE_BRACE { if ($8 == null) break; Property prop; Pair pair = (Pair) $8; Accessor get_block = (Accessor) pair.First; Accessor set_block = (Accessor) pair.Second; MemberName name = (MemberName) $4; if (name.TypeArguments != null) syntax_error (lexer.Location, "a property can't have type arguments"); prop = new Property (current_class, (Expression) $3, (int) $2, false, name, (Attributes) $1, get_block, set_block); current_container.AddProperty (prop); implicit_value_parameter_type = null; if (RootContext.Documentation != null) prop.DocComment = ConsumeStoredComment (); } ; accessor_declarations : get_accessor_declaration { $$ = new Pair ($1, null); } | get_accessor_declaration accessor_declarations { Pair pair = (Pair) $2; pair.First = $1; $$ = pair; } | set_accessor_declaration { $$ = new Pair (null, $1); } | set_accessor_declaration accessor_declarations { Pair pair = (Pair) $2; pair.Second = $1; $$ = pair; } | 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; iterator_container = SimpleIteratorContainer.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; if (SimpleIteratorContainer.Simple.Yields) accessor.SetYields (); iterator_container = 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, null); } 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, indexer_parameters.ArrayParameter); } lexer.PropertyParsing = false; iterator_container = SimpleIteratorContainer.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; if (SimpleIteratorContainer.Simple.Yields) accessor.SetYields (); iterator_container = 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; } member_name { MemberName name = MakeName ((MemberName) $6); if ($3 != null) { ClassPart part = PartialContainer.CreatePart ( current_namespace, current_class, name, (int) $2, (Attributes) $1, Kind.Interface, (Location) $3); current_container = part.PartialContainer; current_class = part; } else { current_class = new Interface ( current_namespace, current_class, name, (int) $2, (Attributes) $1); current_container.AddInterface (current_class); current_container = current_class; RootContext.Tree.RecordDecl (current_namespace.NS, name, current_class); } } opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; if ($8 != null) current_class.Bases = (ArrayList) $8; current_class.SetParameterInfo ((ArrayList) $9); if (RootContext.Documentation != null) { current_class.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 { lexer.ConstraintsParsing = false; } opt_statement_list CLOSE_BRACE { Report.Error (531, lexer.Location, "'{0}': interface members cannot have a definition", $4); $$ = 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 interface_method_declaration_body { lexer.ConstraintsParsing = false; MemberName name = (MemberName) $4; if ($9 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); GenericMethod generic = null; if (name.TypeArguments != null) { generic = new GenericMethod (current_namespace, current_class, name, (Expression) $3, (Parameters) $6); generic.SetParameterInfo ((ArrayList) $9); } $$ = new Method (current_class, generic, (Expression) $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 interface_method_declaration_body { lexer.ConstraintsParsing = false; MemberName name = (MemberName) $4; if ($9 != null && name.TypeArguments == null) Report.Error (80, lexer.Location, "Contraints 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; } accessor_declarations { has_get = has_set = false; lexer.PropertyParsing = false; } 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, (Expression) $3, (int) $2, true, name, (Attributes) $1, null, null); Report.Error (548, p.Location, "`{0}': property or indexer must have at least one accessor", p.GetSignatureForError ()); break; } Pair pair = (Pair) $7; p = new Property (current_class, (Expression) $3, (int) $2, true, name, (Attributes) $1, (Accessor)pair.First, (Accessor)pair.Second); if (pair.First != null && ((Accessor)(pair.First)).Block != null) { Report.Error (531, p.Location, "`{0}.get': interface members cannot have a definition", p.GetSignatureForError ()); $$ = null; break; } if (pair.Second != null && ((Accessor)(pair.Second)).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, (Expression) $4, (int) $2, true, new MemberName (lt.Value, lt.Location), null, (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 { lexer.EventParsing = true; } event_accessor_declarations { lexer.EventParsing = false; } 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 formal_parameter_list CLOSE_BRACKET OPEN_BRACE { lexer.PropertyParsing = true; } accessor_declarations { has_get = has_set = false; lexer.PropertyParsing = false; } CLOSE_BRACE { Indexer i = null; if ($10 == null) { i = new Indexer (current_class, (Expression) $3, new MemberName (TypeContainer.DefaultIndexerName, (Location) $4), (int) $2, true, (Parameters) $6, (Attributes) $1, null, null); Report.Error (548, i.Location, "`{0}': property or indexer must have at least one accessor", i.GetSignatureForError ()); break; } Pair pair = (Pair) $10; i = new Indexer (current_class, (Expression) $3, new MemberName (TypeContainer.DefaultIndexerName, (Location) $4), (int) $2, true, (Parameters) $6, (Attributes) $1, (Accessor)pair.First, (Accessor)pair.Second); if (pair.First != null && ((Accessor)(pair.First)).Block != null) { Report.Error (531, i.Location, "`{0}.get': interface members cannot have a definition", i.GetSignatureForError ()); $$ = null; break; } if (pair.Second != null && ((Accessor)(pair.Second)).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 { iterator_container = SimpleIteratorContainer.GetSimple (); } operator_body { if ($3 == null) break; OperatorDeclaration decl = (OperatorDeclaration) $3; Parameter [] param_list = new Parameter [decl.arg2type != null ? 2 : 1]; param_list[0] = new Parameter (decl.arg1type, decl.arg1name, Parameter.Modifier.NONE, null, decl.location); if (decl.arg2type != null) param_list[1] = new Parameter (decl.arg2type, decl.arg2name, Parameter.Modifier.NONE, null, decl.location); Operator op = new Operator ( current_class, decl.optype, decl.ret_type, (int) $2, new Parameters (param_list, null), (ToplevelBlock) $5, (Attributes) $1, decl.location); if (RootContext.Documentation != null) { op.DocComment = tmpComment; Lexer.doc_state = XmlCommentState.Allowed; } if (SimpleIteratorContainer.Simple.Yields) op.SetYields (); // Note again, checking is done in semantic analysis current_container.AddOperator (op); current_local_parameters = null; iterator_container = null; } ; operator_body : block | SEMICOLON { $$ = null; } ; operator_declarator : type OPERATOR overloadable_operator OPEN_PARENS type IDENTIFIER CLOSE_PARENS { LocatedToken lt = (LocatedToken) $6; Operator.OpType op = (Operator.OpType) $3; CheckUnaryOperator (op, lt.Location); if (op == Operator.OpType.Addition) op = Operator.OpType.UnaryPlus; if (op == Operator.OpType.Subtraction) op = Operator.OpType.UnaryNegation; Parameter [] pars = new Parameter [1]; Expression type = (Expression) $5; pars [0] = new Parameter (type, lt.Value, Parameter.Modifier.NONE, null, lt.Location); current_local_parameters = new Parameters (pars, null); if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } $$ = new OperatorDeclaration (op, (Expression) $1, type, lt.Value, null, null, (Location) $2); } | type OPERATOR overloadable_operator OPEN_PARENS type IDENTIFIER COMMA type IDENTIFIER CLOSE_PARENS { LocatedToken ltParam1 = (LocatedToken) $6; LocatedToken ltParam2 = (LocatedToken) $9; CheckBinaryOperator ((Operator.OpType) $3, (Location) $2); Parameter [] pars = new Parameter [2]; Expression typeL = (Expression) $5; Expression typeR = (Expression) $8; pars [0] = new Parameter (typeL, ltParam1.Value, Parameter.Modifier.NONE, null, ltParam1.Location); pars [1] = new Parameter (typeR, ltParam2.Value, Parameter.Modifier.NONE, null, ltParam2.Location); current_local_parameters = new Parameters (pars, null); if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } $$ = new OperatorDeclaration ((Operator.OpType) $3, (Expression) $1, typeL, ltParam1.Value, typeR, ltParam2.Value, (Location) $2); } | conversion_operator_declarator | type OPERATOR overloadable_operator OPEN_PARENS type IDENTIFIER COMMA type IDENTIFIER COMMA type IDENTIFIER CLOSE_PARENS { Report.Error (1534, (Location) $2, "Overloaded binary operator `{0}' takes two parameters", Operator.GetName ((Operator.OpType) $3)); $$ = null; } | type OPERATOR overloadable_operator OPEN_PARENS CLOSE_PARENS { Report.Error (1535, (Location) $2, "Overloaded unary operator `{0}' takes one parameter", Operator.GetName ((Operator.OpType) $3)); $$ = null; } ; 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 type IDENTIFIER CLOSE_PARENS { LocatedToken lt = (LocatedToken) $6; Parameter [] pars = new Parameter [1]; pars [0] = new Parameter ((Expression) $5, lt.Value, Parameter.Modifier.NONE, null, lt.Location); current_local_parameters = new Parameters (pars, null); if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } $$ = new OperatorDeclaration (Operator.OpType.Implicit, (Expression) $3, (Expression) $5, lt.Value, null, null, (Location) $2); } | EXPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS { LocatedToken lt = (LocatedToken) $6; Parameter [] pars = new Parameter [1]; pars [0] = new Parameter ((Expression) $5, lt.Value, Parameter.Modifier.NONE, null, lt.Location); current_local_parameters = new Parameters (pars, null); if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.NotAllowed; } $$ = new OperatorDeclaration (Operator.OpType.Explicit, (Expression) $3, (Expression) $5, lt.Value, null, null, (Location) $2); } | 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; c.ModFlags = (int) $2; if (RootContext.Documentation != null) c.DocComment = ConsumeStoredComment (); if (c.Name == current_container.Basename){ if ((c.ModFlags & Modifiers.STATIC) != 0){ if ((c.ModFlags & Modifiers.Accessibility) != 0){ Report.Error (515, c.Location, "`{0}': access modifiers are not allowed on static constructors", c.GetSignatureForError ()); } c.ModFlags = Modifiers.Check (Constructor.AllowedModifiers, (int) $2, Modifiers.PRIVATE, c.Location); if (c.Initializer != null){ Report.Error (514, c.Location, "`{0}': static constructor cannot have an explicit `this' or `base' constructor call", c.GetSignatureForError ()); } if (!c.Parameters.Empty){ Report.Error (132, c.Location, "`{0}': The static constructor must be parameterless", c.GetSignatureForError ()); } } else { c.ModFlags = Modifiers.Check (Constructor.AllowedModifiers, (int) $2, Modifiers.PRIVATE, c.Location); } } else { // We let another layer check the validity of the constructor. //Console.WriteLine ("{0} and {1}", c.Name, current_container.Basename); } current_container.AddConstructor (c); current_local_parameters = null; if (RootContext.Documentation != null) Lexer.doc_state = XmlCommentState.Allowed; } ; constructor_declarator : IDENTIFIER { if (RootContext.Documentation != null) { tmpComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } } OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { current_local_parameters = (Parameters) $4; } opt_constructor_initializer { LocatedToken lt = (LocatedToken) $1; $$ = new Constructor (current_class, lt.Value, 0, (Parameters) $4, (ConstructorInitializer) $7, lt.Location); } ; constructor_body : block | SEMICOLON { $$ = null; } ; opt_constructor_initializer : /* empty */ { $$ = null; } | constructor_initializer ; 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", new Parameters (null, null), (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 { foreach (VariableDeclaration var in (ArrayList) $5) { MemberName name = new MemberName (var.identifier, var.Location); Event e = new EventField ( current_class, (Expression) $4, (int) $2, false, name, var.expression_or_array_initializer, (Attributes) $1); 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 = (Expression) $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); $$ = null; } else { Pair pair = (Pair) $8; if (name.TypeArguments != null) syntax_error (lexer.Location, "an event can't have type arguments"); if (pair.First == null || pair.Second == null) // CS0073 is already reported, so no CS0065 here. $$ = null; else { Event e = new EventProperty ( current_class, (Expression) $4, (int) $2, false, name, null, (Attributes) $1, (Accessor) pair.First, (Accessor) pair.Second); 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 Pair ($1, $2); } | remove_accessor_declaration add_accessor_declaration { $$ = new Pair ($2, $1); } | 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, null); lexer.EventParsing = false; } block { $$ = new Accessor ((ToplevelBlock) $4, 0, (Attributes) $1, (Location) $2); lexer.EventParsing = true; } | 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, null); lexer.EventParsing = false; } block { $$ = new Accessor ((ToplevelBlock) $4, 0, (Attributes) $1, (Location) $2); lexer.EventParsing = true; } | 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; iterator_container = SimpleIteratorContainer.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; Pair pair = (Pair) $6; Accessor get_block = (Accessor) pair.First; Accessor set_block = (Accessor) pair.Second; MemberName name; if (decl.interface_type != null) name = new MemberName ( decl.interface_type, TypeContainer.DefaultIndexerName, decl.location); else name = new MemberName (TypeContainer.DefaultIndexerName, decl.location); indexer = new Indexer (current_class, decl.type, name, (int) $2, false, decl.param_list, (Attributes) $1, get_block, set_block); 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_formal_parameter_list CLOSE_BRACKET { Parameters pars = (Parameters) $4; if (pars.HasArglist) { // "__arglist is not valid in this context" Report.Error (1669, (Location) $2, "__arglist is not valid in this context"); } else if (pars.FixedParameters == null && pars.ArrayParameter == null){ 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 ((Expression) $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.HasArglist) { // "__arglist is not valid in this context" Report.Error (1669, (Location) $4, "__arglist is not valid in this context"); } else if (pars.FixedParameters == null && pars.ArrayParameter == null){ Report.Error (1551, (Location) $4, "Indexers must have at least one parameter"); } MemberName name = (MemberName) $2; $$ = new IndexerDeclaration ((Expression) $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 opt_partial ENUM IDENTIFIER opt_enum_base { if (RootContext.Documentation != null) enumTypeComment = Lexer.consume_doc_comment (); } enum_body opt_semicolon { LocatedToken lt = (LocatedToken) $5; Location enum_location = lt.Location; if ($3 != null) { Report.Error (267, lt.Location, "The partial modifier can only appear immediately before `class', `struct' or `interface'"); break; // assumes that the parser put us in a switch } MemberName name = MakeName (new MemberName (lt.Value, enum_location)); Enum e = new Enum (current_namespace, current_class, (Expression) $6, (int) $2, name, (Attributes) $1); if (RootContext.Documentation != null) e.DocComment = enumTypeComment; EnumMember em = null; foreach (VariableDeclaration ev in (ArrayList) $8) { em = new EnumMember (e, em, (Expression) ev.expression_or_array_initializer, new MemberName (ev.identifier, ev.Location), ev.OptAttributes); // if (RootContext.Documentation != null) em.DocComment = ev.DocComment; e.AddEnumMember (em); } current_container.AddEnum (e); RootContext.Tree.RecordDecl (current_namespace.NS, name, 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 { lexer.ConstraintsParsing = true; } type member_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { MemberName name = MakeName ((MemberName) $6); Delegate del = new Delegate (current_namespace, current_class, (Expression) $5, (int) $2, name, (Parameters) $8, (Attributes) $1); if (RootContext.Documentation != null) { del.DocComment = Lexer.consume_doc_comment (); Lexer.doc_state = XmlCommentState.Allowed; } current_container.AddDelegate (del); RootContext.Tree.RecordDecl (current_namespace.NS, name, del); current_delegate = del; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; } SEMICOLON { current_delegate.SetParameterInfo ((ArrayList) $11); $$ = current_delegate; current_delegate = null; } ; opt_nullable : /* empty */ { lexer.CheckNullable (false); $$ = false; } | INTERR { lexer.CheckNullable (true); $$ = true; } ; namespace_or_type_name : member_name | IDENTIFIER DOUBLE_COLON IDENTIFIER { LocatedToken lt1 = (LocatedToken) $1; LocatedToken lt2 = (LocatedToken) $3; $$ = new MemberName (lt1.Value, lt2.Value, lt2.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_argument_list { LocatedToken lt = (LocatedToken) $1; $$ = new MemberName (lt.Value, (TypeArguments) $2, lt.Location); } ; opt_type_argument_list : /* empty */ { $$ = null; } | OP_GENERICS_LT type_arguments OP_GENERICS_GT { $$ = $2; if (RootContext.Version == LanguageVersion.ISO_1) Report.FeatureIsNotStandardized (lexer.Location, "generics"); } | GENERIC_DIMENSION { $$ = new TypeArguments ((int) $1, lexer.Location); if (RootContext.Version == LanguageVersion.ISO_1) Report.FeatureIsNotStandardized (lexer.Location, "generics"); } ; type_arguments : type { TypeArguments type_args = new TypeArguments (lexer.Location); type_args.Add ((Expression) $1); $$ = type_args; } | type_arguments COMMA type { TypeArguments type_args = (TypeArguments) $1; type_args.Add ((Expression) $3); $$ = type_args; } ; /* * 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; $$ = name.GetTypeExpression (); if ((bool) $2) $$ = new ComposedCast ((Expression) $$, "?", lexer.Location); } | builtin_types opt_nullable { if ((bool) $2) $$ = new ComposedCast ((Expression) $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 ((Expression) $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 ((Expression) $1, "?", lexer.Location); } | non_expression_type rank_specifier { Location loc = GetLocation ($1); if (loc.IsNull) loc = lexer.Location; $$ = new ComposedCast ((Expression) $1, (string) $2, loc); } | non_expression_type STAR { Location loc = GetLocation ($1); if (loc.IsNull) loc = lexer.Location; $$ = new ComposedCast ((Expression) $1, "*", loc); } | expression rank_specifiers { $$ = new ComposedCast ((Expression) $1, (string) $2); } | expression STAR { $$ = new ComposedCast ((Expression) $1, "*"); } // // We need this because the parser will happily go and reduce IDENTIFIER STAR // through this different path // | multiplicative_expression STAR { $$ = new ComposedCast ((Expression) $1, "*"); } ; type_list : type { ArrayList types = new ArrayList (4); types.Add ($1); $$ = types; } | type_list COMMA type { ArrayList types = (ArrayList) $1; types.Add ($3); $$ = types; } ; /* * 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 opt_nullable { string rank_specifiers = (string) $2; if ((bool) $3) rank_specifiers += "?"; $$ = new ComposedCast ((Expression) $1, rank_specifiers); } ; // // Expressions, section 7.5 // primary_expression : literal { // 7.5.1: Literals } | member_name { MemberName mn = (MemberName) $1; $$ = mn.GetTypeExpression (); } | IDENTIFIER DOUBLE_COLON IDENTIFIER { LocatedToken lt1 = (LocatedToken) $1; LocatedToken lt2 = (LocatedToken) $3; $$ = new QualifiedAliasMember (lt1.Value, lt2.Value, lt2.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_OPEN_PARENS // or CLOSE_PARENS_MINUS. } ; parenthesized_expression : parenthesized_expression_0 CLOSE_PARENS_NO_CAST { $$ = $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; $$ = new MemberAccess ((Expression) $1, lt.Value, (TypeArguments) $4, lt.Location); } ; predefined_type : builtin_types ; invocation_expression : primary_expression { $$ = lexer.Location; } OPEN_PARENS opt_argument_list CLOSE_PARENS { if ($1 == null) { Location l = (Location) $3; Report.Error (1, l, "Parse error"); } $$ = new Invocation ((Expression) $1, (ArrayList) $4); } | 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_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 { $$ = 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 (expr, (string) $2); } else if (!(expr is SimpleName || expr is MemberAccess || expr is ConstructedType || expr is QualifiedAliasMember)){ Error_ExpectingTypeName (expr); $$ = TypeManager.system_object_expr; } else { // // So we extract the string corresponding to the SimpleName // or MemberAccess // $$ = new ComposedCast (expr, (string) $2); } } ; 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 { LocatedToken lt = (LocatedToken) $3; $$ = new BaseAccess (lt.Value, 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 ; object_or_delegate_creation_expression : NEW type OPEN_PARENS opt_argument_list CLOSE_PARENS { $$ = new New ((Expression) $2, (ArrayList) $4, (Location) $1); } ; array_creation_expression : NEW type OPEN_BRACKET expression_list CLOSE_BRACKET opt_rank_specifier opt_array_initializer { $$ = new ArrayCreation ((Expression) $2, (ArrayList) $4, (string) $6, (ArrayList) $7, (Location) $1); } | NEW type rank_specifiers array_initializer { $$ = new ArrayCreation ((Expression) $2, (string) $3, (ArrayList) $4, (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; } ; opt_rank_specifier : /* empty */ { $$ = ""; } | rank_specifiers { $$ = $1; } ; opt_rank_specifier_or_nullable : /* empty */ { $$ = ""; } | INTERR { $$ = "?"; } | opt_nullable rank_specifiers { if ((bool) $1) $$ = "?" + $2; else $$ = $2; } | opt_nullable rank_specifiers INTERR { 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; } ; void_pointer_expression : void_pointer_expression STAR { $$ = new ComposedCast ((Expression) $1, "*", lexer.Location); } | VOID STAR { $$ = new ComposedCast (TypeManager.system_void_expr, "*", lexer.Location);; } ; typeof_expression : TYPEOF OPEN_PARENS VOID CLOSE_PARENS { $$ = new TypeOfVoid ((Location) $1); } | TYPEOF OPEN_PARENS void_pointer_expression CLOSE_PARENS { $$ = new TypeOf ((Expression) $3, (Location) $1); } | TYPEOF OPEN_PARENS { lexer.TypeOfParsing = true; } type CLOSE_PARENS { lexer.TypeOfParsing = false; $$ = new TypeOf ((Expression) $4, lexer.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 Unary (Unary.Operator.Indirection, (Expression) $1, lt.Location); $$ = new MemberAccess (deref, lt.Value, lt.Location); } ; anonymous_method_expression : DELEGATE opt_anonymous_method_signature { oob_stack.Push (current_local_parameters); current_local_parameters = (Parameters)$2; // Force the next block to be created as a ToplevelBlock oob_stack.Push (current_block); oob_stack.Push (top_current_block); current_block = null; } block { Location loc = (Location) $1; top_current_block = (Block) oob_stack.Pop (); current_block = (Block) oob_stack.Pop (); if (RootContext.Version == LanguageVersion.ISO_1){ Report.FeatureIsNotStandardized (loc, "anonymous methods"); $$ = null; } else { ToplevelBlock anon_block = (ToplevelBlock) $4; anon_block.Parent = current_block; $$ = new AnonymousMethod ((Parameters) $2, (ToplevelBlock) top_current_block, anon_block, loc); } current_local_parameters = (Parameters) oob_stack.Pop (); } ; opt_anonymous_method_signature : /* empty */ { $$ = null; } | anonymous_method_signature ; anonymous_method_signature : OPEN_PARENS opt_anonymous_method_parameter_list CLOSE_PARENS { if ($2 == null) $$ = Parameters.EmptyReadOnlyParameters; else { ArrayList par_list = (ArrayList) $2; Parameter [] pars = new Parameter [par_list.Count]; par_list.CopyTo (pars); $$ = new Parameters (pars, null); } } ; opt_anonymous_method_parameter_list : /* empty */ { $$ = null; } | anonymous_method_parameter_list { $$ = $1; } ; anonymous_method_parameter_list : anonymous_method_parameter { ArrayList a = new ArrayList (4); a.Add ($1); $$ = a; } | anonymous_method_parameter_list COMMA anonymous_method_parameter { ArrayList a = (ArrayList) $1; a.Add ($3); $$ = a; } ; anonymous_method_parameter : opt_parameter_modifier type IDENTIFIER { LocatedToken lt = (LocatedToken) $3; $$ = new Parameter ((Expression) $2, lt.Value, (Parameter.Modifier) $1, null, lt.Location); } | PARAMS type IDENTIFIER { Report.Error (1670, ((LocatedToken) $3).Location, "The `params' modifier is not allowed in anonymous method declaration"); $$ = null; } ; default_value_expression : DEFAULT_OPEN_PARENS type CLOSE_PARENS { $$ = 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_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 Unary (Unary.Operator.Indirection, (Expression) $2, (Location) $1); } | BITWISE_AND prefixed_unary_expression { $$ = new Unary (Unary.Operator.AddressOf, (Expression) $2, (Location) $1); } ; pre_increment_expression : OP_INC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement, (Expression) $2, (Location) $1); } ; pre_decrement_expression : OP_DEC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement, (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 INTERR INTERR expression { $$ = new Nullable.NullCoalescingOperator ((Expression) $1, (Expression) $4, lexer.Location); } // We'll be resolved into a `parenthesized_expression_0' later on. | conditional_or_expression INTERR CLOSE_PARENS { $$ = new ComposedCast ((Expression) $1, "?", lexer.Location); lexer.PutbackCloseParens (); } ; assignment_expression : prefixed_unary_expression ASSIGN expression { $$ = new Assign ((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); } ; expression : conditional_expression | assignment_expression ; constant_expression : expression ; boolean_expression : expression ; // // 10 classes // class_declaration : opt_attributes opt_modifiers opt_partial CLASS { lexer.ConstraintsParsing = true; } member_name { MemberName name = MakeName ((MemberName) $6); int mod_flags = (int) $2; if ($3 != null) { ClassPart part = PartialContainer.CreatePart ( current_namespace, current_class, name, mod_flags, (Attributes) $1, Kind.Class, (Location) $3); current_container = part.PartialContainer; current_class = part; } else { if ((mod_flags & Modifiers.STATIC) != 0) { current_class = new StaticClass ( current_namespace, current_class, name, mod_flags, (Attributes) $1); } else { current_class = new Class ( current_namespace, current_class, name, mod_flags, (Attributes) $1); } current_container.AddClassOrStruct (current_class); current_container = current_class; RootContext.Tree.RecordDecl (current_namespace.NS, name, current_class); } } opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; if ($8 != null) { if (current_class.Name == "System.Object") { Report.Error (537, current_class.Location, "The class System.Object cannot have a base " + "class or implement an interface."); } current_class.Bases = (ArrayList) $8; } current_class.SetParameterInfo ((ArrayList) $9); if (RootContext.Documentation != null) { current_class.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 */ { $$ = null; } | class_base { $$ = $1; } ; class_base : COLON type_list { $$ = $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.Add ($2); $$ = 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 { if (current_block == null){ current_block = new ToplevelBlock ((ToplevelBlock) top_current_block, current_local_parameters, (Location) $1); top_current_block = current_block; } else { current_block = new Block (current_block, (Location) $1, Location.Null); } } opt_statement_list CLOSE_BRACE { while (current_block.Implicit) current_block = current_block.Parent; $$ = current_block; current_block.SetEndLocation ((Location) $4); current_block = current_block.Parent; if (current_block == null) top_current_block = null; } ; 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 (lt.Value, labeled, lt.Location)) current_block.AddStatement (labeled); } statement ; declaration_statement : local_variable_declaration SEMICOLON { 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 { 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; if (!(expr is SimpleName || expr is MemberAccess || expr is ComposedCast || expr is ConstructedType || expr is QualifiedAliasMember)) { Error_ExpectingTypeName (expr); $$ = null; } else { // // So we extract the string corresponding to the SimpleName // or MemberAccess // if ((string) $2 == "") $$ = $1; else $$ = new ComposedCast ((Expression) $1, (string) $2); } } | builtin_types opt_rank_specifier_or_nullable { if ((string) $2 == "") $$ = $1; else $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location); } ; local_variable_pointer_type : primary_expression STAR { Expression expr = (Expression) $1; if (!(expr is SimpleName || expr is MemberAccess || expr is ComposedCast || expr is ConstructedType || expr is QualifiedAliasMember)) { Error_ExpectingTypeName (expr); $$ = null; } else $$ = new ComposedCast ((Expression) $1, "*"); } | builtin_types STAR { $$ = new ComposedCast ((Expression) $1, "*", lexer.Location); } | VOID STAR { $$ = new ComposedCast (TypeManager.system_void_expr, "*", (Location) $1); } | local_variable_pointer_type STAR { $$ = new ComposedCast ((Expression) $1, "*"); } ; local_variable_declaration : local_variable_type variable_declarators { if ($1 != null) $$ = 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 ((Expression) $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 : invocation_expression { $$ = new StatementExpression ((ExpressionStatement) $1); } | object_creation_expression { $$ = new StatementExpression ((ExpressionStatement) $1); } | assignment_expression { $$ = new StatementExpression ((ExpressionStatement) $1); } | post_increment_expression { $$ = new StatementExpression ((ExpressionStatement) $1); } | post_decrement_expression { $$ = new StatementExpression ((ExpressionStatement) $1); } | pre_increment_expression { $$ = new StatementExpression ((ExpressionStatement) $1); } | pre_decrement_expression { $$ = new StatementExpression ((ExpressionStatement) $1); } | error { Report.Error (1002, GetLocation ($1), "Expecting `;'"); $$ = null; } ; object_creation_expression : object_or_delegate_creation_expression { note ("complain if this is a delegate maybe?"); } ; 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); if (RootContext.WarningLevel >= 3){ // FIXME: location for warning should be loc property of $5. if ($5 == EmptyStatement.Value) Report.Warning (642, 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); if (RootContext.WarningLevel >= 3){ // FIXME: location for warning should be loc property of $5 and $7. if ($5 == EmptyStatement.Value) Report.Warning (642, l, "Possible mistaken empty statement"); if ($7 == EmptyStatement.Value) Report.Warning (642, l, "Possible mistaken empty statement"); } } ; switch_statement : SWITCH OPEN_PARENS { 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.Error (1522, lexer.Location, "Empty switch block"); } | 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 { Block topmost = current_block; while (topmost.Implicit) topmost = topmost.Parent; $$ = new SwitchSection ((ArrayList) $1, topmost); } ; 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) $2); } | 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 { Block assign_block = new Block (current_block); current_block = assign_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; Location l = lexer.Location; Expression expr; if (decl.expression_or_array_initializer is Expression){ expr = (Expression) decl.expression_or_array_initializer; } else if (decl.expression_or_array_initializer == null) { expr = null; } else { ArrayList init = (ArrayList) decl.expression_or_array_initializer; expr = new ArrayCreation (type, "", init, decl.Location); } LocalVariableReference var; var = new LocalVariableReference (assign_block, decl.identifier, l); if (expr != null) { Assign a = new Assign (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); while (current_block.Implicit) current_block = current_block.Parent; $$ = current_block; current_block = current_block.Parent; } ; 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' Block b = new Block (current_block, Block.Flags.Implicit); b.AddStatement ((Statement) $1); $$ = 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 { Block foreach_block = new Block (current_block); current_block = foreach_block; LocatedToken lt = (LocatedToken) $4; Location l = lt.Location; LocalInfo vi; 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); } while (current_block.Implicit) current_block = current_block.Parent; $$ = current_block; current_block = current_block.Parent; } ; 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.FeatureIsNotStandardized (lt.Location, "yield statement"); $$ = null; } if (iterator_container == null){ Report.Error (204, lt.Location, "yield statement can only be used within a method, operator or property"); $$ = null; } else { iterator_container.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.FeatureIsNotStandardized (lt.Location, "yield statement"); $$ = null; } if (iterator_container == null){ Report.Error (204, lt.Location, "yield statement can only be used within a method, operator or property"); $$ = null; } else { iterator_container.SetYields (); $$ = new YieldBreak (lt.Location); } } ; opt_expression : /* empty */ | expression ; try_statement : TRY block catch_clauses { Catch g = null; ArrayList c = (ArrayList)$3; for (int i = 0; i < c.Count; ++i) { Catch cc = (Catch) c [i]; if (cc.IsGeneral) { if (i != c.Count - 1) Report.Error (1017, cc.loc, "Try statement already has an empty catch block"); g = cc; c.RemoveAt (i); i--; } } // Now s contains the list of specific catch clauses // and g contains the general one. $$ = new Try ((Block) $2, c, g, null, ((Block) $2).loc); } | TRY block opt_catch_clauses FINALLY block { Catch g = null; ArrayList s = new ArrayList (4); ArrayList catch_list = (ArrayList) $3; if (catch_list != null){ foreach (Catch cc in catch_list) { if (cc.IsGeneral) g = cc; else s.Add (cc); } } $$ = new Try ((Block) $2, s, g, (Block) $5, ((Block) $2).loc); } | TRY block error { Report.Error (1524, (Location) $1, "Expected catch or finally"); $$ = null; } ; opt_catch_clauses : /* empty */ { $$ = null; } | catch_clauses ; 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)); current_block = new Block (current_block); Block b = declare_local_variables (type, one, lt.Location); current_block = b; } } } block { Expression type = null; string id = null; if ($2 != null){ DictionaryEntry cc = (DictionaryEntry) $2; type = (Expression) cc.Key; LocatedToken lt = (LocatedToken) cc.Value; if (lt != null){ id = lt.Value; while (current_block.Implicit) current_block = current_block.Parent; current_block = current_block.Parent; } } $$ = new Catch (type, id, (Block) $4, ((Block) $4).loc); } ; opt_catch_args : /* empty */ { $$ = null; } | catch_args ; catch_args : OPEN_PARENS type opt_identifier CLOSE_PARENS { $$ = new DictionaryEntry ($2, $3); } ; 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; Block assign_block = new Block (current_block); current_block = assign_block; 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); while (current_block.Implicit) current_block = current_block.Parent; $$ = current_block; current_block = current_block.Parent; } ; 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 resource_acquisition CLOSE_PARENS { Block assign_block = new Block (current_block); current_block = assign_block; if ($3 is DictionaryEntry){ DictionaryEntry de = (DictionaryEntry) $3; Location l = (Location) $1; Expression type = (Expression) de.Key; ArrayList var_declarators = (ArrayList) de.Value; ArrayList vars = new ArrayList (4); 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; if (decl.expression_or_array_initializer is Expression){ expr = (Expression) decl.expression_or_array_initializer; } else { ArrayList init = (ArrayList) decl.expression_or_array_initializer; if (init == null) { Report.Error (210, l, "You must provide an initializer in a fixed or using statement declaration"); } expr = new ArrayCreation (type, "", init, decl.Location); } 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.Add (new DictionaryEntry (var, expr)); // Assign a = new Assign (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. $$ = new DictionaryEntry (type, vars); } else { $$ = $3; } } embedded_statement { Using u = new Using ($5, (Statement) $6, (Location) $1); current_block.AddStatement (u); while (current_block.Implicit) current_block = current_block.Parent; $$ = current_block; current_block = current_block.Parent; } ; resource_acquisition : local_variable_declaration | expression ; %% // // A class used to pass around variable declarations and constants // public class VariableDeclaration { public string identifier; public object 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; this.expression_or_array_initializer = 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 Expression type; public MemberName interface_type; public Parameters param_list; public Location location; public IndexerDeclaration (Expression 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 IIteratorContainer // public class SimpleIteratorContainer : IIteratorContainer { public bool Yields; public static SimpleIteratorContainer Simple = new SimpleIteratorContainer (); // // Reset and return // public static SimpleIteratorContainer GetSimple () { Simple.Yields = false; return Simple; } public void SetYields () { Yields = true; } } // // A class used to hold info about an operator declarator // public class OperatorDeclaration { public Operator.OpType optype; public Expression ret_type, arg1type, arg2type; public string arg1name, arg2name; public Location location; public OperatorDeclaration (Operator.OpType op, Expression ret_type, Expression arg1type, string arg1name, Expression arg2type, string arg2name, Location location) { optype = op; this.ret_type = ret_type; this.arg1type = arg1type; this.arg1name = arg1name; this.arg2type = arg2type; this.arg2name = arg2name; this.location = location; } } void Error_ExpectingTypeName (Expression expr) { if (expr is Invocation){ Report.Error (1002, expr.Location, "Expecting `;'"); } else { Report.Error (201, expr.Location, "Only assignment, call, increment, decrement, and new object expressions can be used as a statement"); } } TypeContainer pop_current_class () { TypeContainer retval = current_class; current_class = current_class.Parent; current_container = current_container.Parent; if (current_class != current_container) { if (!(current_class is ClassPart) || ((ClassPart) current_class).PartialContainer != current_container) throw new InternalErrorException (); } else if (current_container is ClassPart) current_container = ((ClassPart) 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 == ""){ if (ns.Name != "") 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, Block.Flags.Implicit, 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; if (decl.expression_or_array_initializer is Expression){ expr = (Expression) decl.expression_or_array_initializer; } else { ArrayList init = (ArrayList) decl.expression_or_array_initializer; expr = new ArrayCreation (type, "", init, decl.Location); } LocalVariableReference var; var = new LocalVariableReference (implicit_block, decl.identifier, loc); assign = new Assign (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, Block.Flags.Implicit); 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; } void CheckAttributeTarget (string a, Location l) { switch (a) { case "assembly" : case "module" : case "field" : case "method" : case "param" : case "property" : case "type" : return; default : Report.Error (658, l, "`" + a + "' is an invalid attribute target"); break; } } void CheckUnaryOperator (Operator.OpType op, Location l) { 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.Addition: case Operator.OpType.Subtraction: break; default : Report.Error (1019, l, "Overloadable unary operator expected"); break; } } void CheckBinaryOperator (Operator.OpType op, Location l) { switch (op) { case Operator.OpType.Addition: case Operator.OpType.Subtraction: case Operator.OpType.Multiply: case Operator.OpType.Division: case Operator.OpType.Modulus: case Operator.OpType.BitwiseAnd: case Operator.OpType.BitwiseOr: case Operator.OpType.ExclusiveOr: case Operator.OpType.LeftShift: case Operator.OpType.RightShift: case Operator.OpType.Equality: case Operator.OpType.Inequality: case Operator.OpType.GreaterThan: case Operator.OpType.LessThan: case Operator.OpType.GreaterThanOrEqual: case Operator.OpType.LessThanOrEqual: break; default : Report.Error (1020, l, "Overloadable binary operator expected"); break; } } 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; } } public CSharpParser (SeekableStreamReader reader, SourceFile file, ArrayList defines) { current_namespace = new NamespaceEntry (null, file, null, Location.Null); this.name = file.Name; this.file = file; current_container = RootContext.Tree.Types; // TODO: Make RootContext.Tree.Types a PartialContainer. current_class = current_container; current_container.NamespaceEntry = current_namespace; oob_stack = new Stack (); switch_stack = new Stack (); lexer = new Tokenizer (reader, file, defines); } public void parse () { 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); Report.Error (-25, lexer.Location, "Parsing error"); if (yacc_verbose_flag > 0) Console.WriteLine (e); } RootContext.Tree.Types.NamespaceEntry = null; } void CheckToken (int error, int yyToken, string msg, Location loc) { if (yyToken >= Token.FIRST_KEYWORD && yyToken <= Token.LAST_KEYWORD){ Report.Error (error, loc, String.Format ("{0}: `{1}' is a keyword", msg, yyNames [yyToken].ToLower ())); return; } 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; } /* end end end */ }