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
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 // Indicates if parsing should be verbose
\r
34 static public bool yacc_verbose_flag = false;
\r
37 static public ArrayList defines;
\r
39 // ---------------------------------------------------
\r
42 // Name of the file we are parsing
\r
43 protected string name;
\r
45 // Input stream to parse from.
\r
46 protected System.IO.TextReader input;
\r
48 // Current namespace definition
\r
49 protected Namespace current_namespace;
\r
51 // Current typecontainer definition
\r
52 protected TypeContainer current_container;
\r
54 // ---------------------------------------------------
\r
55 // What the descendants MUST reimplement
\r
58 /// Parses the current "input"
\r
60 public abstract int parse();
\r
63 /// Lists the extensions this parser can handle
\r
65 public abstract string[] extensions();
\r
67 string [] list = { ".cs" };
\r
71 // ---------------------------------------------------
\r
72 // What the descendants DONT HAVE to reimplement
\r
75 /// Initializes this parser from a file and parses it
\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
81 // file exceptions must be caught by caller
\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
94 /// Initializes this parser from a string and parses it
\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
103 input = new StringReader(source);
\r
108 // ---------------------------------------------------
\r
111 static private void MapParsers()
\r
114 mapOfParsers = new Hashtable();
\r
116 Assembly thisAssembly = Assembly.GetExecutingAssembly();
\r
117 foreach(Type type in thisAssembly.GetTypes())
\r
119 if (type.BaseType != null)
\r
120 if (type.BaseType.FullName == "Mono.Languages.GenericParser")
\r
122 GenericParser parser = (GenericParser)Activator.CreateInstance(type);
\r
123 foreach(string fileExtension in parser.extensions())
\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
129 mapOfParsers.Add(theFileExtension, parser);
\r
136 /// Find the descendant parser that knows how to parse the specified file
\r
137 /// based on the files extension
\r
139 /// <param name="fileName">Name of the file to be parsed</param>
\r
140 public static GenericParser GetSpecificParserFor(string fileName)
\r
143 string fileExtension;
\r
145 if (mapOfParsers == null)
\r
148 if ((i = fileName.LastIndexOf(".")) < 0)
\r
151 fileExtension = fileName.Substring(i).ToLower();
\r
153 return (GenericParser)mapOfParsers[fileExtension];
\r
157 public static int Tokenize(string fileName)
\r
159 GenericParser parser = GetSpecificParserFor(fileName);
\r
161 if (parser == null)
\r
163 Console.WriteLine("Do not know how to compile " + fileName);
\r
170 input = File.OpenRead (input_file);
\r
173 Report.Error (2001, "Source file '" + input_file + "' could not be opened");
\r
178 Tokenizer lexer = new Tokenizer (input, input_file, defines);
\r
179 int token, tokens = 0, errors = 0;
\r
181 while ((token = lexer.token ()) != Token.EOF){
\r
182 Location l = lexer.Location;
\r
184 if (token == Token.ERROR)
\r
187 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
\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
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
203 GenericParser parser = GetSpecificParserFor(fileName);
\r
205 if (parser == null)
\r
207 Console.WriteLine("Do not know how to compile " + fileName);
\r
213 errors = parser.ParseFile(fileName);
\r
215 catch (FileNotFoundException ex)
\r
217 error(2001, "Source file \'" + fileName + "\' could not be found!!!");
\r
218 Console.WriteLine (ex);
\r
221 catch (Exception ex)
\r
223 Console.WriteLine (ex);
\r
224 Console.WriteLine ("Compilation aborted");
\r
232 // Given the @class_name name, it creates a fully qualified name
\r
233 // based on the containing declaration space
\r
235 protected string MakeName(string class_name)
\r
237 string ns = current_namespace.Name;
\r
238 string container_name = current_container.Name;
\r
240 if (container_name == "")
\r
243 return ns + "." + class_name;
\r
248 return container_name + "." + class_name;
\r
252 // Used to report back to the user the result of a declaration
\r
253 // in the current declaration space
\r
255 protected void CheckDef (AdditionResult result, string name, Location l)
\r
257 if (result == AdditionResult.Success)
\r
262 case AdditionResult.NameExists:
\r
263 Report.Error (102, l, "The container '" + current_container.Name +
\r
264 "' already contains a definition for '"+
\r
270 // This is handled only for static Constructors, because
\r
271 // in reality we handle these by the semantic analysis later
\r
273 case AdditionResult.MethodExists:
\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
280 case AdditionResult.EnclosingClash:
\r
281 Report.Error (542, l, "Member names cannot be the same as their enclosing type");
\r
284 case AdditionResult.NotAConstructor:
\r
285 Report.Error (1520, l, "Class, struct, or interface method must have a return type");
\r
291 // Used to report back to the user the result of a declaration
\r
292 // in the current declaration space
\r
294 protected void CheckDef (bool result, string name, Location l)
\r
298 CheckDef (AdditionResult.NameExists, name, l);
\r
303 /// Emits error messages and increments a global count of them
\r
305 /// <param name="code"></param>
\r
306 /// <param name="desc"></param>
\r
307 static public void error (int code, string desc)
\r
309 Console.WriteLine ("error MC"+code+": "+ desc);
\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
319 Console.WriteLine (l.Name + "(" + l.Row + ",?" + /*l.Col +*/
\r
320 "): error MC" + code + ": " + text);
\r
324 // ---------------------------------------------------
\r
327 public GenericParser()
\r