/// This module was generated by the StaticLang tool from
/// Goldie v0.9: http://www.semitwist.com/goldie/

// Goldie: GOLD Engine for D
// GoldieLib
// Written in the D programming language.

module samples.calculatorStatic.calc.lang;

version = Goldie_StaticStyle;
private enum _packageName = "samples.calculatorStatic.calc";
private enum _shortPackageName = "calc";
version(Goldie_StaticStyle) {} else
	version = Goldie_DynamicStyle;

version(DigitalMars)
{
	import std.compiler;
	static if(version_major == 2 && version_minor == 57)
	{
		version(Goldie_StaticStyle)
			static assert(false, "Goldie's static-style and grammar compiling don't work on DMD 2.057 due to DMD Issue #7375");
		else
			version = Goldie_OmitGrmcLib;
	}
}

static if(true) // Workaround for DMD Issue #7386
{
	// To help with StaticLang. See note in stbuild.conf
	version(Goldie_OmitGrmcLib) {} else
		version = Goldie_IncludeGrmcLib;
}

version(Goldie_StaticStyle)
{
	// Ensure Goldie versions match
	import goldie.ver;
	static if(goldieVerStr != "0.9")
	{
		pragma(msg,
			"You're using Goldie v"~goldieVerStr~", but this static-style language "~
			"was generated with Goldie v0.9. You must regenerate the langauge "~
			"with 'goldie-staticlang'."
		);
		static assert(false, "Mismatched Goldie versions");
	}
}

import std.stdio;
import std.string;

import semitwist.util.all;

import goldie.base;
version(Goldie_DynamicStyle) import goldie.file;
import goldie.exception;
import goldie.lexer;
import goldie.parser;
import goldie.token;

import goldie.grmc.ast;
import tools.util;

static if(true) // Workaround for DMD Issue #7386
{
	version(Goldie_IncludeGrmcLib) import goldie.langs.grm.all;
}

//TODO: Create a function to fix symbolLookup after changing the language details.
//      Maybe cause the accessors to set a "dirty" flag which will re-gen symbolLookup
//      next time symbolLookup is accessed.
//TODO: In SemiTwistLib, create an "accessor"/"property" mixin similar to "getter"

version(Goldie_DynamicStyle)
string toLangIdent(string ident, string shortPackageName)
{
	return ident~"_"~shortPackageName;
}

version(Goldie_DynamicStyle)
public class Language
{
	string name;
	string ver;
	string author;
	string about;
	bool   caseSensitive;
	string filename;
	
	protected Symbol[][string] symbolLookup;
	
	Symbol[]    symbolTable;
	CharSet[]   charSetTable;
	Rule[]      ruleTable;
	DFAState[]  dfaTable;
	LALRState[] lalrTable;
	
	int startSymbolIndex;
	int initialDFAState;
	int initialLALRState;
	
	int eofSymbolIndex;
	int errorSymbolIndex;
	
	/// The NFA and DFA in Graphviz DOT format.
	///
	/// These are always empty unless the Langauge was created
	/// via Goldie.compileGrammarDebug or Goldie.compileGrammarFileDebug.
	///
	/// Languages loaded from a CGT or via staticlang will never have these filled in.
	string nfaDot;
	//string dfaRawDot;
	string dfaDot;

	int nfaNumStates;
	//int dfaRawNumStates;
	//int dfaNumStates;

	/// Only use this if you're going to manually create a language
	/// without using Goldie's CGT-loading or staticlang.
	public this()
	{
	}
	
	package this(string cgtFilename)
	{
		auto goldFile = new CGTFile(cgtFilename);
		filename = cgtFilename;
		
		this.symbolLookup     = goldFile.symbolLookup;
		this.name             = goldFile.name;
		this.ver              = goldFile.ver;
		this.author           = goldFile.author;
		this.about            = goldFile.about;
		this.caseSensitive    = goldFile.caseSensitive;
		this.startSymbolIndex = goldFile.startSymbolIndex;
		this.initialDFAState  = goldFile.initialDFAState;
		this.initialLALRState = goldFile.initialLALRState;
		this.eofSymbolIndex   = goldFile.eofSymbolIndex;
		this.errorSymbolIndex = goldFile.errorSymbolIndex;
		this.symbolTable      = goldFile.symbolTable;
		this.charSetTable     = goldFile.charSetTable;
		this.ruleTable        = goldFile.ruleTable;
		this.dfaTable         = goldFile.dfaTable;
		this.lalrTable        = goldFile.lalrTable;
	}
	
	void save(string cgtFilename)
	{
		auto goldFile = new CGTFile();
		
		goldFile.symbolLookup = this.symbolLookup;

		goldFile.name             = this.name;
		goldFile.ver              = this.ver;
		goldFile.author           = this.author;
		goldFile.about            = this.about;
		goldFile.caseSensitive    = this.caseSensitive;
		goldFile.startSymbolIndex = this.startSymbolIndex;
		goldFile.initialDFAState  = this.initialDFAState;
		goldFile.initialLALRState = this.initialLALRState;
		goldFile.eofSymbolIndex   = this.eofSymbolIndex;
		goldFile.errorSymbolIndex = this.errorSymbolIndex;
		goldFile.symbolTable      = this.symbolTable;
		goldFile.charSetTable     = this.charSetTable;
		goldFile.ruleTable        = this.ruleTable;
		goldFile.dfaTable         = this.dfaTable;
		goldFile.lalrTable        = this.lalrTable;

		goldFile.save(cgtFilename);
	}
	
	protected Lexer lexCodeX(Lexer lexer, string source, string filename)
	{
		lexer.process(source, this, filename);
		return lexer;
	}
	
	protected Parser parseTokensX(Parser parser, Token[] tokens, string filename, Lexer lexerUsed)
	{
		parser.process(tokens, this, filename, lexerUsed);
		return parser;
	}

	Lexer lexCodeX(string source, string filename="")
	{
		return lexCodeX(new Lexer(), source, filename);
	}
	
	Parser parseTokensX(Token[] tokens, string filename="", Lexer lexerUsed=null)
	{
		return parseTokensX(new Parser(), tokens, filename, lexerUsed);
	}

	Lexer lexFileX(string filename)
	{
		return lexCodeX(readUTFFile!string(filename), filename);
	}

	Parser parseFileX(string filename)
	{
		auto lexer = lexFileX(filename);
		return parseTokensX(lexer.tokens, filename, lexer);
	}

	Parser parseCodeX(string source, string filename="")
	{
		auto lexer = lexCodeX(source, filename);
		return parseTokensX(lexer.tokens, filename, lexer);
	}

	protected Symbol[] lookupSymbol(string symName)
	{
		if(symName in symbolLookup)
			return symbolLookup[symName];
		else
			return [];
	}

	Symbol[] symbolsByName(string name)
	{
		return lookupSymbol(name).dup;
	}
	
	SymbolType[] symbolTypesByName(string name)
	{
		return
			lookupSymbol(name).map(
				(Symbol sym) { return sym.type; }
			);
	}
	
	string symbolTypesStrByName(string name)
	{
		return symbolTypesByName(name).symbolTypesToString();
	}
	
	//TODO: This is just a quick-n-dirty implementation atm, probably runs slow
	int ruleIdOf(string parentSymbol, string[] subSymbols...)
	{
		void throwNoSuchRule()
		{
			throw new Exception("Rule does not exist: %s ::= %s".format(parentSymbol, subSymbols));
		}
		
		foreach(string symName; subSymbols)
		{
			if(isSymbolNameAmbiguous(symName))
				throw new Exception(
					"Symbol '%s' is ambiguous, it could be any of the following types: %s\nGoldie does not yet support disambiguation of symbol names at runtime."
						.format(symName, symbolTypesStrByName(symName))
				);
			
			if(!isSymbolNameValid(symName) && symName !is null)
				throwNoSuchRule();
		}
		
		foreach(int ruleId, Rule rule; ruleTable)
		{
			// Wrong parentSymbol?
			if(rule.symbolIndex != lookupSymbol(parentSymbol)[0].id)
				continue;
			
			// Is this token an empty rule?
			if(rule.subSymbolIndicies.length == 0)
			{
				// Can't require an explicit null for consistency with static-mode,
				// without requiring it be '[null]', because it'll get mistaken
				// for a string[] instead of a string.
				if((subSymbols.length == 1 && subSymbols[0] is null) || subSymbols.length == 0)
					return ruleId;
				else
					continue;
			}

			// Wrong subSymbols length?
			if(subSymbols.length != rule.subSymbolIndicies.length)
				continue;
			
			// Looking for empty rule?
			if(subSymbols.length == 1 && subSymbols[0] is null)
			{
				// Already checked if this token was empty, so no match:
				continue;
			}
			
			bool foundMatch = true;
			foreach(int i, int subSymbolIndex; rule.subSymbolIndicies)
			if(subSymbolIndex != lookupSymbol(subSymbols[i])[0].id)
			{
				foundMatch = false;
				break;
			}

			if(foundMatch)
				return ruleId;
		}

		throwNoSuchRule();
		assert(0);
	}
	
	string ruleToString(int ruleId)
	{
		auto rule = ruleTable[ruleId];
		string str = symbolTable[rule.symbolIndex].name;
		str ~= " ::=";
		foreach(subSymId; rule.subSymbolIndicies)
		{
			str ~= " ";
			str ~= symbolTable[subSymId].name;
		}
		return str;
	}

	string[] uniqueSymbolNames()
	{
		return symbolLookup.keys;
	}

	bool isSymbolNameValid(string name)
	{
		return lookupSymbol(name).length >= 1;
	}
	
	bool isSymbolNameAmbiguous(string name)
	{
		return lookupSymbol(name).length > 1;
	}

	@property Symbol eofSymbol()
	{
		return symbolTable[eofSymbolIndex];
	}

	@property Symbol errorSymbol()
	{
		return symbolTable[errorSymbolIndex];
	}

	static Language load(string cgtFilename)
	{
		return new Language(cgtFilename);
	}

	/// Use Language.load() instead
	deprecated static Language loadCGT(string filename)
	{
		return load(filename);
	}

	static if(true) // Workaround for DMD Issue #7386
	version(Goldie_IncludeGrmcLib)
	{
		static bool compileGrammarGoldCompatibility = false;

		static Language compileGrammarFile(string filename)
		{
			return compileGrammarFileImpl(filename, false, false);
		}

		static Language compileGrammar(string grammarDefinition, string filename="")
		{
			return compileGrammarImpl(grammarDefinition, false, filename);
		}

		static Language compileGrammarFileDebug(string filename, bool verbose=false)
		{
			return compileGrammarFileImpl(filename, true, verbose);
		}

		static Language compileGrammarDebug(string grammarDefinition, string filename="", bool verbose=false)
		{
			return compileGrammarImpl(grammarDefinition, true, filename, verbose);
		}

		private static Language compileGrammarFileImpl(string filename, bool keepDebugInfo, bool verbose)
		{
			return compileGrammarImpl(readUTFFile!string(filename), keepDebugInfo, filename, verbose);
		}

		private static Language compileGrammarImpl(string grammarDefinition, bool keepDebugInfo, string filename, bool verbose=false)
		{
			Parser parser;
			AST ast;
			try
			{
				{
					mixin(verboseSection!"Parsing grammar description");
					parser = language_grm.parseCodeX(grammarDefinition, filename);
				}

				scope(failure)
					if(ast) ast.writeErrorMsg();
					
				ast = new AST(parser, keepDebugInfo);
				ast.goldCompat = compileGrammarGoldCompatibility;
				ast.verbose = verbose;
				ast.genLanguage(parser.parseTreeX);
			}
			catch(ParseException e)
			{
				writeln(e.msg);
				return null;
			}

			ast.writeErrorMsg();
			
			if(ast.numErrors > 0)
				return null;
			
			//mixin(traceVal!("ast.lang.author"));
			//foreach(sym; ast.lang.symbolTable)
			//	mixin(traceVal!("sym"));

			return ast.lang;
		}
	}
}

version(Goldie_StaticStyle)
{
	import goldie.lang;
	
	package alias Language_calc ThisStaticLanguage;

	private enum _langInstanceName = "language_" ~ _shortPackageName;
	private enum _langClassName    = toLangIdent(Language.stringof, _shortPackageName);
	private enum _lexerClassName   = toLangIdent(Lexer   .stringof, _shortPackageName);
	private enum _parserClassName  = toLangIdent(Parser  .stringof, _shortPackageName);
	private enum _tokenClassName   = toLangIdent(Token   .stringof, _shortPackageName);

	mixin(`
		import `~_packageName~`.lexer;
		import `~_packageName~`.parser;
		import `~_packageName~`.langHelper;
		import `~_packageName~`.token;

		package alias `~_lexerClassName ~` ThisStaticLexer;
		package alias `~_parserClassName~` ThisStaticParser;
		package alias `~_tokenClassName ~` ThisStaticToken;

		`~_langClassName~` `~_langInstanceName~`;

		// This is a workaround for the cyclic dependency probelms in static constructors
		private extern(C) void `~_langInstanceName~`_staticCtor()
		{
			`~_langInstanceName~` = new `~_langClassName~`();
		}
	`);
}

// Static-style Language
version(Goldie_StaticStyle)
public class Language_calc : Language
{
	static enum staticName   = "Calc";
	static enum staticVer    = "0.01";
	static enum staticAuthor = "Nick Sabalausky";
	static enum staticAbout  = "Basic Calculator Grammar";
	static enum staticCaseSensitive = false;

	static enum staticStartSymbolIndex = 10;
	static enum staticInitialDFAState  = 0;
	static enum staticInitialLALRState = 0;
	static enum staticEofSymbolIndex   = 0;
	static enum staticErrorSymbolIndex = 1;

	private static enum _staticUniqueSymbolNameArray = [
		"(",
		")",
		"*",
		"+",
		"-",
		"/",
		"<Add Exp>",
		"<Mult Exp>",
		"<Negate Exp>",
		"<Value>",
		"EOF",
		"Error",
		"Number",
		"Whitespace",
	];

	private static enum _staticSymbolTable = [
		Symbol("EOF",SymbolType.EOF,0),
		Symbol("Error",SymbolType.Error,1),
		Symbol("Whitespace",SymbolType.Whitespace,2),
		Symbol("-",SymbolType.Terminal,3),
		Symbol("(",SymbolType.Terminal,4),
		Symbol(")",SymbolType.Terminal,5),
		Symbol("*",SymbolType.Terminal,6),
		Symbol("/",SymbolType.Terminal,7),
		Symbol("+",SymbolType.Terminal,8),
		Symbol("Number",SymbolType.Terminal,9),
		Symbol("<Add Exp>",SymbolType.NonTerminal,10),
		Symbol("<Mult Exp>",SymbolType.NonTerminal,11),
		Symbol("<Negate Exp>",SymbolType.NonTerminal,12),
		Symbol("<Value>",SymbolType.NonTerminal,13),
	];
	
	private static enum _staticCharSetTable = [
		CharSet([CharPair('\U00000009','\U0000000D'),CharPair('\U00000020','\U00000020'),CharPair('\U000000A0','\U000000A0')]),
		CharSet([CharPair('\U0000002D','\U0000002D')]),
		CharSet([CharPair('\U00000028','\U00000028')]),
		CharSet([CharPair('\U00000029','\U00000029')]),
		CharSet([CharPair('\U0000002A','\U0000002A')]),
		CharSet([CharPair('\U0000002F','\U0000002F')]),
		CharSet([CharPair('\U0000002B','\U0000002B')]),
		CharSet([CharPair('\U00000030','\U00000039')]),
	];
	
	private static enum _staticRuleTable = [
		Rule( 10, [10,8,11] ),
		Rule( 10, [10,3,11] ),
		Rule( 10, [11] ),
		Rule( 11, [11,6,12] ),
		Rule( 11, [11,7,12] ),
		Rule( 11, [12] ),
		Rule( 12, [3,13] ),
		Rule( 12, [13] ),
		Rule( 13, [9] ),
		Rule( 13, [4,10,5] ),
	];
	
	private static enum _staticDFATable = [
		DFAState( false, -1, [DFAStateEdge(0,1),DFAStateEdge(1,2),DFAStateEdge(2,3),DFAStateEdge(3,4),DFAStateEdge(4,5),DFAStateEdge(5,6),DFAStateEdge(6,7),DFAStateEdge(7,8)] ),
		DFAState( true, 2, [DFAStateEdge(0,1)] ),
		DFAState( true, 3, [] ),
		DFAState( true, 4, [] ),
		DFAState( true, 5, [] ),
		DFAState( true, 6, [] ),
		DFAState( true, 7, [] ),
		DFAState( true, 8, [] ),
		DFAState( true, 9, [DFAStateEdge(7,8)] ),
	];
	
	private static enum _staticLALRTable = [
		LALRState( [LALRAction(3,LALRAction.Type.Shift,1),LALRAction(4,LALRAction.Type.Shift,2),LALRAction(9,LALRAction.Type.Shift,3),LALRAction(10,LALRAction.Type.Goto,4),LALRAction(11,LALRAction.Type.Goto,5),LALRAction(12,LALRAction.Type.Goto,6),LALRAction(13,LALRAction.Type.Goto,7)] ),
		LALRState( [LALRAction(4,LALRAction.Type.Shift,2),LALRAction(9,LALRAction.Type.Shift,3),LALRAction(13,LALRAction.Type.Goto,8)] ),
		LALRState( [LALRAction(3,LALRAction.Type.Shift,1),LALRAction(4,LALRAction.Type.Shift,2),LALRAction(9,LALRAction.Type.Shift,3),LALRAction(10,LALRAction.Type.Goto,9),LALRAction(11,LALRAction.Type.Goto,5),LALRAction(12,LALRAction.Type.Goto,6),LALRAction(13,LALRAction.Type.Goto,7)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Reduce,8),LALRAction(3,LALRAction.Type.Reduce,8),LALRAction(5,LALRAction.Type.Reduce,8),LALRAction(6,LALRAction.Type.Reduce,8),LALRAction(7,LALRAction.Type.Reduce,8),LALRAction(8,LALRAction.Type.Reduce,8)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Accept,0),LALRAction(3,LALRAction.Type.Shift,10),LALRAction(8,LALRAction.Type.Shift,11)] ),
		LALRState( [LALRAction(6,LALRAction.Type.Shift,12),LALRAction(7,LALRAction.Type.Shift,13),LALRAction(0,LALRAction.Type.Reduce,2),LALRAction(3,LALRAction.Type.Reduce,2),LALRAction(5,LALRAction.Type.Reduce,2),LALRAction(8,LALRAction.Type.Reduce,2)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Reduce,5),LALRAction(3,LALRAction.Type.Reduce,5),LALRAction(5,LALRAction.Type.Reduce,5),LALRAction(6,LALRAction.Type.Reduce,5),LALRAction(7,LALRAction.Type.Reduce,5),LALRAction(8,LALRAction.Type.Reduce,5)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Reduce,7),LALRAction(3,LALRAction.Type.Reduce,7),LALRAction(5,LALRAction.Type.Reduce,7),LALRAction(6,LALRAction.Type.Reduce,7),LALRAction(7,LALRAction.Type.Reduce,7),LALRAction(8,LALRAction.Type.Reduce,7)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Reduce,6),LALRAction(3,LALRAction.Type.Reduce,6),LALRAction(5,LALRAction.Type.Reduce,6),LALRAction(6,LALRAction.Type.Reduce,6),LALRAction(7,LALRAction.Type.Reduce,6),LALRAction(8,LALRAction.Type.Reduce,6)] ),
		LALRState( [LALRAction(3,LALRAction.Type.Shift,10),LALRAction(5,LALRAction.Type.Shift,14),LALRAction(8,LALRAction.Type.Shift,11)] ),
		LALRState( [LALRAction(3,LALRAction.Type.Shift,1),LALRAction(4,LALRAction.Type.Shift,2),LALRAction(9,LALRAction.Type.Shift,3),LALRAction(11,LALRAction.Type.Goto,15),LALRAction(12,LALRAction.Type.Goto,6),LALRAction(13,LALRAction.Type.Goto,7)] ),
		LALRState( [LALRAction(3,LALRAction.Type.Shift,1),LALRAction(4,LALRAction.Type.Shift,2),LALRAction(9,LALRAction.Type.Shift,3),LALRAction(11,LALRAction.Type.Goto,16),LALRAction(12,LALRAction.Type.Goto,6),LALRAction(13,LALRAction.Type.Goto,7)] ),
		LALRState( [LALRAction(3,LALRAction.Type.Shift,1),LALRAction(4,LALRAction.Type.Shift,2),LALRAction(9,LALRAction.Type.Shift,3),LALRAction(12,LALRAction.Type.Goto,17),LALRAction(13,LALRAction.Type.Goto,7)] ),
		LALRState( [LALRAction(3,LALRAction.Type.Shift,1),LALRAction(4,LALRAction.Type.Shift,2),LALRAction(9,LALRAction.Type.Shift,3),LALRAction(12,LALRAction.Type.Goto,18),LALRAction(13,LALRAction.Type.Goto,7)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Reduce,9),LALRAction(3,LALRAction.Type.Reduce,9),LALRAction(5,LALRAction.Type.Reduce,9),LALRAction(6,LALRAction.Type.Reduce,9),LALRAction(7,LALRAction.Type.Reduce,9),LALRAction(8,LALRAction.Type.Reduce,9)] ),
		LALRState( [LALRAction(6,LALRAction.Type.Shift,12),LALRAction(7,LALRAction.Type.Shift,13),LALRAction(0,LALRAction.Type.Reduce,1),LALRAction(3,LALRAction.Type.Reduce,1),LALRAction(5,LALRAction.Type.Reduce,1),LALRAction(8,LALRAction.Type.Reduce,1)] ),
		LALRState( [LALRAction(6,LALRAction.Type.Shift,12),LALRAction(7,LALRAction.Type.Shift,13),LALRAction(0,LALRAction.Type.Reduce,0),LALRAction(3,LALRAction.Type.Reduce,0),LALRAction(5,LALRAction.Type.Reduce,0),LALRAction(8,LALRAction.Type.Reduce,0)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Reduce,3),LALRAction(3,LALRAction.Type.Reduce,3),LALRAction(5,LALRAction.Type.Reduce,3),LALRAction(6,LALRAction.Type.Reduce,3),LALRAction(7,LALRAction.Type.Reduce,3),LALRAction(8,LALRAction.Type.Reduce,3)] ),
		LALRState( [LALRAction(0,LALRAction.Type.Reduce,4),LALRAction(3,LALRAction.Type.Reduce,4),LALRAction(5,LALRAction.Type.Reduce,4),LALRAction(6,LALRAction.Type.Reduce,4),LALRAction(7,LALRAction.Type.Reduce,4),LALRAction(8,LALRAction.Type.Reduce,4)] ),
	];
	
	static immutable staticUniqueSymbolNameArray = _staticUniqueSymbolNameArray;
	static immutable staticSymbolTable  = _staticSymbolTable;
	static immutable staticCharSetTable = _staticCharSetTable;
	static immutable staticRuleTable    = _staticRuleTable;
	static immutable staticDFATable     = _staticDFATable;
	static immutable staticLALRTable    = _staticLALRTable;
	
	static enum packageName      = _packageName;
	static enum shortPackageName = _shortPackageName;
	static enum langInstanceName = _langInstanceName;
	static enum langClassName    = _langClassName;
	static enum lexerClassName   = _lexerClassName;
	static enum parserClassName  = _parserClassName;
	static enum tokenClassName   = _tokenClassName;

/+static private Language_calc _inst;
static @property Language_calc inst()
{
	if(!_inst)
		_inst = new Language_calc();
	return _inst;
}+/

	public this()
	{
		super();
		
		name   = staticName;
		ver    = staticVer;
		author = staticAuthor;
		about  = staticAbout;
		caseSensitive = staticCaseSensitive;

		startSymbolIndex = staticStartSymbolIndex;
		initialDFAState  = staticInitialDFAState;
		initialLALRState = staticInitialLALRState;
		eofSymbolIndex   = staticEofSymbolIndex;
		errorSymbolIndex = staticErrorSymbolIndex;

		symbolTable  = staticSymbolTable.dup;

		charSetTable = staticCharSetTable.goldieBaseDup();
		ruleTable    = staticRuleTable   .goldieBaseDup();
		dfaTable     = staticDFATable    .goldieBaseDup();
		lalrTable    = staticLALRTable   .goldieBaseDup();

		symbolLookup = [
				"("                  : [Symbol("(",SymbolType.Terminal,4)],
				")"                  : [Symbol(")",SymbolType.Terminal,5)],
				"*"                  : [Symbol("*",SymbolType.Terminal,6)],
				"+"                  : [Symbol("+",SymbolType.Terminal,8)],
				"-"                  : [Symbol("-",SymbolType.Terminal,3)],
				"/"                  : [Symbol("/",SymbolType.Terminal,7)],
				"<Add Exp>"          : [Symbol("<Add Exp>",SymbolType.NonTerminal,10)],
				"<Mult Exp>"         : [Symbol("<Mult Exp>",SymbolType.NonTerminal,11)],
				"<Negate Exp>"       : [Symbol("<Negate Exp>",SymbolType.NonTerminal,12)],
				"<Value>"            : [Symbol("<Value>",SymbolType.NonTerminal,13)],
				"EOF"                : [Symbol("EOF",SymbolType.EOF,0)],
				"Error"              : [Symbol("Error",SymbolType.Error,1)],
				"Number"             : [Symbol("Number",SymbolType.Terminal,9)],
				"Whitespace"         : [Symbol("Whitespace",SymbolType.Whitespace,2)]
			];
	}

	public ThisStaticLexer lexCode(string source, string filename="")
	{
		return cast(ThisStaticLexer)lexCodeX(source, filename);
	}
	
	public ThisStaticParser parseTokens(Token[] tokens, string filename="", Lexer lexerUsed=null)
	{
		return cast(ThisStaticParser)parseTokensX(tokens, filename, lexerUsed);
	}

	public ThisStaticLexer lexFile(string filename)
	{
		return cast(ThisStaticLexer)lexFileX(filename);
	}

	public ThisStaticParser parseFile(string filename)
	{
		return cast(ThisStaticParser)parseFileX(filename);
	}

	public ThisStaticParser parseCode(string source, string filename="")
	{
		return cast(ThisStaticParser)parseCodeX(source, filename);
	}

	override Lexer lexCodeX(string source, string filename="")
	{
		return super.lexCodeX(new ThisStaticLexer(), source, filename);
	}
	
	override Parser parseTokensX(Token[] tokens, string filename="", Lexer lexerUsed=null)
	{
		return super.parseTokensX(new ThisStaticParser(), tokens, filename, lexerUsed);
	}

	static bool staticIsSymbolNameValid(string name)
	{
		return staticLookupSymbol(name).length >= 1;
	}
	
	static bool staticIsSymbolNameAmbiguous(string name)
	{
		return staticLookupSymbol(name).length > 1;
	}

	static Symbol staticEofSymbol()
	{
		return staticSymbolTable[staticEofSymbolIndex];
	}

	static Symbol staticErrorSymbol()
	{
		return staticSymbolTable[staticErrorSymbolIndex];
	}
	
	override bool isSymbolNameValid(string name)
	{
		return typeof(this).staticIsSymbolNameValid(name);
	}
	
	override bool isSymbolNameAmbiguous(string name)
	{
		return typeof(this).staticIsSymbolNameAmbiguous(name);
	}
	
	override Symbol eofSymbol()
	{
		return typeof(this).staticEofSymbol();
	}
	
	override Symbol errorSymbol()
	{
		return typeof(this).staticErrorSymbol();
	}

	protected static Symbol[] staticLookupSymbol(string symName)
	{
		switch(symName)
		{
		case "(":                 return [Symbol("(",SymbolType.Terminal,4)];
			case ")":                 return [Symbol(")",SymbolType.Terminal,5)];
			case "*":                 return [Symbol("*",SymbolType.Terminal,6)];
			case "+":                 return [Symbol("+",SymbolType.Terminal,8)];
			case "-":                 return [Symbol("-",SymbolType.Terminal,3)];
			case "/":                 return [Symbol("/",SymbolType.Terminal,7)];
			case "<Add Exp>":         return [Symbol("<Add Exp>",SymbolType.NonTerminal,10)];
			case "<Mult Exp>":        return [Symbol("<Mult Exp>",SymbolType.NonTerminal,11)];
			case "<Negate Exp>":      return [Symbol("<Negate Exp>",SymbolType.NonTerminal,12)];
			case "<Value>":           return [Symbol("<Value>",SymbolType.NonTerminal,13)];
			case "EOF":               return [Symbol("EOF",SymbolType.EOF,0)];
			case "Error":             return [Symbol("Error",SymbolType.Error,1)];
			case "Number":            return [Symbol("Number",SymbolType.Terminal,9)];
			case "Whitespace":        return [Symbol("Whitespace",SymbolType.Whitespace,2)];
			default:
				return [];
		}
	}

	protected override Symbol[] lookupSymbol(string symName)
	{
		return typeof(this).staticLookupSymbol(symName);
	}
}
