Interpret StackyMath!
Ruby, 412 410 404 392 380 377 characters
def e m,x='Exception';warn m+x+?!*3;exit;end
def o;e'StackUnderflow'if$*==[];$*.pop;end
u=->n{e'DivisionByZero'if n.infinite?;e'NumberOverflow'if n>2**64;$*<<n}
f=->n{e'NegativeFactorial'if n<0;e'FloatingFactorial'if n.to_i<n;n<2?1:f[n-1]*n}
gets.gsub(/(\d+)|([+*\/%^-])|(!)|D/){$1?u[$1.to_f]:$2?u[eval"o#{$2>?A?:**:$2}o"]:$3?u[f[o]]:u[x=o]+u[x]}
e'EmptyProgram',''if$*==[]
p o
This is regular precision version using Float
. The result precision is as in the sample code, but numeric overflow detection is not exact.
Sample run:
bash-4.3$ ruby StackyMath.rb <<< '654,489,48,43/5*7D+-*%'
77.68749999999909
Ruby, 378 377 characters
def e m,x='Exception';warn m+x+?!*3;exit;end
def o;e'StackUnderflow'if$*==[];$*.pop;end
u=->n{e'NumberOverflow'if n>2**64;$*<<n}
f=->n{e'NegativeFactorial'if n<0;e'FloatingFactorial'if n.to_i<n;n<2?1:f[n-1]*n}
gets.gsub(/(\d+)|([+*\/%^-])|(!)|D/){$1?u[Rational$1]:$2?u[eval"o#{$2>?A?:**:$2}o"]:$3?u[f[o]]:u[x=o]+u[x]}rescue e'DivisionByZero'
e'EmptyProgram',''if$*==[]
p o.to_f
This is high precision version using Rational
. The result precision is not always the same as in the sample code, but numeric overflow detection is exact.
Sample run:
bash-4.3$ ruby StackyMath-hi.rb <<< '654,489,48,43/5*7D+-*%'
77.6875
JavaScript (ES6), 430 bytes
422 bytes with ES7 by changing Math.pow(2,2)
to 2**2
e=m=>{throw alert(m)};u=prompt();u?alert(eval('u.match(/\\d+|[^,]/g).map(o=>s.push(t=o=="/"?(b=p(a=2))?a/b:e`DivisionByZero43*"?2*23-"?2-23+"?2+23%"?2%23^"?Math.pow(2,2)3D"?s.push(r=2)&&r3!"?eval("for(r=i=2;i<0?e`Negative54:i%1?e`Floating54:--i;)r*=i;r"):+o)&&t==Infinity&&e`NumberOverflow4,s=[],p=_=>s.length?s.pop():e`StackUnderflow4);t'.replace(/[2-5]/g,x=>[,,'p()',':o=="','Exception!!!`','Factorial'][x]))):e`EmptyProgram!!!`
Explanation
Uses eval
to replace certain common phrases. Ungolfed and without the eval
it looks like this:
e=m=>{throw alert(m)}; // e = throw error, alert displays
// message, throw stops execution
u=prompt(); // u = received input
u?alert( // display the result
u.match(/\d+|[^,]/g) // get array of numbers and operators
.map(o=> // iterate over operators
s.push(t= // t = last pushed value
// Execute operator
o=="/"?(b=p(a=p()))?a/b: // make sure argument B is not 0
e`DivisionByZeroException!!!`:
o=="*"?p()*p():
o=="-"?p()-p():
o=="+"?p()+p():
o=="%"?p()%p():
o=="^"?Math.pow(p(),p()):
o=="D"?s.push(r=p())&&r:
o=="!"?eval(" // eval to enable for loop in ternary
for( // no factorial in JS so do this manually
r=i=p();
i<0?e`NegativeFactorialException!!!` // check for errors
:i%1?
e`FloatingFactorialException!!!`
:--i;
)
r*=i;
r"): // return r
+o // if not an operator cast as a number
)&&t==Infinity&& // JS turns anything over 64 bit float
e`NumberOverflowException!!!`, // max value into Infinity
s=[], // s = stack array
p=_=>s.length?s.pop(): // p = check stack then pop
e`StackUnderflowException!!!`
)&&t // return top stack element
):e`EmptyProgram!!!` // error if input length is 0