Add new test
[mono.git] / mcs / mcs / cs-parser.jay
1 %{
2 //
3 // cs-parser.jay: The Parser for the C# compiler
4 //
5 // Author: Miguel de Icaza (miguel@gnu.org)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11 // TODO:
12 //   (1) Get rid of the *Collections.cs, that is an idea I took from System.CodeDOM
13 //       And come to think of it, it is not that great, it duplicates a lot of code
14 //       for something which is not really needed.  We still have piles of typecasts
15 //       anwyays (due to the nature of the stack being a collection of Objects).
16 //
17 //   (2) Figure out why error productions dont work.  `type-declaration' is a
18 //       great spot to put an `error' because you can reproduce it with this input:
19 //       "public X { }"
20 //
21 //   (3) Move Modifier checking from each object into the parser itself, that will
22 //       get rid of the global "error" symbol that we use now to report errors. 
23 //       We still need to pass a pointer to the tree.ErrorHandler, but that is a 
24 //       separate problem
25 //
26 using System.Text;
27 using System;
28
29 namespace Mono.CSharp
30 {
31         using System.Collections;
32         using Mono.Languages;
33
34         /// <summary>
35         ///    The C# Parser
36         /// </summary>
37         public class CSharpParser : GenericParser {
38                 Namespace     current_namespace;
39                 TypeContainer current_container;
40         
41                 // <summary>
42                 //   Current block is used to add statements as we find
43                 //   them.  
44                 // </summary>
45
46                 Block      current_block;
47
48                 // <summary>
49                 //   Current interface is used by the various declaration
50                 //   productions in the interface declaration to "add"
51                 //   the interfaces as we find them.
52                 // </summary>
53                 Interface  current_interface;
54
55                 // <summary>
56                 //   This is used by the unary_expression code to resolve
57                 //   a name against a parameter.  
58                 // </summary>
59                 Parameters current_local_parameters;
60
61                 // <summary>
62                 //   Using during property parsing to describe the implicit
63                 //   value parameter that is passed to the "set" and "get"accesor
64                 //   methods (properties and indexers).
65                 // </summary>
66                 string     implicit_value_parameter_type;
67                 Parameters indexer_parameters;
68
69                 // <summary>
70                 //   Used to determine if we are parsing the get/set pair
71                 //   of an indexer or a property
72                 // </summmary>
73                 bool  parsing_indexer;
74
75                 //
76                 // An out-of-band stack.
77                 //
78                 Stack oob_stack;
79 %}
80
81 %token EOF
82 %token NONE   /* This token is never returned by our lexer */
83 %token ERROR            // This is used not by the parser, but by the tokenizer.
84                         // do not remove.
85
86 /*
87  *These are the C# keywords
88  */
89 %token ABSTRACT 
90 %token AS
91 %token ADD
92 %token ASSEMBLY
93 %token BASE     
94 %token BOOL     
95 %token BREAK    
96 %token BYTE     
97 %token CASE     
98 %token CATCH    
99 %token CHAR     
100 %token CHECKED  
101 %token CLASS    
102 %token CONST    
103 %token CONTINUE 
104 %token DECIMAL  
105 %token DEFAULT  
106 %token DELEGATE 
107 %token DO       
108 %token DOUBLE   
109 %token ELSE     
110 %token ENUM     
111 %token EVENT    
112 %token EXPLICIT 
113 %token EXTERN   
114 %token FALSE    
115 %token FINALLY  
116 %token FIXED    
117 %token FLOAT    
118 %token FOR      
119 %token FOREACH  
120 %token GOTO     
121 %token IF       
122 %token IMPLICIT 
123 %token IN       
124 %token INT      
125 %token INTERFACE
126 %token INTERNAL 
127 %token IS       
128 %token LOCK     
129 %token LONG     
130 %token NAMESPACE
131 %token NEW      
132 %token NULL     
133 %token OBJECT   
134 %token OPERATOR 
135 %token OUT      
136 %token OVERRIDE 
137 %token PARAMS   
138 %token PRIVATE  
139 %token PROTECTED
140 %token PUBLIC   
141 %token READONLY 
142 %token REF      
143 %token RETURN   
144 %token REMOVE
145 %token SBYTE    
146 %token SEALED   
147 %token SHORT    
148 %token SIZEOF   
149 %token STACKALLOC
150 %token STATIC   
151 %token STRING   
152 %token STRUCT   
153 %token SWITCH   
154 %token THIS     
155 %token THROW    
156 %token TRUE     
157 %token TRY      
158 %token TYPEOF   
159 %token UINT     
160 %token ULONG    
161 %token UNCHECKED
162 %token UNSAFE   
163 %token USHORT   
164 %token USING    
165 %token VIRTUAL  
166 %token VOID     
167 %token VOLATILE
168 %token WHILE    
169
170 /* C# keywords which are not really keywords */
171 %token GET           "get"
172 %token SET           "set"
173
174 /* C# single character operators/punctuation. */
175 %token OPEN_BRACE    "{"
176 %token CLOSE_BRACE   "}"
177 %token OPEN_BRACKET  "["
178 %token CLOSE_BRACKET "]"
179 %token OPEN_PARENS   "("
180 %token CLOSE_PARENS  ")"
181 %token DOT           "."
182 %token COMMA         ","
183 %token COLON         ":"
184 %token SEMICOLON     ";"
185 %token TILDE         "~"
186
187 %token PLUS           "+"
188 %token MINUS          "-"
189 %token BANG           "!"
190 %token ASSIGN         "="
191 %token OP_LT          "<"
192 %token OP_GT          ">"
193 %token BITWISE_AND    "&"
194 %token BITWISE_OR     "|"
195 %token STAR           "*"
196 %token PERCENT        "%"
197 %token DIV            "/"
198 %token CARRET         "^"
199 %token INTERR         "?"
200
201 /* C# multi-character operators. */
202 %token OP_INC                 "++"
203 %token OP_DEC                 "--"
204 %token OP_SHIFT_LEFT          "<<"
205 %token OP_SHIFT_RIGHT         ">>"
206 %token OP_LE                  "<="
207 %token OP_GE                  ">="
208 %token OP_EQ                  "=="
209 %token OP_NE                  "!="
210 %token OP_AND                 "&&"
211 %token OP_OR                  "||"
212 %token OP_MULT_ASSIGN         "*="
213 %token OP_DIV_ASSIGN          "/="
214 %token OP_MOD_ASSIGN          "%="
215 %token OP_ADD_ASSIGN          "+="
216 %token OP_SUB_ASSIGN          "-="
217 %token OP_SHIFT_LEFT_ASSIGN   "<<="
218 %token OP_SHIFT_RIGHT_ASSIGN  ">>="
219 %token OP_AND_ASSIGN          "&="
220 %token OP_XOR_ASSIGN          "^="
221 %token OP_OR_ASSIGN           "|="
222 %token OP_PTR                 "->"
223
224 /* Numbers */
225 %token LITERAL_INTEGER           "int literal"
226 %token LITERAL_FLOAT             "float literal"
227 %token LITERAL_DOUBLE            "double literal"
228 %token LITERAL_DECIMAL           "decimal literal"
229 %token LITERAL_CHARACTER         "character literal"
230 %token LITERAL_STRING            "string literal"
231
232 %token IDENTIFIER
233
234 /* Add precedence rules to solve dangling else s/r conflict */
235 %nonassoc LOWPREC
236 %nonassoc IF
237 %nonassoc ELSE
238 %right ASSIGN
239 %left OP_OR
240 %left OP_AND
241 %left BITWISE_OR
242 %left BITWISE_AND
243 %left OP_SHIFT_LEFT OP_SHIFT_RIGHT
244 %left PLUS MINUS
245 %left STAR DIV PERCENT
246 %right BANG CARRET UMINUS
247 %nonassoc OP_INC OP_DEC
248 %left OPEN_PARENS
249 %left OPEN_BRACKET OPEN_BRACE
250 %left DOT
251 %nonassoc HIGHPREC
252
253 %start compilation_unit
254 /*%start namespace_declaration */
255 %%
256
257 compilation_unit
258         : opt_using_directives opt_namespace_member_declarations opt_attributes opt_EOF
259           {
260                 // Check that using comes only before namespace elements
261           }
262         ;
263
264 opt_EOF
265         : /* empty */
266         | EOF
267         ;
268
269 using_directives
270         : using_directive 
271         | using_directives using_directive
272         ;
273
274 using_directive
275         : using_alias_directive
276         | using_namespace_directive
277         ;
278
279 using_alias_directive
280         : USING IDENTIFIER ASSIGN 
281           namespace_or_type_name SEMICOLON
282           {
283                   current_namespace.UsingAlias ((string) $2, (string) $4, lexer.Location);
284           }
285         ;
286
287 using_namespace_directive
288         : USING namespace_name SEMICOLON 
289           {
290                 current_namespace.Using ((string) $2);
291           }
292         ;
293
294 //  namespace_declarations
295 //      : namespace_declaration
296 //      | namespace_declarations namespace_declaration
297
298 namespace_declaration
299         : NAMESPACE qualified_identifier 
300           {
301                 current_namespace = RootContext.Tree.RecordNamespace (current_namespace, name, (string) $2);
302           } 
303           namespace_body opt_semicolon
304           { 
305                 current_namespace = current_namespace.Parent;
306           }
307         ;
308
309 opt_semicolon
310         : /* empty */
311         | SEMICOLON
312         ;
313
314 opt_comma
315         : /* empty */
316         | COMMA
317         ;
318
319 qualified_identifier
320         : IDENTIFIER
321         | qualified_identifier DOT IDENTIFIER { 
322             $$ = (($1).ToString ()) + "." + ($3.ToString ()); }
323         ;
324
325
326 namespace_name
327         : namespace_or_type_name
328         ;
329
330 namespace_body
331         : OPEN_BRACE
332           opt_using_directives
333           opt_namespace_member_declarations
334           CLOSE_BRACE
335           {
336           }
337         ;
338
339 opt_using_directives
340         : /* empty */
341         | using_directives
342         ;
343
344 opt_namespace_member_declarations
345         : /* empty */
346         | namespace_member_declarations
347         ;
348
349 namespace_member_declarations
350         : namespace_member_declaration
351         | namespace_member_declarations namespace_member_declaration
352         ;
353
354 namespace_member_declaration
355         : type_declaration
356           {
357                 string name = "";
358                 int mod_flags;
359
360                 if ($1 is Class){
361                         Class c = (Class) $1;
362                         mod_flags = c.ModFlags;
363                         name = c.Name;
364                 } else if ($1 is Struct){
365                         Struct s = (Struct) $1;
366                         mod_flags = s.ModFlags;
367                         name = s.Name;
368                 } else
369                         break;
370
371                 if ((mod_flags & (Modifiers.PRIVATE|Modifiers.PROTECTED)) != 0){
372                         Report.Error (
373                                 1527, lexer.Location, 
374                                 "Namespace elements cant be explicitly " +
375                                 "declared private or protected in `" + name + "'");
376                 }
377           }
378         | namespace_declaration
379         ;
380
381 type_declaration
382         : class_declaration             
383         | struct_declaration            
384         | interface_declaration         
385         | enum_declaration              
386         | delegate_declaration
387 //
388 // Enable this when we have handled all errors, because this acts as a generic fallback
389 //
390 //      | error {
391 //              Report.Error (1518, lexer.Location, "Expected class, struct, interface, enum or delegate");
392 //        }
393         ;
394
395 //
396 // Attributes 17.2
397 //
398 opt_attributes
399         : /* empty */ { $$ = null; }
400         | attribute_section opt_attributes
401           {
402                 Attributes attrs = null;
403                 AttributeSection sect = (AttributeSection) $1;
404
405                 if (sect.Target == "assembly"){
406                         RootContext.AddGlobalAttributes (sect, lexer.Location);
407                         sect = null;
408                 }
409
410                 if ($2 != null) {
411                         if (sect != null){
412                                 attrs = (Attributes) $2;
413                                 attrs.AddAttribute (sect);
414                         }
415                 } else {
416                         if (sect != null)
417                                 attrs = new Attributes (sect, lexer.Location);
418                 }
419                 
420                 $$ = attrs;
421           }
422         ;
423
424 attribute_section
425         : OPEN_BRACKET attribute_target_specifier attribute_list CLOSE_BRACKET
426           {
427                 string target = null;
428                 
429                 if ($2 != null)
430                         target = (string) $2;
431                 
432                 $$ = new AttributeSection (target, (ArrayList) $3);
433           }
434         | OPEN_BRACKET attribute_list CLOSE_BRACKET
435           {
436                 $$ = new AttributeSection (null, (ArrayList) $2);
437           }
438         ;
439  
440 attribute_target_specifier
441         : attribute_target COLON
442           {
443                 $$ = $1;
444           }
445         ;
446
447 attribute_target
448         : IDENTIFIER
449           {
450                 CheckAttributeTarget ((string) $1);
451                 $$ = $1;
452           }
453         | EVENT  { $$ = "event"; }        
454         | RETURN { $$ = "return"; }
455         ;
456
457 attribute_list
458         : attribute
459           {
460                 ArrayList attrs = new ArrayList ();
461                 attrs.Add ($1);
462
463                 $$ = attrs;
464                
465           }
466         | attribute_list COMMA attribute
467           {
468                 ArrayList attrs = (ArrayList) $1;
469                 attrs.Add ($3);
470
471                 $$ = attrs;
472           }
473         ;
474
475 attribute
476         : attribute_name
477           {
478                 $$ = lexer.Location;
479           }
480           opt_attribute_arguments
481           {
482                 $$ = new Attribute ((string) $1, (ArrayList) $3, (Location) $2);
483           }
484         ;
485
486 attribute_name
487         : type_name  { /* reserved attribute name or identifier: 17.4 */ }
488         ;
489
490 opt_attribute_arguments
491         : /* empty */   { $$ = null; }
492         | OPEN_PARENS attribute_arguments CLOSE_PARENS
493           {
494                 $$ = $2;
495           }
496         ;
497
498
499 attribute_arguments
500         : positional_argument_list
501           {
502                 ArrayList args = new ArrayList ();
503                 args.Add ($1);
504                 
505                 $$ = args;
506           }
507         | positional_argument_list COMMA named_argument_list
508           {
509                 ArrayList args = new ArrayList ();
510                 args.Add ($1);
511                 args.Add ($3);
512
513                 $$ = args;
514           }
515         | named_argument_list
516           {
517                 ArrayList args = new ArrayList ();
518                 args.Add (null);
519                 args.Add ($1);
520                 
521                 $$ = args;
522           }
523         ;
524
525
526 positional_argument_list
527         : expression
528           {
529                 ArrayList args = new ArrayList ();
530                 args.Add (new Argument ((Expression) $1, Argument.AType.Expression));
531
532                 $$ = args;
533           }
534         | positional_argument_list COMMA expression
535          {
536                 ArrayList args = (ArrayList) $1;
537                 args.Add (new Argument ((Expression) $3, Argument.AType.Expression));
538
539                 $$ = args;
540          }
541         ;
542
543 named_argument_list
544         : named_argument
545           {
546                 ArrayList args = new ArrayList ();
547                 args.Add ($1);
548
549                 $$ = args;
550           }
551         | named_argument_list COMMA named_argument
552           {       
553                 ArrayList args = (ArrayList) $1;
554                 args.Add ($3);
555
556                 $$ = args;
557           }
558         ;
559
560 named_argument
561         : IDENTIFIER ASSIGN expression
562           {
563                 $$ = new DictionaryEntry (
564                         (string) $1, 
565                         new Argument ((Expression) $3, Argument.AType.Expression));
566           }
567         ;
568
569                   
570 class_body
571         :  OPEN_BRACE opt_class_member_declarations CLOSE_BRACE
572         ;
573
574 opt_class_member_declarations
575         : /* empty */
576         | class_member_declarations
577         ;
578
579 class_member_declarations
580         : class_member_declaration
581         | class_member_declarations 
582           class_member_declaration
583         ;
584
585 class_member_declaration
586         : constant_declaration                  // done
587         | field_declaration                     // done
588         | method_declaration                    // done
589         | property_declaration                  // done
590         | event_declaration                     // done
591         | indexer_declaration                   // done
592         | operator_declaration                  // done
593         | constructor_declaration               // done
594         | destructor_declaration                // done
595         | type_declaration
596         ;
597
598 struct_declaration
599         : opt_attributes
600           opt_modifiers
601           STRUCT IDENTIFIER
602           { 
603                 Struct new_struct;
604                 string full_struct_name = MakeName ((string) $4);
605
606                 new_struct = new Struct (current_container, full_struct_name, (int) $2, 
607                                          (Attributes) $1, lexer.Location);
608                 current_container = new_struct;
609                 current_container.Namespace = current_namespace;
610                 RootContext.Tree.RecordStruct (full_struct_name, new_struct);
611           }
612           opt_struct_interfaces
613           struct_body
614           opt_semicolon
615           {
616                 Struct new_struct = (Struct) current_container;
617
618                 current_container = current_container.Parent;
619                 CheckDef (current_container.AddStruct (new_struct), new_struct.Name);
620                 $$ = new_struct;
621           }
622         ;
623
624 opt_struct_interfaces
625         : /* empty */
626         | struct_interfaces
627         ;
628
629 struct_interfaces
630         : struct_interface
631         | struct_interfaces struct_interface
632         ; 
633
634 struct_interface
635         : COLON type_list
636         ;
637
638 struct_body
639         : OPEN_BRACE opt_struct_member_declarations CLOSE_BRACE
640         ;
641
642 opt_struct_member_declarations
643         : /* empty */
644         | struct_member_declarations
645         ;
646
647 struct_member_declarations
648         : struct_member_declaration
649         | struct_member_declarations struct_member_declaration
650         ;
651
652 struct_member_declaration
653         : constant_declaration
654         | field_declaration
655         | method_declaration
656         | property_declaration
657         | event_declaration
658         | indexer_declaration
659         | operator_declaration
660         | constructor_declaration
661         | type_declaration
662
663         /*
664          * This is only included so we can flag error 575: 
665          * destructors only allowed on class types
666          */
667         | destructor_declaration 
668         ;
669
670 constant_declaration
671         : opt_attributes 
672           opt_modifiers
673           CONST
674           type
675           constant_declarators
676           SEMICOLON
677           {
678                 foreach (VariableDeclaration constant in (ArrayList) $5){
679                         Const c = new Const (
680                                 (string) $4, (string) constant.identifier, 
681                                 (Expression) constant.expression_or_array_initializer, (int) $2, (Attributes) $1,
682                                 constant.Location);
683
684                         CheckDef (current_container.AddConstant (c), c.Name);
685                 }
686           }
687         ;
688
689 constant_declarators
690         : constant_declarator 
691           {
692                 ArrayList constants = new ArrayList ();
693                 constants.Add ($1);
694                 $$ = constants;
695           }
696         | constant_declarators COMMA constant_declarator
697           {
698                 ArrayList constants = (ArrayList) $1;
699
700                 constants.Add ($3);
701           }
702         ;
703
704 constant_declarator
705         : IDENTIFIER ASSIGN constant_expression
706           {
707                 $$ = new VariableDeclaration ((string) $1, $3, lexer.Location);
708           }
709         ;
710
711 field_declaration
712         : opt_attributes
713           opt_modifiers
714           type 
715           variable_declarators
716           SEMICOLON
717           { 
718                 string type = (string) $3;
719                 int mod = (int) $2;
720
721                 foreach (VariableDeclaration var in (ArrayList) $4){
722                         Field field = new Field (type, mod, var.identifier, 
723                                                  var.expression_or_array_initializer, (Attributes) $1, var.Location);
724
725                         CheckDef (current_container.AddField (field), field.Name);
726                 }
727           }
728         ;
729
730 variable_declarators
731         : variable_declarator 
732           {
733                 ArrayList decl = new ArrayList ();
734                 decl.Add ($1);
735                 $$ = decl;
736           }
737         | variable_declarators COMMA variable_declarator
738           {
739                 ArrayList decls = (ArrayList) $1;
740                 decls.Add ($3);
741                 $$ = $1;
742           }
743         ;
744
745 variable_declarator
746         : IDENTIFIER ASSIGN variable_initializer
747           {
748                 $$ = new VariableDeclaration ((string) $1, $3, lexer.Location);
749           }
750         | IDENTIFIER
751           {
752                 $$ = new VariableDeclaration ((string) $1, null, lexer.Location);
753           }
754         ;
755
756 variable_initializer
757         : expression
758           {
759                 $$ = $1;
760           }
761         | array_initializer
762           {
763                 $$ = $1;
764           }
765         | STACKALLOC type OPEN_BRACKET expression CLOSE_BRACKET
766           {
767                 $$ = new StackAlloc ((string) $2, (Expression) $4, lexer.Location);
768           }
769         ;
770
771 method_declaration
772         : method_header
773           method_body
774           {
775                 Method method = (Method) $1;
776                 Block b = (Block) $2;
777                 const int extern_abstract = (Modifiers.EXTERN | Modifiers.ABSTRACT);
778
779                 if (b == null){
780                         if ((method.ModFlags & extern_abstract) == 0){
781                                 Report.Error (
782                                         501, lexer.Location,  current_container.MakeName (method.Name) +
783                                         "must declare a body because it is not marked abstract or extern");
784                         }
785                 } else {
786                         if ((method.ModFlags & Modifiers.EXTERN) != 0){
787                                 Report.Error (
788                                         179, lexer.Location, current_container.MakeName (method.Name) +
789                                         " is declared extern, but has a body");
790                         }
791                 }
792
793                 method.Block = (Block) $2;
794                 CheckDef (current_container.AddMethod (method), method.Name);
795
796                 current_local_parameters = null;
797           }
798         ;
799
800 opt_error_modifier
801         : /* empty */
802         | modifiers 
803           {
804                 int m = (int) $1;
805                 int i = 1;
806
807                 while (m != 0){
808                         if ((i & m) != 0){
809                                 Report.Error (
810                                         1585, lexer.Location, "Member modifier `" + 
811                                         Modifiers.Name (i) + "' must precede member type and name");
812                         }
813                         m &= ~i;
814                         i = i << 1;
815                 }
816           }
817         ;
818
819 method_header
820         : opt_attributes
821           opt_modifiers
822           type
823           member_name
824           OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS 
825           {
826                 Method method = new Method ((string) $3, (int) $2, (string) $4, 
827                                             (Parameters) $6, (Attributes) $1, lexer.Location);
828
829                 current_local_parameters = (Parameters) $6;
830
831                 $$ = method;
832           }
833         | opt_attributes
834           opt_modifiers
835           VOID
836           member_name
837           OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS 
838           {
839                 Method method = new Method ("System.Void", (int) $2, (string) $4, 
840                                             (Parameters) $6, (Attributes) $1, lexer.Location);
841
842                 current_local_parameters = (Parameters) $6;
843                 $$ = method;
844           }
845         ;
846
847 method_body
848         : block
849         | SEMICOLON             { $$ = null; }
850         ;
851
852 opt_formal_parameter_list
853         : /* empty */                   { $$ = Parameters.GetEmptyReadOnlyParameters (); }
854         | formal_parameter_list
855         ;
856
857 formal_parameter_list
858         : fixed_parameters              
859           { 
860                 ArrayList pars_list = (ArrayList) $1;
861
862                 Parameter [] pars = new Parameter [pars_list.Count];
863                 pars_list.CopyTo (pars);
864
865                 $$ = new Parameters (pars, null, lexer.Location); 
866           } 
867         | fixed_parameters COMMA parameter_array
868           {
869                 ArrayList pars_list = (ArrayList) $1;
870
871                 Parameter [] pars = new Parameter [pars_list.Count];
872                 pars_list.CopyTo (pars);
873
874                 $$ = new Parameters (pars, (Parameter) $3, lexer.Location); 
875           }
876         | parameter_array 
877           {
878                 $$ = new Parameters (null, (Parameter) $1, lexer.Location);
879           }
880         ;
881
882 fixed_parameters
883         : fixed_parameter       
884           {
885                 ArrayList pars = new ArrayList ();
886
887                 pars.Add ($1);
888                 $$ = pars;
889           }
890         | fixed_parameters COMMA fixed_parameter
891           {
892                 ArrayList pars = (ArrayList) $1;
893
894                 pars.Add ($3);
895                 $$ = $1;
896           }
897         ;
898
899 fixed_parameter
900         : opt_attributes
901           opt_parameter_modifier
902           type
903           IDENTIFIER
904           {
905                 $$ = new Parameter ((string) $3, (string) $4, (Parameter.Modifier) $2, (Attributes) $1);
906           }
907         ;
908
909 opt_parameter_modifier
910         : /* empty */           { $$ = Parameter.Modifier.NONE; }
911         | parameter_modifier
912         ;
913
914 parameter_modifier
915         : REF                   { $$ = Parameter.Modifier.REF; }
916         | OUT                   { $$ = Parameter.Modifier.OUT; }
917         ;
918
919 parameter_array
920         : opt_attributes PARAMS type IDENTIFIER
921           { 
922                 $$ = new Parameter ((string) $3, (string) $4, Parameter.Modifier.PARAMS, (Attributes) $1);
923                 note ("type must be a single-dimension array type"); 
924           }
925         ;
926
927 member_name 
928         : qualified_identifier
929         ;
930
931 property_declaration
932         : opt_attributes
933           opt_modifiers
934           type member_name
935           OPEN_BRACE 
936           {
937                 implicit_value_parameter_type = (string) $3;
938
939                 lexer.PropertyParsing = true;
940
941                 $$ = lexer.Location;
942           }
943           accessor_declarations 
944           {
945                 lexer.PropertyParsing = false;
946           }
947           CLOSE_BRACE
948           { 
949                 Property prop;
950                 Pair pair = (Pair) $7;
951                 Block get_block = null;
952                 Block set_block = null;
953
954                 if (pair.First != null)
955                         get_block = (Block) pair.First;
956                 if (pair.Second != null)
957                         set_block = (Block) pair.Second;
958
959                 prop = new Property ((string) $3, (string) $4, (int) $2, get_block, set_block,
960                                      (Attributes) $1, (Location) $6);
961                 
962                 CheckDef (current_container.AddProperty (prop), prop.Name);
963                 implicit_value_parameter_type = null;
964           }
965         ;
966
967 accessor_declarations
968         : get_accessor_declaration opt_set_accessor_declaration
969           { 
970                 $$ = new Pair ($1, $2);
971           }
972         | set_accessor_declaration opt_get_accessor_declaration
973           {
974                 $$ = new Pair ($2, $1);
975           }
976         ;
977
978 opt_get_accessor_declaration
979         : /* empty */                   { $$ = null; }
980         | get_accessor_declaration
981         ;
982
983 opt_set_accessor_declaration
984         : /* empty */                   { $$ = null; }
985         | set_accessor_declaration
986         ;
987
988 get_accessor_declaration
989         : opt_attributes GET
990           {
991                 // If this is not the case, then current_local_parameters has already
992                 // been set in indexer_declaration
993                 if (parsing_indexer == false)
994                         current_local_parameters = null;
995                 else 
996                         current_local_parameters = indexer_parameters;
997                 lexer.PropertyParsing = false;
998           }
999           accessor_body
1000           {
1001                 $$ = $4;
1002                 current_local_parameters = null;
1003                 lexer.PropertyParsing = true;
1004           }
1005         ;
1006
1007 set_accessor_declaration
1008         : opt_attributes SET 
1009           {
1010                 Parameter [] args;
1011                 Parameter implicit_value_parameter = new Parameter (
1012                         implicit_value_parameter_type, "value", 
1013                         Parameter.Modifier.NONE, null);
1014
1015                 if (parsing_indexer == false) {
1016                         args  = new Parameter [1];
1017                         args [0] = implicit_value_parameter;
1018                 } else {
1019                         Parameter [] fp = indexer_parameters.FixedParameters;
1020                         int count = fp.Length;
1021
1022                         args = new Parameter [count + 1];
1023         
1024                         fp.CopyTo (args, 0);
1025                         args [count] = implicit_value_parameter;
1026                 }
1027                 
1028                 current_local_parameters = new Parameters (args, null, lexer.Location);
1029                 lexer.PropertyParsing = false;
1030           }
1031           accessor_body
1032           {
1033                 $$ = $4;
1034                 current_local_parameters = null;
1035                 lexer.PropertyParsing = true;
1036           }
1037         ;
1038
1039 accessor_body
1040         : block 
1041         | SEMICOLON             { $$ = new Block (null); }
1042         ;
1043
1044 interface_declaration
1045         : opt_attributes
1046           opt_modifiers
1047           INTERFACE IDENTIFIER
1048           {
1049                 Interface new_interface;
1050                 string full_interface_name = MakeName ((string) $4);
1051
1052                 new_interface = new Interface (current_container, full_interface_name, (int) $2, 
1053                                                (Attributes) $1, lexer.Location);
1054                 if (current_interface != null) {
1055                         Location l = lexer.Location;
1056                         Report.Error (-2, l, "Internal compiler error: interface inside interface");
1057                 }
1058                 current_interface = new_interface;
1059                 new_interface.Namespace = current_namespace;
1060                 RootContext.Tree.RecordInterface (full_interface_name, new_interface);
1061           }
1062           opt_interface_base
1063           interface_body
1064           { 
1065                 Interface new_interface = (Interface) current_interface;
1066
1067                 if ($6 != null)
1068                         new_interface.Bases = (ArrayList) $6;
1069
1070                 current_interface = null;
1071                 CheckDef (current_container.AddInterface (new_interface), new_interface.Name);
1072           }
1073         ;
1074
1075 opt_interface_base
1076         : /* empty */                     { $$ = null; }
1077         | interface_base
1078         ;
1079
1080 interface_base
1081         : COLON interface_type_list       { $$ = $2; }
1082         ;
1083
1084 interface_type_list
1085         : interface_type
1086           {
1087                 ArrayList interfaces = new ArrayList ();
1088
1089                 interfaces.Add ($1);
1090                 $$ = interfaces;
1091           }
1092         | interface_type_list COMMA interface_type
1093           {
1094                 ArrayList interfaces = (ArrayList) $1;
1095                 interfaces.Add ($3);
1096                 $$ = interfaces;
1097           }
1098         ;
1099
1100 interface_body
1101         : OPEN_BRACE
1102           opt_interface_member_declarations
1103           CLOSE_BRACE
1104         ;
1105
1106 opt_interface_member_declarations
1107         : /* empty */
1108         | interface_member_declarations
1109         ;
1110
1111 interface_member_declarations
1112         : interface_member_declaration
1113         | interface_member_declarations interface_member_declaration
1114         ;
1115
1116 interface_member_declaration
1117         : interface_method_declaration          
1118           { 
1119                 InterfaceMethod m = (InterfaceMethod) $1;
1120
1121                 CheckDef (current_interface.AddMethod (m), m.Name);
1122           }
1123         | interface_property_declaration        
1124           { 
1125                 InterfaceProperty p = (InterfaceProperty) $1;
1126
1127                 CheckDef (current_interface.AddProperty (p), p.Name);
1128           }
1129         | interface_event_declaration 
1130           { 
1131                 InterfaceEvent e = (InterfaceEvent) $1;
1132
1133                 CheckDef (current_interface.AddEvent (e), e.Name);
1134           }
1135         | interface_indexer_declaration
1136           { 
1137                 InterfaceIndexer i = (InterfaceIndexer) $1;
1138
1139                 CheckDef (current_interface.AddIndexer (i), "indexer");
1140           }
1141         ;
1142
1143 opt_new
1144         : /* empty */   { $$ = false; }
1145         | NEW           { $$ = true; }
1146         ;
1147
1148 interface_method_declaration
1149         : opt_attributes opt_new type IDENTIFIER 
1150           OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
1151           SEMICOLON
1152           {
1153                 $$ = new InterfaceMethod ((string) $3, (string) $4, (bool) $2, 
1154                                           (Parameters) $6, (Attributes) $1, lexer.Location);
1155           }
1156         | opt_attributes opt_new VOID IDENTIFIER 
1157           OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
1158           SEMICOLON
1159           {
1160                 $$ = new InterfaceMethod ("System.Void", (string) $4, (bool) $2, (Parameters) $6, 
1161                                           (Attributes) $1, lexer.Location);
1162           }
1163         ;
1164
1165 interface_property_declaration
1166         : opt_attributes
1167           opt_new
1168           type IDENTIFIER 
1169           OPEN_BRACE 
1170           { lexer.PropertyParsing = true; }
1171           interface_accesors 
1172           { lexer.PropertyParsing = false; }
1173           CLOSE_BRACE
1174           {
1175                 int gs = (int) $7;
1176
1177                 $$ = new InterfaceProperty ((string) $3, (string) $4, (bool) $2, 
1178                                             (gs & 1) == 1, (gs & 2) == 2, (Attributes) $1,
1179                                             lexer.Location);
1180           }
1181         ;
1182
1183 interface_accesors
1184         : opt_attributes GET SEMICOLON          { $$ = 1; }
1185         | opt_attributes SET SEMICOLON          { $$ = 2; }
1186         | opt_attributes GET SEMICOLON opt_attributes SET SEMICOLON 
1187           { $$ = 3; }
1188         | opt_attributes SET SEMICOLON opt_attributes GET SEMICOLON
1189           { $$ = 3; }
1190         ;
1191
1192 interface_event_declaration
1193         : opt_attributes opt_new EVENT type IDENTIFIER SEMICOLON
1194           {
1195                 $$ = new InterfaceEvent ((string) $4, (string) $5, (bool) $2, (Attributes) $1);
1196           }
1197         ;
1198
1199 interface_indexer_declaration 
1200         : opt_attributes opt_new type THIS 
1201           OPEN_BRACKET formal_parameter_list CLOSE_BRACKET
1202           OPEN_BRACE 
1203           { lexer.PropertyParsing = true; }
1204           interface_accesors 
1205           { lexer.PropertyParsing = false; }
1206           CLOSE_BRACE
1207           {
1208                 int a_flags = (int) $10;
1209
1210                 bool do_get = (a_flags & 1) == 1;
1211                 bool do_set = (a_flags & 2) == 2;
1212
1213                 $$ = new InterfaceIndexer ((string) $3, (Parameters) $6, do_get, do_set,
1214                                            (bool) $2, (Attributes) $1, lexer.Location);
1215           }
1216         ;
1217
1218 operator_declaration
1219         : opt_attributes opt_modifiers operator_declarator block
1220           {
1221                 OperatorDeclaration decl = (OperatorDeclaration) $3;
1222                 
1223                 Operator op = new Operator (decl.optype, decl.ret_type, (int) $2, decl.arg1type, decl.arg1name,
1224                                             decl.arg2type, decl.arg2name, (Block) $4, (Attributes) $1, decl.location);
1225
1226                 // Note again, checking is done in semantic analysis
1227                 current_container.AddOperator (op);
1228
1229                 current_local_parameters = null;
1230           }
1231         ;
1232
1233 operator_declarator
1234         : type OPERATOR overloadable_operator 
1235           OPEN_PARENS type IDENTIFIER CLOSE_PARENS
1236         {
1237                 Operator.OpType op = (Operator.OpType) $3;
1238                 CheckUnaryOperator (op);
1239
1240                 if (op == Operator.OpType.Addition)
1241                         op = Operator.OpType.UnaryPlus;
1242
1243                 if (op == Operator.OpType.Subtraction)
1244                         op = Operator.OpType.UnaryNegation;
1245
1246                 Parameter [] pars = new Parameter [1];
1247
1248                 pars [0] = new Parameter ((string) $5, (string) $6, Parameter.Modifier.NONE, null);
1249
1250                 current_local_parameters = new Parameters (pars, null, lexer.Location);
1251
1252                 $$ = new OperatorDeclaration (op, (string) $1, (string) $5, (string) $6,
1253                                               null, null, lexer.Location);
1254         }
1255         | type OPERATOR overloadable_operator
1256           OPEN_PARENS 
1257                 type IDENTIFIER COMMA
1258                 type IDENTIFIER 
1259           CLOSE_PARENS
1260         {
1261                CheckBinaryOperator ((Operator.OpType) $3);
1262
1263                Parameter [] pars = new Parameter [2];
1264
1265                pars [0] = new Parameter ((string) $5, (string) $6, Parameter.Modifier.NONE, null);
1266                pars [1] = new Parameter ((string) $8, (string) $9, Parameter.Modifier.NONE, null);
1267
1268                current_local_parameters = new Parameters (pars, null, lexer.Location);
1269                
1270                $$ = new OperatorDeclaration ((Operator.OpType) $3, (string) $1, (string) $5, (string) $6,
1271                                              (string) $8, (string) $9, lexer.Location);
1272         }
1273         | conversion_operator_declarator
1274         ;
1275
1276 overloadable_operator
1277 // Unary operators:
1278         : BANG   { $$ = Operator.OpType.LogicalNot; }
1279         | TILDE  { $$ = Operator.OpType.OnesComplement; }  
1280         | OP_INC { $$ = Operator.OpType.Increment; }
1281         | OP_DEC { $$ = Operator.OpType.Decrement; }
1282         | TRUE   { $$ = Operator.OpType.True; }
1283         | FALSE  { $$ = Operator.OpType.False; }
1284 // Unary and binary:
1285         | PLUS { $$ = Operator.OpType.Addition; }
1286         | MINUS { $$ = Operator.OpType.Subtraction; }
1287 // Binary:
1288         | STAR { $$ = Operator.OpType.Multiply; }
1289         | DIV {  $$ = Operator.OpType.Division; }
1290         | PERCENT { $$ = Operator.OpType.Modulus; }
1291         | BITWISE_AND { $$ = Operator.OpType.BitwiseAnd; }
1292         | BITWISE_OR { $$ = Operator.OpType.BitwiseOr; }
1293         | CARRET { $$ = Operator.OpType.ExclusiveOr; }
1294         | OP_SHIFT_LEFT { $$ = Operator.OpType.LeftShift; }
1295         | OP_SHIFT_RIGHT { $$ = Operator.OpType.RightShift; }
1296         | OP_EQ { $$ = Operator.OpType.Equality; }
1297         | OP_NE { $$ = Operator.OpType.Inequality; }
1298         | OP_GT { $$ = Operator.OpType.GreaterThan; }
1299         | OP_LT { $$ = Operator.OpType.LessThan; }
1300         | OP_GE { $$ = Operator.OpType.GreaterThanOrEqual; }
1301         | OP_LE { $$ = Operator.OpType.LessThanOrEqual; }
1302         ;
1303
1304 conversion_operator_declarator
1305         : IMPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS
1306           {
1307                 Parameter [] pars = new Parameter [1];
1308
1309                 pars [0] = new Parameter ((string) $5, (string) $6, Parameter.Modifier.NONE, null);
1310
1311                 current_local_parameters = new Parameters (pars, null, lexer.Location);  
1312                   
1313                 $$ = new OperatorDeclaration (Operator.OpType.Implicit, (string) $3, (string) $5, (string) $6,
1314                                               null, null, lexer.Location);
1315           }
1316         | EXPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS
1317           {
1318                 Parameter [] pars = new Parameter [1];
1319
1320                 pars [0] = new Parameter ((string) $5, (string) $6, Parameter.Modifier.NONE, null);
1321
1322                 current_local_parameters = new Parameters (pars, null, lexer.Location);  
1323                   
1324                 $$ = new OperatorDeclaration (Operator.OpType.Explicit, (string) $3, (string) $5, (string) $6,
1325                                               null, null, lexer.Location);
1326           }
1327         | IMPLICIT error 
1328           {
1329                 syntax_error (lexer.Location, "'operator' expected");
1330           }
1331         | EXPLICIT error 
1332           {
1333                 syntax_error (lexer.Location, "'operator' expected");
1334           }
1335         ;
1336
1337 constructor_declaration
1338         : opt_attributes
1339           opt_modifiers
1340           constructor_declarator
1341           block
1342           { 
1343                 Constructor c = (Constructor) $3;
1344                 c.Block = (Block) $4;
1345                 c.ModFlags = (int) $2;
1346                 c.OptAttributes = (Attributes) $1;
1347
1348                 if ((c.ModFlags & Modifiers.STATIC) != 0){
1349                         if ((c.ModFlags & Modifiers.Accessibility) != 0) {
1350                                 Location l = lexer.Location;
1351                                 Report.Error (515, l, "Access modifiers are not allowed on static constructors");
1352                         }
1353
1354                         if (c.Initializer != null){
1355                                 Location l = lexer.Location;
1356                                 Report.Error (514, l, "Static constructors can not have an explicit this or base constructor invocations");
1357                         }
1358
1359                         if (!c.Parameters.Empty){
1360                                 Location l = lexer.Location;
1361                                 Report.Error (132, l, "Static constructors should not have parameters");
1362                         }
1363                 } 
1364                 
1365                 CheckDef (current_container.AddConstructor (c), c.Name);
1366
1367                 current_local_parameters = null;
1368           }
1369         ;
1370
1371 constructor_declarator
1372         : IDENTIFIER 
1373           OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS 
1374           {
1375                 oob_stack.Push (lexer.Location);
1376
1377                 current_local_parameters = (Parameters) $3;
1378           }
1379           opt_constructor_initializer
1380           {
1381                 Location l = (Location) oob_stack.Pop ();
1382                 $$ = new Constructor ((string) $1, (Parameters) $3, (ConstructorInitializer) $6, l);
1383           }
1384         ;
1385
1386 opt_constructor_initializer
1387         : /* empty */                   { $$ = null; }
1388         | constructor_initializer
1389         ;
1390
1391 constructor_initializer
1392         : COLON BASE OPEN_PARENS opt_argument_list CLOSE_PARENS
1393           {
1394                 $$ = new ConstructorBaseInitializer ((ArrayList) $4, lexer.Location);
1395           }
1396         | COLON THIS OPEN_PARENS opt_argument_list CLOSE_PARENS
1397           {
1398                 $$ = new ConstructorThisInitializer ((ArrayList) $4, lexer.Location);
1399           }
1400         ;
1401
1402 destructor_declaration
1403         : opt_attributes TILDE IDENTIFIER OPEN_PARENS CLOSE_PARENS block
1404           {
1405                 if ((string) $3 != current_container.Basename){
1406                         Report.Error (574, lexer.Location, "Name of destructor must match name of class");
1407                 } else if (!(current_container is Class)){
1408                         Report.Error (575, lexer.Location, "Destructors are only allowed in class types");
1409                 } else {
1410                         Location l = lexer.Location;
1411
1412                         Method d = new Method (
1413                                 "System.Void", 0, "Finalize", 
1414                                 new Parameters (null, null, l), (Attributes) $1, l);
1415                   
1416                         d.Block = (Block) $6;
1417                         CheckDef (current_container.AddMethod (d), d.Name);
1418                 }
1419           }
1420         ;
1421
1422 event_declaration
1423         : opt_attributes
1424           opt_modifiers
1425           EVENT type variable_declarators SEMICOLON
1426           {
1427                 foreach (VariableDeclaration var in (ArrayList) $5) {
1428
1429                         Event e = new Event ((string) $4, var.identifier, var.expression_or_array_initializer,
1430                                              (int) $2, null, null, (Attributes) $1, lexer.Location);
1431
1432                         CheckDef (current_container.AddEvent (e), e.Name);
1433                                        
1434                 }
1435           }
1436         | opt_attributes
1437           opt_modifiers
1438           EVENT type member_name
1439           OPEN_BRACE
1440           {
1441                 implicit_value_parameter_type = (string) $4;  
1442                 lexer.EventParsing = true;
1443           }
1444           event_accessor_declarations
1445           {
1446                 lexer.EventParsing = false;  
1447           }
1448           CLOSE_BRACE
1449           {
1450                 Pair pair = (Pair) $8;
1451                 Block add_block = null;
1452                 Block rem_block = null;
1453
1454                 if (pair.First != null)
1455                         add_block = (Block) pair.First;
1456                 if (pair.Second != null)
1457                         rem_block = (Block) pair.Second;
1458                 
1459                 Event e = new Event ((string) $4, (string) $5, null, (int) $2, add_block, rem_block,
1460                                      (Attributes) $1, lexer.Location);
1461                 
1462                 CheckDef (current_container.AddEvent (e), e.Name);
1463                 implicit_value_parameter_type = null;
1464           }
1465         ;
1466
1467 event_accessor_declarations
1468         : add_accessor_declaration remove_accessor_declaration
1469         {
1470                 $$ = new Pair ($1, $2);
1471         }
1472         | remove_accessor_declaration add_accessor_declaration
1473         {
1474                 $$ = new Pair ($2, $1);
1475         }       
1476         ;
1477
1478 add_accessor_declaration
1479         : opt_attributes ADD
1480           {
1481                 Parameter [] args = new Parameter [1];
1482                 Parameter implicit_value_parameter = new Parameter (
1483                         implicit_value_parameter_type, "value", 
1484                         Parameter.Modifier.NONE, null);
1485
1486                 args [0] = implicit_value_parameter;
1487                 
1488                 current_local_parameters = new Parameters (args, null, lexer.Location);  
1489                 lexer.EventParsing = false;
1490           }
1491           block
1492           {
1493                 $$ = $4;
1494                 lexer.EventParsing = true;
1495           }
1496         ;
1497
1498 remove_accessor_declaration
1499         : opt_attributes REMOVE
1500           {
1501                 Parameter [] args = new Parameter [1];
1502                 Parameter implicit_value_parameter = new Parameter (
1503                         implicit_value_parameter_type, "value", 
1504                         Parameter.Modifier.NONE, null);
1505
1506                 args [0] = implicit_value_parameter;
1507                 
1508                 current_local_parameters = new Parameters (args, null, lexer.Location);  
1509                 lexer.EventParsing = false;
1510           }
1511           block
1512           {
1513                 $$ = $4;
1514                 lexer.EventParsing = true;
1515           }
1516         ;
1517
1518 indexer_declaration
1519         : opt_attributes opt_modifiers indexer_declarator 
1520           OPEN_BRACE 
1521           {
1522                 IndexerDeclaration decl = (IndexerDeclaration) $3;
1523
1524                 implicit_value_parameter_type = decl.type;
1525                 
1526                 lexer.PropertyParsing = true;
1527                 parsing_indexer  = true;
1528                 
1529                 indexer_parameters = decl.param_list;
1530                 $$ = lexer.Location;
1531           }
1532           accessor_declarations 
1533           {
1534                   lexer.PropertyParsing = false;
1535                   parsing_indexer  = false;
1536           }
1537           CLOSE_BRACE
1538           { 
1539                 // The signature is computed from the signature of the indexer.  Look
1540                 // at section 3.6 on the spec
1541
1542                 Indexer indexer;
1543                 IndexerDeclaration decl = (IndexerDeclaration) $3;
1544                 Pair pair = (Pair) $6;
1545                 Block get_block = null;
1546                 Block set_block = null;
1547
1548                 if (pair.First != null)
1549                         get_block = (Block) pair.First;
1550                 if (pair.Second != null)
1551                         set_block = (Block) pair.Second;
1552
1553                 indexer = new Indexer (decl.type, decl.interface_type, (int) $2, decl.param_list,
1554                                        get_block, set_block, (Attributes) $1, (Location) $5);
1555
1556                 // Note that there is no equivalent of CheckDef for this case
1557                 // We shall handle this in semantic analysis
1558                 
1559                 current_container.AddIndexer (indexer);
1560                 
1561                 current_local_parameters = null;
1562                 implicit_value_parameter_type = null;
1563                 indexer_parameters = null;
1564           }
1565         ;
1566
1567 indexer_declarator
1568         : type THIS OPEN_BRACKET opt_formal_parameter_list CLOSE_BRACKET
1569           {
1570                 Parameters pars = (Parameters) $4;
1571
1572                 if (pars.FixedParameters == null){
1573                         Report.Error (1551, lexer.Location, "Indexers must have at least one parameter");
1574                 }
1575
1576                 $$ = new IndexerDeclaration ((string) $1, null, pars);
1577           }
1578         | type qualified_identifier DOT THIS OPEN_BRACKET opt_formal_parameter_list CLOSE_BRACKET
1579           {
1580                 Parameters pars = (Parameters) $6;
1581
1582                 if (pars.FixedParameters == null){
1583                         Report.Error (1551, lexer.Location, "Indexers must have at least one parameter");
1584                 }
1585                 $$ = new IndexerDeclaration ((string) $1, (string) $2, pars);
1586           }
1587         ;
1588
1589 enum_declaration
1590         : opt_attributes
1591           opt_modifiers
1592           ENUM IDENTIFIER
1593           opt_enum_base
1594           enum_body
1595           opt_semicolon
1596           { 
1597                 string full_name = MakeName ((string) $4);
1598                 Enum e = new Enum (current_container, (string) $5, (int) $2, full_name, (Attributes) $1, lexer.Location);
1599
1600                 foreach (VariableDeclaration ev in (ArrayList) $6){
1601                         CheckDef (e.AddEnumMember (ev.identifier, 
1602                                                    (Expression) ev.expression_or_array_initializer,
1603                                                    (Location) ev.Location),
1604                                   ev.identifier);
1605                 }
1606
1607                 CheckDef (current_container.AddEnum (e), name);
1608           }
1609         ;
1610
1611 opt_enum_base
1612         : /* empty */           { $$ = "System.Int32"; }
1613         | COLON type            { $$ = $2;   }
1614         ;
1615
1616 enum_body
1617         : OPEN_BRACE opt_enum_member_declarations CLOSE_BRACE
1618           {
1619                 $$ = $2;
1620           }
1621         ;
1622
1623 opt_enum_member_declarations
1624         : /* empty */                   { $$ = new ArrayList (); }
1625         | enum_member_declarations opt_comma { $$ = $1; }
1626         ;
1627
1628 enum_member_declarations
1629         : enum_member_declaration 
1630           {
1631                 ArrayList l = new ArrayList ();
1632
1633                 l.Add ($1);
1634                 $$ = l;
1635           }
1636         | enum_member_declarations COMMA enum_member_declaration
1637           {
1638                 ArrayList l = (ArrayList) $1;
1639
1640                 l.Add ($3);
1641
1642                 $$ = l;
1643           }
1644         ;
1645
1646 enum_member_declaration
1647         : opt_attributes IDENTIFIER 
1648           {
1649                 $$ = new VariableDeclaration ((string) $2, null, lexer.Location);
1650           }
1651         | opt_attributes IDENTIFIER
1652           {
1653                   $$ = lexer.Location;
1654           }
1655           ASSIGN expression
1656           { 
1657                 $$ = new VariableDeclaration ((string) $2, $5, lexer.Location);
1658           }
1659         ;
1660
1661 delegate_declaration
1662         : opt_attributes
1663           opt_modifiers
1664           DELEGATE type   
1665           IDENTIFIER OPEN_PARENS 
1666           opt_formal_parameter_list
1667           CLOSE_PARENS 
1668           SEMICOLON
1669           {
1670                 Delegate del = new Delegate ((string) $4, (int) $2, 
1671                                              MakeName ((string) $5), (Parameters) $7, 
1672                                              (Attributes) $1, lexer.Location);
1673                   
1674                 CheckDef (current_container.AddDelegate (del), del.Name);
1675           }     
1676         | opt_attributes
1677           opt_modifiers
1678           DELEGATE VOID   
1679           IDENTIFIER OPEN_PARENS 
1680           opt_formal_parameter_list
1681           CLOSE_PARENS 
1682           SEMICOLON
1683           {
1684                 Delegate del = new Delegate ("System.Void", (int) $2, (string) $5, (Parameters) $7, 
1685                                              (Attributes) $1, lexer.Location);
1686
1687                 CheckDef (current_container.AddDelegate (del), del.Name);
1688           }
1689         ;
1690
1691 type_name
1692         : namespace_or_type_name
1693         ;
1694
1695 namespace_or_type_name
1696         : qualified_identifier
1697         ;
1698
1699 /* 
1700  * Before you think of adding a return_type, notice that we have been
1701  * using two rules in the places where it matters (one rule using type
1702  * and another identical one that uses VOID as the return type).  This
1703  * gets rid of a shift/reduce couple
1704  */
1705 type
1706         : type_name {   /* class_type */
1707                 /* 
1708                    This does interfaces, delegates, struct_types, class_types, 
1709                    parent classes, and more! 4.2 
1710                  */
1711                 $$ = $1; 
1712           }
1713         | builtin_types
1714         | array_type
1715         | pointer_type    
1716         ;
1717
1718
1719 pointer_type
1720         : type STAR
1721           {
1722                 //
1723                 // Note that here only unmanaged types are allowed but we
1724                 // can't perform checks during this phase - we do it during
1725                 // semantic analysis.
1726                 //
1727                 $$ = (string) $1 + "*";
1728           }
1729         | VOID STAR
1730           {
1731                 $$ = "System.Void*";
1732           }
1733         ;
1734
1735 non_expression_type
1736         : builtin_types 
1737           {
1738                 $$ = new SimpleName ((string) $1, lexer.Location);
1739           }
1740         | non_expression_type rank_specifier
1741           {
1742                 $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
1743           }
1744         | non_expression_type STAR
1745           {
1746                 $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);
1747           }
1748         | expression rank_specifiers 
1749           {
1750                 $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
1751           }
1752         | expression STAR 
1753           {
1754                 $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);
1755           }
1756         ;
1757
1758 type_list
1759         : type
1760           {
1761                 ArrayList types = new ArrayList ();
1762
1763                 types.Add ($1);
1764                 $$ = types;
1765           }
1766         | type_list COMMA type
1767           {
1768                 ArrayList types = (ArrayList) $1;
1769
1770                 types.Add ($3);
1771                 $$ = types;
1772           }
1773         ;
1774
1775 /*
1776  * replaces all the productions for isolating the various
1777  * simple types, but we need this to reuse it easily in local_variable_type
1778  */
1779 builtin_types
1780         : OBJECT        { $$ = "System.Object"; }
1781         | STRING        { $$ = "System.String"; }
1782         | BOOL          { $$ = "System.Boolean"; }
1783         | DECIMAL       { $$ = "System.Decimal"; }
1784         | FLOAT         { $$ = "System.Single"; }
1785         | DOUBLE        { $$ = "System.Double"; }
1786         | integral_type
1787         ;
1788
1789 integral_type
1790         : SBYTE         { $$ = "System.SByte"; }
1791         | BYTE          { $$ = "System.Byte"; }
1792         | SHORT         { $$ = "System.Int16"; }
1793         | USHORT        { $$ = "System.UInt16"; }
1794         | INT           { $$ = "System.Int32"; }
1795         | UINT          { $$ = "System.UInt32"; }
1796         | LONG          { $$ = "System.Int64"; }
1797         | ULONG         { $$ = "System.UInt64"; }
1798         | CHAR          { $$ = "System.Char"; }
1799         ;
1800
1801 interface_type
1802         : type_name
1803         ;
1804
1805 array_type
1806         : type rank_specifiers
1807           {
1808                   $$ = (string) $1 + (string) $2;
1809           }
1810         ;
1811
1812 //
1813 // Expressions, section 7.5
1814 //
1815 primary_expression
1816         : literal
1817           {
1818                 // 7.5.1: Literals
1819           }
1820  
1821         | qualified_identifier
1822           {
1823                 string name = (string) $1;
1824
1825                 $$ = null;
1826                 $$ = DecomposeQI (name, lexer.Location);
1827           }
1828         | parenthesized_expression
1829         | member_access
1830         | invocation_expression
1831         | element_access
1832         | this_access
1833         | base_access
1834         | post_increment_expression
1835         | post_decrement_expression
1836         | new_expression
1837         | typeof_expression
1838         | sizeof_expression
1839         | checked_expression
1840         | unchecked_expression
1841         | pointer_member_access
1842         // TODO: pointer_element_access
1843         // TODO: sizeof-expression
1844         ;
1845
1846 literal
1847         : boolean_literal
1848         | integer_literal
1849         | real_literal
1850         | LITERAL_CHARACTER     { $$ = new CharLiteral ((char) lexer.Value); }
1851         | LITERAL_STRING        { $$ = new StringLiteral ((string) lexer.Value); }
1852         | NULL                  { $$ = NullLiteral.Null; }
1853         ;
1854
1855 real_literal
1856         : LITERAL_FLOAT         { $$ = new FloatLiteral ((float) lexer.Value); }
1857         | LITERAL_DOUBLE        { $$ = new DoubleLiteral ((double) lexer.Value); }
1858         | LITERAL_DECIMAL       { $$ = new DecimalLiteral ((decimal) lexer.Value); }
1859         ;
1860
1861 integer_literal
1862         : LITERAL_INTEGER       { 
1863                 object v = lexer.Value;
1864
1865                 // 
1866                 // FIXME: Possible optimization would be to 
1867                 // compute the *Literal objects directly in the scanner
1868                 //
1869                 if (v is int)
1870                         $$ = new IntLiteral ((Int32) v); 
1871                 else if (v is uint)
1872                         $$ = new UIntLiteral ((UInt32) v);
1873                 else if (v is long)
1874                         $$ = new LongLiteral ((Int64) v);
1875                 else if (v is ulong)
1876                         $$ = new ULongLiteral ((UInt64) v);
1877                 else
1878                         Console.WriteLine ("OOPS.  Unexpected result from scanner");
1879           }
1880         ;
1881
1882 boolean_literal
1883         : TRUE                  { $$ = new BoolLiteral (true); }
1884         | FALSE                 { $$ = new BoolLiteral (false); }
1885         ;
1886
1887 parenthesized_expression
1888         : OPEN_PARENS expression CLOSE_PARENS
1889           { $$ = $2; }
1890         ;
1891
1892 member_access
1893         : primary_expression DOT IDENTIFIER
1894           {
1895                 $$ = new MemberAccess ((Expression) $1, (string) $3, lexer.Location);
1896           }
1897         | predefined_type DOT IDENTIFIER
1898           {
1899                 $$ = new SimpleName ((string) $1 + "." + (string) $3, lexer.Location);
1900           }
1901         ;
1902
1903 predefined_type
1904         : builtin_types
1905         ;
1906
1907 invocation_expression
1908         : primary_expression OPEN_PARENS opt_argument_list CLOSE_PARENS
1909           {
1910                 if ($1 == null) {
1911                         Location l = lexer.Location;
1912                         Report.Error (1, l, "THIS IS CRAZY");
1913                 }
1914                 $$ = new Invocation ((Expression) $1, (ArrayList) $3, lexer.Location);
1915           }
1916         ; 
1917
1918 opt_argument_list
1919         : /* empty */           { $$ = null; }
1920         | argument_list
1921         ;
1922
1923 argument_list
1924         : argument              
1925           { 
1926                 ArrayList list = new ArrayList ();
1927                 list.Add ($1);
1928                 $$ = list;
1929           }
1930         | argument_list COMMA argument
1931           {
1932                 ArrayList list = (ArrayList) $1;
1933                 list.Add ($3);
1934                 $$ = list;
1935           }
1936         ;
1937
1938 argument
1939         : expression
1940           {
1941                 $$ = new Argument ((Expression) $1, Argument.AType.Expression);
1942           }
1943         | REF variable_reference 
1944           { 
1945                 $$ = new Argument ((Expression) $2, Argument.AType.Ref);
1946           }
1947         | OUT variable_reference 
1948           { 
1949                 $$ = new Argument ((Expression) $2, Argument.AType.Out);
1950           }
1951         ;
1952
1953 variable_reference
1954         : expression { note ("section 5.4"); $$ = $1; }
1955         ;
1956
1957 element_access
1958         : primary_expression OPEN_BRACKET expression_list CLOSE_BRACKET 
1959           {
1960                 $$ = new ElementAccess ((Expression) $1, (ArrayList) $3, lexer.Location);
1961           }
1962         | primary_expression rank_specifiers
1963           {
1964                 // So the super-trick is that primary_expression
1965                 // can only be either a SimpleName or a MemberAccess. 
1966                 // The MemberAccess case arises when you have a fully qualified type-name like :
1967                 // Foo.Bar.Blah i;
1968                 // SimpleName is when you have
1969                 // Blah i;
1970                   
1971                 Expression expr = (Expression) $1;  
1972                 if (!(expr is SimpleName || expr is MemberAccess)) {
1973                         Location l = lexer.Location;
1974                         Report.Error (-1, l, "Invalid Type definition");
1975                         $$ = "System.Object";
1976                 }
1977                 
1978                 //
1979                 // So we extract the string corresponding to the SimpleName
1980                 // or MemberAccess
1981                 // 
1982                 $$ = new SimpleName (GetQualifiedIdentifier (expr) + (string) $2, lexer.Location);
1983           }
1984         ;
1985
1986 expression_list
1987         : expression
1988           {
1989                 ArrayList list = new ArrayList ();
1990                 list.Add ($1);
1991                 $$ = list;
1992           }
1993         | expression_list COMMA expression
1994           {
1995                 ArrayList list = (ArrayList) $1;
1996                 list.Add ($3);
1997                 $$ = list;
1998           }
1999         ;
2000
2001 this_access
2002         : THIS
2003           {
2004                 $$ = new This (lexer.Location);
2005           }
2006         ;
2007
2008 base_access
2009         : BASE DOT IDENTIFIER
2010           {
2011                 $$ = new BaseAccess ((string) $3, lexer.Location);
2012           }
2013         | BASE OPEN_BRACKET expression_list CLOSE_BRACKET
2014           {
2015                 $$ = new BaseIndexerAccess ((ArrayList) $3, lexer.Location);
2016           }
2017         ;
2018
2019 post_increment_expression
2020         : primary_expression OP_INC
2021           {
2022                 $$ = new UnaryMutator (UnaryMutator.Mode.PostIncrement,
2023                                        (Expression) $1, lexer.Location);
2024           }
2025         ;
2026
2027 post_decrement_expression
2028         : primary_expression OP_DEC
2029           {
2030                 $$ = new UnaryMutator (UnaryMutator.Mode.PostDecrement,
2031                                        (Expression) $1, lexer.Location);
2032           }
2033         ;
2034
2035 new_expression
2036         : object_or_delegate_creation_expression
2037         | array_creation_expression
2038         ;
2039
2040 object_or_delegate_creation_expression
2041         : NEW type OPEN_PARENS opt_argument_list CLOSE_PARENS
2042           {
2043                 $$ = new New ((string) $2, (ArrayList) $4, lexer.Location);
2044           }
2045         ;
2046
2047 array_creation_expression
2048         : NEW type OPEN_BRACKET expression_list CLOSE_BRACKET 
2049           opt_rank_specifier
2050           opt_array_initializer
2051           {
2052                 $$ = new ArrayCreation ((string) $2, (ArrayList) $4, (string) $6, (ArrayList) $7, 
2053                                         lexer.Location);
2054           }
2055         | NEW type rank_specifiers array_initializer
2056           {
2057                 $$ = new ArrayCreation ((string) $2, (string) $3, (ArrayList) $4, lexer.Location);
2058           }
2059         | NEW type error 
2060           {
2061                 Report.Error (1526, lexer.Location, "new expression requires () or [] after type");
2062           }
2063         ;
2064
2065 opt_rank_specifier
2066         : /* empty */
2067           {
2068                   $$ = "";
2069           }
2070         | rank_specifiers
2071           {
2072                         $$ = $1;
2073           }
2074         ;
2075
2076 rank_specifiers
2077         : rank_specifier
2078           {
2079                   $$ = $1;
2080           }
2081         | rank_specifiers rank_specifier
2082           {
2083                   $$ = (string) $2 + (string) $1;
2084           }             
2085         ;
2086
2087 rank_specifier
2088         : OPEN_BRACKET opt_dim_separators CLOSE_BRACKET
2089           {
2090                 $$ = "[" + (string) $2 + "]";
2091           }
2092         ;
2093
2094 opt_dim_separators
2095         : /* empty */
2096           {
2097                 $$ = "";
2098           }
2099         | dim_separators
2100           {
2101                   $$ = $1;
2102           }               
2103         ;
2104
2105 dim_separators
2106         : COMMA
2107           {
2108                 $$ = ",";
2109           }
2110         | dim_separators COMMA
2111           {
2112                 $$ = (string) $1 + ",";
2113           }
2114         ;
2115
2116 opt_array_initializer
2117         : /* empty */
2118           {
2119                 $$ = null;
2120           }
2121         | array_initializer
2122           {
2123                 $$ = $1;
2124           }
2125         ;
2126
2127 array_initializer
2128         : OPEN_BRACE CLOSE_BRACE
2129           {
2130                 ArrayList list = new ArrayList ();
2131                 $$ = list;
2132           }
2133         | OPEN_BRACE variable_initializer_list opt_comma CLOSE_BRACE
2134           {
2135                 $$ = (ArrayList) $2;
2136           }
2137         ;
2138
2139 variable_initializer_list
2140         : variable_initializer
2141           {
2142                 ArrayList list = new ArrayList ();
2143                 list.Add ($1);
2144                 $$ = list;
2145           }
2146         | variable_initializer_list COMMA variable_initializer
2147           {
2148                 ArrayList list = (ArrayList) $1;
2149                 list.Add ($3);
2150                 $$ = list;
2151           }
2152         ;
2153
2154 typeof_expression
2155         : TYPEOF OPEN_PARENS type CLOSE_PARENS
2156           {
2157                 $$ = new TypeOf ((string) $3, lexer.Location);
2158           }
2159         ;
2160
2161 sizeof_expression
2162         : SIZEOF OPEN_PARENS type CLOSE_PARENS { 
2163                 $$ = new SizeOf ((string) $3, lexer.Location);
2164
2165                 note ("Verify type is unmanaged"); 
2166                 note ("if (5.8) builtin, yield constant expression");
2167           }
2168         ;
2169
2170 checked_expression
2171         : CHECKED OPEN_PARENS expression CLOSE_PARENS
2172           {
2173                 $$ = new CheckedExpr ((Expression) $3);
2174           }
2175         ;
2176
2177 unchecked_expression
2178         : UNCHECKED OPEN_PARENS expression CLOSE_PARENS
2179           {
2180                 $$ = new UnCheckedExpr ((Expression) $3);
2181           }
2182         ;
2183
2184 pointer_member_access 
2185         : primary_expression OP_PTR IDENTIFIER
2186           {
2187                 Expression deref;
2188
2189                 deref = new Unary (Unary.Operator.Indirection, (Expression) $1, lexer.Location);
2190                 $$ = new MemberAccess (deref, (string) $3, lexer.Location);
2191           }
2192
2193 unary_expression
2194         : primary_expression
2195         | BANG prefixed_unary_expression
2196           {
2197                 $$ = new Unary (Unary.Operator.LogicalNot, (Expression) $2, lexer.Location);
2198           }
2199         | TILDE prefixed_unary_expression
2200           {
2201                 $$ = new Unary (Unary.Operator.OnesComplement, (Expression) $2, lexer.Location);
2202           }
2203         | OPEN_PARENS expression CLOSE_PARENS unary_expression
2204           {
2205                   $$ = new Cast ((Expression) $2, (Expression) $4, lexer.Location);
2206           }
2207         | OPEN_PARENS non_expression_type CLOSE_PARENS prefixed_unary_expression
2208           {
2209                   $$ = new Cast ((Expression) $2, (Expression) $4, lexer.Location);
2210           }
2211         ;
2212
2213         //
2214         // The idea to split this out is from Rhys' grammar
2215         // to solve the problem with casts.
2216         //
2217 prefixed_unary_expression
2218         : unary_expression
2219         | PLUS prefixed_unary_expression
2220           { 
2221                 $$ = new Unary (Unary.Operator.UnaryPlus, (Expression) $2, lexer.Location);
2222           } 
2223         | MINUS prefixed_unary_expression 
2224           { 
2225                 $$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, lexer.Location);
2226           }
2227         | OP_INC prefixed_unary_expression 
2228           {
2229                 $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement,
2230                                        (Expression) $2, lexer.Location);
2231           }
2232         | OP_DEC prefixed_unary_expression 
2233           {
2234                 $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement,
2235                                        (Expression) $2, lexer.Location);
2236           }
2237         | STAR prefixed_unary_expression
2238           {
2239                 $$ = new Unary (Unary.Operator.Indirection, (Expression) $2, lexer.Location);
2240           }
2241         | BITWISE_AND prefixed_unary_expression
2242           {
2243                 $$ = new Unary (Unary.Operator.AddressOf, (Expression) $2, lexer.Location);
2244           }
2245         ;
2246
2247 pre_increment_expression
2248         : OP_INC prefixed_unary_expression 
2249           {
2250                 $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement,
2251                                        (Expression) $2, lexer.Location);
2252           }
2253         ;
2254
2255 pre_decrement_expression
2256         : OP_DEC prefixed_unary_expression 
2257           {
2258                 $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement,
2259                                        (Expression) $2, lexer.Location);
2260           }
2261         ;
2262
2263 multiplicative_expression
2264         : prefixed_unary_expression
2265         | multiplicative_expression STAR prefixed_unary_expression
2266           {
2267                 $$ = new Binary (Binary.Operator.Multiply, 
2268                                  (Expression) $1, (Expression) $3, lexer.Location);
2269           }
2270         | multiplicative_expression DIV prefixed_unary_expression
2271           {
2272                 $$ = new Binary (Binary.Operator.Division, 
2273                                  (Expression) $1, (Expression) $3, lexer.Location);
2274           }
2275         | multiplicative_expression PERCENT prefixed_unary_expression 
2276           {
2277                 $$ = new Binary (Binary.Operator.Modulus, 
2278                                  (Expression) $1, (Expression) $3, lexer.Location);
2279           }
2280         ;
2281
2282 additive_expression
2283         : multiplicative_expression
2284         | additive_expression PLUS multiplicative_expression 
2285           {
2286                 $$ = new Binary (Binary.Operator.Addition, 
2287                                  (Expression) $1, (Expression) $3, lexer.Location);
2288           }
2289         | additive_expression MINUS multiplicative_expression
2290           {
2291                 $$ = new Binary (Binary.Operator.Subtraction, 
2292                                  (Expression) $1, (Expression) $3, lexer.Location);
2293           }
2294         ;
2295
2296 shift_expression
2297         : additive_expression
2298         | shift_expression OP_SHIFT_LEFT additive_expression
2299           {
2300                 $$ = new Binary (Binary.Operator.LeftShift, 
2301                                  (Expression) $1, (Expression) $3, lexer.Location);
2302           }
2303         | shift_expression OP_SHIFT_RIGHT additive_expression
2304           {
2305                 $$ = new Binary (Binary.Operator.RightShift, 
2306                                  (Expression) $1, (Expression) $3, lexer.Location);
2307           }
2308         ; 
2309
2310 relational_expression
2311         : shift_expression
2312         | relational_expression OP_LT shift_expression
2313           {
2314                 $$ = new Binary (Binary.Operator.LessThan, 
2315                                  (Expression) $1, (Expression) $3, lexer.Location);
2316           }
2317         | relational_expression OP_GT shift_expression
2318           {
2319                 $$ = new Binary (Binary.Operator.GreaterThan, 
2320                                  (Expression) $1, (Expression) $3, lexer.Location);
2321           }
2322         | relational_expression OP_LE shift_expression
2323           {
2324                 $$ = new Binary (Binary.Operator.LessThanOrEqual, 
2325                                  (Expression) $1, (Expression) $3, lexer.Location);
2326           }
2327         | relational_expression OP_GE shift_expression
2328           {
2329                 $$ = new Binary (Binary.Operator.GreaterThanOrEqual, 
2330                                  (Expression) $1, (Expression) $3, lexer.Location);
2331           }
2332         | relational_expression IS type
2333           {
2334                 $$ = new Is ((Expression) $1, (string) $3, lexer.Location);
2335           }
2336         | relational_expression AS type
2337           {
2338                 $$ = new As ((Expression) $1, (string) $3, lexer.Location);
2339           }
2340         ;
2341
2342 equality_expression
2343         : relational_expression
2344         | equality_expression OP_EQ relational_expression
2345           {
2346                 $$ = new Binary (Binary.Operator.Equality, 
2347                                  (Expression) $1, (Expression) $3, lexer.Location);
2348           }
2349         | equality_expression OP_NE relational_expression
2350           {
2351                 $$ = new Binary (Binary.Operator.Inequality, 
2352                                  (Expression) $1, (Expression) $3, lexer.Location);
2353           }
2354         ; 
2355
2356 and_expression
2357         : equality_expression
2358         | and_expression BITWISE_AND equality_expression
2359           {
2360                 $$ = new Binary (Binary.Operator.BitwiseAnd, 
2361                                  (Expression) $1, (Expression) $3, lexer.Location);
2362           }
2363         ;
2364
2365 exclusive_or_expression
2366         : and_expression
2367         | exclusive_or_expression CARRET and_expression
2368           {
2369                 $$ = new Binary (Binary.Operator.ExclusiveOr, 
2370                                  (Expression) $1, (Expression) $3, lexer.Location);
2371           }
2372         ;
2373
2374 inclusive_or_expression
2375         : exclusive_or_expression
2376         | inclusive_or_expression BITWISE_OR exclusive_or_expression
2377           {
2378                 $$ = new Binary (Binary.Operator.BitwiseOr, 
2379                                  (Expression) $1, (Expression) $3, lexer.Location);
2380           }
2381         ;
2382
2383 conditional_and_expression
2384         : inclusive_or_expression
2385         | conditional_and_expression OP_AND inclusive_or_expression
2386           {
2387                 $$ = new Binary (Binary.Operator.LogicalAnd, 
2388                                  (Expression) $1, (Expression) $3, lexer.Location);
2389           }
2390         ;
2391
2392 conditional_or_expression
2393         : conditional_and_expression
2394         | conditional_or_expression OP_OR conditional_and_expression
2395           {
2396                 $$ = new Binary (Binary.Operator.LogicalOr, 
2397                                  (Expression) $1, (Expression) $3, lexer.Location);
2398           }
2399         ;
2400
2401 conditional_expression
2402         : conditional_or_expression
2403         | conditional_or_expression INTERR expression COLON expression 
2404           {
2405                 $$ = new Conditional ((Expression) $1, (Expression) $3, (Expression) $5, lexer.Location);
2406           }
2407         ;
2408
2409 assignment_expression
2410         : prefixed_unary_expression ASSIGN expression
2411           {
2412                 $$ = new Assign ((Expression) $1, (Expression) $3, lexer.Location);
2413           }
2414         | prefixed_unary_expression OP_MULT_ASSIGN expression
2415           {
2416                 Location l = lexer.Location;
2417
2418                 $$ = new Assign ((Expression) $1,
2419                                  new Binary (Binary.Operator.Multiply, 
2420                                              (Expression) $1,
2421                                              (Expression) $3, l), l);
2422           }
2423         | prefixed_unary_expression OP_DIV_ASSIGN expression
2424           {
2425                 Location l = lexer.Location;
2426
2427                 $$ = new Assign ((Expression) $1,
2428                                  new Binary (Binary.Operator.Division, 
2429                                              (Expression) $1,
2430                                              (Expression) $3, l), l);
2431           }
2432         | prefixed_unary_expression OP_MOD_ASSIGN expression
2433           {
2434                 Location l = lexer.Location;
2435
2436                 $$ = new Assign ((Expression) $1,
2437                                  new Binary (Binary.Operator.Modulus, 
2438                                              (Expression) $1,
2439                                              (Expression) $3, l), l);
2440           }
2441         | prefixed_unary_expression OP_ADD_ASSIGN expression
2442           {
2443                 Location l = lexer.Location;
2444
2445                 $$ = new Assign ((Expression) $1,
2446                                  new Binary (Binary.Operator.Addition, 
2447                                              (Expression) $1,
2448                                              (Expression) $3, l), l);
2449           }
2450         | prefixed_unary_expression OP_SUB_ASSIGN expression
2451           {
2452                 Location l = lexer.Location;
2453
2454                 $$ = new Assign ((Expression) $1,
2455                                  new Binary (Binary.Operator.Subtraction, 
2456                                              (Expression) $1,
2457                                              (Expression) $3, l), l);
2458           }
2459         | prefixed_unary_expression OP_SHIFT_LEFT_ASSIGN expression
2460           {
2461                 Location l = lexer.Location;
2462
2463                 $$ = new Assign ((Expression) $1,
2464                                  new Binary (Binary.Operator.LeftShift, 
2465                                              (Expression) $1,
2466                                              (Expression) $3, l), l);
2467           }
2468         | prefixed_unary_expression OP_SHIFT_RIGHT_ASSIGN expression
2469           {
2470                 Location l = lexer.Location;
2471
2472                 $$ = new Assign ((Expression) $1,
2473                                  new Binary (Binary.Operator.RightShift, 
2474                                              (Expression) $1,
2475                                              (Expression) $3, l), l);
2476           }
2477         | prefixed_unary_expression OP_AND_ASSIGN expression
2478           {
2479                 Location l = lexer.Location;
2480
2481                 $$ = new Assign ((Expression) $1,
2482                                  new Binary (Binary.Operator.BitwiseAnd, 
2483                                              (Expression) $1,
2484                                              (Expression) $3, l), l);
2485           }
2486         | prefixed_unary_expression OP_OR_ASSIGN expression
2487           {
2488                 Location l = lexer.Location;
2489
2490                 $$ = new Assign ((Expression) $1,
2491                                  new Binary (Binary.Operator.BitwiseOr, 
2492                                              (Expression) $1,
2493                                              (Expression) $3, l), l);
2494           }
2495         | prefixed_unary_expression OP_XOR_ASSIGN expression
2496           {
2497                 Location l = lexer.Location;
2498
2499                 $$ = new Assign ((Expression) $1,
2500                                  new Binary (Binary.Operator.ExclusiveOr, 
2501                                              (Expression) $1,
2502                                              (Expression) $3, l), l);
2503           }
2504         ;
2505
2506 expression
2507         : conditional_expression
2508         | assignment_expression
2509         ;
2510
2511 constant_expression
2512         : expression
2513         ;
2514
2515 boolean_expression
2516         : expression
2517         ;
2518
2519 //
2520 // 10 classes
2521 //
2522 class_declaration
2523         : opt_attributes
2524           opt_modifiers
2525           CLASS IDENTIFIER
2526           {
2527                 Class new_class;
2528                 string name;
2529
2530                 name = MakeName ((string) $4);
2531
2532                 new_class = new Class (current_container, name, (int) $2, 
2533                                        (Attributes) $1, lexer.Location);
2534                 current_container = new_class;
2535                 current_container.Namespace = current_namespace;
2536                 RootContext.Tree.RecordClass (name, new_class);
2537           }
2538           opt_class_base
2539           class_body 
2540           opt_semicolon 
2541           {
2542                 Class new_class = (Class) current_container;
2543
2544                 if ($6 != null)
2545                         new_class.Bases = (ArrayList) $6;
2546
2547                 current_container = current_container.Parent;
2548                 CheckDef (current_container.AddClass (new_class), new_class.Name);
2549
2550                 $$ = new_class;
2551           }
2552         ;       
2553
2554 opt_modifiers
2555         : /* empty */           { $$ = (int) 0; }
2556         | modifiers
2557         ;
2558
2559 modifiers
2560         : modifier
2561         | modifiers modifier
2562           { 
2563                 int m1 = (int) $1;
2564                 int m2 = (int) $2;
2565
2566                 if ((m1 & m2) != 0) {
2567                         Location l = lexer.Location;
2568                         Report.Error (1004, l, "Duplicate modifier: `" + Modifiers.Name (m2) + "'");
2569                 }
2570                 $$ = (int) (m1 | m2);
2571           }
2572         ;
2573
2574 modifier
2575         : NEW                   { $$ = Modifiers.NEW; }
2576         | PUBLIC                { $$ = Modifiers.PUBLIC; }
2577         | PROTECTED             { $$ = Modifiers.PROTECTED; }
2578         | INTERNAL              { $$ = Modifiers.INTERNAL; }
2579         | PRIVATE               { $$ = Modifiers.PRIVATE; }
2580         | ABSTRACT              { $$ = Modifiers.ABSTRACT; }
2581         | SEALED                { $$ = Modifiers.SEALED; }
2582         | STATIC                { $$ = Modifiers.STATIC; }
2583         | READONLY              { $$ = Modifiers.READONLY; }
2584         | VIRTUAL               { $$ = Modifiers.VIRTUAL; }
2585         | OVERRIDE              { $$ = Modifiers.OVERRIDE; }
2586         | EXTERN                { $$ = Modifiers.EXTERN; }
2587         | VOLATILE              { $$ = Modifiers.VOLATILE; }
2588         | UNSAFE                { $$ = Modifiers.UNSAFE; }
2589         ;
2590
2591 opt_class_base
2592         : /* empty */           { $$ = null; }
2593         | class_base            { $$ = $1;   }
2594         ;
2595
2596 class_base
2597         : COLON type_list { $$ = $2; }
2598         ;
2599
2600 //
2601 // Statements (8.2)
2602 //
2603
2604 //
2605 // A block is "contained" on the following places:
2606 //      method_body
2607 //      property_declaration as part of the accessor body (get/set)
2608 //      operator_declaration
2609 //      constructor_declaration
2610 //      destructor_declaration
2611 //      event_declaration as part of add_accessor_declaration or remove_accessor_declaration
2612 //      
2613 block
2614         : OPEN_BRACE 
2615           {
2616                 current_block = new Block (current_block);
2617           } 
2618           opt_statement_list CLOSE_BRACE 
2619           { 
2620                 while (current_block.Implicit)
2621                         current_block = current_block.Parent;
2622                 $$ = current_block;
2623                 current_block = current_block.Parent;
2624           }
2625         ;
2626
2627 opt_statement_list
2628         : /* empty */
2629         | statement_list 
2630         ;
2631
2632 statement_list
2633         : statement
2634         | statement_list statement
2635         ;
2636
2637 statement
2638         : declaration_statement
2639           {
2640                 if ((Block) $1 != current_block){
2641                         current_block.AddStatement ((Statement) $1);
2642                         current_block = (Block) $1;
2643                 }
2644           }
2645         | embedded_statement
2646           {
2647                 Statement s = (Statement) $1;
2648
2649
2650                 current_block.AddStatement ((Statement) $1);
2651           }
2652         | labeled_statement
2653         ;
2654
2655 embedded_statement
2656         : block
2657         | empty_statement
2658         | expression_statement
2659         | selection_statement
2660         | iteration_statement
2661         | jump_statement                  
2662         | try_statement
2663         | checked_statement
2664         | unchecked_statement
2665         | lock_statement
2666         | using_statement
2667         | unsafe_statement
2668         | fixed_statement
2669         ;
2670
2671 empty_statement
2672         : SEMICOLON
2673           {
2674                   $$ = new EmptyStatement ();
2675           }
2676         ;
2677
2678 labeled_statement
2679         : IDENTIFIER COLON 
2680           {
2681                 LabeledStatement labeled = new LabeledStatement ((string) $1);
2682
2683                 if (!current_block.AddLabel ((string) $1, labeled)){
2684                         Location l = lexer.Location;
2685                         Report.Error (140, l, "The label '" + ((string) $1) + "' is a duplicate");
2686                 }       
2687                 current_block.AddStatement (labeled);
2688           }
2689           statement
2690         ;
2691
2692 declaration_statement
2693         : local_variable_declaration SEMICOLON
2694           {
2695                 DictionaryEntry de = (DictionaryEntry) $1;
2696
2697                 $$ = declare_local_variables ((string) de.Key, (ArrayList) de.Value, lexer.Location);
2698           }
2699
2700         | local_constant_declaration SEMICOLON
2701           {
2702                 DictionaryEntry de = (DictionaryEntry) $1;
2703
2704                 $$ = declare_local_constant ((string) de.Key, (VariableDeclaration) de.Value);
2705           }
2706         ;
2707
2708 /* 
2709  * The following is from Rhys' grammar:
2710  * > Types in local variable declarations must be recognized as 
2711  * > expressions to prevent reduce/reduce errors in the grammar.
2712  * > The expressions are converted into types during semantic analysis.
2713  */
2714 local_variable_type
2715         : primary_expression opt_rank_specifier
2716           { 
2717                 // FIXME: Do something smart here regarding the composition of the type.
2718
2719                 // Ok, the above "primary_expression" is there to get rid of
2720                 // both reduce/reduce and shift/reduces in the grammar, it should
2721                 // really just be "type_name".  If you use type_name, a reduce/reduce
2722                 // creeps up.  If you use qualified_identifier (which is all we need
2723                 // really) two shift/reduces appear.
2724                 // 
2725
2726                 // So the super-trick is that primary_expression
2727                 // can only be either a SimpleName or a MemberAccess. 
2728                 // The MemberAccess case arises when you have a fully qualified type-name like :
2729                 // Foo.Bar.Blah i;
2730                 // SimpleName is when you have
2731                 // Blah i;
2732                   
2733                 Expression expr = (Expression) $1;  
2734                 if (!(expr is SimpleName || expr is MemberAccess)) {
2735                         Location l = lexer.Location;
2736                         Report.Error (-1, l, "Invalid Type definition");
2737                         $$ = "System.Object";
2738                 }
2739                 
2740                 //
2741                 // So we extract the string corresponding to the SimpleName
2742                 // or MemberAccess
2743                 // 
2744                 $$ = GetQualifiedIdentifier (expr) + (string) $2;
2745           }
2746         | builtin_types opt_rank_specifier
2747           {
2748                   $$ = (string) $1 + (string) $2;
2749           }
2750         ;
2751
2752 local_variable_pointer_type
2753         : primary_expression STAR
2754           {
2755                 Expression expr = (Expression) $1;  
2756                 if (!(expr is SimpleName || expr is MemberAccess)) {
2757                         Location l = lexer.Location;
2758                         Report.Error (-1, l, "Invalid Type definition");
2759                         $$ = "System.Object";
2760                 }
2761                 
2762                 $$ = GetQualifiedIdentifier (expr) + "*";
2763           }
2764         | builtin_types STAR
2765           {
2766                 $$ = (string) $1 + "*";
2767           }
2768         | VOID STAR
2769           {
2770                 $$ = "System.Void*";
2771           }
2772         | local_variable_pointer_type STAR
2773           {
2774                 $$ = (string) $1 + "*";
2775           }
2776         ;
2777
2778 local_variable_declaration
2779         : local_variable_type variable_declarators
2780           {
2781                 $$ = new DictionaryEntry ($1, $2);
2782           }
2783         | local_variable_pointer_type opt_rank_specifier variable_declarators
2784         {
2785                 $$ = new DictionaryEntry ((string) $1 + (string) $2, $3);
2786         }
2787         ;
2788
2789 local_constant_declaration
2790         : CONST local_variable_type constant_declarator
2791           {
2792                 $$ = new DictionaryEntry ($2, $3);
2793           }
2794         ;
2795
2796 expression_statement
2797         : statement_expression SEMICOLON
2798           {
2799                 $$ = $1;
2800           }
2801         ;
2802
2803         //
2804         // We have to do the wrapping here and not in the case above,
2805         // because statement_expression is used for example in for_statement
2806         //
2807 statement_expression
2808         : invocation_expression         { $$ = new StatementExpression ((ExpressionStatement) $1); }
2809         | object_creation_expression    { $$ = new StatementExpression ((ExpressionStatement) $1); }
2810         | assignment_expression         { $$ = new StatementExpression ((ExpressionStatement) $1); }
2811         | post_increment_expression     { $$ = new StatementExpression ((ExpressionStatement) $1); }
2812         | post_decrement_expression     { $$ = new StatementExpression ((ExpressionStatement) $1); }
2813         | pre_increment_expression      { $$ = new StatementExpression ((ExpressionStatement) $1); }
2814         | pre_decrement_expression      { $$ = new StatementExpression ((ExpressionStatement) $1); }
2815         | error {
2816                 Report.Error (1002, lexer.Location, "Expecting `;'");
2817           }
2818         ;
2819
2820 object_creation_expression
2821         : object_or_delegate_creation_expression
2822           { note ("complain if this is a delegate maybe?"); } 
2823         ;
2824
2825 selection_statement
2826         : if_statement
2827         | switch_statement
2828         ; 
2829
2830 if_statement
2831         : IF OPEN_PARENS boolean_expression CLOSE_PARENS 
2832           embedded_statement
2833           { 
2834                 $$ = new If ((Expression) $3, (Statement) $5);
2835
2836                 if (RootContext.WarningLevel >= 3){
2837                         if ($5 is EmptyStatement)
2838                                 Report.Warning (642, lexer.Location, "Possibly mistaken empty statement");
2839                 }
2840
2841           }
2842         | IF OPEN_PARENS boolean_expression CLOSE_PARENS
2843           embedded_statement ELSE embedded_statement
2844           {
2845                 $$ = new If ((Expression) $3, (Statement) $5, (Statement) $7);
2846           }
2847         ;
2848
2849 switch_statement
2850         : SWITCH OPEN_PARENS 
2851           { 
2852                 oob_stack.Push (lexer.Location);
2853           }
2854           expression CLOSE_PARENS 
2855           switch_block
2856           {
2857                 $$ = new Switch ((Expression) $4, (ArrayList) $6, (Location) oob_stack.Pop ());
2858           }
2859         ;
2860
2861 switch_block
2862         : OPEN_BRACE
2863           opt_switch_sections
2864           CLOSE_BRACE
2865           {
2866                 $$ = $2;
2867           }
2868         ;
2869
2870 opt_switch_sections
2871         : /* empty */           
2872           {
2873                 Report.Error (1522, lexer.Location, "Empty switch block"); 
2874           }
2875         | switch_sections
2876         ;
2877
2878 switch_sections
2879         : switch_section 
2880           {
2881                 ArrayList sections = new ArrayList ();
2882
2883                 sections.Add ($1);
2884                 $$ = sections;
2885           }
2886         | switch_sections switch_section
2887           {
2888                 ArrayList sections = (ArrayList) $1;
2889
2890                 sections.Add ($2);
2891                 $$ = sections;
2892           }
2893         ;
2894
2895 switch_section
2896         : switch_labels
2897           {
2898                 current_block = new Block (current_block);
2899           }
2900           statement_list 
2901           {
2902                 while (current_block.Implicit)
2903                         current_block = current_block.Parent;
2904                 $$ = new SwitchSection ((ArrayList) $1, current_block);
2905                 current_block = current_block.Parent;
2906           }
2907         ;
2908
2909 switch_labels
2910         : switch_label 
2911           {
2912                 ArrayList labels = new ArrayList ();
2913
2914                 labels.Add ($1);
2915                 $$ = labels;
2916           }
2917         | switch_labels switch_label 
2918           {
2919                 ArrayList labels = (ArrayList) ($1);
2920                 labels.Add ($2);
2921
2922                 $$ = labels;
2923           }
2924         ;
2925
2926 switch_label
2927         : CASE constant_expression COLON        { $$ = new SwitchLabel ((Expression) $2, lexer.Location); }
2928         | DEFAULT COLON                         { $$ = new SwitchLabel (null, lexer.Location); }
2929         | error {
2930                 Report.Error (
2931                         1523, lexer.Location, 
2932                         "The keyword case or default must precede code in switch block");
2933           }
2934         ;
2935
2936 iteration_statement
2937         : while_statement
2938         | do_statement
2939         | for_statement
2940         | foreach_statement
2941         ;
2942
2943 while_statement
2944         : WHILE OPEN_PARENS boolean_expression CLOSE_PARENS embedded_statement
2945         {
2946                 $$ = new While ((Expression) $3, (Statement) $5);
2947         
2948                 if (RootContext.WarningLevel >= 3){
2949                         if ($5 is EmptyStatement)
2950                                 Report.Warning (642, lexer.Location, "Possibly mistaken empty statement");
2951                 }
2952         }
2953         ;
2954
2955 do_statement
2956         : DO embedded_statement 
2957           WHILE OPEN_PARENS boolean_expression CLOSE_PARENS SEMICOLON
2958           {
2959                 $$ = new Do ((Statement) $2, (Expression) $5);
2960           }
2961         ;
2962
2963 for_statement
2964         : FOR OPEN_PARENS 
2965           opt_for_initializer SEMICOLON
2966           {
2967                 Block assign_block = new Block (current_block);
2968                 current_block = assign_block;
2969
2970                 if ($3 is DictionaryEntry){
2971                         DictionaryEntry de = (DictionaryEntry) $3;
2972                         
2973                         string type = (string) de.Key;
2974                         ArrayList var_declarators = (ArrayList) de.Value;
2975
2976                         foreach (VariableDeclaration decl in var_declarators){
2977
2978                                 VariableInfo vi;
2979
2980                                 vi = current_block.AddVariable (
2981                                         type, decl.identifier, current_local_parameters, decl.Location);
2982                                 if (vi == null){
2983                                         Report.Error (128, decl.Location, 
2984                                                       "A local variable `" + decl.identifier + 
2985                                                       "' is already defined in this scope");
2986                                 } else {
2987                                         Location l = lexer.Location;
2988                                         Expression expr;
2989                                         if (decl.expression_or_array_initializer is Expression){
2990                                                 expr = (Expression) decl.expression_or_array_initializer;
2991                                                 
2992                                         } else {
2993                                                 
2994                                                 ArrayList init = (ArrayList) decl.expression_or_array_initializer;
2995                                                 
2996                                                 string base_type = type.Substring (0, type.IndexOf ("["));
2997                                                 string rank = type.Substring (type.IndexOf ("["));
2998                                                 
2999                                                 expr = new ArrayCreation (base_type, rank, init, decl.Location);
3000                                         }
3001                                         
3002                                         LocalVariableReference var;
3003                                         var = new LocalVariableReference (
3004                                                                           assign_block, decl.identifier, l);
3005                                         
3006                                         Assign a = new Assign (var, expr, decl.Location);
3007                                         
3008                                         assign_block.AddStatement (new StatementExpression (a));
3009                                 }
3010                         }
3011                         
3012                         $3 = null;
3013                 } 
3014           } 
3015           opt_for_condition SEMICOLON
3016           opt_for_iterator CLOSE_PARENS 
3017           embedded_statement
3018           {
3019                 For f = new For ((Statement) $3, (Expression) $6, (Statement) $8, (Statement) $10);
3020
3021                 if (RootContext.WarningLevel >= 3){
3022                         if ($10 is EmptyStatement)
3023                                 Report.Warning (642, lexer.Location, "Possibly mistaken empty statement");
3024                 }
3025
3026                 current_block.AddStatement (f);
3027                 while (current_block.Implicit)
3028                         current_block = current_block.Parent;
3029                 $$ = current_block;
3030                 current_block = current_block.Parent;
3031           }
3032         ;
3033
3034 opt_for_initializer
3035         : /* empty */           { $$ = new EmptyStatement (); }
3036         | for_initializer       
3037         ;
3038
3039 for_initializer
3040         : local_variable_declaration
3041         | statement_expression_list
3042         ;
3043
3044 opt_for_condition
3045         : /* empty */           { $$ = null; }
3046         | boolean_expression
3047         ;
3048
3049 opt_for_iterator
3050         : /* empty */           { $$ = new EmptyStatement (); }
3051         | for_iterator
3052         ;
3053
3054 for_iterator
3055         : statement_expression_list
3056         ;
3057
3058 statement_expression_list
3059         : statement_expression  
3060           {
3061                 Block b = new Block (null, true);
3062
3063                 b.AddStatement ((Statement) $1);
3064                 $$ = b;
3065           }
3066         | statement_expression_list COMMA statement_expression
3067           {
3068                 Block b = (Block) $1;
3069
3070                 b.AddStatement ((Statement) $3);
3071                 $$ = $1;
3072           }
3073         ;
3074
3075 foreach_statement
3076         : FOREACH OPEN_PARENS type IDENTIFIER IN 
3077           {
3078                 oob_stack.Push (lexer.Location);
3079           }
3080           expression CLOSE_PARENS 
3081           {
3082                 oob_stack.Push (current_block);
3083
3084                 Block foreach_block = new Block (current_block, true);
3085                 LocalVariableReference v;
3086                 Location l = lexer.Location;
3087                 VariableInfo vi;
3088
3089                 vi = foreach_block.AddVariable ((string) $3, (string) $4, current_local_parameters, l);
3090                 if (vi == null){
3091                         Report.Error (
3092                                 128, l, "A local variable `" + (string) $4 + "' is already "+
3093                                 "defined in this scope");
3094                 }
3095
3096                 v = new LocalVariableReference (foreach_block, (string) $4, l);
3097
3098                 current_block.AddStatement (foreach_block);
3099                 current_block = foreach_block;
3100
3101                 oob_stack.Push (v);
3102           } 
3103           embedded_statement 
3104           {
3105                 LocalVariableReference v = (LocalVariableReference) oob_stack.Pop ();
3106                 Block prev_block = (Block) oob_stack.Pop ();
3107                 Location l = (Location) oob_stack.Pop ();
3108
3109                 while (current_block != prev_block)
3110                         current_block = current_block.Parent;
3111
3112                 $$ = new Foreach ((string) $3, v, (Expression) $7, (Statement) $10, l);
3113           }
3114         ;
3115
3116 jump_statement
3117         : break_statement
3118         | continue_statement
3119         | goto_statement
3120         | return_statement
3121         | throw_statement
3122         ;
3123
3124 break_statement
3125         : BREAK SEMICOLON
3126           {
3127                 $$ = new Break (lexer.Location);
3128           }
3129         ;
3130
3131 continue_statement
3132         : CONTINUE SEMICOLON
3133           {
3134                 $$ = new Continue (lexer.Location);
3135           }
3136         ;
3137
3138 goto_statement
3139         : GOTO IDENTIFIER SEMICOLON 
3140           {
3141                 $$ = new Goto (current_block, (string) $2, lexer.Location);
3142           }
3143         | GOTO CASE constant_expression SEMICOLON
3144           {
3145                 $$ = new GotoCase ((Expression) $3, lexer.Location);
3146           }
3147         | GOTO DEFAULT SEMICOLON 
3148           {
3149                 $$ = new GotoDefault (lexer.Location);
3150           }
3151         ; 
3152
3153 return_statement
3154         : RETURN opt_expression SEMICOLON
3155           {
3156                 $$ = new Return ((Expression) $2, lexer.Location);
3157           }
3158         ;
3159
3160 throw_statement
3161         : THROW opt_expression SEMICOLON
3162           {
3163                 $$ = new Throw ((Expression) $2, lexer.Location);
3164           }
3165         ;
3166
3167 opt_expression
3168         : /* empty */
3169         | expression
3170         ;
3171
3172 try_statement
3173         : TRY block catch_clauses 
3174         {
3175                 Catch g = null;
3176                 ArrayList s = new ArrayList ();
3177                 
3178                 foreach (Catch cc in (ArrayList) $3) {
3179                         if (cc.Type == null)
3180                                 g = cc;
3181                         else
3182                                 s.Add (cc);
3183                 }
3184
3185                 // Now s contains the list of specific catch clauses
3186                 // and g contains the general one.
3187                 
3188                 $$ = new Try ((Block) $2, s, g, null);
3189         }
3190         | TRY block opt_catch_clauses FINALLY block
3191           {
3192                 Catch g = null;
3193                 ArrayList s = new ArrayList ();
3194                 ArrayList catch_list = (ArrayList) $3;
3195
3196                 if (catch_list != null){
3197                         foreach (Catch cc in catch_list) {
3198                                 if (cc.Type == null)
3199                                         g = cc;
3200                                 else
3201                                         s.Add (cc);
3202                         }
3203                 }
3204
3205                 $$ = new Try ((Block) $2, s, g, (Block) $5);
3206           }
3207         | TRY block error 
3208           {
3209                 Report.Error (1524, lexer.Location, "Expected catch or finally");
3210           }
3211         ;
3212
3213 opt_catch_clauses
3214         : /* empty */  { $$ = null; }
3215         | catch_clauses
3216         ;
3217
3218 catch_clauses
3219         : catch_clause 
3220           {
3221                 ArrayList l = new ArrayList ();
3222
3223                 l.Add ($1);
3224                 $$ = l;
3225           }
3226         | catch_clauses catch_clause
3227           {
3228                 ArrayList l = (ArrayList) $1;
3229
3230                 l.Add ($2);
3231                 $$ = l;
3232           }
3233         ;
3234
3235 opt_identifier
3236         : /* empty */   { $$ = null; }
3237         | IDENTIFIER
3238         ;
3239
3240 catch_clause 
3241         : CATCH opt_catch_args 
3242         {
3243                 string type = null, id = null;
3244                 
3245                 if ($2 != null) {
3246                         DictionaryEntry cc = (DictionaryEntry) $2;
3247                         type = (string) cc.Key;
3248                         id   = (string) cc.Value;
3249
3250                         if (id != null){
3251                                 ArrayList one = new ArrayList ();
3252                                 Location loc = lexer.Location;
3253
3254                                 one.Add (new VariableDeclaration (id, null, loc));
3255
3256                                 $1 = current_block;
3257                                 current_block = new Block (current_block);
3258                                 Block b = declare_local_variables (type, one, loc);
3259                                 current_block = b;
3260
3261                                 
3262                         }
3263                 }
3264         } block {
3265                 string type = null, id = null;
3266
3267                 if ($2 != null){
3268                         DictionaryEntry cc = (DictionaryEntry) $2;
3269                         type = (string) cc.Key;
3270                         id   = (string) cc.Value;
3271
3272                         if ($1 != null){
3273                                 while (current_block != (Block) $1)
3274                                         current_block = current_block.Parent;
3275                         }
3276                 }
3277
3278
3279                 $$ = new Catch (type, id , (Block) $4, lexer.Location);
3280         }
3281         ;
3282
3283 opt_catch_args
3284         : /* empty */ { $$ = null; }
3285         | catch_args
3286         ;         
3287
3288 catch_args 
3289         : OPEN_PARENS type opt_identifier CLOSE_PARENS 
3290         {
3291                 $$ = new DictionaryEntry ($2, $3);
3292         }
3293         ;
3294
3295 checked_statement
3296         : CHECKED block
3297           {
3298                 $$ = new Checked ((Block) $2);
3299           }
3300         ;
3301
3302 unchecked_statement
3303         : UNCHECKED block
3304           {
3305                 $$ = new Unchecked ((Block) $2);
3306           }
3307         ;
3308
3309 unsafe_statement
3310         : UNSAFE 
3311         {
3312                 if (!RootContext.Unsafe){
3313                         Report.Error (227, lexer.Location, 
3314                                 "Unsafe code can only be used if --unsafe is used");
3315                 }
3316         } block {
3317                 $$ = new Unsafe ((Block) $3);
3318         }
3319         ;
3320
3321 fixed_statement
3322         : FIXED OPEN_PARENS 
3323           pointer_type fixed_pointer_declarators 
3324           CLOSE_PARENS 
3325           {
3326                 Block assign_block = new Block (current_block, true);
3327                 ArrayList list = (ArrayList) $4;
3328                 string type = (string) $3;
3329                 Location l = lexer.Location;
3330                 int top = list.Count;
3331
3332                 for (int i = 0; i < top; i++){
3333                         Pair p = (Pair) list [i];
3334                         VariableInfo v;
3335
3336                         v = current_block.AddVariable (type, (string) p.First,current_local_parameters, l);
3337                         if (v == null){
3338                                 Report.Error (
3339                                         128, l, "A local variable `" + (string) p.First + "' is already "+
3340                                         "defined in this scope");
3341                         }
3342                         v.ReadOnly = true;
3343                         p.First = v;
3344                         list [i] = p;
3345                 }
3346                 current_block.AddStatement (assign_block);
3347                 current_block = assign_block;
3348                 oob_stack.Push (assign_block);
3349                 oob_stack.Push (l);
3350           }
3351           embedded_statement 
3352           {
3353                 Location l = (Location) oob_stack.Pop ();
3354                 Block assign_block = (Block) oob_stack.Pop ();
3355
3356                 ArrayList list = (ArrayList) $4;
3357                 int top = list.Count;
3358
3359                 $$ = new Fixed ((string) $3, (ArrayList) $4, (Statement) $7, l);
3360           }
3361         ;
3362
3363 fixed_pointer_declarators
3364         : fixed_pointer_declarator      { 
3365                 ArrayList declarators = new ArrayList (); 
3366                 declarators.Add ($1);
3367                 $$ = declarators;
3368           }
3369         | fixed_pointer_declarators COMMA fixed_pointer_declarator
3370           {
3371                 ArrayList declarators = (ArrayList) $1;
3372                 declarators.Add ($3);
3373                 $$ = declarators;
3374           }
3375         ;
3376
3377 fixed_pointer_declarator
3378         : IDENTIFIER ASSIGN expression
3379           {     
3380                 $$ = new Pair ($1, $3);
3381           }
3382         ;
3383
3384 lock_statement
3385         : LOCK OPEN_PARENS expression CLOSE_PARENS 
3386           {
3387                 //
3388           } 
3389           embedded_statement
3390           {
3391                 $$ = new Lock ((Expression) $3, (Statement) $6, lexer.Location);
3392           }
3393         ;
3394
3395 using_statement
3396         : USING OPEN_PARENS resource_acquisition CLOSE_PARENS 
3397           {
3398                 Block assign_block = new Block (current_block);
3399                 current_block = assign_block;
3400
3401                 oob_stack.Push (lexer.Location);
3402                 
3403                 if ($3 is DictionaryEntry){
3404                         DictionaryEntry de = (DictionaryEntry) $3;
3405                         Location l = lexer.Location;
3406
3407                         string type = (string) de.Key;
3408                         ArrayList var_declarators = (ArrayList) de.Value;
3409
3410                         foreach (VariableDeclaration decl in var_declarators){
3411                                 if (current_block.AddVariable (
3412                                         type, decl.identifier, 
3413                                         current_local_parameters, decl.Location) == null){
3414                                         Report.Error (128, decl.Location, 
3415                                         "A local variable `" + decl.identifier + "' is already" +
3416                                         "defined in this scope");
3417                                 }
3418                         }
3419
3420                         ArrayList vars = new ArrayList ();
3421
3422                         foreach (VariableDeclaration decl in var_declarators){
3423
3424                                 Expression expr;
3425                                 if (decl.expression_or_array_initializer is Expression){
3426                                         expr = (Expression) decl.expression_or_array_initializer;
3427                                         
3428                                 } else {
3429
3430                                         ArrayList init = (ArrayList) decl.expression_or_array_initializer;
3431                                         
3432                                         string base_type = type.Substring (0, type.IndexOf ("["));
3433                                         string rank = type.Substring (type.IndexOf ("["));
3434                                         
3435                                         expr = new ArrayCreation (base_type, rank, init, decl.Location);
3436                                 }
3437
3438                                 LocalVariableReference var;
3439                                 VariableInfo vi;
3440
3441                                 var = new LocalVariableReference (assign_block, decl.identifier, l);
3442                                 vi = var.VariableInfo;
3443                                 vi.ReadOnly = true;
3444
3445                                 // This is so that it is not a warning on using variables
3446                                 vi.Used = true;
3447
3448                                 vars.Add (new DictionaryEntry (var, expr));                             
3449
3450                                 // Assign a = new Assign (var, expr, decl.Location);
3451                                 // assign_block.AddStatement (new StatementExpression (a));
3452                         }
3453                         $3 = new DictionaryEntry (type, vars);
3454                  }
3455           } 
3456           embedded_statement
3457           {
3458                 Using u = new Using ($3, (Statement) $6, (Location) oob_stack.Pop ());
3459                 current_block.AddStatement (u);
3460                 while (current_block.Implicit)
3461                         current_block = current_block.Parent;
3462                 $$ = current_block;
3463                 current_block = current_block.Parent;
3464           }
3465         ; 
3466
3467 resource_acquisition
3468         : local_variable_declaration
3469         | expression
3470         ;
3471
3472 %%
3473
3474 // <summary>
3475 //   A class used to pass around variable declarations and constants
3476 // </summary>
3477 public class VariableDeclaration {
3478         public string identifier;
3479         public object expression_or_array_initializer;
3480         public Location Location;
3481
3482         public VariableDeclaration (string id, object eoai, Location l){
3483                 this.identifier = id;
3484                 this.expression_or_array_initializer = eoai;
3485                 this.Location = l;
3486         }
3487 }
3488
3489 // <summary>
3490 //   A class used to hold info about an indexer declarator
3491 // </summary>
3492
3493 public class IndexerDeclaration {
3494         public string type;
3495         public string interface_type;
3496         public Parameters param_list;
3497
3498         public IndexerDeclaration (string type, string interface_type, Parameters param_list)
3499         {
3500                 this.type = type;
3501                 this.interface_type = interface_type;
3502                 this.param_list = param_list;
3503         }
3504 }
3505
3506 // <summary>
3507 //  A class used to hold info about an operator declarator
3508 // </summary>
3509
3510 public class OperatorDeclaration {
3511         public Operator.OpType optype;
3512         public string ret_type;
3513         public string arg1type;
3514         public string arg1name;
3515         public string arg2type;
3516         public string arg2name;
3517         public Location location;
3518
3519         public OperatorDeclaration (Operator.OpType op, string ret_type, string arg1type, string arg1name,
3520                                     string arg2type, string arg2name, Location location)
3521         {
3522                 optype = op;
3523                 this.ret_type = ret_type;
3524                 this.arg1type = arg1type;
3525                 this.arg1name = arg1name;
3526                 this.arg2type = arg2type;
3527                 this.arg2name = arg2name;
3528                 this.location = location;
3529         }
3530
3531 }
3532
3533 // <summary>
3534 //   Given the @class_name name, it creates a fully qualified name
3535 //   based on the containing declaration space
3536 // </summary>
3537 string 
3538 MakeName (string class_name)
3539 {
3540         string ns = current_namespace.Name;
3541         string container_name = current_container.Name;
3542
3543         if (container_name == ""){
3544                 if (ns != "")
3545                         return ns + "." + class_name;
3546                 else
3547                         return class_name;
3548         } else
3549                 return container_name + "." + class_name;
3550 }
3551
3552 // <summary>
3553 //   Used to report back to the user the result of a declaration
3554 //   in the current declaration space
3555 // </summary>
3556 void 
3557 CheckDef (AdditionResult result, string name)
3558 {
3559         if (result == AdditionResult.Success)
3560                 return;
3561
3562         Location l = lexer.Location;
3563         
3564         switch (result){
3565         case AdditionResult.NameExists:
3566                 Report.Error (102, l, "The namespace `" + current_container.Name + 
3567                                  "' already contains a definition for `"+
3568                                  name + "'");
3569                 break;
3570
3571
3572                 //
3573                 // This is handled only for static Constructors, because
3574                 // in reality we handle these by the semantic analysis later
3575                 //
3576         case AdditionResult.MethodExists:
3577                 Report.Error (
3578                         111, l, "Class `"+current_container.Name+
3579                         "' already defines a member called '" + 
3580                         name + "' with the same parameter types (more than one default constructor)");
3581                 break;
3582
3583         case AdditionResult.EnclosingClash:
3584                 Report.Error (542, l, "Member names cannot be the same as their enclosing type");
3585                 break;
3586                 
3587         case AdditionResult.NotAConstructor:
3588                 Report.Error (1520, l, "Class, struct, or interface method must have a return type");
3589                 break;
3590         }
3591 }
3592
3593 void 
3594 CheckDef (bool result, string name)
3595 {
3596         if (result)
3597                 return;
3598         CheckDef (AdditionResult.NameExists, name);
3599 }
3600
3601 Expression
3602 SimpleLookup (string name, Location loc)
3603 {
3604         //
3605         // we need to check against current_block not being null
3606         // as `expression' is allowed in argument_lists, which 
3607         // do not exist inside a block.  
3608         //
3609         if (current_block != null){
3610                 if (current_block.IsVariableDefined (name))
3611                         return new LocalVariableReference (current_block, name, loc);
3612         }
3613
3614         if (current_local_parameters != null){
3615                 int idx;
3616                 Parameter par = current_local_parameters.GetParameterByName (name, out idx);
3617                 if (par != null)
3618                         return new ParameterReference (current_local_parameters, idx, name);
3619         }
3620
3621         return null;
3622 }
3623
3624 Expression DecomposeQI (string name, Location loc)
3625 {
3626         Expression o;
3627
3628         if (name.IndexOf ('.') == -1){
3629                 o = SimpleLookup (name, loc);
3630                 if (o == null)
3631                         return new SimpleName (name, loc);
3632                 return o;
3633         } else {
3634                 int pos = name.LastIndexOf (".");
3635                 string left = name.Substring (0, pos);
3636                 string right = name.Substring (pos + 1);
3637
3638                 o = DecomposeQI (left, loc);
3639                 return new MemberAccess (o, right, loc);
3640         }
3641 }
3642
3643 // <summary>
3644 //  This method is used to get at the complete string representation of
3645 //  a fully-qualified type name, hiding inside a MemberAccess ;-)
3646 //  This is necessary because local_variable_type admits primary_expression
3647 //  as the type of the variable. So we do some extra checking
3648 // </summary>
3649 string GetQualifiedIdentifier (Expression expr)
3650 {
3651         if (expr is SimpleName)
3652                 return ((SimpleName)expr).Name;
3653         else if (expr is MemberAccess)
3654                 return GetQualifiedIdentifier (((MemberAccess)expr).Expr) + "." + ((MemberAccess) expr).Identifier;
3655         else 
3656                 throw new Exception ("Expr has to be either SimpleName or MemberAccess! (" + expr + ")");
3657         
3658 }
3659
3660 Block declare_local_variables (string type, ArrayList variable_declarators, Location loc)
3661 {
3662         Block implicit_block;
3663         ArrayList inits = null;
3664
3665         //
3666         // We use the `Used' property to check whether statements
3667         // have been added to the current block.  If so, we need
3668         // to create another block to contain the new declaration
3669         // otherwise, as an optimization, we use the same block to
3670         // add the declaration.
3671         //
3672         // FIXME: A further optimization is to check if the statements
3673         // that were added were added as part of the initialization
3674         // below.  In which case, no other statements have been executed
3675         // and we might be able to reduce the number of blocks for
3676         // situations like this:
3677         //
3678         // int j = 1;  int k = j + 1;
3679         //
3680         if (current_block.Used)
3681                 implicit_block = new Block (current_block, true);
3682         else
3683                 implicit_block = current_block;
3684
3685         foreach (VariableDeclaration decl in variable_declarators){
3686
3687                 if (implicit_block.AddVariable (type, decl.identifier, current_local_parameters, decl.Location) != null) {
3688                         if (decl.expression_or_array_initializer != null){
3689                                 if (inits == null)
3690                                         inits = new ArrayList ();
3691                                 inits.Add (decl);
3692                         }
3693                 } else {
3694                         Report.Error (128, decl.Location, "A local variable `" + decl.identifier +
3695                                          "' is already defined in this scope");
3696                 }
3697         }
3698
3699         if (inits == null)
3700                 return implicit_block;
3701
3702         foreach (VariableDeclaration decl in inits){
3703                 Assign assign;
3704                 Expression expr;
3705                 
3706                 if (decl.expression_or_array_initializer is Expression){
3707                         expr = (Expression) decl.expression_or_array_initializer;
3708
3709                 } else {
3710                         ArrayList init = (ArrayList) decl.expression_or_array_initializer;
3711                         
3712                         string base_type = type.Substring (0, type.IndexOf ("["));
3713                         string rank = type.Substring (type.IndexOf ("["));
3714
3715                         expr = new ArrayCreation (base_type, rank, init, decl.Location);
3716                         
3717                 }
3718
3719                 LocalVariableReference var;
3720                 var = new LocalVariableReference (implicit_block, decl.identifier, loc);
3721
3722                 assign = new Assign (var, expr, decl.Location);
3723
3724                 implicit_block.AddStatement (new StatementExpression (assign));
3725         }
3726         
3727         return implicit_block;
3728 }
3729
3730 Block declare_local_constant (string type, VariableDeclaration decl)
3731 {
3732         Block implicit_block;
3733
3734         if (current_block.Used)
3735                 implicit_block = new Block (current_block, true);
3736         else
3737                 implicit_block = current_block;
3738
3739         if (!(implicit_block.AddConstant (type, decl.identifier, (Expression) decl.expression_or_array_initializer,
3740                                           current_local_parameters, decl.Location))){
3741                 Report.Error (128, decl.Location, "A local variable `" + decl.identifier +
3742                               "' is already defined in this scope");
3743         }
3744         
3745         return implicit_block;
3746 }
3747
3748 void CheckAttributeTarget (string a)
3749 {
3750         switch (a) {
3751
3752         case "assembly" : case "field" : case "method" : case "param" : case "property" : case "type" :
3753                 return;
3754                 
3755         default :
3756                 Location l = lexer.Location;
3757                 Report.Error (658, l, "`" + a + "' is an invalid attribute target");
3758                 break;
3759         }
3760
3761 }
3762
3763 void CheckUnaryOperator (Operator.OpType op)
3764 {
3765         switch (op) {
3766                 
3767         case Operator.OpType.LogicalNot: 
3768         case Operator.OpType.OnesComplement: 
3769         case Operator.OpType.Increment:
3770         case Operator.OpType.Decrement:
3771         case Operator.OpType.True: 
3772         case Operator.OpType.False: 
3773         case Operator.OpType.Addition: 
3774         case Operator.OpType.Subtraction:
3775                 
3776                 break;
3777                 
3778         default :
3779                 Location l = lexer.Location;
3780                 Report.Error (1019, l, "Overloadable unary operator expected"); 
3781                 break;
3782                 
3783         }
3784 }
3785
3786 void CheckBinaryOperator (Operator.OpType op)
3787 {
3788         switch (op) {
3789                 
3790         case Operator.OpType.Addition: 
3791         case Operator.OpType.Subtraction: 
3792         case Operator.OpType.Multiply:
3793         case Operator.OpType.Division:
3794         case Operator.OpType.Modulus: 
3795         case Operator.OpType.BitwiseAnd: 
3796         case Operator.OpType.BitwiseOr:
3797         case Operator.OpType.ExclusiveOr: 
3798         case Operator.OpType.LeftShift: 
3799         case Operator.OpType.RightShift:
3800         case Operator.OpType.Equality: 
3801         case Operator.OpType.Inequality:
3802         case Operator.OpType.GreaterThan: 
3803         case Operator.OpType.LessThan: 
3804         case Operator.OpType.GreaterThanOrEqual:
3805         case Operator.OpType.LessThanOrEqual:
3806                 break;
3807                 
3808         default :
3809                 Location l = lexer.Location;
3810                 Report.Error (1020, l, "Overloadable binary operator expected");
3811                 break;
3812         }
3813         
3814 }
3815
3816 void syntax_error (Location l, string msg)
3817 {
3818         Report.Error (1003, l, "Syntax error, " + msg);
3819 }
3820
3821 void output (string s)
3822 {
3823         Console.WriteLine (s);
3824 }
3825
3826 void note (string s)
3827 {
3828         // Used to put annotations
3829 }
3830
3831 Tokenizer lexer;
3832
3833 public Tokenizer Lexer {
3834         get {
3835                 return lexer;
3836         }
3837 }                  
3838
3839 public CSharpParser (string name, System.IO.Stream input, ArrayList defines)
3840 {
3841         current_namespace = new Namespace (null, "");
3842         this.name = name;
3843         this.input = input;
3844         current_container = RootContext.Tree.Types;
3845         current_container.Namespace = current_namespace;
3846         oob_stack = new Stack ();
3847
3848         lexer = new Tokenizer (input, name, defines);
3849 }
3850
3851 public override int parse ()
3852 {
3853         StringBuilder value = new StringBuilder ();
3854
3855         global_errors = 0;
3856         try {
3857                 if (yacc_verbose_flag)
3858                         yyparse (lexer, new yydebug.yyDebugSimple ());
3859                 else
3860                         yyparse (lexer);
3861         } catch (Exception e){
3862                 // Console.WriteLine ("Fatal error: " + name);
3863                 // Console.WriteLine (lexer.location);
3864
3865                 // 
3866                 // Please do not remove this, it is used during debugging
3867                 // of the grammar
3868                 //
3869                 Console.WriteLine (lexer.location + "  : Parsing error ");
3870                 Console.WriteLine (e);
3871                 global_errors++;
3872         }
3873         
3874         return global_errors;
3875 }
3876
3877 /* end end end */
3878 }