Help making a math evaluator (interpreter)

  1. What do you want to achieve?
    I want to be pointed in the right direction regarding how I would make a math interpreter or any simple code interpreter. I am not asking for, and do not want scripts, but rather a word of advice, tips, and a nudge toward the right concepts. Here is the end goal of what I am trying to make: String Calculator - Resources / Community Resources - DevForum | Roblox
  2. What is the issue?
    I have got to the point of the 4 basic arithmetic operators, but I am stuck and confused as to how to continue.
  3. What solutions have you tried so far?
    I have looked on the dev forum and other places and will continue to look, but the tutorials (few as they are) are either complicated algorithms or solutions that I do not understand. Here is my code, it allows you to perform the order of operations with ±*/, but I would like help expanding it.
local functions = {}
functions["+"] = function(num1, num2)
	return tonumber(num1) + tonumber(num2)
end
functions["-"] = function(num1, num2)
	return tonumber(num1) - tonumber(num2)
end
functions["*"] = function(num1, num2)
	return tonumber(num1) * tonumber(num2)
end
functions["/"] = function(num1, num2)
	return tonumber(num1) / tonumber(num2)
end
local function eval(exp)
	exp = exp:gsub("%s", "")
	local Lexer = {}
	local LastMath = ""
	local SplitTable = exp:split("")
	local i = 1
	while 0 < #SplitTable do
		if tonumber(SplitTable[i]) then
			LastMath = LastMath .. SplitTable[i]
			table.remove(SplitTable,i)
		else
			Lexer[#Lexer+1] = tonumber(LastMath)
			LastMath = ""
			if ("+-/*"):find(SplitTable[i]) then
				Lexer[#Lexer+1] = SplitTable[i]
				table.remove(SplitTable,i)
			end
		end
	end
	Lexer[#Lexer+1] = LastMath
	while #Lexer > 1 do
		local operation = table.find(Lexer, "*") or table.find(Lexer, "/")
		if operation then
			local res = functions[Lexer[operation]](Lexer[operation - 1],Lexer[operation + 1])
			Lexer[operation-1] = res
			table.remove(Lexer, operation)
			table.remove(Lexer, operation)
		elseif tonumber(Lexer[1]) and functions[tostring(Lexer[2])] and tonumber(Lexer[3]) then
			local res = functions[Lexer[2]](Lexer[1],Lexer[3])
			table.remove(Lexer,1)
			table.remove(Lexer,1)
			Lexer[1] = res
			end
	end
	return Lexer[1]
end

Just do print(eval(“your math expression”)) in order to try it. As I said, I am stuck at this point and do not know how to continue. Thanks for any help you give!

One thing you’ll need to do is to convert your flat list-based structure into a tree-based one. That lets you support things like parentheses or unary operators more easily

You can google “abstract syntax tree” for some examples

You could also just farm your math out to some REST API that evaluates it for you. Not as fast or as fun, but would work quickly

3 Likes

Googling this was kind of tricky – there are a lot of low-effort articles on the internet that show up as the first result. I can understand why you felt they were too technical: they were badly written!

Here’s one that’s very tutorial in nature. Building an Expression Evaluator
It breaks it down into three steps (tokenizing, converting to reverse polish notation, then evaluating the expression). It will explain how to include operator precedence and parentheses.

1 Like

@nicemike40 I was also kind of stuck when trying to figure out how to build an algorithm that would allow you to traverse a tree, backward. I will not do the REST API option because the whole point of this was for me to make it, and learn from it.
@blobbyblob Thanks for the suggestion, I will look more into that article.