2004-08-06 Bernie Solomon <bernard@ugsolutions.com>
[mono.git] / mcs / mbas / genericparser.cs
1 //\r
2 // GenericParser.cs: The Base Parser for the Mono compilers\r
3 //\r
4 // Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)\r
5 //\r
6 // Licensed under the terms of the GNU GPL\r
7 //\r
8 // Copyright (C) 2001 Ximian, Inc.\r
9 //\r
10 \r
11 namespace Mono.Languages\r
12 {\r
13         using System;\r
14         using System.Reflection;\r
15         using System.Collections;\r
16         using System.IO;\r
17         using Mono.MonoBASIC;\r
18 \r
19         /// <summary>\r
20         /// Base class to support multiple Jay generated parsers\r
21         /// </summary>\r
22         public abstract class GenericParser\r
23         {\r
24                 // ---------------------------------------------------\r
25                 // Class state\r
26 \r
27                 // Count of errors found while parsing\r
28                 static protected int global_errors;\r
29 \r
30                 // Maps extensions to specific parsers\r
31                 static private Hashtable mapOfParsers;\r
32 \r
33                 // Maps extensions to specific parsers\r
34                 static private GenericParser defaultParser = null;\r
35 \r
36                 // Indicates if parsing should be verbose\r
37                 static public bool yacc_verbose_flag = false;\r
38 \r
39                 // Context to use\r
40                 static public ArrayList defines;\r
41 \r
42                 // ---------------------------------------------------\r
43                 // Instance state\r
44 \r
45                 // Name of the file we are parsing\r
46                 protected string name;\r
47 \r
48                 // Input stream to parse from.\r
49                 protected System.IO.TextReader input;\r
50 \r
51                 // Current namespace definition\r
52                 protected Namespace     current_namespace;\r
53 \r
54                 // Current typecontainer definition\r
55                 protected TypeContainer current_container;\r
56                 \r
57                 // ---------------------------------------------------\r
58                 // What the descendants MUST reimplement\r
59 \r
60                 /// <summary>\r
61                 /// Parses the current "input"\r
62                 /// </summary>\r
63                 protected abstract int parse();\r
64 \r
65                 /// <summary>\r
66                 /// Lists the extensions this parser can handle\r
67                 /// </summary>\r
68                 public abstract string[] extensions();\r
69                 /* {\r
70                         string [] list = { ".cs" };\r
71                         return list;\r
72                 } */\r
73 \r
74                 // ---------------------------------------------------\r
75                 // What the descendants DONT HAVE to reimplement\r
76 \r
77                 /// <summary>\r
78                 /// Initializes this parser from a file and parses it\r
79                 /// </summary>\r
80                 /// <param name="fileName">Name of the file to be parsed</param>\r
81                 /// <param name="context">Context to output the parsed tree</param>\r
82                 public int ParseFile(string fileName)\r
83                 {\r
84                         // file exceptions must be caught by caller\r
85 \r
86                         global_errors = 0;\r
87                         name = fileName;\r
88                         // TODO: Encoding switching as needed\r
89                         //   We are here forcing StreamReader to assume current system codepage,\r
90                         //   because normally it defaults to UTF-8\r
91                         input = new StreamReader(fileName, System.Text.Encoding.Default); \r
92                         //rc = context;\r
93                         return parse();\r
94                 }\r
95 \r
96                 /// <summary>\r
97                 /// Initializes this parser from a string and parses it\r
98                 /// </summary>\r
99                 /// <param name="source">String to be parsed</param>\r
100                 /// <param name="sourceName">Name of the source to be parsed (just for error reporting)</param>\r
101                 /// <param name="context">Context to output the parsed tree</param>\r
102                 public int ParseString(string source, string sourceName)\r
103                 {\r
104                         global_errors = 0;\r
105                         name = sourceName;\r
106                         input = new StringReader(source);\r
107                         //rc = context;\r
108                         return parse();\r
109                 }\r
110 \r
111                 // ---------------------------------------------------\r
112                 // Class methods\r
113 \r
114                 static private void MapParsers()\r
115                 {\r
116                         mapOfParsers = new Hashtable();\r
117 \r
118                         Assembly thisAssembly = Assembly.GetExecutingAssembly();\r
119                         foreach(Type type in thisAssembly.GetTypes())\r
120                         {\r
121                                 if (type.BaseType != null)\r
122                                         if (type.BaseType.FullName == "Mono.Languages.GenericParser")\r
123                                         {\r
124                                                 GenericParser parser = (GenericParser)Activator.CreateInstance(type);\r
125                                                 foreach(string fileExtension in parser.extensions())\r
126                                                 {                                                                                               \r
127                                                         string theFileExtension = fileExtension.ToLower();\r
128                                                         if (mapOfParsers.Contains(theFileExtension))\r
129                                                                 Console.WriteLine("[TRACE] " + type.FullName + " can't try to parse '" + theFileExtension + "' files too");\r
130                                                         else\r
131                                                                 mapOfParsers.Add(theFileExtension, parser);\r
132                                                 }\r
133                                                 object[] attribs = type.GetCustomAttributes(typeof(DefaultParserAttribute), false);\r
134                                                 if (attribs != null && attribs.Length > 0)\r
135                                                 {\r
136                                                         if (defaultParser == null)\r
137                                                                 defaultParser = parser;\r
138                                                         else\r
139                                                                 Console.WriteLine("[TRACE] " + type.FullName + " can't be another default parser");                                                             \r
140                                                 }\r
141                                         }\r
142                         }\r
143                 }\r
144 \r
145                 /// <summary>\r
146                 /// Find the descendant parser that knows how to parse the specified file\r
147                 /// based on the file extension, or the default parser otherwise, if available\r
148                 /// </summary>\r
149                 /// <param name="fileName">Name of the file to be parsed</param>\r
150                 public static GenericParser GetSpecificParserFor(string fileName)\r
151                 {\r
152                         int i;\r
153                         GenericParser chosenParser = null;\r
154                         \r
155                         if (mapOfParsers == null)\r
156                                 MapParsers();\r
157                         \r
158                         if ((i = fileName.LastIndexOf(".")) > 0)\r
159                         {\r
160                                 string fileExtension = fileName.Substring(i).ToLower();\r
161                                 chosenParser = (GenericParser)mapOfParsers[fileExtension];\r
162                         }\r
163                         \r
164                         if (chosenParser != null)                       \r
165                                 return chosenParser;\r
166                                 \r
167                         return defaultParser;\r
168                 }\r
169 \r
170                 \r
171                 public static int Tokenize(string fileName)\r
172                 {\r
173                         GenericParser parser = GetSpecificParserFor(fileName);\r
174                                                 \r
175                         if (parser == null)\r
176                         {\r
177                                 Console.WriteLine("Do not know how to compile " + fileName);\r
178                                 return 1;\r
179                         }\r
180 \r
181 /*                      Stream input;\r
182 \r
183                         try {\r
184                                 input = File.OpenRead (input_file);\r
185 \r
186                         } catch {\r
187                                 Report.Error (2001, "Source file '" + input_file + "' could not be opened");\r
188                                 return 1;\r
189                         }\r
190 \r
191                         using (input){\r
192                                 Tokenizer lexer = new Tokenizer (input, input_file, defines);\r
193                                 int token, tokens = 0, errors = 0;\r
194 \r
195                                 while ((token = lexer.token ()) != Token.EOF){\r
196                                         Location l = lexer.Location;\r
197                                         tokens++;\r
198                                         if (token == Token.ERROR)\r
199                                                 errors++;\r
200                                 }\r
201                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");\r
202                         }\r
203 */                      \r
204                         return 0;\r
205                 }\r
206 \r
207 \r
208                 /// <summary>\r
209                 /// Find the descendant parser that knows how to parse the specified file\r
210                 /// based on the files extension, and parses it using the chosen parser\r
211                 /// </summary>\r
212                 /// <param name="fileName">Name of the file to be parsed</param>\r
213                 /// <param name="context">Context to output the parsed tree</param>\r
214                 public static int Parse(string fileName)\r
215                 {\r
216                         int errors;\r
217                         GenericParser parser = GetSpecificParserFor(fileName);\r
218                                                 \r
219                         if (parser == null)\r
220                         {\r
221                                 Console.WriteLine("Do not know how to compile " + fileName);\r
222                                 return 1;\r
223                         }\r
224                         \r
225                         try \r
226                         {\r
227                                 errors = parser.ParseFile(fileName);\r
228                         } \r
229                         catch (FileNotFoundException)\r
230                         {\r
231                                 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");\r
232                                 return 1;\r
233                         }\r
234                         catch (DirectoryNotFoundException)\r
235                         {\r
236                                 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");\r
237                                 return 1;\r
238                         }                       \r
239                         catch (Exception ex)\r
240                         {\r
241                                 Console.WriteLine (ex);\r
242                                 Console.WriteLine ("Compilation aborted");\r
243                                 return 1;\r
244                         }\r
245                         \r
246                         return errors;\r
247                 }\r
248 \r
249                 // <summary>\r
250                 //   Given the @class_name name, it creates a fully qualified name\r
251                 //   based on the containing declaration space\r
252                 // </summary>\r
253                 protected string MakeName(string class_name)\r
254                 {\r
255                         string ns = current_namespace.Name;\r
256                         string container_name = current_container.Name;\r
257 \r
258                         if (container_name == "")\r
259                         {\r
260                                 if (ns != "")\r
261                                         return ns + "." + class_name;\r
262                                 else\r
263                                         return class_name;\r
264                         } \r
265                         else\r
266                                 return container_name + "." + class_name;\r
267                 }\r
268 \r
269                 // <summary>\r
270                 //   Used to report back to the user the result of a declaration\r
271                 //   in the current declaration space\r
272                 // </summary>\r
273                 protected void CheckDef (AdditionResult result, string name, Location l)\r
274                 {\r
275                         if (result == AdditionResult.Success)\r
276                                 return;\r
277 \r
278                         switch (result)\r
279                         {\r
280                                 case AdditionResult.NameExists:\r
281                                         Report.Error (102, l, "The container '" + current_container.Name + \r
282                                                 "' already contains a definition for '"+\r
283                                                 name + "'");\r
284                                         break;\r
285 \r
286 \r
287                                         //\r
288                                         // This is handled only for static Constructors, because\r
289                                         // in reality we handle these by the semantic analysis later\r
290                                         //\r
291                                 case AdditionResult.MethodExists:\r
292                                         Report.Error (\r
293                                                 111, l, "Class `"+current_container.Name+\r
294                                                 "' already defines a member called '" + \r
295                                                 name + "' with the same parameter types (more than one default constructor)");\r
296                                         break;\r
297 \r
298                                 case AdditionResult.EnclosingClash:\r
299                                         Report.Error (542, l, "Member names cannot be the same as their enclosing type");\r
300                                         break;\r
301                 \r
302                                 case AdditionResult.NotAConstructor:\r
303                                         Report.Error (1520, l, "Class, struct, or interface method must have a return type");\r
304                                         break;\r
305                         }\r
306                 }\r
307 \r
308                 // <summary>\r
309                 //   Used to report back to the user the result of a declaration\r
310                 //   in the current declaration space\r
311                 // </summary>\r
312                 protected void CheckDef (bool result, string name, Location l)\r
313                 {\r
314                         if (result)\r
315                                 return;\r
316                         CheckDef (AdditionResult.NameExists, name, l);\r
317                 }\r
318 \r
319 \r
320                 // ---------------------------------------------------\r
321                 // Constructors\r
322 \r
323                 public GenericParser()\r
324                 {\r
325                         // DO NOTHING\r
326                 }\r
327 \r
328         }\r
329 }