%{ // // 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) // // 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; IIteratorContainer iterator_container; /// /// Current block is used to add statements as we find /// them. /// Block current_block; /// /// If true, creates a toplevel block in the block production /// This is flagged by the delegate creation /// bool create_toplevel_block; /// /// /// Current interface is used by the various declaration /// productions in the interface declaration to "add" /// the interfaces as we find them. /// Interface current_interface; 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; public bool yacc_verbose_flag; // Name of the file we are parsing public string name; /// /// The current file. /// SourceFile file; %} %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 /* 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 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 /* 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 attribute_sections opt_EOF | attribute_sections opt_EOF | opt_EOF /* allow empty files */ ; opt_EOF : /* empty */ | EOF ; outer_declarations : outer_declaration | outer_declarations outer_declaration ; outer_declaration : using_directive | namespace_member_declaration ; using_directives : using_directive | using_directives using_directive ; using_directive : using_alias_directive | using_namespace_directive ; using_alias_directive : USING IDENTIFIER ASSIGN namespace_or_type_name SEMICOLON { current_namespace.UsingAlias ((string) $2, (MemberName) $4, lexer.Location); } | USING error { CheckIdentifierToken (yyToken); } ; using_namespace_directive : USING namespace_name SEMICOLON { current_namespace.Using ((string) $2, lexer.Location); } ; // // 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_name { Attributes attrs = (Attributes) $1; if (attrs != null) { foreach (AttributeSection asec in attrs.AttributeSections) if (asec.Target == "assembly") CodeGen.Assembly.AddAttribute (current_container, asec); else Report.Error(1518, Lexer.Location, "Attributes cannot be applied to namespaces." + " Expected class, delegate, enum, interface, or struct"); } current_namespace = RootContext.Tree.RecordNamespace (current_namespace, file, (string) $3, lexer.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.GetName (); } ; namespace_body : OPEN_BRACE opt_using_directives opt_namespace_member_declarations CLOSE_BRACE { } ; opt_using_directives : /* empty */ | using_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 { string name = ""; int mod_flags; if ($1 is Class){ Class c = (Class) $1; mod_flags = c.ModFlags; name = c.Name; } else if ($1 is Struct){ Struct s = (Struct) $1; mod_flags = s.ModFlags; name = s.Name; } else break; if ((mod_flags & (Modifiers.PRIVATE|Modifiers.PROTECTED)) != 0){ Report.Error ( 1527, lexer.Location, "Namespace elements cant be explicitly " + "declared private or protected in `" + name + "'"); } current_namespace.DeclarationFound = true; } | namespace_declaration { current_namespace.DeclarationFound = true; } | field_declaration { Report.Error (116, lexer.Location, "A namespace can only contain types and namespace declarations"); } | method_declaration { Report.Error (116, lexer.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, lexer.Location, "Expected class, struct, interface, enum or delegate"); // } ; // // Attributes 17.2 // opt_attributes : /* empty */ | attribute_sections { $$ = $1; } ; attribute_sections : attribute_section { AttributeSection sect = (AttributeSection) $1; if (sect.Target == "assembly") { CodeGen.Assembly.AddAttribute (current_container, sect); $$ = null; } else if (sect.Target == "module") { CodeGen.Module.AddAttribute (current_container, sect); $$ = null; } else $$ = new Attributes (sect); } | attribute_sections attribute_section { Attributes attrs = $1 as Attributes; AttributeSection sect = (AttributeSection) $2; if (sect.Target == "assembly") { CodeGen.Assembly.AddAttribute (current_container, sect); } else if (sect.Target == "module") { CodeGen.Module.AddAttribute (current_container, sect); } else { if (attrs == null) attrs = new Attributes (sect); else attrs.AddAttributeSection (sect); } $$ = attrs; } ; attribute_section : OPEN_BRACKET attribute_target_specifier attribute_list opt_comma CLOSE_BRACKET { string target = null; if ($2 != null) target = (string) $2; $$ = new AttributeSection (target, (ArrayList) $3); } | OPEN_BRACKET attribute_list opt_comma CLOSE_BRACKET { $$ = new AttributeSection (null, (ArrayList) $2); } ; attribute_target_specifier : attribute_target COLON { $$ = $1; } ; attribute_target : IDENTIFIER { CheckAttributeTarget ((string) $1); $$ = $1; } | 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 { $$ = lexer.Location; } opt_attribute_arguments { // // Attributes need a string, not an expression: generic types will fail here. // $$ = new Attribute (((Expression) $1).ToString (), (ArrayList) $3, (Location) $2); } ; attribute_name : 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 : IDENTIFIER ASSIGN expression { $$ = new DictionaryEntry ( (string) $1, 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 STRUCT IDENTIFIER { Struct new_struct; string full_struct_name = MakeName ((string) $4); new_struct = new Struct (current_namespace, current_container, full_struct_name, (int) $2, (Attributes) $1, lexer.Location); current_container = new_struct; RootContext.Tree.RecordDecl (full_struct_name, new_struct); lexer.ConstraintsParsing = true; } opt_type_parameter_list opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; } struct_body opt_semicolon { Struct new_struct = (Struct) current_container; if ($8 != null && $6 == null) Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); if ($6 != null) CheckDef (new_struct.SetParameterInfo ((ArrayList) $6, (ArrayList) $8), new_struct.Name, new_struct.Location); if ($7 != null) new_struct.Bases = (ArrayList) $7; current_container = current_container.Parent; CheckDef (current_container.AddStruct (new_struct), new_struct.Name, new_struct.Location); $$ = new_struct; } | opt_attributes opt_modifiers STRUCT error { CheckIdentifierToken (yyToken); } ; struct_body : OPEN_BRACE 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 { foreach (VariableDeclaration constant in (ArrayList) $5){ Location l = constant.Location; Const c = new Const ( (Expression) $4, (string) constant.identifier, (Expression) constant.expression_or_array_initializer, (int) $2, (Attributes) $1, l); CheckDef (current_container.AddConstant (c), c.Name, l); } } ; constant_declarators : constant_declarator { ArrayList constants = new ArrayList (4); constants.Add ($1); $$ = constants; } | constant_declarators COMMA constant_declarator { ArrayList constants = (ArrayList) $1; constants.Add ($3); } ; constant_declarator : IDENTIFIER ASSIGN constant_expression { $$ = new VariableDeclaration ((string) $1, $3, lexer.Location); } ; field_declaration : opt_attributes opt_modifiers type variable_declarators SEMICOLON { Expression type = (Expression) $3; int mod = (int) $2; foreach (VariableDeclaration var in (ArrayList) $4){ Location l = var.Location; Field field = new Field (type, mod, var.identifier, var.expression_or_array_initializer, (Attributes) $1, l); CheckDef (current_container.AddField (field), field.Name, l); } } | opt_attributes opt_modifiers VOID variable_declarators SEMICOLON { Report.Error (670, lexer.Location, "void type is not allowed for fields"); } ; variable_declarators : variable_declarator { ArrayList decl = new ArrayList (4); 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 ((string) $1, $3, lexer.Location); } | IDENTIFIER { $$ = new VariableDeclaration ((string) $1, null, lexer.Location); } ; variable_initializer : expression { $$ = $1; } | array_initializer { $$ = $1; } | STACKALLOC type OPEN_BRACKET expression CLOSE_BRACKET { $$ = new StackAlloc ((Expression) $2, (Expression) $4, lexer.Location); } ; method_declaration : method_header { iterator_container = (IIteratorContainer) $1; } method_body { Method method = (Method) $1; Block b = (Block) $3; const int extern_abstract = (Modifiers.EXTERN | Modifiers.ABSTRACT); if (b == null){ if ((method.ModFlags & extern_abstract) == 0){ Report.Error ( 501, lexer.Location, current_container.MakeName (method.Name) + "must declare a body because it is not marked abstract or extern"); } } else { if ((method.ModFlags & Modifiers.EXTERN) != 0){ Report.Error ( 179, lexer.Location, current_container.MakeName (method.Name) + " is declared extern, but has a body"); } } method.Block = (Block) $3; CheckDef (current_container.AddMethod (method), method.Name, method.Location); current_local_parameters = null; iterator_container = null; } ; 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 `" + Modifiers.Name (i) + "' must precede member type and name"); } 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_container, name.Name, (Attributes) $1, lexer.Location); CheckDef (generic.SetParameterInfo (name.TypeArguments, (ArrayList) $9), name.Name, lexer.Location); method = new Method (generic, (Expression) $3, (int) $2, false, name, (Parameters) $6, (Attributes) $1, lexer.Location); } else method = new Method (current_container, (Expression) $3, (int) $2, false, name, (Parameters) $6, (Attributes) $1, lexer.Location); current_local_parameters = (Parameters) $6; $$ = 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_container, name.Name, (Attributes) $1, lexer.Location); CheckDef (generic.SetParameterInfo (name.TypeArguments, (ArrayList) $9), name.Name, lexer.Location); method = new Method (generic, TypeManager.system_void_expr, (int) $2, false, name, (Parameters) $6, (Attributes) $1, lexer.Location); } else method = new Method (current_container, TypeManager.system_void_expr, (int) $2, false, name, (Parameters) $6, (Attributes) $1, lexer.Location); current_local_parameters = (Parameters) $6; $$ = method; } | opt_attributes opt_modifiers type modifiers namespace_or_type_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { Report.Error (1585, lexer.Location, String.Format ("Modifier {0} should appear before type", Modifiers.Name ((int) $4))); Method method = new Method (current_container, TypeManager.system_void_expr, 0, false, (MemberName) $5, (Parameters) $6, (Attributes) $1, lexer.Location); current_local_parameters = (Parameters) $6; $$ = method; } ; 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, lexer.Location); } | 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, lexer.Location); } | parameter_array { $$ = new Parameters (null, (Parameter) $1, lexer.Location); } ; 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 { $$ = new Parameter ((Expression) $3, (string) $4, (Parameter.Modifier) $2, (Attributes) $1); } | opt_attributes opt_parameter_modifier type error { CheckIdentifierToken (yyToken); $$ = 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 { $$ = new Parameter ((Expression) $3, (string) $4, Parameter.Modifier.PARAMS, (Attributes) $1); note ("type must be a single-dimension array type"); } | opt_attributes PARAMS type error { CheckIdentifierToken (yyToken); $$ = null; } ; property_declaration : opt_attributes opt_modifiers type namespace_or_type_name OPEN_BRACE { implicit_value_parameter_type = (Expression) $3; lexer.PropertyParsing = true; $$ = lexer.Location; iterator_container = SimpleIteratorContainer.GetSimple (); } accessor_declarations { lexer.PropertyParsing = false; } CLOSE_BRACE { Property prop; Pair pair = (Pair) $7; 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"); Location loc = (Location) $6; prop = new Property (current_container, (Expression) $3, (int) $2, false, name, (Attributes) $1, get_block, set_block, loc); if (SimpleIteratorContainer.Simple.Yields) prop.SetYields (); CheckDef (current_container.AddProperty (prop), prop.Name, loc); implicit_value_parameter_type = null; iterator_container = null; } ; accessor_declarations : get_accessor_declaration opt_set_accessor_declaration { $$ = new Pair ($1, $2); } | set_accessor_declaration opt_get_accessor_declaration { $$ = new Pair ($2, $1); } ; opt_get_accessor_declaration : /* empty */ { $$ = null; } | get_accessor_declaration ; opt_set_accessor_declaration : /* empty */ { $$ = null; } | set_accessor_declaration ; get_accessor_declaration : opt_attributes 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; } accessor_body { $$ = new Accessor ((Block) $4, (Attributes) $1); current_local_parameters = null; lexer.PropertyParsing = true; } ; set_accessor_declaration : opt_attributes SET { Parameter [] args; Parameter implicit_value_parameter = new Parameter ( implicit_value_parameter_type, "value", Parameter.Modifier.NONE, null); if (parsing_indexer == false) { args = new Parameter [1]; args [0] = implicit_value_parameter; current_local_parameters = new Parameters (args, null, lexer.Location); } 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.Location); } lexer.PropertyParsing = false; } accessor_body { $$ = new Accessor ((Block) $4, (Attributes) $1); current_local_parameters = null; lexer.PropertyParsing = true; } ; accessor_body : block | SEMICOLON { $$ = null; } ; interface_declaration : opt_attributes opt_modifiers INTERFACE IDENTIFIER { Interface new_interface; string full_interface_name = MakeName ((string) $4); new_interface = new Interface (current_namespace, current_container, full_interface_name, (int) $2, (Attributes) $1, lexer.Location); if (current_interface != null) { Location l = lexer.Location; Report.Error (-2, l, "Internal compiler error: interface inside interface"); } current_interface = new_interface; current_container = new_interface; RootContext.Tree.RecordDecl (full_interface_name, new_interface); lexer.ConstraintsParsing = true; } opt_type_parameter_list opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; } interface_body opt_semicolon { Interface new_interface = (Interface) current_interface; if ($8 != null && $6 == null) Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); if ($6 != null) CheckDef (new_interface.SetParameterInfo ((ArrayList) $6, (ArrayList) $8), new_interface.Name, new_interface.Location); if ($7 != null) new_interface.Bases = (ArrayList) $7; current_interface = null; current_container = current_container.Parent; CheckDef (current_container.AddInterface (new_interface), new_interface.Name, new_interface.Location); } | opt_attributes opt_modifiers INTERFACE error { CheckIdentifierToken (yyToken); } ; 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 { Method m = (Method) $1; CheckDef (current_interface.AddMethod (m), m.Name, m.Location); } | interface_property_declaration { Property p = (Property) $1; CheckDef (current_interface.AddProperty (p), p.Name, p.Location); } | interface_event_declaration { if ($1 != null){ Event e = (Event) $1; CheckDef (current_interface.AddEvent (e), e.Name, lexer.Location); } } | interface_indexer_declaration { Indexer i = (Indexer) $1; current_interface.AddIndexer (i); } ; opt_new : opt_modifiers { int val = (int) $1; val = Modifiers.Check (Modifiers.NEW | Modifiers.UNSAFE, val, 0, lexer.Location); $$ = val; } ; interface_method_declaration : opt_attributes opt_new type IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON { $$ = new Method (current_container, (Expression) $3, (int) $2, true, new MemberName ((string) $4), (Parameters) $6, (Attributes) $1, lexer.Location); } | opt_attributes opt_new VOID IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON { $$ = new Method (current_container, TypeManager.system_void_expr, (int) $2, true, new MemberName ((string) $4), (Parameters) $6, (Attributes) $1, lexer.Location); } ; interface_property_declaration : opt_attributes opt_new type IDENTIFIER OPEN_BRACE { lexer.PropertyParsing = true; } interface_accessors { lexer.PropertyParsing = false; } CLOSE_BRACE { InterfaceAccessorInfo pinfo = (InterfaceAccessorInfo) $7; $$ = new Property (current_container, (Expression) $3, (int) $2, true, new MemberName ((string) $4), (Attributes) $1, pinfo.Get, pinfo.Set, lexer.Location); } | opt_attributes opt_new type error { CheckIdentifierToken (yyToken); $$ = null; } ; interface_accessors : opt_attributes GET SEMICOLON { $$ = new InterfaceAccessorInfo (true, false, (Attributes) $1, null); } | opt_attributes SET SEMICOLON { $$ = new InterfaceAccessorInfo (false, true, null, (Attributes) $1); } | opt_attributes GET SEMICOLON opt_attributes SET SEMICOLON { $$ = new InterfaceAccessorInfo (true, true, (Attributes) $1, (Attributes) $3); } | opt_attributes SET SEMICOLON opt_attributes GET SEMICOLON { $$ = new InterfaceAccessorInfo (true, true, (Attributes) $3, (Attributes) $1); } ; interface_event_declaration : opt_attributes opt_new EVENT type IDENTIFIER SEMICOLON { $$ = new Event ((Expression) $4, (int) $2, true, new MemberName ((string) $5), null, (Attributes) $1, null, null, lexer.Location); } | opt_attributes opt_new EVENT type error { CheckIdentifierToken (yyToken); $$ = null; } | opt_attributes opt_new EVENT type IDENTIFIER ASSIGN { Report.Error (68, lexer.Location, "Event declarations on interfaces can not be initialized."); $$ = null; } | opt_attributes opt_new EVENT type IDENTIFIER OPEN_BRACE event_accessor_declarations CLOSE_BRACE { Report.Error (69, lexer.Location, "Event accessors not valid on interfaces"); $$ = null; } ; interface_indexer_declaration : opt_attributes opt_new type THIS OPEN_BRACKET formal_parameter_list CLOSE_BRACKET OPEN_BRACE { lexer.PropertyParsing = true; } interface_accessors { lexer.PropertyParsing = false; } CLOSE_BRACE { InterfaceAccessorInfo info = (InterfaceAccessorInfo) $10; $$ = new Indexer (current_container, (Expression) $3, (int) $2, true, MemberName.Null, (Parameters) $6, (Attributes) $1, info.Get, info.Set, lexer.Location); } ; operator_declaration : opt_attributes opt_modifiers operator_declarator { iterator_container = SimpleIteratorContainer.GetSimple (); } operator_body { OperatorDeclaration decl = (OperatorDeclaration) $3; Operator op = new Operator (decl.optype, decl.ret_type, (int) $2, decl.arg1type, decl.arg1name, decl.arg2type, decl.arg2name, (Block) $5, (Attributes) $1, decl.location); 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 { Operator.OpType op = (Operator.OpType) $3; CheckUnaryOperator (op); if (op == Operator.OpType.Addition) op = Operator.OpType.UnaryPlus; if (op == Operator.OpType.Subtraction) op = Operator.OpType.UnaryNegation; Parameter [] pars = new Parameter [1]; pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null); current_local_parameters = new Parameters (pars, null, lexer.Location); $$ = new OperatorDeclaration (op, (Expression) $1, (Expression) $5, (string) $6, null, null, lexer.Location); } | type OPERATOR overloadable_operator OPEN_PARENS type IDENTIFIER COMMA type IDENTIFIER CLOSE_PARENS { CheckBinaryOperator ((Operator.OpType) $3); Parameter [] pars = new Parameter [2]; pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null); pars [1] = new Parameter ((Expression) $8, (string) $9, Parameter.Modifier.NONE, null); current_local_parameters = new Parameters (pars, null, lexer.Location); $$ = new OperatorDeclaration ((Operator.OpType) $3, (Expression) $1, (Expression) $5, (string) $6, (Expression) $8, (string) $9, lexer.Location); } | conversion_operator_declarator ; overloadable_operator // Unary operators: : BANG { $$ = Operator.OpType.LogicalNot; } | TILDE { $$ = Operator.OpType.OnesComplement; } | OP_INC { $$ = Operator.OpType.Increment; } | OP_DEC { $$ = Operator.OpType.Decrement; } | TRUE { $$ = Operator.OpType.True; } | FALSE { $$ = Operator.OpType.False; } // Unary and binary: | PLUS { $$ = Operator.OpType.Addition; } | MINUS { $$ = Operator.OpType.Subtraction; } // Binary: | STAR { $$ = Operator.OpType.Multiply; } | DIV { $$ = Operator.OpType.Division; } | PERCENT { $$ = Operator.OpType.Modulus; } | BITWISE_AND { $$ = Operator.OpType.BitwiseAnd; } | BITWISE_OR { $$ = Operator.OpType.BitwiseOr; } | CARRET { $$ = Operator.OpType.ExclusiveOr; } | OP_SHIFT_LEFT { $$ = Operator.OpType.LeftShift; } | OP_SHIFT_RIGHT { $$ = Operator.OpType.RightShift; } | OP_EQ { $$ = Operator.OpType.Equality; } | OP_NE { $$ = Operator.OpType.Inequality; } | OP_GT { $$ = Operator.OpType.GreaterThan; } | OP_LT { $$ = Operator.OpType.LessThan; } | OP_GE { $$ = Operator.OpType.GreaterThanOrEqual; } | OP_LE { $$ = Operator.OpType.LessThanOrEqual; } ; conversion_operator_declarator : IMPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS { Parameter [] pars = new Parameter [1]; pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null); current_local_parameters = new Parameters (pars, null, lexer.Location); $$ = new OperatorDeclaration (Operator.OpType.Implicit, (Expression) $3, (Expression) $5, (string) $6, null, null, lexer.Location); } | EXPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS { Parameter [] pars = new Parameter [1]; pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null); current_local_parameters = new Parameters (pars, null, lexer.Location); $$ = new OperatorDeclaration (Operator.OpType.Explicit, (Expression) $3, (Expression) $5, (string) $6, null, null, lexer.Location); } | IMPLICIT error { syntax_error (lexer.Location, "'operator' expected"); } | EXPLICIT error { syntax_error (lexer.Location, "'operator' expected"); } ; constructor_declaration : opt_attributes opt_modifiers constructor_declarator constructor_body { Constructor c = (Constructor) $3; c.Block = (Block) $4; c.OptAttributes = (Attributes) $1; c.ModFlags = (int) $2; if (c.Name == current_container.Basename){ if ((c.ModFlags & Modifiers.STATIC) != 0){ if ((c.ModFlags & Modifiers.Accessibility) != 0){ Report.Error ( 515, c.Location, String.Format ( "`{0}.{1}': static constructor can not have access modifiers", c.Name, current_container.Name)); } c.ModFlags = Modifiers.Check (Constructor.AllowedModifiers, (int) $2, Modifiers.PRIVATE, c.Location); if (c.Initializer != null){ Report.Error ( 514, c.Location, "Static constructors can not have an explicit this or base " + "constructor invocations"); } if (!c.Parameters.Empty){ Report.Error ( 132, c.Location, "Static constructors should not have parameters"); } } 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); } CheckDef (current_container.AddConstructor (c), c.Name, c.Location); current_local_parameters = null; } ; constructor_declarator : IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { oob_stack.Push (lexer.Location); current_local_parameters = (Parameters) $3; } opt_constructor_initializer { Location l = (Location) oob_stack.Pop (); $$ = new Constructor (current_container, (string) $1, 0, (Parameters) $3, (ConstructorInitializer) $6, l); } ; 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, current_local_parameters, lexer.Location); } | COLON THIS OPEN_PARENS opt_argument_list CLOSE_PARENS { $$ = new ConstructorThisInitializer ((ArrayList) $4, current_local_parameters, lexer.Location); } | COLON error { Report.Error (1018, lexer.Location, "Keyword this or base expected"); $$ = null; } ; opt_finalizer : /* EMPTY */ { $$ = 0; } | UNSAFE { $$ = Modifiers.UNSAFE; } | EXTERN { $$ = Modifiers.EXTERN; } ; destructor_declaration : opt_attributes opt_finalizer TILDE IDENTIFIER OPEN_PARENS CLOSE_PARENS block { if ((string) $4 != current_container.Basename){ Report.Error (574, lexer.Location, "Name of destructor must match name of class"); } else if (!(current_container is Class)){ Report.Error (575, lexer.Location, "Destructors are only allowed in class types"); } else { Location l = lexer.Location; int m = (int) $2; if (!RootContext.StdLib && current_container.Name == "System.Object") m |= Modifiers.PROTECTED | Modifiers.VIRTUAL; else m |= Modifiers.PROTECTED | Modifiers.OVERRIDE; if ((m & Modifiers.UNSAFE) != 0){ if (!RootContext.Unsafe){ Report.Error (227, l, "Unsafe code requires the --unsafe command " + "line option to be specified"); } } Method d = new Destructor ( current_container, TypeManager.system_void_expr, m, "Finalize", new Parameters (null, null, l), (Attributes) $1, l); d.Block = (Block) $7; CheckDef (current_container.AddMethod (d), d.Name, d.Location); } } ; event_declaration : opt_attributes opt_modifiers EVENT type variable_declarators SEMICOLON { foreach (VariableDeclaration var in (ArrayList) $5) { MemberName name = new MemberName (var.identifier); Event e = new Event ((Expression) $4, (int) $2, false, name, var.expression_or_array_initializer, (Attributes) $1, null, null, lexer.Location); CheckDef (current_container.AddEvent (e), e.Name, e.Location); } } | opt_attributes opt_modifiers EVENT type namespace_or_type_name OPEN_BRACE { implicit_value_parameter_type = (Expression) $4; lexer.EventParsing = true; oob_stack.Push (lexer.Location); } event_accessor_declarations { lexer.EventParsing = false; } CLOSE_BRACE { Location loc = (Location) oob_stack.Pop (); if ($8 == null){ Report.Error (65, lexer.Location, "Event must have both add and remove accesors"); $$ = null; } else { Pair pair = (Pair) $8; Accessor add_accessor = null; Accessor rem_accessor = null; if (pair.First != null) add_accessor = (Accessor) pair.First; if (pair.Second != null) rem_accessor = (Accessor) pair.Second; MemberName name = (MemberName) $5; if (name.TypeArguments != null) syntax_error (lexer.Location, "an event can't have type arguments"); Event e = new Event ((Expression) $4, (int) $2, false, name, null, (Attributes) $1, add_accessor, rem_accessor, loc); CheckDef (current_container.AddEvent (e), e.Name, loc); implicit_value_parameter_type = null; } } ; 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; } ; 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); args [0] = implicit_value_parameter; current_local_parameters = new Parameters (args, null, lexer.Location); lexer.EventParsing = false; } block { $$ = new Accessor ((Block) $4, (Attributes) $1); lexer.EventParsing = true; } | opt_attributes ADD error { Report.Error (73, lexer.Location, "Add or remove accessor must have a body"); $$ = 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); args [0] = implicit_value_parameter; current_local_parameters = new Parameters (args, null, lexer.Location); lexer.EventParsing = false; } block { $$ = new Accessor ((Block) $4, (Attributes) $1); lexer.EventParsing = true; } | opt_attributes REMOVE error { Report.Error (73, lexer.Location, "Add or remove accessor must have a body"); $$ = 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; oob_stack.Push (lexer.Location); } accessor_declarations { lexer.PropertyParsing = false; parsing_indexer = false; } CLOSE_BRACE { // The signature is computed from the signature of the indexer. Look // at section 3.6 on the spec Location loc = (Location) oob_stack.Pop (); 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, "", null); else name = MemberName.Null; indexer = new Indexer (current_container, decl.type, (int) $2, false, name, decl.param_list, (Attributes) $1, get_block, set_block, loc); // Note that there is no equivalent of CheckDef for this case // We shall handle this in semantic analysis 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.FixedParameters == null && pars.ArrayParameter == null){ Report.Error (1551, lexer.Location, "Indexers must have at least one parameter"); } $$ = new IndexerDeclaration ((Expression) $1, null, pars); } | type namespace_or_type_name DOT THIS OPEN_BRACKET opt_formal_parameter_list CLOSE_BRACKET { Parameters pars = (Parameters) $6; if (pars.FixedParameters == null && pars.ArrayParameter == null){ Report.Error (1551, lexer.Location, "Indexers must have at least one parameter"); } MemberName name = (MemberName) $2; if (name.TypeArguments != null) syntax_error (lexer.Location, "an indexer can't have type arguments"); $$ = new IndexerDeclaration ((Expression) $1, name, pars); } ; enum_declaration : opt_attributes opt_modifiers ENUM IDENTIFIER opt_enum_base enum_body opt_semicolon { Location enum_location = lexer.Location; string full_name = MakeName ((string) $4); Enum e = new Enum (current_namespace, current_container, (Expression) $5, (int) $2, full_name, (Attributes) $1, enum_location); foreach (VariableDeclaration ev in (ArrayList) $6) { Location loc = (Location) ev.Location; CheckDef (e.AddEnumMember (ev.identifier, (Expression) ev.expression_or_array_initializer, loc, ev.OptAttributes), ev.identifier, loc); } CheckDef (current_container.AddEnum (e), full_name, enum_location); RootContext.Tree.RecordDecl (full_name, e); } ; opt_enum_base : /* empty */ { $$ = TypeManager.system_int32_expr; } | COLON type { $$ = $2; } ; enum_body : OPEN_BRACE opt_enum_member_declarations CLOSE_BRACE { $$ = $2; } ; 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 { $$ = new VariableDeclaration ((string) $2, null, lexer.Location, (Attributes) $1); } | opt_attributes IDENTIFIER { $$ = lexer.Location; } ASSIGN expression { $$ = new VariableDeclaration ((string) $2, $5, lexer.Location, (Attributes) $1); } ; delegate_declaration : opt_attributes opt_modifiers DELEGATE type IDENTIFIER opt_type_parameter_list OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { Location l = lexer.Location; Delegate del = new Delegate (current_namespace, current_container, (Expression) $4, (int) $2, MakeName ((string) $5), (Parameters) $8, (Attributes) $1, l); CheckDef (current_container.AddDelegate (del), del.Name, l); current_delegate = del; lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; } SEMICOLON { if ($11 != null && $6 == null) Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); if ($6 != null) CheckDef (current_delegate.SetParameterInfo ((ArrayList) $6, (ArrayList) $11), current_delegate.Name, current_delegate.Location); current_delegate = null; } | opt_attributes opt_modifiers DELEGATE VOID IDENTIFIER opt_type_parameter_list OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { Location l = lexer.Location; Delegate del = new Delegate ( current_namespace, current_container, TypeManager.system_void_expr, (int) $2, MakeName ((string) $5), (Parameters) $8, (Attributes) $1, l); CheckDef (current_container.AddDelegate (del), del.Name, l); current_delegate = del; lexer.ConstraintsParsing = true; } opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; } SEMICOLON { if ($11 != null && $6 == null) Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); if ($6 != null) CheckDef (current_delegate.SetParameterInfo ((ArrayList) $6, (ArrayList) $11), current_delegate.Name, current_delegate.Location); current_delegate = null; } ; type_name : namespace_or_type_name { $$ = ((MemberName) $1).GetTypeExpression (lexer.Location); } ; namespace_or_type_name : IDENTIFIER opt_type_argument_list { $$ = new MemberName ((string) $1, (TypeArguments) $2); } | namespace_or_type_name DOT IDENTIFIER opt_type_argument_list { $$ = new MemberName ((MemberName) $1, (string) $3, (TypeArguments) $4); } // | namespace_or_type_name DOT DEFAULT // { // $$ = new DefaultValueExpression ((Expression) $1, lexer.Location); // } ; // // TODO: // Figure out what to do with the list // opt_type_argument_list : /* empty */ { $$ = null; } | OP_GENERICS_LT type_arguments OP_GENERICS_GT { $$ = $2; } ; 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 : type_name { /* class_type */ } | builtin_types | 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, "*", lexer.Location); } ; non_expression_type : builtin_types | non_expression_type rank_specifier { $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location); } | non_expression_type STAR { $$ = new ComposedCast ((Expression) $1, "*", lexer.Location); } | expression rank_specifiers { $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location); } | expression STAR { $$ = new ComposedCast ((Expression) $1, "*", lexer.Location); } // // We need this because the parser will happily go and reduce IDENTIFIER STAR // through this different path // | multiplicative_expression STAR { $$ = new ComposedCast ((Expression) $1, "*", lexer.Location); } ; 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; } ; interface_type : type_name ; array_type : type rank_specifiers { $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location); } ; // // Expressions, section 7.5 // primary_expression : literal { // 7.5.1: Literals } | type_name { $$ = $1; } | 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); } | LITERAL_STRING { $$ = new StringLiteral ((string) lexer.Value); } | NULL { $$ = NullLiteral.Null; } ; real_literal : LITERAL_FLOAT { $$ = new FloatLiteral ((float) lexer.Value); } | LITERAL_DOUBLE { $$ = new DoubleLiteral ((double) lexer.Value); } | LITERAL_DECIMAL { $$ = new DecimalLiteral ((decimal) lexer.Value); } ; integer_literal : LITERAL_INTEGER { object v = lexer.Value; if (v is int){ int i = (int) v; if (i == 0) $$ = IntLiteral.Zero; else if (i == 1) $$ = IntLiteral.One; else $$ = new IntLiteral (i); } else if (v is uint) $$ = new UIntLiteral ((UInt32) v); else if (v is long) $$ = new LongLiteral ((Int64) v); else if (v is ulong) $$ = new ULongLiteral ((UInt64) v); else Console.WriteLine ("OOPS. Unexpected result from scanner"); } ; boolean_literal : TRUE { $$ = new BoolLiteral (true); } | FALSE { $$ = new BoolLiteral (false); } ; 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, lexer.Location); } ;; member_access : primary_expression DOT IDENTIFIER { $$ = new MemberAccess ((Expression) $1, (string) $3, lexer.Location); } | predefined_type DOT IDENTIFIER { $$ = new MemberAccess ((Expression) $1, (string) $3, lexer.Location); } ; predefined_type : builtin_types ; invocation_expression : primary_expression OPEN_PARENS opt_argument_list CLOSE_PARENS { if ($1 == null) { Location l = lexer.Location; Report.Error (1, l, "Parse error"); } $$ = new Invocation ((Expression) $1, (ArrayList) $3, lexer.Location); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS CLOSE_PARENS { $$ = new Invocation ((Expression) $1, new ArrayList (), lexer.Location); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS primary_expression { $$ = new InvocationOrCast ((Expression) $1, (Expression) $3, lexer.Location); } ; 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, ", or ) expected"); } ; argument : expression { $$ = new Argument ((Expression) $1, Argument.AType.Expression); } | REF variable_reference { $$ = new Argument ((Expression) $2, Argument.AType.Ref); } | OUT variable_reference { $$ = new Argument ((Expression) $2, Argument.AType.Out); } ; variable_reference : expression { note ("section 5.4"); $$ = $1; } ; element_access : primary_expression OPEN_BRACKET expression_list CLOSE_BRACKET { $$ = new ElementAccess ((Expression) $1, (ArrayList) $3, lexer.Location); } | 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, lexer.Location); } else if (!(expr is SimpleName || expr is MemberAccess || expr is ConstructedType)){ Error_ExpectingTypeName (lexer.Location, expr); $$ = TypeManager.system_object_expr; } else { // // So we extract the string corresponding to the SimpleName // or MemberAccess // $$ = new ComposedCast (expr, (string) $2, lexer.Location); } } ; 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, lexer.Location); } ; base_access : BASE DOT IDENTIFIER { $$ = new BaseAccess ((string) $3, lexer.Location); } | BASE OPEN_BRACKET expression_list CLOSE_BRACKET { $$ = new BaseIndexerAccess ((ArrayList) $3, lexer.Location); } | BASE error { Report.Error (175, "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, lexer.Location); } ; post_decrement_expression : primary_expression OP_DEC { $$ = new UnaryMutator (UnaryMutator.Mode.PostDecrement, (Expression) $1, lexer.Location); } ; 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, lexer.Location); } ; 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, lexer.Location); } | NEW type rank_specifiers array_initializer { $$ = new ArrayCreation ((Expression) $2, (string) $3, (ArrayList) $4, lexer.Location); } | NEW type error { Report.Error (1526, lexer.Location, "new expression requires () or [] after type"); } ; opt_rank_specifier : /* empty */ { $$ = ""; } | rank_specifiers { $$ = $1; } ; rank_specifiers : rank_specifier opt_rank_specifier { $$ = (string) $2 + (string) $1; } ; rank_specifier : OPEN_BRACKET opt_dim_separators CLOSE_BRACKET { $$ = "[" + (string) $2 + "]"; } ; opt_dim_separators : /* empty */ { $$ = ""; } | dim_separators { $$ = $1; } ; dim_separators : COMMA { $$ = ","; } | dim_separators COMMA { $$ = (string) $1 + ","; } ; opt_array_initializer : /* empty */ { $$ = null; } | array_initializer { $$ = $1; } ; array_initializer : OPEN_BRACE CLOSE_BRACE { ArrayList list = new ArrayList (4); $$ = list; } | OPEN_BRACE variable_initializer_list opt_comma CLOSE_BRACE { $$ = (ArrayList) $2; } ; variable_initializer_list : variable_initializer { ArrayList list = new ArrayList (4); list.Add ($1); $$ = list; } | variable_initializer_list COMMA variable_initializer { ArrayList list = (ArrayList) $1; list.Add ($3); $$ = list; } ; typeof_expression : TYPEOF OPEN_PARENS VOID CLOSE_PARENS { $$ = new TypeOfVoid (lexer.Location); } | TYPEOF OPEN_PARENS type CLOSE_PARENS { $$ = new TypeOf ((Expression) $3, lexer.Location); } ; sizeof_expression : SIZEOF OPEN_PARENS type CLOSE_PARENS { $$ = new SizeOf ((Expression) $3, lexer.Location); } ; checked_expression : CHECKED OPEN_PARENS expression CLOSE_PARENS { $$ = new CheckedExpr ((Expression) $3, lexer.Location); } ; unchecked_expression : UNCHECKED OPEN_PARENS expression CLOSE_PARENS { $$ = new UnCheckedExpr ((Expression) $3, lexer.Location); } ; pointer_member_access : primary_expression OP_PTR IDENTIFIER { Expression deref; deref = new Unary (Unary.Operator.Indirection, (Expression) $1, lexer.Location); $$ = new MemberAccess (deref, (string) $3, lexer.Location); } ; anonymous_method_expression : DELEGATE opt_anonymous_method_signature { oob_stack.Push (current_local_parameters); current_local_parameters = (Parameters)$2; create_toplevel_block = true; } block { create_toplevel_block = false; if (!RootContext.V2){ Report.Error (-213, lexer.Location, "Anonymous methods are only supported in V2"); $$ = null; } else $$ = new AnonymousMethod ((Parameters) $2, (Block) $4, lexer.Location); current_local_parameters = (Parameters) oob_stack.Pop (); } ; opt_anonymous_method_signature : /* empty */ { $$ = Parameters.EmptyReadOnlyParameters; } | 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, lexer.Location); } } ; 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 { $$ = new Parameter ((Expression) $2, (string) $2, (Parameter.Modifier) $1, 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, lexer.Location); } | TILDE prefixed_unary_expression { $$ = new Unary (Unary.Operator.OnesComplement, (Expression) $2, lexer.Location); } | cast_expression ; cast_list : parenthesized_expression_0 CLOSE_PARENS_CAST unary_expression { $$ = new Cast ((Expression) $1, (Expression) $3, lexer.Location); } | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS cast_expression { $$ = new Cast ((Expression) $1, (Expression) $3, lexer.Location); } ; cast_expression : cast_list | OPEN_PARENS non_expression_type CLOSE_PARENS prefixed_unary_expression { $$ = 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, lexer.Location); } | MINUS prefixed_unary_expression { $$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, lexer.Location); } | OP_INC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement, (Expression) $2, lexer.Location); } | OP_DEC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement, (Expression) $2, lexer.Location); } | STAR prefixed_unary_expression { $$ = new Unary (Unary.Operator.Indirection, (Expression) $2, lexer.Location); } | BITWISE_AND prefixed_unary_expression { $$ = new Unary (Unary.Operator.AddressOf, (Expression) $2, lexer.Location); } ; pre_increment_expression : OP_INC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement, (Expression) $2, lexer.Location); } ; pre_decrement_expression : OP_DEC prefixed_unary_expression { $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement, (Expression) $2, lexer.Location); } ; multiplicative_expression : prefixed_unary_expression | multiplicative_expression STAR prefixed_unary_expression { $$ = new Binary (Binary.Operator.Multiply, (Expression) $1, (Expression) $3, lexer.Location); } | multiplicative_expression DIV prefixed_unary_expression { $$ = new Binary (Binary.Operator.Division, (Expression) $1, (Expression) $3, lexer.Location); } | multiplicative_expression PERCENT prefixed_unary_expression { $$ = new Binary (Binary.Operator.Modulus, (Expression) $1, (Expression) $3, lexer.Location); } ; additive_expression : multiplicative_expression | additive_expression PLUS multiplicative_expression { $$ = new Binary (Binary.Operator.Addition, (Expression) $1, (Expression) $3, lexer.Location); } | additive_expression MINUS multiplicative_expression { $$ = new Binary (Binary.Operator.Subtraction, (Expression) $1, (Expression) $3, lexer.Location); } ; shift_expression : additive_expression | shift_expression OP_SHIFT_LEFT additive_expression { $$ = new Binary (Binary.Operator.LeftShift, (Expression) $1, (Expression) $3, lexer.Location); } | shift_expression OP_SHIFT_RIGHT additive_expression { $$ = new Binary (Binary.Operator.RightShift, (Expression) $1, (Expression) $3, lexer.Location); } ; relational_expression : shift_expression | relational_expression OP_LT shift_expression { $$ = new Binary (Binary.Operator.LessThan, (Expression) $1, (Expression) $3, lexer.Location); } | relational_expression OP_GT shift_expression { $$ = new Binary (Binary.Operator.GreaterThan, (Expression) $1, (Expression) $3, lexer.Location); } | relational_expression OP_LE shift_expression { $$ = new Binary (Binary.Operator.LessThanOrEqual, (Expression) $1, (Expression) $3, lexer.Location); } | relational_expression OP_GE shift_expression { $$ = new Binary (Binary.Operator.GreaterThanOrEqual, (Expression) $1, (Expression) $3, lexer.Location); } | relational_expression IS type { $$ = new Is ((Expression) $1, (Expression) $3, lexer.Location); } | relational_expression AS type { $$ = new As ((Expression) $1, (Expression) $3, lexer.Location); } ; equality_expression : relational_expression | equality_expression OP_EQ relational_expression { $$ = new Binary (Binary.Operator.Equality, (Expression) $1, (Expression) $3, lexer.Location); } | equality_expression OP_NE relational_expression { $$ = new Binary (Binary.Operator.Inequality, (Expression) $1, (Expression) $3, lexer.Location); } ; and_expression : equality_expression | and_expression BITWISE_AND equality_expression { $$ = new Binary (Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3, lexer.Location); } ; exclusive_or_expression : and_expression | exclusive_or_expression CARRET and_expression { $$ = new Binary (Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3, lexer.Location); } ; inclusive_or_expression : exclusive_or_expression | inclusive_or_expression BITWISE_OR exclusive_or_expression { $$ = new Binary (Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3, lexer.Location); } ; conditional_and_expression : inclusive_or_expression | conditional_and_expression OP_AND inclusive_or_expression { $$ = new Binary (Binary.Operator.LogicalAnd, (Expression) $1, (Expression) $3, lexer.Location); } ; conditional_or_expression : conditional_and_expression | conditional_or_expression OP_OR conditional_and_expression { $$ = new Binary (Binary.Operator.LogicalOr, (Expression) $1, (Expression) $3, lexer.Location); } ; conditional_expression : conditional_or_expression | conditional_or_expression INTERR expression COLON expression { $$ = new Conditional ((Expression) $1, (Expression) $3, (Expression) $5, lexer.Location); } ; assignment_expression : prefixed_unary_expression ASSIGN expression { $$ = new Assign ((Expression) $1, (Expression) $3, lexer.Location); } | prefixed_unary_expression OP_MULT_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.Multiply, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_DIV_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.Division, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_MOD_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.Modulus, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_ADD_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.Addition, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_SUB_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.Subtraction, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_SHIFT_LEFT_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.LeftShift, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_SHIFT_RIGHT_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.RightShift, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_AND_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_OR_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3, l); } | prefixed_unary_expression OP_XOR_ASSIGN expression { Location l = lexer.Location; $$ = new CompoundAssign ( Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3, l); } ; expression : conditional_expression | assignment_expression ; constant_expression : expression ; boolean_expression : expression ; // // 10 classes // class_declaration : opt_attributes opt_modifiers CLASS IDENTIFIER { Class new_class; string name; name = MakeName ((string) $4); new_class = new Class (current_namespace, current_container, name, (int) $2, (Attributes) $1, lexer.Location); current_container = new_class; RootContext.Tree.RecordDecl (name, new_class); lexer.ConstraintsParsing = true; } opt_type_parameter_list opt_class_base opt_type_parameter_constraints_clauses { lexer.ConstraintsParsing = false; } class_body opt_semicolon { Class new_class = (Class) current_container; if ($8 != null && $6 == null) Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); if ($6 != null) CheckDef (new_class.SetParameterInfo ((ArrayList) $6, (ArrayList) $8), new_class.Name, new_class.Location); if ($7 != null) { if (new_class.Name == "System.Object") { Report.Error (537, new_class.Location, "The class System.Object cannot have a base class or implement an interface."); } new_class.Bases = (ArrayList) $7; } current_container = current_container.Parent; CheckDef (current_container.AddClass (new_class), new_class.Name, new_class.Location); $$ = new_class; } | opt_attributes opt_modifiers CLASS IDENTIFIER { lexer.ConstraintsParsing = true; } WHERE { Report.Error (80, lexer.Location, "Contraints are not allowed on non-generic declarations"); yyErrorFlag = 0; $$ = null; } ; 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 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_list : /* empty */ { $$ = null; } | type_parameter_list { $$ = $1; } ; type_parameter_list : OP_GENERICS_LT type_parameters OP_GENERICS_GT { $$ = $2; } ; type_parameters : type_parameter { // // Do some profiling to find the optimal size, for now we // assume most people will be generic on one type (saves space // ArrayList type_parameters = new ArrayList (1); type_parameters.Add ($1); $$ = type_parameters; } | type_parameters COMMA type_parameter { ArrayList type_parameters = (ArrayList) $1; type_parameters.Add ($3); $$ = type_parameters; } ; type_parameter : IDENTIFIER ; opt_type_parameter_constraints_clauses : /* empty */ { $$ = null; } | type_parameter_constraints_clauses { $$ = $1; } ; type_parameter_constraints_clauses : type_parameter_constraints_clause | type_parameter_constraints_clauses type_parameter_constraints_clause { ArrayList constraints = (ArrayList) $1; constraints.Add ($2); $$ = constraints; } ; type_parameter_constraints_clause : WHERE type_parameter COLON type_parameter_constraints { ArrayList constraints = new ArrayList (1); constraints.Add (new Constraints ((string) $2, (ArrayList) $4, lexer.Location)); $$ = constraints; } ; 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 { $$ = true; } ; // // 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 || create_toplevel_block){ current_block = new ToplevelBlock (current_local_parameters, lexer.Location); } else { current_block = new Block (current_block, current_local_parameters, lexer.Location, Location.Null); } } opt_statement_list CLOSE_BRACE { while (current_block.Implicit) current_block = current_block.Parent; $$ = current_block; current_block.SetEndLocation (lexer.Location); current_block = current_block.Parent; } ; 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; } } | embedded_statement { current_block.AddStatement ((Statement) $1); } | labeled_statement ; embedded_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 ; empty_statement : SEMICOLON { $$ = EmptyStatement.Value; } ; labeled_statement : IDENTIFIER COLON { LabeledStatement labeled = new LabeledStatement ((string) $1, lexer.Location); if (!current_block.AddLabel ((string) $1, labeled)){ Location l = lexer.Location; Report.Error (140, l, "The label '" + ((string) $1) + "' is a duplicate"); } current_block.AddStatement (labeled); } statement ; declaration_statement : local_variable_declaration SEMICOLON { if ($1 != null){ DictionaryEntry de = (DictionaryEntry) $1; $$ = declare_local_variables ((Expression) de.Key, (ArrayList) de.Value, lexer.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 { // 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)) { Error_ExpectingTypeName (lexer.Location, 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, lexer.Location); } } | builtin_types opt_rank_specifier { if ((string) $2 == "") $$ = $1; else $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location); } ; local_variable_pointer_type : primary_expression STAR { Expression expr = (Expression) $1; Location l = lexer.Location; if (!(expr is SimpleName || expr is MemberAccess || expr is ComposedCast || expr is ConstructedType)) { Error_ExpectingTypeName (l, expr); $$ = null; } else $$ = new ComposedCast ((Expression) $1, "*", l); } | builtin_types STAR { $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);; } | VOID STAR { $$ = new ComposedCast (TypeManager.system_void_expr, "*", lexer.Location);; } | local_variable_pointer_type STAR { $$ = new ComposedCast ((Expression) $1, "*", lexer.Location); } ; local_variable_declaration : local_variable_type variable_declarators { if ($1 != null) $$ = new DictionaryEntry ($1, $2); else $$ = null; } | local_variable_pointer_type opt_rank_specifier variable_declarators { if ($1 != null){ Expression t; if ((string) $2 == "") t = (Expression) $1; else t = new ComposedCast ((Expression) $1, (string) $2, lexer.Location); $$ = 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, lexer.Location); } | object_creation_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); } | assignment_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); } | post_increment_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); } | post_decrement_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); } | pre_increment_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); } | pre_decrement_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); } | error { Report.Error (1002, lexer.Location, "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_statement_open if_statement_rest { $$ = $2; } ; if_statement_open : IF OPEN_PARENS { oob_stack.Push (lexer.Location); } ; if_statement_rest : boolean_expression CLOSE_PARENS embedded_statement { Location l = (Location) oob_stack.Pop (); $$ = new If ((Expression) $1, (Statement) $3, l); if (RootContext.WarningLevel >= 3){ if ($3 == EmptyStatement.Value) Report.Warning (642, lexer.Location, "Possibly mistaken empty statement"); } } | boolean_expression CLOSE_PARENS embedded_statement ELSE embedded_statement { Location l = (Location) oob_stack.Pop (); $$ = new If ((Expression) $1, (Statement) $3, (Statement) $5, l); } ; switch_statement : SWITCH OPEN_PARENS { oob_stack.Push (lexer.Location); switch_stack.Push (current_block); } expression CLOSE_PARENS switch_block { $$ = new Switch ((Expression) $4, (ArrayList) $6, (Location) oob_stack.Pop ()); 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, lexer.Location); } | DEFAULT COLON { $$ = new SwitchLabel (null, lexer.Location); } | error { Report.Error ( 1523, lexer.Location, "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 { oob_stack.Push (lexer.Location); } boolean_expression CLOSE_PARENS embedded_statement { Location l = (Location) oob_stack.Pop (); $$ = new While ((Expression) $4, (Statement) $6, l); if (RootContext.WarningLevel >= 3){ if ($6 == EmptyStatement.Value) Report.Warning (642, lexer.Location, "Possibly mistaken empty statement"); } } ; do_statement : DO embedded_statement WHILE OPEN_PARENS { oob_stack.Push (lexer.Location); } boolean_expression CLOSE_PARENS SEMICOLON { Location l = (Location) oob_stack.Pop (); $$ = new Do ((Statement) $2, (Expression) $6, 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, current_local_parameters, 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, lexer.Location)); } } $3 = null; } oob_stack.Push (lexer.Location); } opt_for_condition SEMICOLON opt_for_iterator CLOSE_PARENS embedded_statement { Location l = (Location) oob_stack.Pop (); For f = new For ((Statement) $3, (Expression) $6, (Statement) $8, (Statement) $10, l); if (RootContext.WarningLevel >= 3){ if ($10 == EmptyStatement.Value) Report.Warning (642, lexer.Location, "Possibly mistaken empty statement"); } 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 IDENTIFIER IN { oob_stack.Push (lexer.Location); } expression CLOSE_PARENS { oob_stack.Push (current_block); Block foreach_block = new Block (current_block, Block.Flags.Implicit); LocalVariableReference v = null; Location l = lexer.Location; LocalInfo vi; vi = foreach_block.AddVariable ((Expression) $3, (string) $4, current_local_parameters, l); if (vi != null) { vi.ReadOnly = true; // Get a writable reference to this read-only variable. v = new LocalVariableReference (foreach_block, (string) $4, l, vi, false); } current_block = foreach_block; oob_stack.Push (v); oob_stack.Push (current_block); } embedded_statement { Block foreach_block = (Block) oob_stack.Pop (); LocalVariableReference v = (LocalVariableReference) oob_stack.Pop (); Block prev_block = (Block) oob_stack.Pop (); Location l = (Location) oob_stack.Pop (); current_block = prev_block; if (v != null) { Foreach f = new Foreach ((Expression) $3, v, (Expression) $7, (Statement) $10, l); foreach_block.AddStatement (f); } $$ = foreach_block; } ; jump_statement : break_statement | continue_statement | goto_statement | return_statement | throw_statement | yield_statement ; break_statement : BREAK SEMICOLON { $$ = new Break (lexer.Location); } ; continue_statement : CONTINUE SEMICOLON { $$ = new Continue (lexer.Location); } ; goto_statement : GOTO IDENTIFIER SEMICOLON { $$ = new Goto (current_block, (string) $2, lexer.Location); } | GOTO CASE constant_expression SEMICOLON { $$ = new GotoCase ((Expression) $3, lexer.Location); } | GOTO DEFAULT SEMICOLON { $$ = new GotoDefault (lexer.Location); } ; return_statement : RETURN opt_expression SEMICOLON { $$ = new Return ((Expression) $2, lexer.Location); } ; throw_statement : THROW opt_expression SEMICOLON { $$ = new Throw ((Expression) $2, lexer.Location); } ; yield_statement : IDENTIFIER RETURN expression SEMICOLON { string s = (string) $1; if (s != "yield"){ Report.Error (1003, lexer.Location, "; expected"); $$ = null; } if (!RootContext.V2){ Report.Error (-222, lexer.Location, "yield statement only available in C# 2.0 mode"); $$ = null; } if (iterator_container == null){ Report.Error (204, lexer.Location, "yield statement can only be used within a method, operator or property"); $$ = null; } else { iterator_container.SetYields (); $$ = new Yield ((Expression) $3, lexer.Location); } } | IDENTIFIER BREAK SEMICOLON { string s = (string) $1; if (s != "yield"){ Report.Error (1003, lexer.Location, "; expected"); $$ = null; } if (!RootContext.V2){ Report.Error (-222, lexer.Location, "yield statement only available in C# 2.0 mode"); $$ = null; } if (iterator_container == null){ Report.Error (204, lexer.Location, "yield statement can only be used within a method, operator or property"); $$ = null; } else { iterator_container.SetYields (); $$ = new YieldBreak (lexer.Location); } } ; opt_expression : /* empty */ | expression ; try_statement : TRY block catch_clauses { Catch g = null; ArrayList s = new ArrayList (4); foreach (Catch cc in (ArrayList) $3) { if (cc.IsGeneral) g = cc; else s.Add (cc); } // Now s contains the list of specific catch clauses // and g contains the general one. $$ = new Try ((Block) $2, s, g, null, lexer.Location); } | 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, lexer.Location); } | TRY block error { Report.Error (1524, lexer.Location, "Expected catch or finally"); } ; 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; string id = null; if ($2 != null) { DictionaryEntry cc = (DictionaryEntry) $2; type = (Expression) cc.Key; id = (string) cc.Value; if (id != null){ ArrayList one = new ArrayList (4); Location loc = lexer.Location; one.Add (new VariableDeclaration (id, null, loc)); $1 = current_block; current_block = new Block (current_block); Block b = declare_local_variables (type, one, loc); current_block = b; } } } block { Expression type = null; string id = null; if ($2 != null){ DictionaryEntry cc = (DictionaryEntry) $2; type = (Expression) cc.Key; id = (string) cc.Value; if ($1 != null){ // // FIXME: I can change this for an assignment. // while (current_block != (Block) $1) current_block = current_block.Parent; } } $$ = new Catch (type, id , (Block) $4, lexer.Location); } ; 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 { if (!RootContext.Unsafe){ Report.Error (227, lexer.Location, "Unsafe code can only be used if --unsafe is used"); } } block { $$ = new Unsafe ((Block) $3); } ; fixed_statement : FIXED OPEN_PARENS type fixed_pointer_declarators CLOSE_PARENS { Block assign_block = new Block (current_block, Block.Flags.Implicit); ArrayList list = (ArrayList) $4; Expression type = (Expression) $3; Location l = lexer.Location; int top = list.Count; for (int i = 0; i < top; i++){ Pair p = (Pair) list [i]; LocalInfo v; v = current_block.AddVariable (type, (string) p.First,current_local_parameters, l); if (v == null) continue; v.ReadOnly = true; p.First = v; list [i] = p; } current_block.AddStatement (assign_block); current_block = assign_block; oob_stack.Push (assign_block); oob_stack.Push (l); } embedded_statement { Location l = (Location) oob_stack.Pop (); oob_stack.Pop (); $$ = new Fixed ((Expression) $3, (ArrayList) $4, (Statement) $7, l); } ; fixed_pointer_declarators : fixed_pointer_declarator { ArrayList declarators = new ArrayList (4); declarators.Add ($1); $$ = declarators; } | fixed_pointer_declarators COMMA fixed_pointer_declarator { ArrayList declarators = (ArrayList) $1; declarators.Add ($3); $$ = declarators; } ; fixed_pointer_declarator : IDENTIFIER ASSIGN expression { $$ = new Pair ($1, $3); } ; lock_statement : LOCK OPEN_PARENS expression CLOSE_PARENS { // } embedded_statement { $$ = new Lock ((Expression) $3, (Statement) $6, lexer.Location); } ; using_statement : USING OPEN_PARENS resource_acquisition CLOSE_PARENS { Block assign_block = new Block (current_block); current_block = assign_block; oob_stack.Push (lexer.Location); if ($3 is DictionaryEntry){ DictionaryEntry de = (DictionaryEntry) $3; Location l = lexer.Location; 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, current_local_parameters, decl.Location); if (vi == null) continue; vi.ReadOnly = true; 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; // 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, lexer.Location)); } $3 = new DictionaryEntry (type, vars); } } embedded_statement { Using u = new Using ($3, (Statement) $6, (Location) oob_stack.Pop ()); 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 VariableDeclaration (string id, object eoai, Location l, Attributes opt_attrs) { this.identifier = id; this.expression_or_array_initializer = eoai; this.Location = l; this.OptAttributes = opt_attrs; } public VariableDeclaration (string id, object eoai, Location l) : this (id, eoai, l, null) { } } /// /// Used to pass around interface property information /// public class InterfaceAccessorInfo { public readonly Accessor Get, Set; public InterfaceAccessorInfo (bool has_get, bool has_set, Attributes get_attrs, Attributes set_attrs) { if (has_get) Get = new Accessor (null, get_attrs); if (has_set) Set = new Accessor (null, set_attrs); } } // // 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 IndexerDeclaration (Expression type, MemberName interface_type, Parameters param_list) { this.type = type; this.interface_type = interface_type; this.param_list = param_list; } } // // 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 (Location l, Expression expr) { if (expr is Invocation){ Report.Error (1002, l, "; expected"); } else { Report.Error (-1, l, "Invalid Type definition"); } } // // Given the @class_name name, it creates a fully qualified name // based on the containing declaration space // string MakeName (string class_name) { string ns = current_namespace.FullName; string container_name = current_container.Name; if (container_name == ""){ if (ns != "") return ns + "." + class_name; else return class_name; } else return container_name + "." + class_name; } // // Used to report back to the user the result of a declaration // in the current declaration space // void CheckDef (DeclSpace.AdditionResult result, string name, Location l) { if (result == DeclSpace.AdditionResult.Success) return; switch (result){ case DeclSpace.AdditionResult.NameExists: Report.Error (102, l, "The container `" + current_container.Name + "' already contains a definition for `"+ name + "'"); break; // // This is handled only for static Constructors, because // in reality we handle these by the semantic analysis later // case DeclSpace.AdditionResult.MethodExists: Report.Error ( 111, l, "Class `"+current_container.Name+ "' already defines a member called '" + name + "' with the same parameter types (more than one default constructor)"); break; case DeclSpace.AdditionResult.EnclosingClash: Report.Error (542, l, "Member names cannot be the same as their enclosing type"); break; case DeclSpace.AdditionResult.NotAConstructor: Report.Error (1520, l, "Class, struct, or interface method must have a return type"); break; case DeclSpace.AdditionResult.Error: // Error has already been reported. break; } } void CheckDef (bool result, string name, Location l) { if (result) return; CheckDef (DeclSpace.AdditionResult.NameExists, name, l); } 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); implicit_block.AddChildVariableNames (current_block); } else implicit_block = current_block; foreach (VariableDeclaration decl in variable_declarators){ if (implicit_block.AddVariable (type, decl.identifier, current_local_parameters, 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, lexer.Location)); } 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, current_local_parameters, decl.Location); } return implicit_block; } void CheckAttributeTarget (string a) { switch (a) { case "assembly" : case "module" : case "field" : case "method" : case "param" : case "property" : case "type" : return; default : Location l = lexer.Location; Report.Error (658, l, "`" + a + "' is an invalid attribute target"); break; } } void CheckUnaryOperator (Operator.OpType op) { switch (op) { case Operator.OpType.LogicalNot: case Operator.OpType.OnesComplement: case Operator.OpType.Increment: case Operator.OpType.Decrement: case Operator.OpType.True: case Operator.OpType.False: case Operator.OpType.Addition: case Operator.OpType.Subtraction: break; default : Location l = lexer.Location; Report.Error (1019, l, "Overloadable unary operator expected"); break; } } void CheckBinaryOperator (Operator.OpType op) { 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 : Location l = lexer.Location; Report.Error (1020, l, "Overloadable binary operator expected"); break; } } void syntax_error (Location l, string msg) { Report.Error (1003, l, "Syntax error, " + msg); } void output (string s) { Console.WriteLine (s); } 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; 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) yyparse (lexer, new yydebug.yyDebugSimple ()); else yyparse (lexer); Tokenizer tokenizer = lexer as Tokenizer; tokenizer.cleanup (); } catch (Exception e){ // Please do not remove this, it is used during debugging // of the grammar // Console.WriteLine (e); Report.Error (-25, lexer.Location, "Parsing error"); if (Driver.parser_verbose) Console.WriteLine (e); } } void CheckToken (int error, int yyToken, string msg) { if (yyToken >= Token.FIRST_KEYWORD && yyToken <= Token.LAST_KEYWORD){ Report.Error (error, lexer.Location, String.Format ("{0}: `{1}' is a keyword", msg, yyNames [yyToken].ToLower ())); return; } Report.Error (error, lexer.Location, msg); } void CheckIdentifierToken (int yyToken) { CheckToken (1041, yyToken, "Identifier expected"); } /* end end end */ }