# Calculator

Oct 24th, 2017
178
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. -- This program is public domain. Do whatever you want with it.
2. os.pullEvent = os.pullEventRaw
3.
4. local expr
5.
6. local spacechars = " \t\n\r"
7.
8. local function skipspaces()
9. while spacechars:find(expr:sub(1, 1),1,true) ~= nil and expr:len() > 0 do
10. expr = expr:sub(2)
11. end
12. end
13.
14. local function acceptch(ch)
15. skipspaces()
16. if expr:sub(1,1) == ch then
17. expr = expr:sub(2)
18. return true
19. else
20. return false
21. end
22. end
23.
24. local function acceptnum()
25. skipspaces()
26. -- I'm sure there's a better way
27. for len = expr:len(), 1, -1 do
28. local success, n = pcall(tonumber, expr:sub(1, len))
29. if success and n ~= nil then
30. expr = expr:sub(len + 1)
31. return n
32. end
33. end
34. return nil
35. end
36.
37. local alpha = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
38. local alnum = alpha .. "0123456789"
39.
40. local function acceptident()
41. local n = 0
42. skipspaces()
43. if alpha:find(expr:sub(1, 1),1,true) == nil then return nil end
44. while alnum:find(expr:sub(n+1, n+1),1,true) ~= nil and expr:len() > n do
45. n = n + 1
46. end
47. local ident = expr:sub(1, n)
48. expr = expr:sub(n+1)
49. return ident
50. end
51.
52. local function parse_error(s)
53. error(s and ("parse error: " .. s) or "parse error")
54. end
55.
56. local expression_root
57.
58. local math_functions = {
59. abs = math.abs,
60. acos = math.acos,
61. asin = math.asin,
62. atan = math.atan,
63. atan2 = math.atan2,
64. ceil = math.ceil,
65. floor = math.floor,
66. cos = math.cos,
67. sin = math.sin,
68. tan = math.tan,
69. cosh = math.cosh,
70. sinh = math.sinh,
71. tanh = math.tanh,
73. exp = math.exp,
74. ln = math.log,
75. log = math.log10,
76. pow = math.pow,
77. min = math.min,
78. max = math.max,
79. sqrt = math.sqrt,
80. random = math.random
81. }
82.
83. local math_constants = {
84. pi = math.pi,
85. e = math.exp(1),
86. inf = math.huge,
87. nan = math.huge - math.huge
88. }
89.
90. local function call_function(id, arglist)
91. if math_functions[id] == nil then
92. error("no such function: " .. id)
93. end
94. return math_functions[id](unpack(arglist))
95. end
96.
97. local function get_constant(id)
98. return math_constants[id] or error("no such constant: "..id)
99. end
100.
101. local function num_or_brackets()
102. if acceptch("(") then
103. local n = expression_root()
104. if not acceptch(")") then parse_error("non-matching parentheses") end
105. return n
106. elseif acceptch("-") then
107. return -expression_root()
108. else
109. local id = acceptident()
110. if id ~= nil then
111. if not acceptch("(") then
112. return get_constant(id)
113. elseif acceptch(")") then
114. return call_function(id, {})
115. else
116. local arglist = {}
117. local done = false
118. while not done do
119. table.insert(arglist, expression_root())
120. if acceptch(")") then
121. done = true
122. elseif not acceptch(",") then
123. parse_error("expected , or )")
124. end
125. end
126. return call_function(id, arglist)
127. end
128. else
129. local n = acceptnum()
130. if n == nil then parse_error("expected number or bracketed expression") end
131. return n
132. end
133. end
134. end
135.
136. local function division()
137. local n1 = num_or_brackets()
138. while acceptch("/") do
139. n1 = n1 / num_or_brackets()
140. end
141. return n1
142. end
143.
144. local function multiplication()
145. local n1 = division()
146. while acceptch("*") do
147. n1 = n1 * division()
148. end
149. return n1
150. end
151. local function subtraction()
152. local n1 = multiplication()
153. while acceptch("-") do
154. n1 = n1 - multiplication()
155. end
156. return n1
157. end
159. local n1 = subtraction()
160. while acceptch("+") do
161. n1 = n1 + subtraction()
162. end
163. return n1
164. end
166.
167. local function parse(e)
168. expr = e
169. local success, result = pcall(expression_root)
170. if success and expr ~= "" then
171. print("Garbage after expression?")
172. end
173. if success then
175. else
176. print(result)
177. print("Near: " .. (expr == "" and "end of expression" or expr))
178. end
179. end
180.
181. local function mainloop()
182. local quitting = false
183. print("")
184. print("Welcome to immicalc.")
185. print("This software is public domain.")
186. print("")
187. print("Enter expressions, one per line.")
188. print("Enter 'quit' to quit.")
189. print("")
190. while not quitting do