ALEX'S BLOG OF EVERYTHING

Equation Parsing with Lua

FFFFFFFFFFFFFFFF

const std::unordered_set<std::string> mathlib_items = {
    "sin",
    "cos",
    "tan",
    "asin",
    "acos",
    "atan",
    "abs",
    "exp",
    "log",
    "sqrt",
    "floor",
    "ceil",
    "pi"
};


std::vector<std::string> splitTokens(const std::string& str)
{
    std::vector<std::string> result;
    char token[10] = { '\0' };
    size_t toklen = 0;

    for (const char c : str)
    {
        switch (c)
        {
        case '(': case ')': case '+': case '-': case '*': case '/': case ',': case ' ':
            if (toklen > 0)
            {
                result.push_back(token);
                memset(token, '\0', 10);
                toklen = 0;
            }

            token[0] = c;
            result.push_back(token);
            token[0] = '\0';
            break;

        default:
            token[toklen++] = c;
            break;
        }
    }

    if (toklen > 0)
        result.push_back(token);

    return result;
}


bool FunctionGraph::setFunction(const std::string& str)
{
    std::vector<std::string> tokens = splitTokens(str);

    for (auto& t : tokens)
    {
        if (t == "ln")
            t = "log";
        if (mathlib_items.find(t) != mathlib_items.end())
            t = "math." + t;
    }

    bool sigma = false;
    int commacount = 0;
    int parenscount = 0;
    for (auto& t : tokens)
    {
        if (t == "sigma")
            sigma = true;

        if (sigma)
        {
            if (t == ",")
            {
                if (++commacount == 3)
                    t += " function (n) return ";
            }
            if (t == ")")
            {
                if (--parenscount == 0)
                {
                    t = " end" + t;
                    sigma = false;
                }
            }
            if (t == "(")
                parenscount++;
        }
    }

    bool integral = false;
    commacount = 0;
    parenscount = 0;
    for (auto& t : tokens)
    {
        if (t == "int")
            integral = true;

        if (integral)
        {
            if (t == ",")
            {
                if (++commacount == 2)
                    t += " function (t) return ";
            }
            if (t == ")")
            {
                if (--parenscount == 0)
                {
                    t = " end" + t;
                    integral = false;
                }
            }
            if (t == "(")
                parenscount++;
        }
    }

    std::string funcstr = "require(\"stdlib\")\n\nfunction func(x)\n\treturn ";
    for (const auto& t : tokens)
        funcstr += t;
    funcstr += "\nend\n";

    //std::cout << funcstr << '\n';

    lua_pushnumber(L, 2.7182818);
    lua_setglobal(L, "e");

    if (lua_isvalid(L, luaL_dostring(L, funcstr.c_str())))
        return true;

    return false;
}


double FunctionGraph::operator()(double x) const
{
    lua_getglobal(L, "func");
    lua_pushnumber(L, static_cast<float>(x));
    lua_call(L, 1, 1);

    return lua_tonumber(L, -1);
}