Arithmetic evaluation: Difference between revisions
Content added Content deleted
(→{{header|D}}: Just because it needs attention doesn't mean it's listening in.) |
m (→{{header|D}}: removed bug code and set incorrect tag, for no AST build) |
||
Line 327: | Line 327: | ||
=={{header|D}}== |
=={{header|D}}== |
||
{{incorrect}} |
|||
{{needs-review}} |
|||
module test; |
|||
import std.stdio; |
|||
int calculate(string expr) |
|||
{ |
|||
string take(int count) |
|||
{ |
|||
auto res = expr[0 .. count]; |
|||
expr = expr[count .. $]; |
|||
return res; |
|||
} |
|||
string peek(int count) |
|||
{ |
|||
if (expr.length < count) count = expr.length; |
|||
return expr [0 .. count]; |
|||
} |
|||
int delegate(int level) descent; |
|||
// grab the next number from the input expression |
|||
int getNumber() |
|||
{ |
|||
int res; |
|||
// if our "number" is a parantheses-wrapped expression, evaluate it |
|||
if (peek(1) == "(") { take(1); return descent(0); } |
|||
while (expr.length) |
|||
{ |
|||
auto next = peek(1)[0]; |
|||
// if the next character is a digit ... |
|||
if (next >= '0' && next <= '9') |
|||
{ |
|||
res = res * 10 + (next-'0'); |
|||
take(1); |
|||
} else return res; |
|||
} |
|||
return res; |
|||
} |
|||
// descent evaluates a level-l expression (1: multiplication and division, 0: also addition and subtraction) |
|||
descent = (int l) { |
|||
auto num = getNumber; // get the first number of our expression |
|||
while (expr.length) |
|||
{ |
|||
auto op = take(1)[0]; |
|||
if (op == ')') return num; // expression end |
|||
if (op == '*') num *= getNumber; |
|||
if (op == '/') num /= getNumber; |
|||
if (l == 1) return num; |
|||
if (op == '+') num += descent(1); |
|||
if (op == '-') num -= descent(1); |
|||
} |
|||
return num; |
|||
}; |
|||
return descent(0); |
|||
} |
|||
void main() |
|||
{ |
|||
writefln(calculate("(3+50)*7-9"), ", ", (3+50)*7-9); |
|||
} |
|||
{{works with|DMD|2.007}} |
|||
I'm a D newbie, hope this D code reveals some D unique features. |
|||
<pre>module eval; |
<pre>module eval; |
||
import std.stdio; |
import std.stdio; |
||
Line 398: | Line 336: | ||
// simple stack template |
// simple stack template |
||
void push(U)(inout U[] stk, U top) { |
void push(U)(inout U[] stk, U top) { |
||
stk = stk ~ top ; |
|||
} |
} |
||
U pop(U)(inout U[] stk, bool peektop = false) { |
U pop(U)(inout U[] stk, bool peektop = false) { |
||
U top ; |
|||
if (stk.length > 0) { |
|||
top = stk[$ - 1] ; |
|||
if (!peektop) |
|||
stk.length = stk.length - 1 ; |
|||
} else |
|||
throw new Exception("Invalid Expression") ; // or Empty Stack |
|||
return top ; |
|||
} |
} |
||
// evalutor function |
// evalutor function |
||
T eval(T = long)(string expression) { |
T eval(T = long)(string expression) { |
||
string[] opr ; // operator stack |
|||
T[] num ; // number stack |
|||
uint tokensum = 0 ; |
|||
int[char[]] prece = ["=":0, "(":1, ")":1,"+":2,"-":2,"*":3,"/":3] ; |
|||
void doMath(string op) { // operator executor |
|||
T valR = num.pop() ; |
|||
T valL = num.pop() ; |
|||
switch (op) { |
|||
case "+": return num.push(valL + valR) ; |
|||
case "-": return num.push(valL - valR) ; |
|||
case "*": return num.push(valL * valR) ; |
|||
case "/": return num.push(valL / valR) ; |
|||
} |
|||
} |
|||
} |
|||
opr.push("=") ; |
|||
foreach(m ; RegExp(r"[+*-/()]|\d+").search(expression)) { |
|||
string token = m.match(0) ; |
|||
tokensum += token.length ; |
|||
if (token[0] >= '0' && token[0] <= '9') |
|||
num.push(to!(T)(token)) ; |
|||
else if (token == "(") |
|||
opr.push(token) ; |
|||
else if (token == ")") { |
|||
while(opr.pop(true) != "(") |
|||
doMath(opr.pop()) ; |
|||
opr.pop() ; |
|||
} else { |
|||
while (prece[opr.pop(true)] >= prece[token]) |
|||
doMath(opr.pop()) ; |
|||
opr.push(token) ; |
|||
} |
|||
} |
|||
} |
|||
if (tokensum + count(expression, " ") != expression.length) |
|||
throw new Exception("Invalid Tokens") ; |
|||
while (opr.length > 1) |
|||
doMath(opr.pop()) ; |
|||
if (num.length != 1) |
|||
throw new Exception("Invalid Expression") ; |
|||
return num.pop() ; |
|||
} |
} |
||
void main(string[] args) { |
void main(string[] args) { |
||
foreach(xpr ; std.string.split(join(args[1..$], " "),",")) { |
|||
try{ |
|||
writefln("long: %s = %d", xpr, eval(xpr)) ; |
|||
writefln("int : %s = %d", xpr, eval!(int)(xpr)) ; |
|||
} |
|||
} |
|||
catch (Exception e) { |
|||
writefln("%s : %s", e.msg, xpr) ; |
|||
} |
|||
} |
|||
} |
|||
}</pre> |
|||
} |
|||
/*** sample output |
|||
D:\00MY\dmd>dmd eval |
|||
h:\dmd\bin\..\..\dm\bin\link.exe eval,,,user32+kernel32/noi; |
|||
D:\00MY\dmd>eval 1 + * 2, 4*5-3*2, a1 + b,4*(5-3)*2, 128*256*256*256+1 |
|||
Invalid Expression : 1 + * 2 |
|||
long: 4*5-3*2 = 14 |
|||
int : 4*5-3*2 = 14 |
|||
Invalid Tokens : a1 + b |
|||
long: 4*(5-3)*2 = 16 |
|||
int : 4*(5-3)*2 = 16 |
|||
long: 128*256*256*256+1 = 2147483649 |
|||
int : 128*256*256*256+1 = -2147483647 |
|||
***/</pre> |
|||
=={{header|Haskell}}== |
=={{header|Haskell}}== |