Advertisement
This is comment for paste
Project Einstein: BHv5 Branch
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- MathParserModule.lua
- local MathParser = {}
- -- Step 1: Tokenizer
- local function tokenize(expr)
- local tokens = {}
- local i = 1
- while i <= #expr do
- local c = expr:sub(i, i)
- if c:match("%s") then
- i = i + 1
- elseif c:match("%d") or c == '.' then
- local num = ""
- -- Capture the base number (integer or float)
- while i <= #expr and expr:sub(i, i):match("[%d%.]") do
- num = num .. expr:sub(i, i)
- i = i + 1
- end
- -- Check for scientific notation (immediately following without space)
- if i <= #expr and (expr:sub(i, i) == "e" or expr:sub(i, i) == "E") then
- num = num .. expr:sub(i, i)
- i = i + 1
- -- Optional sign after e/E
- if i <= #expr and (expr:sub(i, i) == "+" or expr:sub(i, i) == "-") then
- num = num .. expr:sub(i, i)
- i = i + 1
- end
- -- Append the exponent digits
- while i <= #expr and expr:sub(i, i):match("%d") do
- num = num .. expr:sub(i, i)
- i = i + 1
- end
- end
- table.insert(tokens, {type = "number", value = tonumber(num)})
- elseif c == "(" or c == ")" then
- table.insert(tokens, {type = "paren", value = c})
- i = i + 1
- else
- -- Try to match multi-character operators
- local op = nil
- -- If the operator "E" appears separated by spaces, treat it as an operator token.
- if expr:sub(i, i) == "E" then
- op = "E"
- i = i + 1
- else
- op = c
- i = i + 1
- end
- table.insert(tokens, {type = "operator", value = op})
- end
- end
- return tokens
- end
- -- Operator precedence and associativity
- local operators = {
- ["E"] = {precedence = 5, associativity = "right"}, -- Scientific notation operator
- ["^"] = {precedence = 4, associativity = "right"},
- ["*"] = {precedence = 3, associativity = "left"},
- ["/"] = {precedence = 3, associativity = "left"},
- ["+"] = {precedence = 2, associativity = "left"},
- ["-"] = {precedence = 2, associativity = "left"},
- }
- -- Step 2: Parser using the shunting-yard algorithm
- local function shuntingYard(tokens)
- local output = {}
- local opStack = {}
- for _, token in ipairs(tokens) do
- if token.type == "number" then
- table.insert(output, token)
- elseif token.type == "operator" then
- local o1 = token.value
- while #opStack > 0 do
- local top = opStack[#opStack]
- if top.type ~= "operator" then break end
- local o2 = top.value
- if (operators[o1].associativity == "left" and operators[o1].precedence <= operators[o2].precedence) or
- (operators[o1].associativity == "right" and operators[o1].precedence < operators[o2].precedence) then
- table.insert(output, table.remove(opStack))
- else
- break
- end
- end
- table.insert(opStack, token)
- elseif token.type == "paren" then
- if token.value == "(" then
- table.insert(opStack, token)
- else -- token.value == ")"
- while #opStack > 0 and opStack[#opStack].value ~= "(" do
- table.insert(output, table.remove(opStack))
- end
- if #opStack == 0 then
- error("Mismatched parentheses")
- end
- table.remove(opStack) -- remove "("
- end
- end
- end
- while #opStack > 0 do
- local top = table.remove(opStack)
- if top.value == "(" or top.value == ")" then
- error("Mismatched parentheses")
- end
- table.insert(output, top)
- end
- return output
- end
- -- Step 3: Evaluate Reverse Polish Notation (RPN)
- local function evaluateRPN(rpn)
- local stack = {}
- for _, token in ipairs(rpn) do
- if token.type == "number" then
- table.insert(stack, token.value)
- elseif token.type == "operator" then
- local b = table.remove(stack)
- local a = table.remove(stack)
- local result = nil
- if token.value == "+" then
- result = a + b
- elseif token.value == "-" then
- result = a - b
- elseif token.value == "*" then
- result = a * b
- elseif token.value == "/" then
- result = a / b
- elseif token.value == "^" then
- result = a ^ b
- elseif token.value == "E" then
- -- Evaluate as: a * (10^b)
- result = a * (10 ^ b)
- else
- error("Unknown operator: " .. token.value)
- end
- table.insert(stack, result)
- end
- end
- if #stack ~= 1 then
- error("Invalid expression")
- end
- return stack[1]
- end
- -- The universal parser function that catches errors and returns an error message
- function MathParser.evaluateExpression(expr)
- local tokens = tokenize(expr)
- local status, result = pcall(function()
- local rpn = shuntingYard(tokens)
- return evaluateRPN(rpn)
- end)
- if not status then
- return "Error: " .. result
- else
- return result
- end
- end
- return MathParser
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement