📄 eqcompiler.cs
字号:
using System;
using System.Collections;
using System.Runtime.InteropServices;
namespace dotMath
{
/// <remarks>
/// Copyright (c) 2001-2004, Stephen Hebert
/// All rights reserved.
///
///
/// Redistribution and use in source and binary forms, with or without modification,
/// are permitted provided that the following conditions are met:
///
/// Redistributions of source code must retain the above copyright notice,
/// this list of conditions and the following disclaimer.
///
/// Redistributions in binary form must reproduce the above
/// copyright notice, this list of conditions and the following disclaimer
/// in the documentation and/or other materials provided with the distribution.
///
/// Neither the name of the .Math, nor the names of its contributors
/// may be used to endorse or promote products derived from this software without
/// specific prior written permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
/// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
/// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
/// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
/// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
/// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
/// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
/// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
/// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
/// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
/// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///
/// </remarks>
///
/// <summary>
/// EqCompiler is the class that takes the parsed tokens and turns them
/// into a network of pre-compiled objects that perform the designated
/// functions.
/// </summary>
public class EqCompiler
{
private string m_sEquation;
private CValue m_Function;
private Parser.Token m_currentToken;
private Parser.Token m_nextToken;
private IEnumerator m_enumTokens;
private SortedList m_slVariables = new SortedList();
private SortedList m_slFunctions = new SortedList();
private SortedList m_slOperations = new SortedList();
private COperator[] m_aOps;
#region Operations and Compiling Functions
/// <summary>
/// CSignNeg provides negative number functionality
/// within an equation.
/// </summary>
private class CSignNeg : CValue
{
CValue m_oValue;
/// <summary>
/// CSignNeg constructor: Grabs onto the assigned
/// CValue object and retains it for processing
/// requested operations.
/// </summary>
/// <param name="oValue">Child operation this object operates upon.</param>
public CSignNeg( CValue oValue )
{
m_oValue = oValue;
}
/// <summary>
/// GetValue(): Performs the negative operation on the child operation and returns the value.
/// </summary>
/// <returns>A double value evaluated and returned with the opposite sign.</returns>
public override double GetValue()
{
return m_oValue.GetValue() * -1;
}
}
/// <summary>
/// Paren() : This method evaluates Parenthesis in the equation and
/// insures they are handled properly according to the Order of Operations. Because this is last in the chain,
/// it also evaluates Variable and Function names.
/// </summary>
/// <returns>CValue object that holds an operation.</returns>
private CValue Paren()
{
bool bFunc = false;
CValue oValue = null;
if( m_currentToken.ToString() == "(" )
{
PositionNextToken();
oValue = Relational();
if( m_currentToken.ToString() == "," )
return oValue;
if( m_currentToken.ToString() != ")" )
throw new ApplicationException("Unmatched parenthesis in equation.");
}
else
{
switch( m_currentToken.TokenType )
{
case Parser.CharType.CT_NUMBER:
oValue = new CNumber( m_currentToken.ToString() );
break;
case Parser.CharType.CT_LETTER:
{
if( m_nextToken.ToString() == "(" )
{
int iIdx = m_slFunctions.IndexOfKey(m_currentToken.ToString());
if( iIdx < 0 )
throw new ApplicationException("Function not found - " + m_currentToken.ToString());
CFunction oFunc = (CFunction)m_slFunctions.GetByIndex( iIdx );
ArrayList alValues = new ArrayList();
do
{
PositionNextToken();
oValue = Paren();
alValues.Add( oValue );
} while (m_currentToken.ToString() == "," );
bFunc = true;
oValue = oFunc.CreateInstance(alValues);
}
else
oValue = GetVariableByName( m_currentToken.ToString() );
break;
}
}
}
if( !bFunc )
PositionNextToken();
return oValue;
}
/// <summary>
/// Sign(): This method detects the existence of sign operators before
/// a number or variable.
/// </summary>
/// <returns>CValue object representing an operation.</returns>
private CValue Sign()
{
bool bNeg = false;
Parser.Token oToken = null;
if( m_currentToken == "+" || m_currentToken == "-" )
{
oToken = m_currentToken;
bNeg = (m_currentToken == "-");
PositionNextToken();
}
//CValue oFunc = Function();
// sdh: should be function when ready.
CValue oFunc = Paren();
if( bNeg )
{
CheckParms( oToken, oFunc);
oFunc = new CSignNeg( oFunc );
}
return oFunc;
}
/// <summary>
/// Power(): Detects the operation to raise one number to the power
/// of another (a^2).
/// </summary>
/// <returns>CValue object representing an operation.</returns>
private CValue Power()
{
CValue oValue = Sign();
while( m_currentToken == "^" )
{
Parser.Token oOp = m_currentToken;
PositionNextToken();
CValue oNextVal = Sign();
CheckParms( oOp, oValue, oNextVal);
oValue = OpFactory(oOp, oValue, oNextVal );
}
return oValue;
}
/// <summary>
/// MultDiv(): Detects the operation to perform multiplication or division.
/// </summary>
/// <returns>CValue object representing an operation.</returns>
private CValue MultDiv()
{
CValue oValue = Power();
while( m_currentToken == "*" || m_currentToken == "/" )
{
Parser.Token oOp = m_currentToken;
PositionNextToken();
CValue oNextVal = Power();
CheckParms( oOp, oValue, oNextVal);
oValue = OpFactory( oOp, oValue, oNextVal );
}
return oValue;
}
/// <summary>
/// AddSub(): Detects the operation to perform addition or substraction.
/// </summary>
/// <returns>CValue object representing an operation.</returns>
private CValue AddSub()
{
CValue oValue = MultDiv();
while( m_currentToken == "+" || m_currentToken == "-" )
{
Parser.Token oOp = m_currentToken;
PositionNextToken();
CValue oNextVal = MultDiv();
CheckParms( oOp, oValue, oNextVal);
oValue = OpFactory( oOp, oValue, oNextVal );
}
return oValue;
}
/// <summary>
/// Relational(): Detects the operation to perform a relational operator (>, <, <=, etc.).
/// </summary>
/// <returns>CValue object representing an operation.</returns>
private CValue Relational()
{
CValue oValue = AddSub();
while (m_currentToken == "&&" ||
m_currentToken == "||" ||
m_currentToken == "==" ||
m_currentToken == "<" ||
m_currentToken == ">" ||
m_currentToken == "<=" ||
m_currentToken == ">=" ||
m_currentToken == "!=" ||
m_currentToken == "<>")
{
Parser.Token oOp = m_currentToken;
PositionNextToken();
CValue oNextVal = Relational();
CheckParms( oOp, oValue, oNextVal);
oValue = OpFactory( oOp, oValue, oNextVal );
}
return oValue;
}
/// <summary>
/// OpFactor(...): Reads the passed operator, identifies the associated implementation object
/// and requests an operation object to be used in evaluating the equation.
/// </summary>
/// <param name="oSourceOp">Parser.Token object representing the operator in question.</param>
/// <param name="oValue1">The first value object to be operated on.</param>
/// <param name="oValue2">The second value object to be operated on.</param>
/// <returns>CValue object representing an operation.</returns>
private CValue OpFactory( Parser.Token oSourceOp, CValue oValue1, CValue oValue2 )
{
foreach( COperator oOp in m_aOps )
{
if( oOp.IsMatch( oSourceOp ))
return oOp.Factory(oValue1, oValue2);
}
throw new ApplicationException("Invalid operator in equation.");
}
#endregion
#region Core Base Classes
/// <summary>
/// CBalue class: This base is the basic building block of
/// all operations, variables, functions, etc.. Any object
/// may call to a CValue object asking for it to resolve itself
/// and return it's processed value.
/// </summary>
public abstract class CValue
{
public abstract double GetValue();
}
/// <summary>
/// CVariable class : Derived from CValue, CVariable implements
/// a named expression variable, holding the name and associated value.
/// This object is accessed when an expression is evaluated or when
/// a user sets a variable value.
/// </summary>
public class CVariable : CValue
{
private string m_sVarName;
private double m_dValue;
/// <summary>
/// CVariable(string) constructor: Creates the object and holds onto the
/// compile-time assigned variable name.
/// </summary>
/// <param name="sVarName">Name of the variable within the expression.</param>
public CVariable( string sVarName )
{
m_sVarName = sVarName;
}
/// <summary>
/// CVariable(string,double) constructor: Creates the objects and holds onto the
/// compile-time assigned variable name and value.
/// </summary>
/// <param name="sVarName">string containing the variable name</param>
/// <param name="dValue">double containing the assigned variable value</param>
public CVariable( string sVarName, double dValue )
{
m_sVarName = sVarName;
}
/// <summary>
/// SetValue(): Allows the setting of the variables value at runtime.
/// </summary>
/// <param name="dValue"></param>
public void SetValue( double dValue )
{
m_dValue = dValue;
}
/// <summary>
/// GetValue(): Returns the value of the variable to the calling client.
/// </summary>
/// <returns>double</returns>
public override double GetValue()
{
return m_dValue;
}
}
/// <summary>
/// CNumber Class: A CValue-derived class that implements a static
/// numeric value in an expression.
/// </summary>
public class CNumber : CValue
{
private double m_dValue;
/// <summary>
/// CNumber(string) constructor: take a string representation of a static number
/// and stores it for future retrieval.
/// </summary>
/// <param name="sValue">string/text representation of a number</param>
public CNumber( string sValue )
{
m_dValue = Convert.ToDouble(sValue);
}
/// <summary>
/// CNumber(double) constructor: takes a double represenation of a static number
/// and stores it for future retrieval.
/// </summary>
/// <param name="dValue"></param>
public CNumber( double dValue )
{
m_dValue = dValue;
}
/// <summary>
/// GetValue(): returns the static value when called upon.
/// </summary>
/// <returns>double</returns>
public override double GetValue()
{
return m_dValue;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -