Kouksi44

Calculator

Aug 1st, 2015
375
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.40 KB | None | 0 0
  1. dofile("Class.lua")   --Load Class API for OOP
  2. import("Classes.lua") -- Import Stack and Queue class
  3.  
  4.  
  5. local opOrder={} -- table that holds the operators , the rank of the operator ( * before + )
  6. opOrder["*"]={rank=2,isLeft=true }
  7. opOrder["/"]={rank=2,isLeft=true }
  8. opOrder["+"]={rank=1,isLeft=false}
  9. opOrder["-"]={rank=1,isLeft=true }
  10. opOrder["^"]={rank=3,isLeft=false}
  11. opOrder["%"]={rank=2,isLeft=true }
  12.  
  13.  
  14. local action={} -- the actions for all standart math operators
  15.  
  16. action["+"]=function(l,r)
  17.         return l+r
  18. end
  19.  
  20. action["-"]=function(l,r)
  21.         return l-r
  22. end
  23.  
  24. action["*"]=function(l,r)
  25.         return l*r
  26. end
  27.  
  28. action["/"]=function(l,r)
  29.         return l/r
  30. end
  31.  
  32. action["^"]=function(l,r)
  33.         return math.pow(l,r)
  34. end
  35.  
  36. action["%"]=function(l,r)
  37.         return math.fmod(l,r)
  38. end
  39.  
  40. local functions={}
  41.  
  42. functions["abs"]=function(val)    return math.abs(val)      end
  43. functions["cos"]=function(val)    return math.cos(val)      end
  44. functions["log"]=function(val)    return math.log(val)      end
  45. functions["sin"]=function(val)    return math.sin(val)      end
  46. functions["tan"]=function(val)    return math.tan(val)      end
  47. functions["sqrt"]=function(val)   return math.sqrt(val)     end
  48. functions["random"]=function(val) return math.random(val)   end
  49. functions["logt"]=function(val)   return math.log10(val)    end
  50.  
  51. -- /**
  52. --  * shuntingYard turns a Queue of tokens(infix expression) and turns it into a (RPN expression)
  53. --  * @param  [Queue] exp Queue representing the infix expression
  54. --  * @return [Queue] Queue representing the RPN expression
  55. --  */
  56. local function shuntingYard(exp)
  57.     local input=exp
  58.     local output=Queue()
  59.     local op=Stack()
  60.     while not input.isEmpty do
  61.         local token=input:dequeue()
  62.         if tonumber(token) then
  63.             output:enqueue(token)
  64.         elseif functions[token] then
  65.             op:push(token)
  66.         elseif opOrder[token] then
  67.             local top=op:peek()
  68.            
  69.             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
  70.                 output:enqueue(op:pop())
  71.                 top=op:peek()
  72.             end
  73.            
  74.             op:push(token)
  75.            
  76.         elseif token=="(" then
  77.             op:push(token)
  78.         elseif token==")" then
  79.             while op:peek()~="(" do
  80.                 if op.isEmpty then
  81.                     return("[ERROR]:The closing bracket is not preceeded by an opening bracket")
  82.                 end
  83.                 output:enqueue(op:pop())
  84.                 if functions[op:peek()] then
  85.                     output:enqueue(op:pop())
  86.                 end
  87.             end
  88.             op:pop()
  89.         end
  90.     end
  91.     while not op.isEmpty do
  92.         if op:peek()=="(" then
  93.             return("[ERROR]:More opening brackets than closing brackets")
  94.         end
  95.         output:enqueue(op:pop())
  96.     end
  97.     return output
  98. end
  99.  
  100. -- /**
  101. --  * toTokenStream turns a string expression into a Queue of Tokens that represent numbers, operators and brackets
  102. --  * @param  [string] sExpression the string that holds the math expression in infix notation
  103. --  * @return [Queue]  the token Queue
  104. --  */
  105. local function toTokenStream(sExpression)
  106.     local _tokens=Queue()
  107.      pos=1
  108.      local nextDigitIsNegative=false
  109.     while pos<=#sExpression do
  110.         local e=sExpression:sub(pos,pos)
  111.         if tonumber(e) then
  112.             local notNum=false
  113.             local number=e
  114.             local p=pos+1
  115.             while notNum==false do
  116.                 if tonumber(sExpression:sub(p,p)) then
  117.                     number=number..sExpression:sub(p,p)
  118.                     p=p+1
  119.                 elseif sExpression:sub(p,p)=="." then
  120.                     number=number..sExpression:sub(p,p)
  121.                     p=p+1
  122.                 else
  123.                     notNum=true
  124.                 end
  125.             end
  126.             if nextDigitIsNegative then
  127.                 number=tonumber(number)*-1
  128.             else
  129.                 number=(tonumber(number))
  130.             end
  131.             _tokens:enqueue(number)
  132.             pos=p
  133.             nextDigitIsNegative=false
  134.         elseif e:match("%a") then
  135.       local f=e
  136.       local notFunc=false
  137.       local p=pos+1
  138.       while notFunc==false do
  139.         if sExpression:sub(p,p):match("%a") then
  140.           f=f..sExpression:sub(p,p)
  141.           p=p+1
  142.         else
  143.           notFunc=true
  144.         end
  145.       end
  146.       _tokens:enqueue(f)
  147.             pos=p
  148.     elseif e==" " then
  149.       pos=pos+1
  150.     else
  151.             if e=="-" then
  152.                 if _tokens:last() and type(_tokens:last())=="number" then
  153.                     _tokens:enqueue(e) 
  154.                 else
  155.                     nextDigitIsNegative=true -- TODO: CURRENTLY NOT WORKING
  156.                 end
  157.             else
  158.                 _tokens:enqueue(e)
  159.             end
  160.             pos=pos+1
  161.         end
  162.     end
  163.     return _tokens
  164. end
  165.  
  166.  
  167. -- /**
  168. --  * evaluateRPN evaluates a RPN expression
  169. --  * @param  [Queue]   reverse the Queue that holds the RPN expression
  170. --  * @return [number]  the result of the expression
  171. --  */
  172. local function evaluateRPN(reverse)
  173.     local op=Stack()
  174.     while not reverse.isEmpty do
  175.         local val=reverse:dequeue()
  176.         if tonumber(val) then
  177.             op:push(val)
  178.         elseif opOrder[val] then
  179.             local r=op:pop()
  180.             local l=op:pop()
  181.             op:push(action[val](tonumber(l) or 0 ,tonumber(r)))
  182.         elseif functions[val] then
  183.             op:push(functions[val](op:pop()))
  184.         end
  185.     end
  186.     return op:pop()
  187. end
  188.  
  189. local expression =table.concat({ ... }, " ")
  190.  
  191.  
  192. if #expression==0 then
  193.         print("Enter your expression: ")
  194.         expression=io.read()
  195. else
  196.         local TOKENSTREAM=toTokenStream(expression)
  197.         local reverse=shuntingYard(TOKENSTREAM)
  198.         local result=evaluateRPN(reverse)
  199.         print(result)
  200.         return
  201.  
  202. end
  203.  
  204.  
  205.  
  206.  
  207. local TOKENSTREAM=toTokenStream(expression)
  208.  
  209. local reverse=shuntingYard(TOKENSTREAM)
  210.  
  211.  
  212.  
  213.  
  214. if type(reverse)=="string" then
  215.         print(reverse)
  216. else
  217.         print("Your result is :"..evaluateRPN(reverse))
  218. end
Advertisement
Add Comment
Please, Sign In to add comment