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
17 using Mono.MonoBASIC;
\r
20 /// Base class to support multiple Jay generated parsers
\r
22 public abstract class GenericParser
\r
24 // ---------------------------------------------------
\r
27 // Count of errors found while parsing
\r
28 static protected int global_errors;
\r
30 // Maps extensions to specific parsers
\r
31 static private Hashtable mapOfParsers;
\r
33 // Maps extensions to specific parsers
\r
34 static private GenericParser defaultParser = null;
\r
36 // Indicates if parsing should be verbose
\r
37 static public bool yacc_verbose_flag = false;
\r
40 static public ArrayList defines;
\r
42 // ---------------------------------------------------
\r
45 // Name of the file we are parsing
\r
46 protected string name;
\r
48 // Input stream to parse from.
\r
49 protected System.IO.TextReader input;
\r
51 // Current namespace definition
\r
52 protected Namespace current_namespace;
\r
54 // Current typecontainer definition
\r
55 protected TypeContainer current_container;
\r
57 // ---------------------------------------------------
\r
58 // What the descendants MUST reimplement
\r
61 /// Parses the current "input"
\r
63 protected abstract int parse();
\r
66 /// Lists the extensions this parser can handle
\r
68 public abstract string[] extensions();
\r
70 string [] list = { ".cs" };
\r
74 // ---------------------------------------------------
\r
75 // What the descendants DONT HAVE to reimplement
\r
78 /// Initializes this parser from a file and parses it
\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
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 string and parses it
\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
106 input = new StringReader(source);
\r
111 // ---------------------------------------------------
\r
114 static private void MapParsers()
\r
116 mapOfParsers = new Hashtable();
\r
118 Assembly thisAssembly = Assembly.GetExecutingAssembly();
\r
119 foreach(Type type in thisAssembly.GetTypes())
\r
121 if (type.BaseType != null)
\r
122 if (type.BaseType.FullName == "Mono.Languages.GenericParser")
\r
124 GenericParser parser = (GenericParser)Activator.CreateInstance(type);
\r
125 foreach(string fileExtension in parser.extensions())
\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
131 mapOfParsers.Add(theFileExtension, parser);
\r
133 object[] attribs = type.GetCustomAttributes(typeof(DefaultParserAttribute), false);
\r
134 if (attribs != null && attribs.Length > 0)
\r
136 if (defaultParser == null)
\r
137 defaultParser = parser;
\r
139 Console.WriteLine("[TRACE] " + type.FullName + " can't be another default parser");
\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
149 /// <param name="fileName">Name of the file to be parsed</param>
\r
150 public static GenericParser GetSpecificParserFor(string fileName)
\r
153 GenericParser chosenParser = null;
\r
155 if (mapOfParsers == null)
\r
158 if ((i = fileName.LastIndexOf(".")) > 0)
\r
160 string fileExtension = fileName.Substring(i).ToLower();
\r
161 chosenParser = (GenericParser)mapOfParsers[fileExtension];
\r
164 if (chosenParser != null)
\r
165 return chosenParser;
\r
167 return defaultParser;
\r
171 public static int Tokenize(string fileName)
\r
173 GenericParser parser = GetSpecificParserFor(fileName);
\r
175 if (parser == null)
\r
177 Console.WriteLine("Do not know how to compile " + fileName);
\r
184 input = File.OpenRead (input_file);
\r
187 Report.Error (2001, "Source file '" + input_file + "' could not be opened");
\r
192 Tokenizer lexer = new Tokenizer (input, input_file, defines);
\r
193 int token, tokens = 0, errors = 0;
\r
195 while ((token = lexer.token ()) != Token.EOF){
\r
196 Location l = lexer.Location;
\r
198 if (token == Token.ERROR)
\r
201 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
\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
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
217 GenericParser parser = GetSpecificParserFor(fileName);
\r
219 if (parser == null)
\r
221 Console.WriteLine("Do not know how to compile " + fileName);
\r
227 errors = parser.ParseFile(fileName);
\r
229 catch (FileNotFoundException)
\r
231 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");
\r
234 catch (DirectoryNotFoundException)
\r
236 Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");
\r
239 catch (Exception ex)
\r
241 Console.WriteLine (ex);
\r
242 Console.WriteLine ("Compilation aborted");
\r
250 // Given the @class_name name, it creates a fully qualified name
\r
251 // based on the containing declaration space
\r
253 protected string MakeName(string class_name)
\r
255 string ns = current_namespace.Name;
\r
256 string container_name = current_container.Name;
\r
258 if (container_name == "")
\r
261 return ns + "." + class_name;
\r
266 return container_name + "." + class_name;
\r
270 // Used to report back to the user the result of a declaration
\r
271 // in the current declaration space
\r
273 protected void CheckDef (AdditionResult result, string name, Location l)
\r
275 if (result == AdditionResult.Success)
\r
280 case AdditionResult.NameExists:
\r
281 Report.Error (102, l, "The container '" + current_container.Name +
\r
282 "' already contains a definition for '"+
\r
288 // This is handled only for static Constructors, because
\r
289 // in reality we handle these by the semantic analysis later
\r
291 case AdditionResult.MethodExists:
\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
298 case AdditionResult.EnclosingClash:
\r
299 Report.Error (542, l, "Member names cannot be the same as their enclosing type");
\r
302 case AdditionResult.NotAConstructor:
\r
303 Report.Error (1520, l, "Class, struct, or interface method must have a return type");
\r
309 // Used to report back to the user the result of a declaration
\r
310 // in the current declaration space
\r
312 protected void CheckDef (bool result, string name, Location l)
\r
316 CheckDef (AdditionResult.NameExists, name, l);
\r
320 // ---------------------------------------------------
\r
323 public GenericParser()
\r