|
> "(.1+45/0.5)*2+3"というサンプルを少し変更して、"-(.1+45/0.5)*2+3"だと計算がうまく行きません。
> こういうのにも対応したいなら、単項演算子の+/-の処理は、因子でやるように構文規則を変えるといいですよ。
下記の変更でいいでしょうか?
他にも、お気づきのてんがあれば、お知らせ下さい。
using System;
namespace ConsoleApplication1 {
class Program {
static void Main( string[] args ) {
構文解析 o構文解析 = new 構文解析();
string[] s計算式 = new string[] {
"-2^2",
"-(.123+.456)",
"4*2^2",
"(4*2)^2",
"((4*2)^2)/2",
"4*2^2/2"
};
double 答;
foreach ( string s式 in s計算式 ) {
答 = o構文解析.計算( s式 );
System.Console.WriteLine( s式 + " = " + 答.ToString() );
}
}
}
public class 構文解析 {
private string m_s計算式;
private int m_i計算位置;
private const double 円定数 = Math.PI / 180.0;
public double 計算( string s計算式_ ) {
m_s計算式 = s計算式_.ToUpper().Replace(" ","");
m_i計算位置 = 0;
try {
return 式();
} catch ( Exception e ) {
System.Console.WriteLine( e.ToString() );
return double.NaN;
}
}
private double 式() {
double 答 = 項();
for ( ; m_i計算位置 < m_s計算式.Length; ) {
switch ( m_s計算式[m_i計算位置] ) {
case '+': m_i計算位置++; 答 += 項(); break;
case '-': m_i計算位置++; 答 -= 項(); break;
default: return 答;
}
}
return 答;
}
private double 項() {
double 答 = 冪乗項();
for ( ; m_i計算位置 < m_s計算式.Length; ) {
switch ( m_s計算式[m_i計算位置] ) {
case '*': m_i計算位置++; 答 *= 冪乗項(); break;
case '/': m_i計算位置++; 答 /= 冪乗項(); break;
default: return 答;
}
}
return 答;
}
private double 冪乗項() {
double 答 = 因子();
for ( ; m_i計算位置 < m_s計算式.Length; ) {
switch ( m_s計算式[m_i計算位置] ) {
case '^': m_i計算位置++; 答 = Math.Pow(答 ,因子()); break;
default: return 答;
}
}
return 答;
}
private double 因子() {
double 答;
char 符号 = '+';
switch ( m_s計算式[m_i計算位置] ) {
case '+': 符号 = m_s計算式[m_i計算位置++]; break;
case '-': 符号 = m_s計算式[m_i計算位置++]; break;
}
if ( m_s計算式[m_i計算位置] == '(' ) {
m_i計算位置++;
答 = 式();
if ( m_s計算式[m_i計算位置] != ')' ) throw new Exception(")なし");
m_i計算位置++;
} else {
答 = 数値();
}
if ( 符号 == '-' ) return -答;
return 答;
}
private double 数値() {
double 答 = double.NaN;
if ( Is数値文字(m_s計算式[m_i計算位置]) == true ) {
string s数値 = string.Empty;
for ( ; m_i計算位置 < m_s計算式.Length; ) {
if ( Is数値文字(m_s計算式[m_i計算位置]) == false ) break;
s数値 += m_s計算式[m_i計算位置++];
}
try {
答 = double.Parse(s数値);
} catch ( Exception e ) {
throw e;
}
} else {
if ( m_i計算位置 + 3 < m_s計算式.Length ) {
string s関数 = m_s計算式.Substring(m_i計算位置 ,3);
switch ( s関数 ) {
case "SIN": m_i計算位置 += 4; 答 = Math.Sin(円定数 * 式()); m_i計算位置++; break;
case "COS": m_i計算位置 += 4; 答 = Math.Cos(円定数 * 式()); m_i計算位置++; break;
case "TAN": m_i計算位置 += 4; 答 = Math.Tan(円定数 * 式()); m_i計算位置++; break;
case "SQR": m_i計算位置 += 4; 答 = Math.Sqrt(式()); m_i計算位置++; break;
}
}
}
return 答;
}
private bool Is数値文字( char 文字 ) {
if ( char.IsDigit( 文字 ) == true ) return true;
if ( 文字.Equals('.') == true ) return true;
return false;
}
}
}
|