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