2 // GenericParser.cs: The Base Parser for the Mono compilers
\r
4 // Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)
\r
6 // Licensed under the terms of the GNU GPL
\r
8 // Copyright (C) 2001 Ximian, Inc.
\r
11 namespace Mono.Languages
\r
14 using System.Reflection;
\r
15 using System.Collections;
\r
18 using Mono.MonoBASIC;
\r
21 /// Base class to support multiple Jay generated parsers
\r
23 public abstract class GenericParser
\r
25 // ---------------------------------------------------
\r
28 // Count of errors found while parsing
\r
29 static protected int global_errors;
\r
31 // Maps extensions to specific parsers
\r
32 static private Hashtable mapOfParsers;
\r
34 // Maps extensions to specific parsers
\r
35 static private GenericParser defaultParser = null;
\r
37 // Indicates if parsing should be verbose
\r
38 static public int yacc_verbose_flag = 0;
\r
41 static public ArrayList defines;
\r
43 // ---------------------------------------------------
\r
46 // Name of the file we are parsing
\r
47 protected string name;
\r
49 // Input stream to parse from.
\r
50 protected System.IO.TextReader input;
\r
52 // Current namespace definition
\r
53 protected Namespace current_namespace;
\r
55 // Current typecontainer definition
\r
56 protected TypeContainer current_container;
\r
58 // ---------------------------------------------------
\r
59 // What the descendants MUST reimplement
\r
62 /// Parses the current "input"
\r
64 protected abstract int parse();
\r
67 /// Lists the extensions this parser can handle
\r
69 public abstract string[] extensions();
\r
71 string [] list = { ".cs" };
\r
75 // ---------------------------------------------------
\r
76 // What the descendants DONT HAVE to reimplement
\r
79 /// Initializes this parser from a file and parses it
\r
81 /// <param name="fileName">Name of the file to be parsed</param>
\r
82 public int ParseFile(string fileName)
\r
84 // file exceptions must be caught by caller
\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
97 /// Initializes this parser from a file and parses it
\r
99 /// <param name="fileName">Name of the file to be parsed</param>
\r
100 /// <param name="encoding">Specific encoding to use in parsing</param>
\r
101 public int ParseFile(string fileName, Encoding encoding)
\r
103 // file exceptions must be caught by caller
\r
107 // TODO: Encoding switching as needed
\r
108 // We are here forcing StreamReader to assume an specific encoding
\r
109 input = new StreamReader(fileName, encoding);
\r
115 /// Initializes this parser from a string and parses it
\r
117 /// <param name="source">String to be parsed</param>
\r
118 /// <param name="sourceName">Name of the source to be parsed (just for error reporting)</param>
\r
119 public int ParseString(string source, string sourceName)
\r
123 input = new StringReader(source);
\r
128 // ---------------------------------------------------
\r
131 static private void MapParsers()
\r
133 mapOfParsers = new Hashtable();
\r
135 Assembly thisAssembly = Assembly.GetExecutingAssembly();
\r
136 foreach(Type type in thisAssembly.GetTypes())
\r
138 if (type.BaseType != null)
\r
139 if (type.BaseType.FullName == "Mono.Languages.GenericParser")
\r
141 GenericParser parser = (GenericParser)Activator.CreateInstance(type);
\r
142 foreach(string fileExtension in parser.extensions())
\r
144 string theFileExtension = fileExtension.ToLower();
\r
145 if (mapOfParsers.Contains(theFileExtension))
\r
146 Console.WriteLine("[TRACE] " + type.FullName + " can't try to parse '" + theFileExtension + "' files too");
\r
148 mapOfParsers.Add(theFileExtension, parser);
\r
150 object[] attribs = type.GetCustomAttributes(typeof(DefaultParserAttribute), false);
\r
151 if (attribs != null && attribs.Length > 0)
\r
153 if (defaultParser == null)
\r
154 defaultParser = parser;
\r
156 Console.WriteLine("[TRACE] " + type.FullName + " can't be another default parser");
\r
163 /// Find the descendant parser that knows how to parse the specified file
\r
164 /// based on the file extension, or the default parser otherwise, if available
\r
166 /// <param name="fileName">Name of the file to be parsed</param>
\r
167 public static GenericParser GetSpecificParserFor(string fileName)
\r
170 GenericParser chosenParser = null;
\r
172 if (mapOfParsers == null)
\r
175 if ((i = fileName.LastIndexOf(".")) > 0)
\r
177 string fileExtension = fileName.Substring(i).ToLower();
\r
178 chosenParser = (GenericParser)mapOfParsers[fileExtension];
\r
181 if (chosenParser != null)
\r
182 return chosenParser;
\r
184 return defaultParser;
\r
189 public static int Tokenize(string fileName)
\r
196 /// Find the descendant parser that knows how to parse the specified file
\r
197 /// based on the files extension, and parses it using the chosen parser
\r
199 /// <param name="fileName">Name of the file to be parsed</param>
201 public static int Parse(string fileName)
\r
203 return Parse(fileName, null);
207 /// Find the descendant parser that knows how to parse the specified file
\r
208 /// based on the files extension, and parses it using the chosen parser
\r
210 /// <param name="fileName">Name of the file to be parsed</param>
\r
211 /// <param name="encoding">Encoding of the file to be parsed</param>
\r
212 public static int Parse(string fileName, Encoding encoding)
\r
215 GenericParser parser = GetSpecificParserFor(fileName);
\r
217 if (parser == null)
\r
219 Console.WriteLine("Do not know how to compile " + fileName);
\r
223 if (encoding == null)
224 encoding = Encoding.Default;
228 errors = parser.ParseFile(fileName, encoding);
\r
230 catch (FileNotFoundException)
\r
232 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");
\r
235 catch (DirectoryNotFoundException)
\r
237 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");
\r
240 catch (Exception ex)
\r
242 Console.WriteLine (ex);
\r
243 Console.WriteLine ("Compilation aborted");
\r
251 // Given the @class_name name, it creates a fully qualified name
\r
252 // based on the containing declaration space
\r
254 protected string MakeName(string class_name)
\r
256 string ns = current_namespace.Name;
\r
257 string container_name = current_container.Name;
\r
259 if (container_name == "")
\r
262 return ns + "." + class_name;
\r
267 return container_name + "." + class_name;
\r
271 // Used to report back to the user the result of a declaration
\r
272 // in the current declaration space
\r
274 protected void CheckDef (AdditionResult result, string name, Location l)
\r
276 if (result == AdditionResult.Success)
\r
281 case AdditionResult.NameExists:
\r
282 Report.Error (102, l, "The container '" + current_container.Name +
\r
283 "' already contains a definition for '"+
\r
289 // This is handled only for static Constructors, because
\r
290 // in reality we handle these by the semantic analysis later
\r
292 case AdditionResult.MethodExists:
\r
294 111, l, "Class `"+current_container.Name+
\r
295 "' already defines a member called '" +
\r
296 name + "' with the same parameter types (more than one default constructor)");
\r
299 case AdditionResult.EnclosingClash:
\r
300 Report.Error (542, l, "Member names cannot be the same as their enclosing type");
\r
303 case AdditionResult.NotAConstructor:
\r
304 Report.Error (1520, l, "Class, struct, or interface method must have a return type");
\r
310 // Used to report back to the user the result of a declaration
\r
311 // in the current declaration space
\r
313 protected void CheckDef (bool result, string name, Location l)
\r
317 CheckDef (AdditionResult.NameExists, name, l);
\r
321 // ---------------------------------------------------
\r
324 public GenericParser()
\r