(Sumber: milist DOTNET) Algoritma Membaca Rumus
-
Wednesday, February 22, 2012 3:16 AMModerator
Mohon pencerahan,
asumsikan saya punya rumus seperti ini "(a+b)-c".
nah dari contoh diatas tersebut, "a", "b" dan "c" nanti akan diganti dengan angka yang akan dinput oleh user.
yang menjadi pertanyaan saya adalah, bagaimana caranya membaca suatu rumus dalam notasi teks menjadi suatu rumus yang bisa dihitung/dijalankan ? adakah algoritmanya ? (mungkin mirip seperti excel)
Terima kasih sebelumnya
Agnes Sannie [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
All Replies
-
Wednesday, February 22, 2012 3:16 AMModerator
Halo,
Coba baca tutorial dari Yohanes Nugroho:
http://yohan.es/compiler/tutorial1/
Di chapter 1 Dragon Book karangan Alfred Aho, Jeffrey Ullman juga langsung bahas bikin beginian tanpa banyak teori.
Dijawab oleh:
Dicky Arinal
Agnes Sannie [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.- Marked As Answer by Agnes SannieMicrosoft Contingent Staff, Moderator Wednesday, February 22, 2012 3:19 AM
-
Wednesday, February 22, 2012 3:17 AMModerator
terima kasih atas pencerahannya,
saya menemukan apa yang saya cari di
http://www.codeproject.com/Articles/23061/MathParser-Math-Formula-Parser
terima kasih banyak.
Agnes Sannie [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.- Marked As Answer by Agnes SannieMicrosoft Contingent Staff, Moderator Wednesday, February 22, 2012 3:19 AM
-
Wednesday, February 22, 2012 3:19 AMModerator
Sekedar pembelajaran, saya iseng-iseng bikin karena kurang kerjaan, mungkin masih beberapa yang buggy karena baru dibikin :) Algoritma sangat sederhana, bisa dipelajari pada chapter 1 buku Dragon book, top down parser dengan rekursif.
Cara penggunaan:
var parser = new ArithmeticParser("3 + x + y")
.SetVariable("x", 2)
.SetVariable("y", 3);
parser.Parse(); // will return 10
Penggunaan lain bisa menggunakan lambda untuk menambah fungsi baru, ingat penambahan fungsi baru cuma bisa dilakukan at compile time!
parser = new ArithmeticParser("pow(3 + 1, sin(3))")
.SetFunction("pow", param => Math.Pow(param[0], param[1]))
.SetFunction("sin", param => Math.Sin(param[0]));
Saat parser di-instantiate, semua variabel akan dikenali dan di set menjadi nol, sehingga code di bawah menjadi mungkin:
var parser = new ArithmeticExpressionParser(Console.ReadLine()); // input ekspresi dari keyboard foreach (var variable in parser.GetVariablesName()) {
Console.Write("Set variable for {0} : ", variable);
parser.SetVariable(variable, double.Parse(Console.ReadLine()));
}
Console.WriteLine(parser.Parse());
Just copy paste this to your Console program.
namespace Konsole
{
public class ParserMain
{
private static void Main()
{
var porsar = new ArithmeticExpressionParser("x + y")
.SetVariable("x", 5)
.SetVariable("y", 3);
Console.WriteLine(porsar.Parse());
Console.Write("Enter expression: ");
var parser = new ArithmeticExpressionParser(Console.ReadLine())
.SetFunction("pow", param => Math.Pow(param[0], param[1]))
.SetFunction("sin", param => Math.Sin(param[0]));
foreach (var symbol in parser.GetVariablesName())
{
Console.Write("Set variable for {0} : ", symbol);
parser.SetVariable(symbol, double.Parse(Console.ReadLine()));
}
Console.WriteLine(parser.Parse());
}
}
public class ArithmeticExpressionParser
{
private IEnumerator<char> _enumerator;
private string _expression;
private bool _notFinished;
private readonly Dictionary<string, double> _variables;
private readonly Dictionary<string, Func<double[], double>> _functions;
public string Expression
{
get { return _expression; }
set
{
_expression = value.Trim();
_variables.Clear();
Parse(); // create variables into symbols dictionary
}
}
public char Current
{
get { return _enumerator.Current; }
}
public ArithmeticExpressionParser(string expression)
{
_variables = new Dictionary<string, double>();
_functions = new Dictionary<string, Func<double[], double>>();
Expression = expression;
}
public ArithmeticExpressionParser SetVariable(string variableName, double value)
{
_variables[variableName] = value;
return this;
}
public ArithmeticExpressionParser SetFunction(string functionName, Func<double[], double> function)
{
_functions[functionName] = function;
return this;
}
public IEnumerable<string> GetVariablesName()
{
return _variables.Keys.ToArray();
}
public IEnumerable<string> GetFunctionsName()
{
return _functions.Keys.ToArray();
}
public double Parse()
{
_notFinished = true;
_enumerator = Expression.GetEnumerator();
_enumerator.MoveNext();
return ParseExpression();
}
private double ParseExpression()
{
double result = ParseTerm();
bool done = false;
while (_notFinished && !done)
{
switch (Current)
{
case '+':
MatchCurrentThenNext('+');
result += ParseTerm();
break;
case '-':
MatchCurrentThenNext('-');
result -= ParseTerm();
break;
default:
done = true;
break;
}
}
return result;
}
private double ParseTerm()
{
double result = ParseFactor();
bool done = false;
while (_notFinished && !done)
{
switch (Current)
{
case '*':
MatchCurrentThenNext('*');
result *= ParseFactor();
break;
case '/':
MatchCurrentThenNext('/');
result /= ParseFactor();
break;
default:
done = true;
break;
}
}
return result;
}
private double ParseFactor()
{
double result;
if (char.IsDigit(Current))
result = ParseNumber();
else if (Current == '-')
{
MatchCurrentThenNext('-');
result = -ParseFactor();
}
else if (Current == '(')
{
MatchCurrentThenNext('(');
result = ParseExpression();
MatchCurrentThenNext(')');
}
else if (char.IsLetter(Current))
result = ParseSymbol();
else
throw new InvalidOperationException("factor syntax error");
return result;
}
private double ParseSymbol()
{
string name = "";
while (_notFinished && (char.IsDigit(Current) ||
char.IsLetter(Current)))
{
name += Current;
MatchCurrentThenNext();
}
double result = _notFinished && Current == '(' ?
ProcessFunction(name) : ProcessVariable(name);
if (_notFinished && char.IsSeparator(Current))
NextNonWhiteSpace();
return result;
}
private double ProcessVariable(string name)
{
// second condition is intended for creating variables when first parsed
return _variables.ContainsKey(name) ? _variables[name] :
(_variables[name] = 0);
}
private double ProcessFunction(string name)
{
double result = 0;
MatchCurrentThenNext('(');
var parameters = new List<double>();
while (Current != ')')
{
parameters.Add(ParseExpression());
if (Current == ',')
{
MatchCurrentThenNext(',');
parameters.Add(ParseExpression());
}
}
if ( _functions.ContainsKey(name) )
result = _functions[name](parameters.ToArray());
else
_functions.Add(name, null);
MatchCurrentThenNext(')');
return result;
}
private double ParseNumber()
{
double result = 0.0;
double restFactor = 0.1;
bool shouldFindRest = false;
do
{
if (Current == '.')
{
MatchCurrentThenNext('.');
shouldFindRest = true;
}
else if (shouldFindRest)
{
result += CharToDouble(Current) * restFactor;
restFactor *= 0.1;
MatchCurrentThenNext();
}
else
{
result *= 10.0;
result += CharToDouble(Current);
MatchCurrentThenNext();
}
} while (_notFinished && (char.IsDigit(Current) || Current == '.'));
return result;
}
private void MatchCurrentThenNext(char currentChar)
{
if (Current == currentChar)
NextNonWhiteSpace();
else
throw new InvalidOperationException("Syntax error");
}
private void MatchCurrentThenNext()
{
MatchCurrentThenNext(Current);
}
private void NextNonWhiteSpace()
{
bool hasNext;
while ((hasNext = _enumerator.MoveNext()) &&
char.IsWhiteSpace(Current)) { }
_notFinished = hasNext;
}
private double CharToDouble(char numberChar)
{
return numberChar - '0';
}
}
}
Dijawab oleh:
Dicky Arinal
Agnes Sannie [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.

