//
// GenericParser.cs: The Base Parser for the Mono compilers
//
// Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)
//
// Licensed under the terms of the GNU GPL
//
// Copyright (C) 2001 Ximian, Inc.
//
namespace Mono.Languages
{
using System;
using System.Reflection;
using System.Collections;
using System.IO;
using Mono.MonoBASIC;
///
/// Base class to support multiple Jay generated parsers
///
public abstract class GenericParser
{
// ---------------------------------------------------
// Class state
// Count of errors found while parsing
static protected int global_errors;
// Maps extensions to specific parsers
static private Hashtable mapOfParsers;
// Maps extensions to specific parsers
static private GenericParser defaultParser = null;
// Indicates if parsing should be verbose
static public bool yacc_verbose_flag = false;
// Context to use
static public ArrayList defines;
// ---------------------------------------------------
// Instance state
// Name of the file we are parsing
protected string name;
// Input stream to parse from.
protected System.IO.TextReader input;
// Current namespace definition
protected Namespace current_namespace;
// Current typecontainer definition
protected TypeContainer current_container;
// ---------------------------------------------------
// What the descendants MUST reimplement
///
/// Parses the current "input"
///
protected abstract int parse();
///
/// Lists the extensions this parser can handle
///
public abstract string[] extensions();
/* {
string [] list = { ".cs" };
return list;
} */
// ---------------------------------------------------
// What the descendants DONT HAVE to reimplement
///
/// Initializes this parser from a file and parses it
///
/// Name of the file to be parsed
/// Context to output the parsed tree
public int ParseFile(string fileName)
{
// file exceptions must be caught by caller
global_errors = 0;
name = fileName;
// TODO: Encoding switching as needed
// We are here forcing StreamReader to assume current system codepage,
// because normally it defaults to UTF-8
input = new StreamReader(fileName, System.Text.Encoding.Default);
//rc = context;
return parse();
}
///
/// Initializes this parser from a string and parses it
///
/// String to be parsed
/// Name of the source to be parsed (just for error reporting)
/// Context to output the parsed tree
public int ParseString(string source, string sourceName)
{
global_errors = 0;
name = sourceName;
input = new StringReader(source);
//rc = context;
return parse();
}
// ---------------------------------------------------
// Class methods
static private void MapParsers()
{
mapOfParsers = new Hashtable();
Assembly thisAssembly = Assembly.GetExecutingAssembly();
foreach(Type type in thisAssembly.GetTypes())
{
if (type.BaseType != null)
if (type.BaseType.FullName == "Mono.Languages.GenericParser")
{
GenericParser parser = (GenericParser)Activator.CreateInstance(type);
foreach(string fileExtension in parser.extensions())
{
string theFileExtension = fileExtension.ToLower();
if (mapOfParsers.Contains(theFileExtension))
Console.WriteLine("[TRACE] " + type.FullName + " can't try to parse '" + theFileExtension + "' files too");
else
mapOfParsers.Add(theFileExtension, parser);
}
object[] attribs = type.GetCustomAttributes(typeof(DefaultParserAttribute), false);
if (attribs != null && attribs.Length > 0)
{
if (defaultParser == null)
defaultParser = parser;
else
Console.WriteLine("[TRACE] " + type.FullName + " can't be another default parser");
}
}
}
}
///
/// Find the descendant parser that knows how to parse the specified file
/// based on the file extension, or the default parser otherwise, if available
///
/// Name of the file to be parsed
public static GenericParser GetSpecificParserFor(string fileName)
{
int i;
GenericParser chosenParser = null;
if (mapOfParsers == null)
MapParsers();
if ((i = fileName.LastIndexOf(".")) > 0)
{
string fileExtension = fileName.Substring(i).ToLower();
chosenParser = (GenericParser)mapOfParsers[fileExtension];
}
if (chosenParser != null)
return chosenParser;
return defaultParser;
}
public static int Tokenize(string fileName)
{
GenericParser parser = GetSpecificParserFor(fileName);
if (parser == null)
{
Console.WriteLine("Do not know how to compile " + fileName);
return 1;
}
/* Stream input;
try {
input = File.OpenRead (input_file);
} catch {
Report.Error (2001, "Source file '" + input_file + "' could not be opened");
return 1;
}
using (input){
Tokenizer lexer = new Tokenizer (input, input_file, defines);
int token, tokens = 0, errors = 0;
while ((token = lexer.token ()) != Token.EOF){
Location l = lexer.Location;
tokens++;
if (token == Token.ERROR)
errors++;
}
Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
}
*/
return 0;
}
///
/// Find the descendant parser that knows how to parse the specified file
/// based on the files extension, and parses it using the chosen parser
///
/// Name of the file to be parsed
/// Context to output the parsed tree
public static int Parse(string fileName)
{
int errors;
GenericParser parser = GetSpecificParserFor(fileName);
if (parser == null)
{
Console.WriteLine("Do not know how to compile " + fileName);
return 1;
}
try
{
errors = parser.ParseFile(fileName);
}
catch (FileNotFoundException)
{
Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");
return 1;
}
catch (DirectoryNotFoundException)
{
Report.Error(2001, "Source file \'" + fileName + "\' could not be found!!!");
return 1;
}
catch (Exception ex)
{
Console.WriteLine (ex);
Console.WriteLine ("Compilation aborted");
return 1;
}
return errors;
}
//
// Given the @class_name name, it creates a fully qualified name
// based on the containing declaration space
//
protected string MakeName(string class_name)
{
string ns = current_namespace.Name;
string container_name = current_container.Name;
if (container_name == "")
{
if (ns != "")
return ns + "." + class_name;
else
return class_name;
}
else
return container_name + "." + class_name;
}
//
// Used to report back to the user the result of a declaration
// in the current declaration space
//
protected void CheckDef (AdditionResult result, string name, Location l)
{
if (result == AdditionResult.Success)
return;
switch (result)
{
case AdditionResult.NameExists:
Report.Error (102, l, "The container '" + current_container.Name +
"' already contains a definition for '"+
name + "'");
break;
//
// This is handled only for static Constructors, because
// in reality we handle these by the semantic analysis later
//
case AdditionResult.MethodExists:
Report.Error (
111, l, "Class `"+current_container.Name+
"' already defines a member called '" +
name + "' with the same parameter types (more than one default constructor)");
break;
case AdditionResult.EnclosingClash:
Report.Error (542, l, "Member names cannot be the same as their enclosing type");
break;
case AdditionResult.NotAConstructor:
Report.Error (1520, l, "Class, struct, or interface method must have a return type");
break;
}
}
//
// Used to report back to the user the result of a declaration
// in the current declaration space
//
protected void CheckDef (bool result, string name, Location l)
{
if (result)
return;
CheckDef (AdditionResult.NameExists, name, l);
}
// ---------------------------------------------------
// Constructors
public GenericParser()
{
// DO NOTHING
}
}
}