private void Level12Assign() { Level11Or(); // get left value if (sp.IsCharMoveOn('=')) { if (SetSymbolValue == null) { value = new StringParser.ConvertError("= operator not supported"); } else { StringParser.ConvertError err = value as StringParser.ConvertError; string symbolname; if (unaryentrytimes == 1 && lvaluename != null) // if 1 entry to unary, and symbol value is set, its a current value { symbolname = lvaluename; } else { // else its an equal without an error but not a symbol, so its not an lvalue value = new StringParser.ConvertError("Lvalue required for = operator"); return; } Evaluate(false, false); // get next expression if (!InError) { value = SetSymbolValue(symbolname, value); } } } }
// for supporting functions.. given a list of types of parameters, collect them, comma separ. public List <Object> Parameters(string name, int min, IEvalParaListType [] ptypes) { List <Object> list = new List <object>(); for (int n = 0; n < ptypes.Length; n++) { Object evres = Evaluate(false, false); if (InError) { return(null); } if ((ptypes[n] == IEvalParaListType.String && (evres is string)) || (ptypes[n] == IEvalParaListType.Number && (evres is double || evres is long)) || (ptypes[n] == IEvalParaListType.NumberOrInteger && (evres is double || evres is long)) || (ptypes[n] == IEvalParaListType.Integer && (evres is long)) || (ptypes[n] == IEvalParaListType.IntegerOrString && (evres is string || evres is long)) || (ptypes[n] == IEvalParaListType.All) ) { if (ptypes[n] is IEvalParaListType.Number && evres is long) { evres = (double)(long)evres; } list.Add(evres); if (n < ptypes.Length - 1) // if not maximum point { if (!sp.IsCharMoveOn(',')) // and not comma.. { if (list.Count() < min) // ensure minimum { value = new StringParser.ConvertError(name + "() requires " + min + " parameters minimum"); return(null); } else { return(list); // have min, return it } } } } else { value = new StringParser.ConvertError(name + "() type mismatch in parameter " + (n + 1) + " wanted " + ptypes[n].ToString().SplitCapsWord()); return(null); } } if (sp.IsChar(',')) // if at max, can't have another { value = new StringParser.ConvertError(name + "() takes " + ptypes.Length + " parameters maximum"); return(null); } return(list); }
private void Level6Equals() { Level5GreaterLess(); // get left value bool equals = false; while (!InError && ((equals = sp.IsString("==")) || sp.IsString("!="))) { sp.MoveOn(2); Object leftside = value; // remember left side value Level5GreaterLess(); // get left value if (InError) { return; } bool result; if (leftside is string || value is string) { if (!(leftside is string) || !(value is string)) { value = new StringParser.ConvertError("Cannot mix string and number types in comparisions"); return; } else { int cmp = String.Compare(leftside as string, value as string, IgnoreCase, Culture); result = equals ? (cmp == 0) : (cmp != 0); } } else if (leftside is double || value is double) { double l = AsDouble(leftside); double r = AsDouble(value); result = equals ? (l == r) : (l != r); } else { long l = (long)(leftside); long r = (long)(value); result = equals ? (l == r) : (l != r); } value = result ? (long)1 : (long)0; } }
public Object Functions(string name, IEval evaluator) { Object ret = BaseFunctions != null?BaseFunctions(name, evaluator) : new StringParser.ConvertError("() not recognised"); StringParser.ConvertError ce = ret as StringParser.ConvertError; if (ce != null && ce.ErrorValue.Contains("() not recognised")) { if (functions.ContainsKey(name)) { FuncDef fd = functions[name]; bool hasparas = fd.parameters.Length > 0; if (hasparas) { IEvalParaListType[] plist = new IEvalParaListType[fd.parameters.Length]; plist = Enumerable.Repeat(IEvalParaListType.All, fd.parameters.Length).ToArray(); List <Object> paras = evaluator.Parameters(name, fd.parameters.Length, plist); if (paras == null) // if error, stop and return error { return(evaluator.Value); } symbols.Push(); for (int i = 0; i < fd.parameters.Length; i++) // add to symbol list on next level the parameter names and values { System.Diagnostics.Debug.WriteLine(symbols.Levels + " " + name + " Push " + fd.parameters[i] + "=" + paras[i]); symbols.Add(fd.parameters[i], paras[i]); } } Eval evfunc = (Eval)evaluator.Clone(); // we need a fresh one just to evaluate this, but with the same configuration Object res = evfunc.Evaluate(fd.funcdef); // and evaluate if (hasparas) { symbols.Pop(); // clear back stack.. } return(res); } } return(ret); }
public Object Evaluate(bool unary, bool checkend) // Allow control of unary entry and check end on a case by case basis { System.Diagnostics.Debug.Assert(sp != null); unaryentrytimes = 0; if (unary) { Level0Unary(); } else { Level12Assign(); } if (!InError && checkend && !sp.IsEOL) { value = new StringParser.ConvertError("Extra characters after expression: " + sp.LineLeft); } //System.Diagnostics.Debug.WriteLine("Evaluate Value is " + value + " : of type " + value.GetType().Name); return(value); }
private void Level1Not() { if (sp.IsCharMoveOn('!')) { Level1Not(); // allow recurse.. lvaluename = null; // clear symbol name, can't use with ! if (IsLong) { value = ((long)value != 0) ? 0L : 1L; } else if (!InError) { value = new StringParser.ConvertError("! only valid with integers"); } } else if (sp.IsCharMoveOn('~')) { Level1Not(); // allow recurse.. lvaluename = null; // clear symbol name, can't use with ~ if (IsLong) { value = ~(long)value; } else if (!InError) { value = new StringParser.ConvertError("~ is only valid with integers"); } } else { Level0Unary(); } }
private void Level5GreaterLess() { Level4Shift(); // get left value while (!InError && sp.IsCharOneOf("<>")) { bool left = sp.GetChar() == '<'; bool equals = sp.IsCharMoveOn('='); sp.SkipSpace(); Object leftside = value; // remember left side value Level4Shift(); // get right side if (InError) { return; } bool result; if (leftside is string || value is string) { if (!(leftside is string) || !(value is string)) { value = new StringParser.ConvertError("Cannot mix string and number types in comparisions"); return; } else { int cmp = String.Compare(leftside as string, value as string, IgnoreCase, Culture); if (left) { result = equals ? (cmp <= 0) : (cmp < 0); } else { result = equals ? (cmp >= 0) : (cmp > 0); } } } else if (leftside is double || value is double) { double l = AsDouble(leftside); double r = AsDouble(value); if (left) { result = equals ? (l <= r) : (l < r); } else { result = equals ? (l >= r) : (l > r); } } else { long l = (long)(leftside); long r = (long)(value); if (left) { result = equals ? (l <= r) : (l < r); } else { result = equals ? (l >= r) : (l > r); } } value = result ? (long)1 : (long)0; } }
private void Level3Add() { Level2Times(); // get left value while (!InError && sp.IsCharOneOf("+-")) { char operation = sp.GetChar(skipspace: true); if (IsString && operation == '-') { value = new StringParser.ConvertError("- is not supported with strings"); return; } Object leftside = value; // remember left side value Level2Times(); // get right side if (InError) { return; } if (leftside is string && IsString) // two strings, + { value = (leftside as string) + (value as string); } else { if (leftside is string || IsString) { value = new StringParser.ConvertError("Cannot mix string and number types"); return; } else if (leftside is double || value is double) // either double, its double { double left = AsDouble(leftside); double right = AsDouble(value); if (operation == '+') { value = left + right; } else { value = left - right; } } else { long left = (long)(leftside); long right = (long)(value); if (operation == '+') { value = left + right; } else { value = left - right; } } } } }
private void Level2Times() { Level1Not(); // get left value while (!InError && sp.IsCharOneOf("*/%")) { if (!IsNumeric) { value = new StringParser.ConvertError("*/% only valid with numbers"); return; } char operation = sp.GetChar(skipspace: true); Object leftside = value; // remember left side value Level1Not(); // get right side if (InError) { return; } else if (!IsNumeric) { value = new StringParser.ConvertError("*/% only valid with numbers"); return; } if (leftside is double || value is double) // either double, its double { double left = AsDouble(leftside); double right = AsDouble(value); if (operation == '*') { value = left * right; } else if (operation == '/') { if (right == 0) { value = new StringParser.ConvertError("Divide by zero"); return; } value = left / right; } else { value = new StringParser.ConvertError("Cannot perform modulo with floating point values"); return; } } else { long left = (long)(leftside); long right = (long)(value); if (operation == '*') { value = left * right; } else if (operation == '/') { if (right == 0) { value = new StringParser.ConvertError("Divide by zero"); return; } value = left / right; } else { value = left % right; } } } }
private void Level0Unary() // Value left as Error, double, long, string { unaryentrytimes++; // counts entry to the unary level.. if 1, and symbolname set, its a symbol def on left side lvaluename = null; long sign = 0; if (sp.IsCharMoveOn('-')) // space allowed after unary minus plus to entry { sign = -1; } else if (sp.IsCharMoveOn('+')) { sign = 1; } if (sp.IsCharMoveOn('(')) // ( value ) { value = Evaluate(false, false); if (!(value is StringParser.ConvertError) && !sp.IsCharMoveOn(')')) { value = new StringParser.ConvertError("Missing ) at end of expression"); } } else { value = sp.ConvertNumberStringSymbolChar(DefaultBase, AllowFP, AllowStrings, ReplaceEscape); if (value is StringParser.ConvertSymbol) // symbol must resolve to a value or Error { string symname = (value as StringParser.ConvertSymbol).SymbolValue; if (sp.IsCharMoveOn('(')) { if (ReturnFunctionValue != null) { value = ReturnFunctionValue(symname, this); if (!(value is StringParser.ConvertError) && !sp.IsCharMoveOn(')')) // must be ) terminated { value = new StringParser.ConvertError("Function not terminated with )"); } } else { value = new StringParser.ConvertError("Functions not supported"); } } else if (ReturnSymbolValue != null) { lvaluename = (sign == 0) ? symname : null; // pass back symbol name found, only if not signed. value = ReturnSymbolValue(symname); // could be Error with symbol value in it. } else { value = new StringParser.ConvertError("Symbols not supported"); } } } // value now Error, double, long, string if (!(value is StringParser.ConvertError) && sign != 0) // if not error, and signed { if (value is double) { value = (double)value * sign; } else if (value is long) { value = (long)value * sign; } else { value = new StringParser.ConvertError("Unary +/- not allowed in front of string"); } } }
private void Level0Unary() // Value left as Error, double, long, string { unaryentrytimes++; // counts entry to the unary level.. if 1, and symbolname set, its a symbol def on left side lvaluename = null; long sign = 0; if (sp.IsCharMoveOn('-')) // space allowed after unary minus plus to entry { sign = -1; } else if (sp.IsCharMoveOn('+')) { sign = 1; } if (sp.IsCharMoveOn('(')) // ( value ) { value = Evaluate(false, false); if (!(value is StringParser.ConvertError) && !sp.IsCharMoveOn(')')) { value = new StringParser.ConvertError("Missing ) at end of expression"); } } else { value = sp.ConvertNumberStringSymbolChar(DefaultBase, AllowFP, AllowStrings, ReplaceEscape, AllowMemberSymbol); if (value is StringParser.ConvertSymbol) // symbol must resolve to a value or Error { string symname = (value as StringParser.ConvertSymbol).SymbolValue; if (sp.IsCharMoveOn('(')) { if (ReturnFunctionValue != null) { value = ReturnFunctionValue(symname, this); if (!(value is StringParser.ConvertError) && !sp.IsCharMoveOn(')')) // must be ) terminated { value = new StringParser.ConvertError("Function not terminated with )"); } } else { value = new StringParser.ConvertError("Functions not supported"); } } else if (ReturnSymbolValue == null) { value = new StringParser.ConvertError("Symbols not supported"); } else { while (AllowArrays && sp.IsCharMoveOn('[')) // is it an array symbol.. { value = Evaluate(false, false); // get [] expression if (value is StringParser.ConvertError) // see what we have back and generate array { break; } if (value is long) { symname += $"[{((long)value).ToStringInvariant()}]"; } else if (value is double) { value = new StringParser.ConvertError("Cannot use floating point value as array index"); break; } else { symname += $"[{((string)value).AlwaysQuoteString()}]"; } if (!sp.IsCharMoveOn(']', false)) // must be ] terminated { value = new StringParser.ConvertError("Array not terminated with ]"); break; } if (!sp.IsLetterDigitUnderscoreMember()) // if no following chars, we are done { break; } string moresym; // more symbol text beyond it if (AllowMemberSymbol) { moresym = sp.NextWord((c) => { return(char.IsLetterOrDigit(c) || c == '_' || c == '.'); }); } else { moresym = sp.NextWord((c) => { return(char.IsLetterOrDigit(c) || c == '_'); }); } symname += moresym; // add on } if (!(value is StringParser.ConvertError)) // if not in error, see if symbols is there { lvaluename = (sign == 0) ? symname : null; // pass back symbol name found, only if not signed. value = ReturnSymbolValue(symname); // could be Error with symbol value in it. } } } } // value now Error, double, long, string if (!(value is StringParser.ConvertError) && sign != 0) // if not error, and signed { if (value is double) { value = (double)value * sign; } else if (value is long) { value = (long)value * sign; } else { value = new StringParser.ConvertError("Unary +/- not allowed in front of string"); } } if (Fake) // if we are faking the eval, return 1L long as the default output. { value = 1L; } }