parsingluainteger

How to evaluate arithmetic expression in pseudo‑SQL style (Lua 5.1)


In love2D I have a string that represents a mathematical expression, for example:

local expr1 = "[p35] div [p36]"
local expr2 = "((([p35]*100) div [p36]) mod 100)"
local params = {p35 = 15025, p36 = 100}

local value1 = evaluateExpression(expr1, params) -- expected 150
local value2 = evaluateExpression(expr1, params) -- expected 25

How can I evaluate this expression?

I've tried to parse p values, than convert SQL-like functions with the Lua.

local function evaluateExpression(expr, params)
    if not expr or not params then return nil end

    expr = expr:gsub("%[p(%d+)%]", function(num)
            local key = "p"..num
            local val = params[key]
            if val == nil then val = 0 end
            return tostring(val)
        end)

    expr = expr:gsub("(%d+)%s+div%s+(%d+)", "math.floor(%1 / %2)")
    expr = expr:gsub("div", "/")
    expr = expr:gsub("mod", "%")

-- "math.floor(15025 / 100)+(((15025*100) / 100) % 100)/100"
    local f, err = loadstring("return " .. expr)
    if not f then
        print("parse error:", err)
        return nil
    end

    local success, result = pcall(f)
    if not success or type(result) ~= "number" then
        print("runtime error:", result)
        return nil
    end

    return result
end

Solution

  • In this replacement string, % is used as an escape character.

    expr = expr:gsub("mod", "%")
    

    Lua 5.1: string.gsub (s, pattern, repl [, n])

    If repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %n, with n between 1 and 9, stands for the value of the n-th captured substring (see below). The sequence %0 stands for the whole match. The sequence %% stands for a single %.

    Escaping the % makes your example work fine:

    expr = expr:gsub("mod", "%%")