using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Data; using log4net; using Axiom.Utils; // FileName : CodeRunner.cs // Author : Sean Kessler namespace Axiom.Interpreter { public class CodeRunner : IDisposable { private static ILog logger = LogManager.GetLogger(typeof(CodeRunner)); private SymbolTable symbolTable = null; private Dictionary precompiles = new Dictionary(); private bool useCache=false; private bool trace=false; private bool parseStrict=false; private bool scanStrict=false; private bool disposed = false; private int parseSymbolCount=0; public CodeRunner() { symbolTable=new SymbolTable(); IsInError=false; } ~CodeRunner() { Dispose(false); } public void Dispose() { if (!disposed) { Dispose(true); GC.SuppressFinalize(this); } } protected virtual void Dispose(bool disposing) { if(disposing) { List streams=new List(precompiles.Values); foreach(Stream stream in streams) { try{stream.Close();stream.Dispose();}catch(Exception){;} } } disposed = true; } public int ParseSymbolsCount { get{return parseSymbolCount;} } public String LastMessage{ get; private set;} public bool IsInError { get; private set;} public bool ScanStrict { get{return scanStrict;} set{scanStrict=value;} } public bool ParseStrict { get{return parseStrict;} set{parseStrict=value;} } public bool Trace { get {return trace;} set {trace=value;} } public bool UseCache { get { return useCache; } set { useCache = value; } } public String GetValue(String name) { if (!symbolTable.ContainsKey(name)) return "null"; Symbol symbol = symbolTable[name]; GenericData genericData = symbol.GenericData; if (null == genericData || genericData.IsNull()) return "null"; return genericData.Get(); } public T GetValue(String name) { if(!symbolTable.ContainsKey(name)) return default(T); Symbol symbol=symbolTable[name]; GenericData genericData=symbol.GenericData; if(null==genericData||genericData.IsNull()) return default(T); return genericData.Get(); } public SymbolTable SymbolTable { get {return symbolTable;} } public void Reset() { if (null == symbolTable) return; symbolTable.Reset(); } public bool Execute(DataTable dataTable, int row, String expression) { Reset(); return ExecuteExpressionOnRow(dataTable, row, expression); } private bool ExecuteExpressionOnRow(DataTable dataTable, int row, String expression) { symbolTable.AddUserSymbols(dataTable); // add symbol names from the data table columns symbolTable.AddUserValues(dataTable.Rows[row], dataTable); if (UseCache) { if (!ApplyRuleWithCache(expression)) return false; } else { if (!Execute(expression))return false; } return true; } /// /// Execute - Executes the given expression. You can then use the helper methods. /// GetValue(String), GetValue(String) to retrieve resulting variables from the symbolTable /// /// /// public bool Execute(String expression) { BinaryReader binaryReader = null; BinaryWriter binaryWriter = null; BinaryReader parserReader = null; BinaryWriter parserWriter = null; BinaryReader assemblerReader = null; Assembler assembler = null; try { IsInError=false; LastMessage=""; binaryReader = new BinaryReader(Utility.StreamFromString(expression)); binaryWriter = new BinaryWriter(new MemoryStream()); Scanner scanner = new Scanner(binaryReader, binaryWriter, symbolTable); scanner.Debug = Trace; if (!scanner.Analyze()) { LastMessage="Failed to scan the input document, possible invalid character sequence."; IsInError=true; logger.ErrorFormat(LastMessage); return false; } binaryWriter.BaseStream.Seek(0, SeekOrigin.Begin); parserReader = new BinaryReader(binaryWriter.BaseStream); parserWriter = new BinaryWriter(new MemoryStream()); Parser parser = new Parser(parserReader, parserWriter, symbolTable); parser.Debug = Trace; parser.Parse(); parseSymbolCount=parser.ParseSymbolsCount; if (parser.IsInError) { LastMessage=String.Format("Failed to parse the input, {0} at {1}", parser.LastMessage, parser.LastLineNumber); IsInError=true; logger.ErrorFormat(LastMessage); return false; } parserWriter.BaseStream.Seek(0, SeekOrigin.Begin); // SEEK TO THE BEGINNING OF THE CODE assemblerReader = new BinaryReader(parserWriter.BaseStream); assembler = new Assembler(assemblerReader, symbolTable); assembler.Debug = Trace; assembler.Assemble(); if(assembler.IsInError) { LastMessage=String.Format("Error: Failed to run the assembler, {0}", assembler.LastMessage); IsInError=true; logger.ErrorFormat(LastMessage); return false; } if (Trace) DumpSymbolTable(); assembler.Dispose(); assembler = null; return true; } catch (Exception exception) { LastMessage=String.Format("Exception:{0}",exception.ToString()); IsInError=true; logger.ErrorFormat(LastMessage); return false; } finally { if (null != binaryReader) { binaryReader.Close();binaryReader.Dispose(); } if (null != binaryWriter) { binaryWriter.Close();binaryWriter.Dispose(); } if (null != parserReader) { parserReader.Close();parserReader.Dispose(); } if (null != parserWriter) { parserWriter.Close(); parserWriter.Dispose(); } if (null != assemblerReader) { assemblerReader.Close(); assemblerReader.Dispose(); } if (null != assembler) { assembler.Dispose();assembler = null; } } } /// /// Disassemble - This method does not execute code. It scans, parses, and disassembles the geenrated bytecode /// /// /// public List Disassemble(String expression) { BinaryReader binaryReader = null; BinaryWriter binaryWriter = null; BinaryReader parserReader = null; BinaryWriter parserWriter = null; BinaryReader assemblerReader = null; Assembler assembler = null; List disassembly=new List(); try { IsInError=false; LastMessage=""; SymbolTable localSymbolTable = new SymbolTable(); binaryReader = new BinaryReader(Utility.StreamFromString(expression)); binaryWriter = new BinaryWriter(new MemoryStream()); Scanner scanner = new Scanner(binaryReader, binaryWriter, localSymbolTable); scanner.Debug = Trace; if (!scanner.Analyze()) { LastMessage="Failed to scan the input document, possible invalid character sequence."; IsInError=true; logger.ErrorFormat(LastMessage); return disassembly; } binaryWriter.BaseStream.Seek(0, SeekOrigin.Begin); parserReader = new BinaryReader(binaryWriter.BaseStream); parserWriter = new BinaryWriter(new MemoryStream()); Parser parser = new Parser(parserReader, parserWriter, localSymbolTable); parser.Debug = Trace; parser.Parse(); parseSymbolCount=parser.ParseSymbolsCount; if (parser.IsInError) { LastMessage=String.Format("Failed to parse the input, {0} at {1}", parser.LastMessage, parser.LastLineNumber); IsInError=true; logger.ErrorFormat(LastMessage); return disassembly; } parserWriter.BaseStream.Seek(0, SeekOrigin.Begin); assemblerReader = new BinaryReader(parserWriter.BaseStream); assembler = new Assembler(assemblerReader, localSymbolTable); assembler.Debug = Trace; return assembler.Disassemble(); } catch (Exception exception) { LastMessage=String.Format("Exception:{0}",exception.ToString()); IsInError=true; logger.ErrorFormat(LastMessage); return disassembly; } finally { if (null != binaryReader) { binaryReader.Close();binaryReader.Dispose(); } if (null != binaryWriter) { binaryWriter.Close();binaryWriter.Dispose(); } if (null != parserReader) { parserReader.Close();parserReader.Dispose(); } if (null != parserWriter) { parserWriter.Close(); parserWriter.Dispose(); } if (null != assemblerReader) { assemblerReader.Close(); assemblerReader.Dispose(); } if (null != assembler) { assembler.Dispose();assembler = null; } } } // The cache will not work as effectively if the expression variables are not loaded directly into the SymbolTable public bool ApplyRuleWithCache(String expression) { BinaryReader assemblerReader = null; Stream precompiledStream = null; Assembler assembler = null; try { int hashcode = expression.GetHashCode(); if (Trace) logger.InfoFormat("Trace:{0}", expression); if (precompiles.ContainsKey(hashcode)) { precompiledStream = precompiles[hashcode]; // if the precompiled cache contains the expression then fetch it } else { precompiledStream = Compile(expression,true); // otherwise compile the expression and add it to the cache. precompiles.Add(hashcode, precompiledStream); } if (null == precompiledStream) return false; precompiledStream.Seek(0, SeekOrigin.Begin); assemblerReader = new BinaryReader(precompiledStream); assembler = new Assembler(assemblerReader, symbolTable); assembler.Assemble(); if(assembler.IsInError) { LastMessage=String.Format("Error: Failed to run the assembler, {0}", assembler.LastMessage); logger.ErrorFormat(LastMessage); return false; } assembler.Dispose(); assembler = null; return true; } catch (Exception exception) { LastMessage=String.Format("Exception:{0}", exception.ToString()); logger.ErrorFormat(LastMessage); return false; } finally { if (null != assembler) { assembler.Dispose(); } } } public AxiomResult SyntaxCheck(String expression) { BinaryReader binaryReader = null; BinaryWriter binaryWriter = null; BinaryReader parserReader = null; BinaryWriter parserWriter = null; AxiomResult axiomResult = new AxiomResult(); try { axiomResult.Success = true; binaryWriter = new BinaryWriter(new MemoryStream()); binaryReader = new BinaryReader(Utility.StreamFromString(expression)); Scanner scanner = new Scanner(binaryReader, binaryWriter, symbolTable); if (!scanner.Analyze()) { axiomResult.Success = false; axiomResult.LastMessage = "Failed to scan the input document, possible invalid character sequence."; return axiomResult; } binaryWriter.BaseStream.Seek(0, SeekOrigin.Begin); parserReader = new BinaryReader(binaryWriter.BaseStream); parserWriter = new BinaryWriter(new MemoryStream()); Parser parser = new Parser(parserReader, parserWriter, symbolTable); // parser.StrictMode=false; // we do not require all variable declarations to be present. parser.StrictStatementMode=true; // we require at least one valid statement to be processed. parser.Parse(); if (parser.IsInError) { axiomResult.Success = false; axiomResult.LastMessage = "Message:" + parser.LastMessage; return axiomResult; } return axiomResult; } catch (Exception exception) { axiomResult.LastMessage = String.Format("Exception:{0}", exception.ToString()); logger.Error(axiomResult.LastMessage); return axiomResult; } finally { if (null != binaryReader) { binaryReader.Close(); binaryReader.Dispose(); } if (null != binaryWriter) { binaryWriter.Close(); binaryWriter.Dispose(); } if (null != parserReader) { parserReader.Close(); parserReader.Dispose(); } if (null != parserWriter) { parserWriter.Close(); parserWriter.Dispose(); } } } private Stream Compile(String expression, bool includeCodeEnd = true) { BinaryReader binaryReader = null; BinaryWriter binaryWriter = null; BinaryReader parserReader = null; BinaryWriter parserWriter = null; try { binaryReader = new BinaryReader(Utility.StreamFromString(expression)); binaryWriter = new BinaryWriter(new MemoryStream()); Scanner scanner = new Scanner(binaryReader, binaryWriter, symbolTable); scanner.Debug = Trace; if(!scanner.Analyze()) { LastMessage = "Failed to scan the input document, possible invalid character sequence"; logger.Info(LastMessage); return null; } binaryReader.Close(); binaryReader.Dispose(); binaryWriter.BaseStream.Seek(0, SeekOrigin.Begin); parserReader = new BinaryReader(binaryWriter.BaseStream); parserWriter = new BinaryWriter(new MemoryStream()); Parser parser = new Parser(parserReader, parserWriter, symbolTable); parser.Debug = Trace; parser.Parse(includeCodeEnd); if (parser.IsInError) { LastMessage = String.Format("Error:{0} at {1}", parser.LastMessage, parser.LastLineNumber); logger.Info(LastMessage); return null; } parserReader.Close(); parserReader.Dispose(); parserReader = null; binaryWriter.Close(); binaryWriter.Dispose(); binaryWriter = null; parserWriter.BaseStream.Seek(0, SeekOrigin.Begin); return parserWriter.BaseStream; } catch (Exception exception) { logger.ErrorFormat("Exception:{0}", exception.ToString()); return null; } finally { if (null != binaryReader) { binaryReader.Close(); binaryReader.Dispose(); } if (null != binaryWriter) { binaryWriter.Close(); binaryWriter.Dispose(); } if (null != parserReader) { parserReader.Close();parserReader.Dispose(); } } } private void DumpSymbolTable() { logger.Info("********************************************************* O U T P U T ************************************************"); List list = new List(symbolTable.Values); // list = (from Symbol symbol in list where symbol.TypeOfSymbol.Equals(Symbol.SymbolType.UserSymbol) select symbol).ToList(); foreach (Symbol symbol in list) { logger.Info(String.Format("SYMBOL NAME:'{0}',VALUE:'{1}'", symbol.SymbolName, null == symbol.GenericData ? "" : symbol.GenericData.ToString())); } } } }