/* * Created by SharpDevelop.GetType * User: Ryan * Date: 8/17/2017 * Time: 11:54 AM * * To change this template use Tools | Options | Coding | Edit Standard Headers. */ using System; using System.IO; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Reflection; using parseManager; using NCalc; namespace parseManager { /// /// Description of ParseManager. /// public class parseManager { standardDefine _invoke = new standardDefine(); string _filepath; bool _active = true; string _define; string _entry = "START"; Type _defineType; MethodInfo _defineMethod; object _defineClassObject; chunk _currentChunk; chunk _lastChunk = null; readonly ENV _mainENV = new ENV(); public ENV _defualtENV; Dictionary _flags = new Dictionary(); Dictionary _chunks = new Dictionary(); Dictionary _methods = new Dictionary(); public parseManager(string filepath) { InitFlags(); _filepath = filepath; _defineType = Type.GetType("standardDefine"); ConstructorInfo defineConstructor = _defineType.GetConstructor(Type.EmptyTypes); _defineClassObject = defineConstructor.Invoke(new object[]{ }); _defualtENV = _mainENV; Parse(); } public parseManager(string filepath, string define) { InitFlags(); _define = define; _filepath = filepath; _defineType = Type.GetType(define); ConstructorInfo defineConstructor = _defineType.GetConstructor(Type.EmptyTypes); _defineClassObject = defineConstructor.Invoke(new object[]{ }); _defualtENV = _mainENV; Parse(); } void InitFlags() { _flags.Add("leaking", false); _flags.Add("forseelabels", true); _flags.Add("debugging", false); _flags.Add("topdown", true); } public bool GetFlag(string flag) { bool f; if (_flags.TryGetValue(flag, out f)) { return f; } return false; } void debug(object msg) { if (_flags["debugging"]) Console.WriteLine(msg); } void _Parse(string data) { foreach (Match m in Regex.Matches(data, @"LOAD ([a-zA-Z0-9_\./]+)")) { Parse(m.Groups[1].ToString()); } foreach (Match m in Regex.Matches(data, @"ENABLE ([a-zA-Z0-9_\./]+)")) { _flags[m.Groups[1].ToString()] = true; } foreach (Match m in Regex.Matches(data, @"ENTRY ([a-zA-Z0-9_\./]+)")) { _entry = m.Groups[1].ToString(); } var match = Regex.Matches(data, @"\[(.+)\][\r\n]*?\{([^\0]+?)\}"); var count = 0; foreach (Match m in match) { string Blck = m.Groups[1].ToString(); string Cont = m.Groups[2].ToString(); int loc = Blck.IndexOf(":", StringComparison.Ordinal); if (loc != -1) { _chunks[Blck.Substring(0, loc)] = new chunk(Blck.Substring(0, loc), Cont, Blck.Substring(loc + 1)); Blck = Blck.Substring(0, loc); } else { _chunks[Blck] = new chunk(Blck, Cont); } count++; if (_lastChunk != null) _lastChunk.SetNextChunk(_chunks[Blck]); _lastChunk = _chunks[Blck]; } } void Parse() { try { StreamReader sr = File.OpenText(_filepath); _Parse(sr.ReadToEnd()); } catch (FileNotFoundException) { Console.WriteLine("File '" + _filepath + "' does not exist! Loading failled!"); } } void Parse(string filename) { try { StreamReader sr = File.OpenText(filename); _Parse(sr.ReadToEnd()); } catch (FileNotFoundException) { Console.WriteLine("Load '" + filename + "' File not found. Loading failled!"); } } public void ParseCode(string code) { _Parse(code); } public chunk[] GetChunks() { var chunks = _chunks.Values; var temp = new chunk[_chunks.Count]; var i = 0; foreach (var item in _chunks) { temp[i] = item.Value; i++; } return temp; } public chunk GetCurrentChunk() { return _currentChunk; } public void Deactivate() { _active = false; } public object InvokeR(string method, object[] args) { //try{ _defineMethod = _defineType.GetMethod(method); return _defineMethod.Invoke(_defineClassObject, args); // } catch { // PushError("Invalid method: "+method); // return null; // } } public int InvokeNR(string method, object[] args) { try { _defineMethod = _defineType.GetMethod(method); _defineMethod.Invoke(_defineClassObject, args); return 0; } catch { PushError("Invalid method: " + method); } return -1; } public void SetBlock(string BLOCK) { chunk cchunk; if (_chunks.TryGetValue(BLOCK, out cchunk)) { _currentChunk = cchunk; _currentChunk.ResetPos(); } else { PushError("Attempt to JUMP to a non existing block!"); } } public ENV GetENV() { return _defualtENV; } public void SetENV() { _defualtENV = _mainENV; } public void SetENV(ENV o) { _defualtENV = o; } public void SetBlock(chunk BLOCK) { _currentChunk = BLOCK; } public void SetBlock() { chunk cchunk; if (_chunks.TryGetValue(_entry, out cchunk)) { _currentChunk = cchunk; _currentChunk.ResetPos(); } else { PushError("Entrypoint is Invalid!"); } } public void PushError(string err) { Console.WriteLine(err); Deactivate(); } public nextType Next(string BLOCK) { if (_currentChunk == null) { SetBlock(BLOCK); } return Next(); } public nextType Next() { GLOBALS.SetPM(this); var tempReturn = new nextType(); if (_currentChunk == null) { SetBlock(); } var cCMD = _currentChunk.GetCLine(); object[] stuff; if (cCMD == null) { if (_flags["leaking"] && _active) { var test = _currentChunk.GetNextChunk(); if (test != null) { SetBlock(_currentChunk.GetNextChunk()); return Next(); } } tempReturn.SetCMDType("EOF"); tempReturn.SetText("Reached the end of the file!"); return tempReturn; } var type = cCMD.GetCMDType(); stuff = cCMD.GetArgs(); if (type == "LOGIC") {//{conds,andors,_funcif,_resultif,_funcelse,_resultelse} var conds = (string[])stuff[0]; var andors = (string[])stuff[1]; var funcif = (string)stuff[2]; var argsif = (string[])stuff[3]; var funcelse = (string)stuff[4]; var argselse = (string[])stuff[5]; var objs = new object[conds.Length]; // contain the actual values of what is in the env var truths = new bool[conds.Length / 3]; var c = 0; for (int i = 0; i < conds.Length; i += 3) { var condA = (object)ResolveVar(new []{ conds[i] })[0]; var e = conds[i + 1]; var condB = (object)ResolveVar(new []{ conds[i + 2] })[0]; if (e == "==") { truths[c] = condA.ToString() == condB.ToString(); } else if (e == ">=") { truths[c] = (double)condA >= (double)condB; } else if (e == "<=") { truths[c] = (double)condA <= (double)condB; } else if (e == "!=" || e == "~=") { truths[c] = condA.ToString() != condB.ToString(); } else if (e == ">") { truths[c] = (double)condA > (double)condB; } else if (e == "<") { truths[c] = (double)condA < (double)condB; } else { PushError("Invalid conditional test! " + e + " is not valid!"); } c++; } var truth = truths[0]; if (truths.Length == 1 && truth) { InvokeNR(funcif, ResolveVar(argsif)); } else if (truths.Length == 1) { InvokeNR(funcelse, ResolveVar(argselse)); } else { for (int i = 1; i < andors.Length; i++) { if (andors[i - 1] == "a") { truth = truth && truths[i]; } else if (andors[i - 1] == "o") { truth = truth || truths[i]; } else { PushError("Invalid conditional test! " + andors[i - 1] + " is not valid!"); } } if (truth) { Console.WriteLine(funcif); InvokeNR(funcif, ResolveVar(argsif)); } else { Console.WriteLine("|" + funcelse + "|"); InvokeNR(funcelse, ResolveVar(argselse)); } } tempReturn.SetCMDType("conditional"); tempReturn.SetText("test turned out to be: " + truth); } else if (type == "LABEL") { cCMD = _currentChunk.GetCLine(); if (cCMD == null) { if (_flags["leaking"] && _active) { SetBlock(_currentChunk.GetNextChunk()); return Next(); } tempReturn.SetCMDType("EOF"); tempReturn.SetText("Reached the end of the file!"); return tempReturn; } type = cCMD.GetCMDType(); stuff = cCMD.GetArgs(); } if (type == "FUNC") { var func = (string)stuff[0]; var args = (string[])stuff[1]; if (args.Length == 1 && args[0] == "") { // assume no args inserted! InvokeNR(func, new object[]{ }); } else { InvokeNR(func, ResolveVar(args)); } tempReturn.SetCMDType("method"); tempReturn.SetText("INVOKED METHOD: " + func); } else if (type == "LINE") { tempReturn.SetCMDType("line"); tempReturn.SetText(parseHeader((string)stuff[0])); } else if (type == "FUNC_R") { var retargs = (string[])stuff[0]; var func = (string)stuff[1]; var args = (string[])stuff[2]; object data; if (args.Length == 1 && args[0] == "") { // assume no args inserted! data = InvokeR(func, new object[]{ }); } else { data = InvokeR(func, ResolveVar(args)); } var env = GetENV(); env[retargs[0]] = data; GLOBALS.Add_Var(retargs[0]); tempReturn.SetCMDType("method"); tempReturn.SetText("INVOKED METHOD: " + func); } else if (type == "ASSIGN") { // TODO add lists/dictonaries support var vars = (string[])stuff[0]; var vals = (string[])stuff[1]; var env = GetENV(); var types = ResolveVar(vals); for (int i = 0; i < types.Length; i++) { env[vars[i]] = types[i]; GLOBALS.Add_Var(vars[i]); } tempReturn.SetCMDType("assignment"); tempReturn.SetText(_currentChunk.GetLine()); } return tempReturn; } public string parseHeader(string header) { var results = Regex.Matches(header, @"(\$.*?\$)"); int len = results.Count; string str; object temp; for (int i = 0; i < len; i++) { str = results[i].ToString(); if (isVar(str.Substring(1, str.Length - 2), out temp)) { header = header.Replace(results[i].ToString(), temp.ToString()); } else { header = header.Replace(results[i].ToString(), "null"); } } return header; } public object[] ResolveVar(string[] v) { //_defualtENV var len = v.Length; var args = new object[len]; object val; double num; bool boo; for (int i = 0; i < len; i++) { if (isVar(v[i], out val)) { args[i] = val; } else if (double.TryParse(v[i], out num)) { args[i] = num; debug("NUMBER: " + num); } else if (v[i][0] == '"' && v[i][v[i].Length - 1] == '"') { args[i] = parseHeader(v[i].Substring(1, v[i].Length - 2)); debug("STRING: " + args[i]); } else if (bool.TryParse(v[i], out boo)) { args[i] = boo; debug("BOOL: " + boo); } else { args[i] = null; } } return args; } public bool isVar(string val, out object v) { if (_defualtENV[val] != null) { v = _defualtENV[val]; return true; } v = null; return false; } } /* * Helper Classes */ public class chunk { string _BLOCK; string _type; string _pureType; string[] _lines; Dictionary _labels = new Dictionary(); List _compiledlines = new List(); int _pos = 0; chunk _next = null; void _clean(string cont) { var m = Regex.Match(_type, @"([a-zA-Z0-9_]+)"); _pureType = m.Groups[1].ToString(); var tCont = Regex.Replace(cont, @"\-\-\[\[[\S\s]+\]\]", "", RegexOptions.Multiline); tCont = Regex.Replace(tCont, @"\-\-.+\r\n", "", RegexOptions.Multiline); tCont = Regex.Replace(tCont, @"\-\-.+\n", "", RegexOptions.Multiline); tCont = Regex.Replace(tCont, @"\t", "", RegexOptions.Multiline); tCont = Regex.Replace(tCont, @"\n\n", "", RegexOptions.Multiline); tCont = Regex.Replace(tCont, @"\r\n\r\n", "", RegexOptions.Multiline); tCont = Regex.Replace(tCont, @"\-\-\[\[[\S\s]+\]\]", "", RegexOptions.Multiline); tCont = Regex.Replace(tCont, @"^\s+$[\r\n]*", "", RegexOptions.Multiline); _lines = tCont.Split(new [] { "\r\n", "\n" }, StringSplitOptions.None); compile(); // compiles the code into something that can be used quickly } void compile() { string temp; for (int i = 0; i < _lines.Length - 1; i++) { temp = _lines[i]; var pureLine = Regex.Match(temp, "^\"(.+)\""); var assignment = Regex.Match(temp, "^([a-zA-Z0-9_,\\[\\]\"]+)=([a-zA-Z\\|&\\^\\+\\-\\*/%0-9_\",\\[\\]]+)"); if (assignment.ToString() != "") { // TODO fix mess! or write own number calculator var expression = new Expression(assignment.Groups[2].Value); if (!expression.HasErrors()) { temp=assignment.Groups[1].Value+"=CALC(\""+assignment.Groups[2]+"\")"; } } var FuncWReturn = Regex.Match(temp, "([\\[\\]\"a-zA-Z0-9_,]+)\\s?=\\s?([a-zA-Z0-9_]+)\\s?\\((.*)\\)"); var FuncWOReturn = Regex.Match(temp, @"^([a-zA-Z0-9_]+)\s?\((.*)\)"); var label = Regex.Match(temp, "::(.*)::"); var logic = Regex.Match(temp, @"if\s*(.+)\s*then\s*(.+?\))\s*\|\s*(.+?\))"); if (logic.ToString() != "") { var condition = logic.Groups[1].ToString(); var tempif = logic.Groups[2].ToString(); var tempelse = logic.Groups[3].ToString(); var argsif = Regex.Match(tempif, @"^([a-zA-Z0-9_]+)\s?\((.*)\)"); var argselse = Regex.Match(tempelse, @"^([a-zA-Z0-9_]+)\s?\((.*)\)"); string _funcif = (argsif.Groups[1]).ToString(); var _argsif = (argsif.Groups[2]).ToString(); string[] _resultif = Regex.Split(_argsif, ",(?=(?:[^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); //Console.WriteLine(string.Join(",",_resultif)); string _funcelse = (argselse.Groups[1]).ToString(); var _argselse = (argselse.Groups[2]).ToString(); string[] _resultelse = Regex.Split(_argselse, ",(?=(?:[^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); //Console.WriteLine(string.Join(",",_resultelse)); var mm = Regex.Matches(condition, "(.+?)([and ]+?[or ]+)"); var conds = new string[(mm.Count + 1) * 3]; var andors = new string[mm.Count]; var count = 0; var p = 0; var p2 = 0; foreach (Match m in mm) { var s1 = m.Groups[1].ToString(); var s1p = Regex.Match(s1, "(.+?)([~!><=]+)+(.+)"); var s1a = s1p.Groups[1].ToString(); var s1b = s1p.Groups[2].ToString(); var s1c = s1p.Groups[3].ToString(); var s2 = m.Groups[2].ToString(); conds[p++] = s1a; conds[p++] = s1b; conds[p++] = s1c; andors[p2++] = s2.Substring(1, 1); count += s1.Length + s2.Length; } var s1p2 = Regex.Match(condition.Substring(count, condition.Length - count - 1), "(.+?)([~!><=]+)+(.+)"); var s1a2 = s1p2.Groups[1].ToString(); var s1b2 = s1p2.Groups[2].ToString(); var s1c2 = s1p2.Groups[3].ToString(); //Console.WriteLine(s1a2+"|"+s1b2+"|"+s1c2); conds[p++] = s1a2; conds[p++] = s1b2; conds[p++] = s1c2; _compiledlines.Add(new CMD("LOGIC", new object[] { conds, andors, _funcif, _resultif, _funcelse, _resultelse })); } else if (label.ToString() != "") { _labels[label.Groups[1].ToString()] = i; _compiledlines.Add(new CMD("LABEL", new object[]{ })); } else if (FuncWReturn.ToString() != "") { var var1 = (FuncWReturn.Groups[1]).ToString(); var func = (FuncWReturn.Groups[2]).ToString(); var args = (FuncWReturn.Groups[3]).ToString(); var retargs = var1.Split(','); var result = Regex.Split(args, ",(?=(?:[^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); _compiledlines.Add(new CMD("FUNC_R", new object[] { retargs, func, result })); } else if (FuncWOReturn.ToString() != "") { var func = (FuncWOReturn.Groups[1]).ToString(); var args = (FuncWOReturn.Groups[2]).ToString(); var result = Regex.Split(args, ",(?=(?:[^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); _compiledlines.Add(new CMD("FUNC", new object[]{ func, result })); } else if (pureLine.ToString() != "") { _compiledlines.Add(new CMD("LINE", new object[]{ pureLine.ToString() })); } else if (assignment.ToString() != "") { var vars = Regex.Split(assignment.Groups[1].ToString(), ",(?=(?:[^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); var vals = Regex.Split(assignment.Groups[2].ToString(), ",(?=(?:[^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); _compiledlines.Add(new CMD("ASSIGN", new object[]{ vars, vals })); } else { _compiledlines.Add(new CMD("UNKNOWN", new object[]{ })); } } } public chunk(string name, string cont, string type) { _BLOCK = name; _type = type; _clean(cont); } public chunk(string name, string cont) { _BLOCK = name; _type = "CODEBLOCK"; _clean(cont); } public string GetName() { return _BLOCK; } public int GetLabel(string lab) { return _labels[lab]; } public bool TryGetLabel(string lab, out int pos) { int p; if (_labels.TryGetValue(lab, out p)) { pos = p; return true; } pos = -1; return false; } public void RemoveNextChunk() { _next = null; } public void SetNextChunk(chunk next) { _next = next; } public chunk GetNextChunk() { return _next; } public chunk SetNextChunk() { return _next; } public string[] GetLines() { return _lines; } public string GetLine() { string temp = _lines[_pos]; if (_pos == _lines.Length) { return null; } return temp; } public CMD GetCLine() { if (_pos < _compiledlines.Count) { return _compiledlines[_pos++]; } return null; } public int GetPos() { return _pos; } public void SetPos(int n) { _pos = n; } public void ResetPos() { _pos = 0; } public string GetChunkPType() { return _pureType; } public string GetChunkType() { return _type; } } public class ENV { ENV _Parent; Dictionary _vars = new Dictionary(); void SetParent(ENV other) { _Parent = other; } public bool TryGetValue(string ind, out object obj) { if (this[ind] != null) { obj = this[ind]; return true; } obj = null; return false; } public object this[string ind] { get { object obj; if (_vars.TryGetValue(ind, out obj)) { return obj; } if (_Parent != null) { return _Parent[ind]; } else { return null; } } set { _vars[ind] = value; } } } public class PList { readonly Dictionary _vars = new Dictionary(); public bool TryGetValue(int ind, out object obj) { if (this[ind] != null) { obj = this[ind]; return true; } obj = null; return false; } public object this[int ind] { get { object obj; if (_vars.TryGetValue(ind, out obj)) { return obj; } return null; } set { _vars[ind] = value; } } } public class nextType { string _type; string _text; Dictionary _other = new Dictionary(); public nextType() { _type = "UNSET"; } public nextType(string type) { _type = type; } public string GetCMDType() { return _type; } public void SetText(string text) { _text = text; } public void SetCMDType(string type) { _type = type; } public string GetText() { return _text; } public object GetData(string name) { return _other[name]; } public void AddData(string varname, object data) { _other[varname] = data; } } public class CMD { string _type; object[] _args; public CMD(string type, object[] args) { _type = type; _args = args; } public string GetCMDType() { return _type; } public object[] GetArgs() { return _args; } } /* * The Standard Methods! */ static class GLOBALS { static standardDefine _define = new standardDefine(); static parseManager _current; static readonly ENV _env = new ENV(); static List _numvars = new List(); public static object GetData(string ind) { return _env[ind]; } public static standardDefine GetDefine() { return _define; } public static void AddData(string ind, object data) { _env[ind] = data; } public static void SetPM(parseManager o) { _current = o; } public static parseManager GetPM() { return _current; } public static void Add_Var(string var) { if (!_numvars.Contains(var)) { _numvars.Add(var); } } public static void Remove_Var(string var) { _numvars.Remove(var); } public static string[] GetVars() { return _numvars.ToArray(); } } } public class standardDefine { public void EXIT() { GLOBALS.GetPM().Deactivate(); } public void QUIT() { Environment.Exit(0); } public int GOTO(string label) { var test = GLOBALS.GetPM(); var c = test.GetCurrentChunk(); int pos; if (c.TryGetLabel(label, out pos)) { c.SetPos(pos); return 0; } else if (test.GetFlag("forseelabels")) { var chunks = test.GetChunks(); for (int i = 0; i < chunks.Length; i++) { if (chunks[i].TryGetLabel(label, out pos)) { test.SetBlock(chunks[i].GetName()); chunks[i].SetPos(pos); return 0; } } } test.PushError("Unable to GOTO a non existing label: " + label + "!"); return 0; } public void JUMP(string block) { var test = GLOBALS.GetPM(); var c = test.GetCurrentChunk(); c.ResetPos(); test.SetBlock(block); } public void SKIP(double n) { var test = GLOBALS.GetPM(); var c = test.GetCurrentChunk(); var pos = c.GetPos(); c.SetPos(pos + (int)n); } public double ADD(double a, double b) { return a + b; } public double SUB(double a, double b) { return a - b; } public double MUL(double a, double b) { return a * b; } public double DIV(double a, double b) { return a / b; } public double MOD(double a, double b) { return a % b; } public double CALC(string ex) { try { Expression e = new Expression(ex); var vars = GLOBALS.GetVars(); var PM = GLOBALS.GetPM(); var env = PM.GetENV(); for (int i = 0; i < vars.Length; i++) { if (env[vars[i]].GetType().ToString().Contains("Double")) e.Parameters[vars[i]] = (double)env[vars[i]]; } return double.Parse(e.Evaluate().ToString()); } catch { GLOBALS.GetPM().PushError("Invalid Expression: "+ex); return double.NaN; } } }