using System; using System.Globalization; namespace AxCopilot.Handlers; internal static class MathEvaluator { private class Evaluator { private readonly string _s; private int _i; public Evaluator(string s) { _s = s; _i = 0; } public double Parse() { double result = ParseExpr(); if (_i < _s.Length) { throw new InvalidOperationException($"예기치 않은 문자: '{_s[_i]}'"); } return result; } private double ParseExpr() { double num = ParseTerm(); while (_i < _s.Length && (_s[_i] == '+' || _s[_i] == '-')) { char c = _s[_i++]; double num2 = ParseTerm(); num = ((c == '+') ? (num + num2) : (num - num2)); } return num; } private double ParseTerm() { double num = ParsePower(); while (_i < _s.Length && (_s[_i] == '*' || _s[_i] == '/' || _s[_i] == '%')) { char c = _s[_i++]; double num2 = ParsePower(); num = c switch { '/' => num / num2, '*' => num * num2, _ => num % num2, }; } return num; } private double ParsePower() { double num = ParseUnary(); if (_i < _s.Length && _s[_i] == '^') { _i++; double y = ParseUnary(); return Math.Pow(num, y); } return num; } private double ParseUnary() { if (_i < _s.Length && _s[_i] == '-') { _i++; return 0.0 - ParsePrimary(); } if (_i < _s.Length && _s[_i] == '+') { _i++; return ParsePrimary(); } return ParsePrimary(); } private double ParsePrimary() { if (_i >= _s.Length) { throw new InvalidOperationException("수식이 불완전합니다."); } if (_i + 1 < _s.Length && _s[_i] == '0' && _s[_i + 1] == 'x') { _i += 2; int i = _i; while (_i < _s.Length && "0123456789abcdef".Contains(_s[_i])) { _i++; } string s = _s; int num = i; return Convert.ToInt64(s.Substring(num, _i - num), 16); } if (char.IsDigit(_s[_i]) || _s[_i] == '.') { int i2 = _i; while (_i < _s.Length && (char.IsDigit(_s[_i]) || _s[_i] == '.')) { _i++; } if (_i < _s.Length && _s[_i] == 'e') { _i++; if (_i < _s.Length && (_s[_i] == '+' || _s[_i] == '-')) { _i++; } while (_i < _s.Length && char.IsDigit(_s[_i])) { _i++; } } string s2 = _s; int num = i2; return double.Parse(s2.Substring(num, _i - num), NumberStyles.Float, CultureInfo.InvariantCulture); } if (_s[_i] == '(') { _i++; double result = ParseExpr(); if (_i < _s.Length && _s[_i] == ')') { _i++; } return result; } if (char.IsLetter(_s[_i])) { int i3 = _i; while (_i < _s.Length && (char.IsLetterOrDigit(_s[_i]) || _s[_i] == '_')) { _i++; } string s3 = _s; int num = i3; string text = s3.Substring(num, _i - num); switch (text) { case "pi": return Math.PI; case "e": return Math.E; case "inf": return double.PositiveInfinity; default: if (_i < _s.Length && _s[_i] == '(') { _i++; double num2 = ParseExpr(); double? num3 = null; if (_i < _s.Length && _s[_i] == ',') { _i++; num3 = ParseExpr(); } if (_i < _s.Length && _s[_i] == ')') { _i++; } if (1 == 0) { } double result2; switch (text) { case "sqrt": result2 = Math.Sqrt(num2); break; case "abs": result2 = Math.Abs(num2); break; case "ceil": result2 = Math.Ceiling(num2); break; case "floor": result2 = Math.Floor(num2); break; case "round": result2 = (num3.HasValue ? Math.Round(num2, (int)num3.Value) : Math.Round(num2)); break; case "sin": result2 = Math.Sin(num2 * Math.PI / 180.0); break; case "cos": result2 = Math.Cos(num2 * Math.PI / 180.0); break; case "tan": result2 = Math.Tan(num2 * Math.PI / 180.0); break; case "asin": result2 = Math.Asin(num2) * 180.0 / Math.PI; break; case "acos": result2 = Math.Acos(num2) * 180.0 / Math.PI; break; case "atan": result2 = Math.Atan(num2) * 180.0 / Math.PI; break; case "log": result2 = (num3.HasValue ? Math.Log(num2, num3.Value) : Math.Log10(num2)); break; case "log2": result2 = Math.Log2(num2); break; case "ln": result2 = Math.Log(num2); break; case "exp": result2 = Math.Exp(num2); break; case "pow": if (!num3.HasValue) { throw new InvalidOperationException("pow(x,y) 형식으로 사용하세요."); } result2 = Math.Pow(num2, num3.Value); break; case "min": result2 = (num3.HasValue ? Math.Min(num2, num3.Value) : num2); break; case "max": result2 = (num3.HasValue ? Math.Max(num2, num3.Value) : num2); break; default: throw new InvalidOperationException("알 수 없는 함수: " + text + "()"); } if (1 == 0) { } return result2; } throw new InvalidOperationException("알 수 없는 식별자: " + text); } } throw new InvalidOperationException($"예기치 않은 문자: '{_s[_i]}'"); } } public static double Evaluate(string expr) { Evaluator evaluator = new Evaluator(expr.Replace(" ", "").Replace("×", "*").Replace("÷", "/") .Replace(",", ",") .ToLowerInvariant()); return evaluator.Parse(); } }