Created
July 29, 2017 09:37
-
-
Save andreafioraldi/97b7dbc188dce006de650b2e14b3dc48 to your computer and use it in GitHub Desktop.
An expression solver based on the reverse polish notation written in Stout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
An expression solver based on the reverse polish notation written in Stout. | |
author = Andrea Fioraldi | |
copyright = Copyright 2017, Andrea Fioraldi | |
license = MIT | |
mail = [email protected] | |
*/ | |
library IO; | |
library Math; | |
library Object; | |
attach operators <- ["+", "-", "*", "/"]; | |
attach opsPrec <- [1, 1, 2, 2]; | |
attach functions <- ["Abs", "Acos", "Acosh", "Asin", "Asinh", "Atan", "Atanh", "Ceil", "Cos", "Cosh", "Cot", "Coth", "Exp", "Exp10", "Exp2", "Fact", "Floor", "GetCatalan", "GetEuler", "GetPI", "Hypot", "Log", "Log10", "Log2", "Pow", "Range", "Sin", "Sinh", "Sqrt", "Tan", "Tanh"]; | |
attach functionsArgs <- [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1]; | |
attach Tokenize <- object { | |
if(args.Length() < 1) | |
throw "Tokenize needs 1 parameter"; | |
s <- args[0]; | |
if(typeof s != typeof "") | |
throw "Tokenize needs a string as parameter"; | |
if(s.Length() == 0) | |
return []; | |
if(s[0] == '+' || s[0] == '-') | |
s = "0" + s; | |
mem = ""; | |
tokens <- []; | |
for(ch : s.ToArray()) { | |
c <- ch.ToString(); | |
if(global.operators.Find(c) != -1 || ch == ',' || ch == '(' || ch == ')') { | |
if(mem == "" && (ch == '+' || ch == '-') && tokens.Last() == "(") { | |
tokens.Push("0"); | |
tokens.Push(c); | |
} | |
else { | |
m1 = mem.Replace(" ", ""); | |
if(m1.Length() > 0) | |
tokens.Push(m1); | |
mem = ""; | |
tokens.Push(c); | |
} | |
} | |
else mem += c; | |
} | |
if(mem != "") | |
tokens.Push(mem.Replace(" ", "")); | |
return tokens; | |
}; | |
attach ToRPN <- object { | |
if(args.Length() < 1) | |
throw "ToRPN needs 1 parameter"; | |
if(typeof args[0] != typeof []) | |
throw "ToRPN needs an array as parameter"; | |
IsReal <- object { | |
try args[0].ToFloat(); | |
catch return false; | |
return true; | |
}; | |
output <- []; | |
stack <- []; | |
for(e : args[0]) { | |
if(IsReal(e)) output.Push(e); | |
else if((ef <- global.functions.Find(e)) != -1) { | |
stack.Push(e, 0); | |
} | |
else if((ef <- global.operators.Find(e)) != -1) { | |
while(stack.Length() > 0 && (s0f <- global.operators.Find(stack[0])) != -1 && global.opsPrec[ef] <= global.opsPrec[s0f]) { | |
output.Push(stack[0]); | |
stack.Pop(0); | |
} | |
stack.Push(e, 0); | |
} | |
else if(e == ",") { | |
while(stack.Length() > 0 && stack[0] != "(") { | |
output.Push(stack[0]); | |
stack.Pop(0); | |
} | |
if(stack.Length() == 0) | |
throw "ToRPN mismatched parentheses"; | |
} | |
else if(e == "(") stack.Push(e, 0); | |
else if(e == ")") { | |
while(stack.Length() > 0 && stack[0] != "(") { | |
output.Push(stack[0]); | |
stack.Pop(0); | |
} | |
if(stack.Length() == 0) | |
throw "ToRPN mismatched parentheses"; | |
stack.Pop(0); | |
if(stack.Length() > 0 && global.functions.Find(stack[0]) != -1) { | |
output.Push(stack[0]); | |
stack.Pop(0); | |
} | |
} | |
else throw "ToRPN invalid token " + e; | |
} | |
while(stack.Length() > 0) { | |
if(stack[0] == "(" || stack[0] == ")") | |
throw "ToRPN mismatched parentheses"; | |
output.Push(stack[0]); | |
stack.Pop(0); | |
} | |
return output; | |
}; | |
attach RPNCalc <- object { | |
if(args.Length() < 1) | |
throw "RPNCalc needs 1 parameter"; | |
if(typeof args[0] != typeof []) | |
throw "RPNCalc needs an array as parameter"; | |
stack <- []; | |
for(e : args[0]) { | |
if(global.operators.Find(e) != -1) { | |
op2 <- stack[0]; | |
op1 <- stack[1]; | |
stack.Pop(0, 2); | |
if(e == "+") | |
stack.Push(op1 + op2, 0); | |
else if(e == "-") | |
stack.Push(op1 - op2, 0); | |
else if(e == "*") | |
stack.Push(op1 * op2, 0); | |
else if(e == "/") | |
stack.Push(op1 / op2, 0); | |
} | |
else if((ef <- global.functions.Find(e)) != -1) { | |
n <- global.functionsArgs[ef]; | |
if(n == 1) { | |
tmp <- stack[0]; | |
stack.Pop(0); | |
stack.Push(Object.Attr(Math, e)(tmp), 0); | |
} | |
else if(n == 2) { | |
tmp2 <- stack[0]; | |
stack.Pop(0); | |
tmp1 <- stack[0]; | |
stack.Pop(0); | |
stack.Push(Object.Attr(Math, e)(tmp1, tmp2), 0); | |
} | |
} | |
else stack.Push(e.ToFloat(), 0); | |
} | |
if(stack.Length() != 1) | |
throw "RPNCalc invalid stack"; | |
return stack[0]; | |
}; | |
attach Calculate <- object { | |
if(args.Length() < 1) | |
throw "Calculate needs 1 parameter"; | |
s <- args[0]; | |
if(typeof s != typeof "") | |
throw "Calculate needs a string as parameter"; | |
return global.RPNCalc(global.ToRPN(global.Tokenize(s))); | |
}; | |
if(addressof main == addressof me) { | |
while(true) { | |
IO.Print("Insert expression: "); | |
exp <- IO.Readl().Trim(); | |
if(exp.Length() > 0) { | |
try IO.Printl("Result: ", global.Calculate(exp)); | |
catch IO.PrintErr("ERROR: ", error, "\n"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment