Skip to content

Instantly share code, notes, and snippets.

@andreafioraldi
Created July 29, 2017 09:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreafioraldi/97b7dbc188dce006de650b2e14b3dc48 to your computer and use it in GitHub Desktop.
Save andreafioraldi/97b7dbc188dce006de650b2e14b3dc48 to your computer and use it in GitHub Desktop.
An expression solver based on the reverse polish notation written in Stout
/*
An expression solver based on the reverse polish notation written in Stout.
author = Andrea Fioraldi
copyright = Copyright 2017, Andrea Fioraldi
license = MIT
mail = andreafioraldi@gmail.com
*/
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