Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- dofile("Class.lua") --Load Class API for OOP
- import("Classes.lua") -- Import Stack and Queue class
- local opOrder={} -- table that holds the operators , the rank of the operator ( * before + )
- opOrder["*"]={rank=2,isLeft=true }
- opOrder["/"]={rank=2,isLeft=true }
- opOrder["+"]={rank=1,isLeft=false}
- opOrder["-"]={rank=1,isLeft=true }
- opOrder["^"]={rank=3,isLeft=false}
- opOrder["%"]={rank=2,isLeft=true }
- local action={} -- the actions for all standart math operators
- action["+"]=function(l,r)
- return l+r
- end
- action["-"]=function(l,r)
- return l-r
- end
- action["*"]=function(l,r)
- return l*r
- end
- action["/"]=function(l,r)
- return l/r
- end
- action["^"]=function(l,r)
- return math.pow(l,r)
- end
- action["%"]=function(l,r)
- return math.fmod(l,r)
- end
- local functions={}
- functions["abs"]=function(val) return math.abs(val) end
- functions["cos"]=function(val) return math.cos(val) end
- functions["log"]=function(val) return math.log(val) end
- functions["sin"]=function(val) return math.sin(val) end
- functions["tan"]=function(val) return math.tan(val) end
- functions["sqrt"]=function(val) return math.sqrt(val) end
- functions["random"]=function(val) return math.random(val) end
- functions["logt"]=function(val) return math.log10(val) end
- -- /**
- -- * shuntingYard turns a Queue of tokens(infix expression) and turns it into a (RPN expression)
- -- * @param [Queue] exp Queue representing the infix expression
- -- * @return [Queue] Queue representing the RPN expression
- -- */
- local function shuntingYard(exp)
- local input=exp
- local output=Queue()
- local op=Stack()
- while not input.isEmpty do
- local token=input:dequeue()
- if tonumber(token) then
- output:enqueue(token)
- elseif functions[token] then
- op:push(token)
- elseif opOrder[token] then
- local top=op:peek()
- while op.isEmpty==false and opOrder[top]~=nil and ((opOrder[token].isLeft and opOrder[token].rank<opOrder[top].rank) or opOrder[token].rank<=opOrder[top].rank) do
- output:enqueue(op:pop())
- top=op:peek()
- end
- op:push(token)
- elseif token=="(" then
- op:push(token)
- elseif token==")" then
- while op:peek()~="(" do
- if op.isEmpty then
- return("[ERROR]:The closing bracket is not preceeded by an opening bracket")
- end
- output:enqueue(op:pop())
- if functions[op:peek()] then
- output:enqueue(op:pop())
- end
- end
- op:pop()
- end
- end
- while not op.isEmpty do
- if op:peek()=="(" then
- return("[ERROR]:More opening brackets than closing brackets")
- end
- output:enqueue(op:pop())
- end
- return output
- end
- -- /**
- -- * toTokenStream turns a string expression into a Queue of Tokens that represent numbers, operators and brackets
- -- * @param [string] sExpression the string that holds the math expression in infix notation
- -- * @return [Queue] the token Queue
- -- */
- local function toTokenStream(sExpression)
- local _tokens=Queue()
- pos=1
- local nextDigitIsNegative=false
- while pos<=#sExpression do
- local e=sExpression:sub(pos,pos)
- if tonumber(e) then
- local notNum=false
- local number=e
- local p=pos+1
- while notNum==false do
- if tonumber(sExpression:sub(p,p)) then
- number=number..sExpression:sub(p,p)
- p=p+1
- elseif sExpression:sub(p,p)=="." then
- number=number..sExpression:sub(p,p)
- p=p+1
- else
- notNum=true
- end
- end
- if nextDigitIsNegative then
- number=tonumber(number)*-1
- else
- number=(tonumber(number))
- end
- _tokens:enqueue(number)
- pos=p
- nextDigitIsNegative=false
- elseif e:match("%a") then
- local f=e
- local notFunc=false
- local p=pos+1
- while notFunc==false do
- if sExpression:sub(p,p):match("%a") then
- f=f..sExpression:sub(p,p)
- p=p+1
- else
- notFunc=true
- end
- end
- _tokens:enqueue(f)
- pos=p
- elseif e==" " then
- pos=pos+1
- else
- if e=="-" then
- if _tokens:last() and type(_tokens:last())=="number" then
- _tokens:enqueue(e)
- else
- nextDigitIsNegative=true -- TODO: CURRENTLY NOT WORKING
- end
- else
- _tokens:enqueue(e)
- end
- pos=pos+1
- end
- end
- return _tokens
- end
- -- /**
- -- * evaluateRPN evaluates a RPN expression
- -- * @param [Queue] reverse the Queue that holds the RPN expression
- -- * @return [number] the result of the expression
- -- */
- local function evaluateRPN(reverse)
- local op=Stack()
- while not reverse.isEmpty do
- local val=reverse:dequeue()
- if tonumber(val) then
- op:push(val)
- elseif opOrder[val] then
- local r=op:pop()
- local l=op:pop()
- op:push(action[val](tonumber(l) or 0 ,tonumber(r)))
- elseif functions[val] then
- op:push(functions[val](op:pop()))
- end
- end
- return op:pop()
- end
- local expression =table.concat({ ... }, " ")
- if #expression==0 then
- print("Enter your expression: ")
- expression=io.read()
- else
- local TOKENSTREAM=toTokenStream(expression)
- local reverse=shuntingYard(TOKENSTREAM)
- local result=evaluateRPN(reverse)
- print(result)
- return
- end
- local TOKENSTREAM=toTokenStream(expression)
- local reverse=shuntingYard(TOKENSTREAM)
- if type(reverse)=="string" then
- print(reverse)
- else
- print("Your result is :"..evaluateRPN(reverse))
- end
Advertisement
Add Comment
Please, Sign In to add comment