(view source code of clcalc.cs as plain text)
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
namespace RobvanderWoude
{
class ClCalc
{
static readonly string progver = "2.01";
static string expression; // calculated end result of input expression
static string expressionstring; // corrected uncalculated input expression
static SortedList<string, string> functions; // list of available Math functions
static bool debugmode = false; // in debug mode, intermediate values for expression and expressionstring are shown
static bool error = false;
static int Main( string[] args )
{
#if DEBUG
debugmode = true;
#endif
#region Initialize
// force decimal dots only, instead of a mixture of dots and commas
Thread.CurrentThread.CurrentCulture = new CultureInfo( "en-US" );
CreateFunctionsList( );
#endregion Initialize
#region Parse Command Line
if ( args.Contains( "/?" ) )
{
return ShowHelp( );
}
// join all arguments into a single string expression
expression = string.Join( " ", args ).Trim( );
if ( Regex.IsMatch( expression, "/DEBUG", RegexOptions.IgnoreCase ) )
{
debugmode = true;
expression = Regex.Replace( expression, @"\s?/DEBUG\s?", " ", RegexOptions.IgnoreCase ).Trim( );
}
if ( string.IsNullOrWhiteSpace( expression ) )
{
return InteractiveConsole( );
}
expressionstring = expression;
DebugOutput( "Initial input" );
#endregion Parse Command Line
EvaluateExpression( );
// Display result
Console.Error.Write( "{0} = ", expressionstring );
Console.WriteLine( "{0}", expression );
// Exit program
int rc = 0;
int.TryParse( Calculate( string.Format( "Math.Round( {0} )", expression ) ), out rc );
return rc;
}
public static string Calculate( string exp )
{
// Based on code by Reed Copsey, Jr
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/2f737e51-bc99-4dc1-9a01-f0a4f7e8aa64/how-to-get-a-list-of-math-methods?forum=csharpgeneral#2af1c643-689a-4469-ad3c-20a3c8b6a24e-isAnswer
Regex regex;
double result;
#region RegEx Patterns
// Math function with single numeric parameter (double)
string pattern1 = @"Math\.(\w+)\(\s*([-\d][\d\.]*)\s*\)";
// Math function with two numeric parameters (both double)
string pattern2 = @"Math\.(\w+)\(\s*([-\d][\d\.]*)\s*,\s*([-\d][\d\.]*)\s*\)";
// Random function without parameters
string patternrandom0 = @"(?:Math\.)?Random\(\s*\)";
// Random function with 1 parameter
string patternrandom1 = @"(?:Math\.)?Random\(\s*([-\d][\d\.]*)\s*\)";
// Random function with 2 parameters
string patternrandom2 = @"(?:Math\.)?Random\(\s*([-\d][\d\.]*)\s*,\s*([-\d][\d\.]*)\s*\)";
// Math.Round with 2 numeric parameters (double, int)
string patternround2 = @"Math\.Round\(\s*([-\d][\d\.]*)\s*,\s*(\d+)\s*\)";
// Math.BigMul with 2 int parameters
string patternbigmul = @"Math\.BigMul\(\s*(\d+)\s*,\s*(\d+)\s*\)";
#endregion RegEx Patterns
if ( Regex.IsMatch( exp, @"Random\(", RegexOptions.IgnoreCase ) )
{
#region Random
int seed = DateTime.Now.Millisecond;
Random random = new Random( seed );
if ( Regex.IsMatch( exp, patternrandom0, RegexOptions.IgnoreCase ) )
{
// Random function without parameters
regex = new Regex( patternrandom0, RegexOptions.IgnoreCase );
MatchCollection matches = regex.Matches( exp );
foreach ( Match match in matches )
{
return random.NextDouble( ).ToString( new CultureInfo( "en-US" ) );
}
}
else if ( Regex.IsMatch( exp, patternrandom1, RegexOptions.IgnoreCase ) )
{
// Random function with 1 parameter
regex = new Regex( patternrandom1, RegexOptions.IgnoreCase );
MatchCollection matches = regex.Matches( exp );
foreach ( Match match in matches )
{
if ( int.TryParse( match.Groups[1].Value, out int upperlimit ) )
{
return random.Next( upperlimit ).ToString( );
}
}
}
else if ( Regex.IsMatch( exp, patternrandom2, RegexOptions.IgnoreCase ) )
{
// Random function with 2 parameters
regex = new Regex( patternrandom2, RegexOptions.IgnoreCase );
MatchCollection matches = regex.Matches( exp );
foreach ( Match match in matches )
{
if ( int.TryParse( match.Groups[1].Value, out int lowerlimit ) && int.TryParse( match.Groups[2].Value, out int upperlimit ) && upperlimit > lowerlimit )
{
return random.Next( lowerlimit, upperlimit ).ToString( );
}
}
}
}
else if ( Regex.IsMatch( exp, patternround2, RegexOptions.IgnoreCase ) )
{
// Math.Round with 2 numeric parameters (double, int)
regex = new Regex( patternround2, RegexOptions.IgnoreCase );
MatchCollection matches = regex.Matches( exp );
foreach ( Match match in matches )
{
if ( double.TryParse( match.Groups[1].Value, out double val ) && int.TryParse( match.Groups[2].Value, out int decimals ) )
{
Type[] types = { typeof( double ), typeof( int ) };
var methodInfo = typeof( Math ).GetMethod( "Round", types );
object[] valobj = { val, decimals };
result = (double)methodInfo.Invoke( null, valobj );
return result.ToString( new CultureInfo( "en-US" ) );
}
}
#endregion Random
}
else if ( Regex.IsMatch( exp, patternbigmul, RegexOptions.IgnoreCase ) )
{
#region BigMul
// Math.BigMul with 2 int parameters
regex = new Regex( patternbigmul, RegexOptions.IgnoreCase );
MatchCollection matches = regex.Matches( exp );
foreach ( Match match in matches )
{
if ( int.TryParse( match.Groups[1].Value, out int val1 ) && int.TryParse( match.Groups[2].Value, out int val2 ) )
{
Type[] types = { typeof( int ), typeof( int ) };
var methodInfo = typeof( Math ).GetMethod( "BigMul", types );
object[] valobj = { val1, val2 };
result = (Int64)methodInfo.Invoke( null, valobj );
return result.ToString( new CultureInfo( "en-US" ) );
}
}
#endregion BigMul
}
else if ( Regex.IsMatch( exp, pattern1, RegexOptions.IgnoreCase ) )
{
#region Math Single Parameter
// Math function with single numeric parameter (double)
regex = new Regex( pattern1, RegexOptions.IgnoreCase );
MatchCollection matches = regex.Matches( exp );
foreach ( Match match in matches )
{
string func = match.Groups[1].Value;
if ( double.TryParse( match.Groups[2].Value, out double val ) )
{
Type[] types = { typeof( double ) };
var methodInfo = typeof( Math ).GetMethod( func, types );
if ( methodInfo != null )
{
object[] valobj = { val };
result = (double)methodInfo.Invoke( null, valobj );
return result.ToString( new CultureInfo( "en-US" ) );
}
error = true;
return "Unknown Function Math." + func;
}
}
#endregion Math Single Parameter
}
else if ( Regex.IsMatch( exp, pattern2, RegexOptions.IgnoreCase ) )
{
#region Math Two Parameters
// Math function with two numeric parameters (both double)
regex = new Regex( pattern2, RegexOptions.IgnoreCase );
MatchCollection matches = regex.Matches( exp );
foreach ( Match match in matches )
{
string func = match.Groups[1].Value;
if ( double.TryParse( match.Groups[2].Value, out double val1 ) && double.TryParse( match.Groups[3].Value, out double val2 ) )
{
Type[] types = { typeof( double ), typeof( double ) };
var methodInfo = typeof( Math ).GetMethod( func, types );
if ( methodInfo != null )
{
object[] valobj = { val1, val2 };
result = (double)methodInfo.Invoke( null, valobj );
return result.ToString( new CultureInfo( "en-US" ) );
}
error = true;
return "Unknown Function Math." + func;
}
}
#endregion Math Two Parameters
}
else
{
#region Numerical Expressions
// use JScript to evaluate numerical expressions with standard operators
try
{
result = JScriptEvaluator.EvalToDouble( exp );
return result.ToString( new CultureInfo( "en-US" ) );
}
catch ( Exception )
{
// no action
}
#endregion Numerical Expressions
}
return string.Empty;
}
public static void CreateFunctionsList( )
{
var methods = typeof( Math ).GetMethods( BindingFlags.Public | BindingFlags.Static ).Select( m => m.Name ).ToList( );
methods = methods.Distinct( ).ToList( );
methods.Remove( "DivRem" ); // this function cannot be implemented easily on the command line
functions = new SortedList<string, string>( );
foreach ( string method in methods )
{
functions.Add( method, method );
}
// for JScript Math compatibility
functions.Add( "Ceil", "Ceiling" );
functions.Add( "Int", "Truncate" );
}
public static void DebugOutput( string description )
{
if ( debugmode )
{
Console.Error.Write( "{0}:\t{1} = ", description, expressionstring );
Console.WriteLine( "{0}", expression );
}
}
public static void EnvVarSubst( )
{
string pattern = @"(?<!%)%([A-Z]\w*)%(?!%)"; // (?<!%) = not preceded by % and (?!%) = not followed by %
Regex regex = new Regex( pattern, RegexOptions.IgnoreCase );
if ( regex.IsMatch( expression ) )
{
MatchCollection matches = regex.Matches( expression );
foreach ( Match match in matches )
{
expression = expression.Replace( match.Value, Environment.GetEnvironmentVariable( match.Groups[1].Value ) );
}
DebugOutput( "Env. variables" );
}
}
public static void EvaluateExpression( )
{
if ( !error ) // in case of errors, do not proceed
{
#region Evaluate pi and e
string pattern = @"(^|[-\s\*/%+\(\)])(e|pi)([-\s\*/%+\(\)]|$)";
Regex regex = new Regex( pattern );
MatchCollection matches = regex.Matches( expression );
foreach ( Match match in matches )
{
expression = expression.Replace( match.Value, string.Format( "{0}{1}{2}", match.Groups[1].Value, Calculate( "Math." + match.Groups[2].Value.ToUpper( ) ), match.Groups[3].Value ) );
expressionstring = expressionstring.Replace( match.Value, string.Format( "{0}Math.{1}{2}", match.Groups[1].Value, match.Groups[2].Value.ToUpper( ), match.Groups[3].Value ) );
DebugOutput( "pi and e" );
}
#endregion Evaluate pi and e
#region Evaluate Math.PI and Math.E
pattern = @"Math\.(E|PI)";
regex = new Regex( pattern, RegexOptions.IgnoreCase );
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
expression = expression.Replace( match.Value, Calculate( string.Format( "Math.{0}", match.Groups[1].Value.ToUpper( ) ) ) );
expressionstring = expressionstring.Replace( match.Value, string.Format( "Math.{0}", match.Groups[1].Value.ToUpper( ) ) );
DebugOutput( "Math.PI and E" );
}
#endregion Evaluate Math.PI and Math.E
#region Evaluate Calls to Random
expression = Regex.Replace( expression, @"Math\.Random", "Random", RegexOptions.IgnoreCase );
expressionstring = Regex.Replace( expressionstring, @"Math\.Random", "Random", RegexOptions.IgnoreCase );
pattern = @"Math\.Random\(([^\(\)]+)\)";
regex = new Regex( pattern, RegexOptions.IgnoreCase );
if ( regex.IsMatch( expression ) )
{
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
string replacement = string.Format( "Random({0})", match.Groups[1].Value );
expression = regex.Replace( expression, Calculate( replacement ) );
expressionstring = regex.Replace( expressionstring, replacement );
DebugOutput( "Random calls" );
}
}
#endregion Evaluate Calls to Random
#region Math Function Names Capitalization
// Correct capitalization of Math functions and translate JScript specific function names to .NET equivalents
foreach ( string func in functions.Keys )
{
pattern = string.Format( @"(Math\.)?{0}\(", func );
regex = new Regex( pattern, RegexOptions.IgnoreCase );
if ( regex.IsMatch( expression ) )
{
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
expression = regex.Replace( expression, string.Format( "Math.{0}(", functions[func] ) );
expressionstring = regex.Replace( expressionstring, string.Format( "Math.{0}(", functions[func] ) );
DebugOutput( "Capitalization" );
}
}
}
#endregion Math Function Names Capitalization
#region Evaluate Expressions Loop
bool completed;
do
{
completed = true;
expression = expression.Trim( );
#region Numeric Only
// Evaluate all expressions between parentheses, numeric only
pattern = @"\(([-\s\d\.\*<>|&/%+]*)\)";
regex = new Regex( pattern, RegexOptions.IgnoreCase );
if ( regex.IsMatch( expression ) )
{
matches = regex.Matches( expression );
completed = Regex.IsMatch( matches[0].Groups[1].Value, @"^\s*[-\d][\d\.]*\s*$" );
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
expression = expression.Replace( match.Value, string.Format( "( {0} )", Calculate( match.Groups[1].Value ) ) );
DebugOutput( "Numeric only" );
}
}
#endregion Numeric Only
#region Random Calls
// Evaluate all Random calls with numeric parameters only
string patternrandom0 = @"Random\((\s*)\)";
regex = new Regex( patternrandom0, RegexOptions.IgnoreCase );
int seed = DateTime.Now.Millisecond;
Random random = new Random( seed );
if ( regex.IsMatch( expression ) )
{
completed = false;
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
expression = expression.Replace( match.Value, random.NextDouble( ).ToString( new CultureInfo( "en-US" ) ) );
DebugOutput( "Random 0 params" );
}
}
string patternrandom1 = @"Random\(\s*(\d+)\s*\)";
regex = new Regex( patternrandom1, RegexOptions.IgnoreCase );
if ( regex.IsMatch( expression ) )
{
completed = false;
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
if ( int.TryParse( match.Groups[1].Value, out int singleparam ) )
{
expression = expression.Replace( match.Value, Calculate( string.Format( "Random( {0} )", singleparam ) ) );
}
DebugOutput( "Random 1 param" );
}
}
string patternrandom2 = @"Random\(\s*(\d+)\s*,\s*(\d+)\s*\)";
regex = new Regex( patternrandom2, RegexOptions.IgnoreCase );
if ( regex.IsMatch( expression ) )
{
completed = false;
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
if ( int.TryParse( match.Groups[1].Value, out int lowerlimit ) && int.TryParse( match.Groups[2].Value, out int upperlimit ) )
{
expression = expression.Replace( match.Value, Calculate( string.Format( "Random( {0}, {1} )", lowerlimit, upperlimit ) ) );
}
DebugOutput( "Random 2 params" );
}
}
#endregion Random Calls
#region Math Calls With Numeric Parameters
// Evaluate all Math functions with numeric parameters only
pattern = @"Math\.(\w+)\(([^\(\)]+)\)";
regex = new Regex( pattern, RegexOptions.IgnoreCase );
if ( regex.IsMatch( expression ) )
{
completed = false;
matches = regex.Matches( expression );
foreach ( Match match in matches )
{
expression = expression.Replace( match.Value, Calculate( match.Value ) );
DebugOutput( "Math numeric" );
}
}
#endregion Math Calls With Numeric Parameters
} while ( !completed && !error ); // loop must be executed at least once without ANY match for both RegExs
#endregion Evaluate Expressions Loop
#region Final Evaluation
if ( !error )
{
expression = Calculate( expression );
DebugOutput( "Final run" );
}
#endregion Final Evaluation
}
}
public static int InteractiveConsole( )
{
expression = string.Empty;
bool debugprompt = true;
bool quit = false;
while ( !quit )
{
#region Prompt
if ( debugprompt )
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine( "Debug mode is {0}", debugmode ? "ON" : "OFF" );
Console.WriteLine( "Type DEBUG and press Enter to toggle debug mode." );
debugprompt = false;
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine( "\nType an expression to calculate, or ? for help, or Q to quit, and press Enter:\n" );
Console.Write( "CLCALC:> " );
Console.ResetColor( );
#endregion Prompt
// Read keyboard input
expression = Console.ReadLine( );
// "Q" for Quit
if ( expression.ToUpper( ).Trim( ) == "Q" )
{
quit = true;
}
else
{
Console.WriteLine( );
// "?" or "HELP" for help on screen
if ( expression.ToUpper( ).Trim( ) == "HELP" || expression.Trim( ) == "?" )
{
ShowHelpInteractive( );
}
else if ( !error )
{
#region Toggle DEBUG Mode
// "DEBUG" to toggle debug mode
if ( expression.ToUpper( ).Contains( "DEBUG" ) )
{
debugmode = !debugmode; // toggle debug mode
expression = string.Empty;
expressionstring = string.Empty;
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine( "Debug mode is {0}", debugmode ? "ON" : "OFF" );
Console.WriteLine( "Type DEBUG and press Enter to toggle debug mode." );
Console.ResetColor( );
}
#endregion Toggle DEBUG Mode
if ( !string.IsNullOrWhiteSpace( expression ) )
{
expressionstring = expression;
// in interactive mode, we don't have the "automatic" evaluation of environment
// variables like we have on the command line, so we need to handle that ourselves
EnvVarSubst( );
EvaluateExpression( );
}
}
error = false;
if ( !string.IsNullOrWhiteSpace( expressionstring ) && !string.IsNullOrWhiteSpace( expression ) )
{
Console.WriteLine( "\n{0} = {1}\n", expressionstring, expression );
}
}
}
return 0;
}
public static void ListFunctions( )
{
List<string> funcs = new List<string>( );
foreach ( string function in functions.Keys )
{
if ( function == functions[function] )
{
funcs.Add( string.Format( "Math.{0}", function ) );
}
else
{
funcs.Add( string.Format( "Math.{0} *", function ) );
}
}
funcs.Add( "Random *" );
funcs.Sort( );
for ( int i = 0; i < funcs.Count; i++ )
{
if ( i % 4 == 3 )
{
Console.Error.WriteLine( funcs[i] );
}
else
{
Console.Error.Write( "{0,-20}", funcs[i] );
}
}
}
public static string RequiredDotNETVersion( )
{
// Get the required .NET Framework version
// By Fernando Gonzalez Sanchez on StackOverflow.com
// https://stackoverflow.com/a/18623516
object[] list = Assembly.GetExecutingAssembly( ).GetCustomAttributes( true );
var attribute = list.OfType<System.Runtime.Versioning.TargetFrameworkAttribute>( ).First( ); // requires Linq
return attribute.FrameworkDisplayName;
}
public static int ShowHelp( params string[] errorMessage )
{
#region Error Message
if ( errorMessage.Length > 0 )
{
List<string> errargs = new List<string>( errorMessage );
errargs.RemoveAt( 0 );
Console.Error.WriteLine( );
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.Write( "ERROR:\t" );
Console.ForegroundColor = ConsoleColor.White;
Console.Error.WriteLine( errorMessage[0], errargs.ToArray( ) );
Console.ResetColor( );
}
#endregion Error Message
#region Help Text
Console.Error.Write( string.Format( @"
ClCalc.exe, Version {0}
Command Line Calculator
Usage: CLCALC [ expression ] [ /DEBUG ]
Run the program without expression to open an interactive console.
Available Operators:
====================
+ - * / % << >> & |
Available Constants:
====================
Math.PI (pi) and Math.E (e)
Available Functions:
====================
", progver ) );
ListFunctions( );
Console.Error.Write( string.Format( @"
* Math.Ceil is equivalent of Math.Ceiling, Math.Int of Math.Truncate;
these equivalents were created for backwards compatibility with ClCalc 1.*
Random is an added function, not part of the .NET System.Math class but of
the .NET System.Random class.
Function names are not case sensitive, but constants e and pi are.
The Math. prefix is not mandatory in the input, except for upper case
Math.E and Math.PI.
For more details on functions and parameters, navigate to:
https://learn.microsoft.com/en-us/dotnet/api/system.math?view=netframework-4.5
EXAMPLES
========
Expression: Evaluates To: Remark:
=========== ============= =======
{0}%var1% & %var2%{0} 0 or 1 AND operator
{0}%var1% | %var2%{0} 0 or 1 OR operator
{0}16 >> 1{0} 8 shift right
{0}16 << 2{0} 64 shift left
{0}16 % 3{0} 1 use whitespace!
Math.Abs( -12 ) 12
Math.Acos( 0.707106781186548 ) 0.785398163397448
Math.Asin( 0.707106781186548 ) 0.785398163397448
Math.Atan( 1 ) 0.785398163397448
Math.Atan2( 1, 1 ) 0.785398163397448
Math.BigMul( 2147483647, 2147483647 ) 4.61168601413242E+18 Int64 result
Math.Ceiling( Math.PI ) 4 round up to int
Math.Cos( pi / 4 ) 0.707106781186548
Math.Cosh( 1 ) 1.54308063481524
Math.Exp( -1 ) * Math.E 1
Math.Floor( Math.E ) 2 round down to int
Math.IEEERemainder( 4, 3 ) 1 like {0}4 % 3{0}
Math.IEEERemainder( 5, 3 ) -1 unlike {0}5 % 3{0}
Math.Log( Math.E ) 1 natural logarithm
Math.Log10( 1000 ) 3 base 10 logarithm
Math.Max( -10, -12 ) -10
Math.Min( -10, -12 ) -12
Math.Pow( 2, 8 ) 256
Math.Round( 12.5 ) 13
Math.Sign( -3 ) -1
Math.Sin( pi / 4 ) 0.707106781186548
Math.Sinh( 1.5 ) 2.12927945509482
Math.Sqrt( 9 ) 3
Math.Tan( pi / 4 ) 1
Math.Tanh( 2 ) 0.964027580075817
Math.Truncate( -12.6 ) -12
Random( ) 0 <= result < 1 floating point
Random( 100 ) 0 <= result < 100 integer
Random( 1, 101 ) 1 <= result < 101 integer
pi / Math.Acos( Math.Pow(0.5, 0.5) ) 4 nested Math calls
Notes:
======
In non-interactive mode, the result is shown on screen and the exit code
({0}errorlevel{0}) equals the rounded value of result, or 0 in case of
error or overflow.
In non-interactive mode, the result is shown in Standard Output stream,
and the initial expression in Standard Error stream, to allow capturing
or redirection of the result only.
In interactive console mode type DEBUG to toggle debug mode.
If expression contains special characters like < or > or | or & it is
highly recommended to enclose the entire expression in doublequotes and
use whitespace around these operators, e.g. {0}16 << 1{0}.
Available constants are case sensitive, function names are not.
{0}Math.PI{0} may be abbreviated to {0}pi{0} (lower case), {0}Math.E{0} to {0}e{0}.
In ClCalc all Math functions are limited to 2 parameters at most, usually of
types Double or Int32.
This program requires {1}.
Culture is set to en-US, so use and expect decimal dots, not commas.
See this web page for methods available in .NET's Math class:
https://learn.microsoft.com/en-us/dotnet/api/system.math?view=netframework-4.5
Credits:
========
Originally based on Eval function (using JScript) by {0}markman{0}:
https://www.codeproject.com/Articles/11939/Evaluate-C-Code-Eval-Function
Written by Rob van der Woude
https://www.robvanderwoude.com
", (char)34, RequiredDotNETVersion( ) ) );
#endregion Help Text
return 0;
}
public static void ShowHelpInteractive( )
{
Console.WriteLine( "\nAvailable Operators:" );
Console.WriteLine( "====================" );
Console.WriteLine( "+ - * / % << >> & |\n" );
Console.WriteLine( "Available Constants:" );
Console.WriteLine( "====================" );
Console.WriteLine( "Math.PI (pi) and Math.E (e)\n" );
Console.WriteLine( "Available Functions:" );
Console.WriteLine( "====================" );
ListFunctions( );
Console.WriteLine( "\nFunction names are not case sensitive, but constants e and pi are." );
Console.WriteLine( "The Math. prefix is not mandatory in the input, except for upper case" );
Console.WriteLine( "Math.E an Math.PI." );
Console.WriteLine( "\nFor more details, run CLCALC with the /? command line switch." );
}
}
public class JScriptEvaluator
{
// Eval function using JScript, by "markman"
// https://www.codeproject.com/Articles/11939/Evaluate-C-Code-Eval-Function
public static int EvalToInteger( string statement )
{
string s = EvalToString( statement );
return int.Parse( s.ToString( ) );
}
public static double EvalToDouble( string statement )
{
string s = EvalToString( statement );
return double.Parse( s );
}
public static string EvalToString( string statement )
{
object o = EvalToObject( statement );
return o.ToString( );
}
public static object EvalToObject( string statement )
{
return _evaluatorType.InvokeMember(
"Eval",
BindingFlags.InvokeMethod,
null,
_evaluator,
new object[] { statement }
);
}
static JScriptEvaluator( )
{
CodeDomProvider provider = new Microsoft.JScript.JScriptCodeProvider( );
CompilerParameters parameters;
parameters = new CompilerParameters
{
GenerateInMemory = true
};
CompilerResults results;
results = provider.CompileAssemblyFromSource( parameters, _jscriptSource );
Assembly assembly = results.CompiledAssembly;
_evaluatorType = assembly.GetType( "Evaluator.Evaluator" );
_evaluator = Activator.CreateInstance( _evaluatorType );
}
private static object _evaluator = null;
private static Type _evaluatorType = null;
private static readonly string _jscriptSource =
@"package Evaluator
{
class Evaluator
{
public function Eval(expr : String) : String
{
return eval(expr);
}
}
}";
}
}
page last modified: 2024-04-16; loaded in 0.0178 seconds