I would like to know if there is a way to work out maths when the user inputs a string like:
- "1+1" (would return 2)
- "2+2" (4)
- "5-4" (1)
- "5-6" (-1)
- "6*2.5" (15)
- "6/2.5" (2.4)
- "6+4+5-2" (13)
Edit: String.
 
        
function clear()
  term.clear()
   term.setCursorPos(1,1)
end
while true do
clear()
print("Method [+ -]")
repeat
local input = read()
until input == "+" or input == "-"
if input == "+" then
mode = "add"
else
mode = "sub"
end
clear()
write("First number: ")
repeat
fNum = read()
until tonumber(fNum)
fNum = tonumber(fNum)
write("Second number: ")
repeat
sNum = read()
until tonumber(sNum)
sNum = tonumber(sNum)
if mode = "add" then
local answ = fNum + sNum
   clear()
   print(fNum.." + "..sNum.." = "..answ)
os.pullEvent("key")
elseif mode == "sub" then
clear()
  local answ = fNum - sNum
  print(fNum.." - "..sNum.." = "..answ)
os.pullEvent("key")
	end
end
Split into new topic.
There is a very simple way, but it's rather dangerous. You can just loadstring it and use that to calculate the string as if it were a Lua statement, but then users can execute any arbitrary code in your program. There are other ways, but they're a fair bit more work, especially if you want anything beyond basic arithmetic.
Uhmm do you mean something like this?Not sure if it works since I typed this on my phone and haven't tested it..Spoiler
function clear() term.clear() term.setCursorPos(1,1) end while true do clear() print("Method [+ -]") repeat local input = read() until input == "+" or input == "-" if input == "+" then mode = "add" else mode = "sub" end clear() write("First number: ") repeat fNum = read() until tonumber(fNum) fNum = tonumber(fNum) write("Second number: ") repeat sNum = read() until tonumber(sNum) sNum = tonumber(sNum) if mode = "add" then local answ = fNum + sNum clear() print(fNum.." + "..sNum.." = "..answ) os.pullEvent("key") elseif mode == "sub" then clear() local answ = fNum - sNum print(fNum.." - "..sNum.." = "..answ) os.pullEvent("key") end end
while true do
  write(">")
  local inStr=read()
  if inStr==nil or inStr=="" then
    break
  end
  if inStr:match("^[%s%d%.%-%+%*%/%%%^]+$") then
    local f,err=loadstring("return "..inStr)
    if f then
      local  succ, res=pcall(f)
      print(res)
    else
      print(err)
    end
  else
    print("Invalid Expression!")
  end
end
local calc = ('calc string here'):gsub(' ', '')
if  not calc:find('^[0-9%-%+/%*%%%^]') then
    local digits = {}
    for i = 1, calc:len() do
       table.insert( digits, calc:sub( i, i )
    end
    -- actual calculating here
end
This would require parsing and all that fancy stuff. Probably not the right term though.. Example:
(untested and from my phone)local calc = ('calc string here'):gsub(' ', '') if not calc:find('^[0-9%-%+/%*%%%^]') then local digits = {} for i = 1, calc:len() do table.insert( digits, calc:sub( i, i ) end -- actual calculating here end
local input = read()
local func = loadstring("return "..input)
if func then
  setfenv(func, {})
  local ok, result = pcall(func)
  if ok then
	print(result)
  else
	printError("Error: ", result)
  end
else
  printError("Invalid input")
end
Well, the easiest way is what Lyqyd said, and you can use a custom environment that doesn't have any apis or global functions (so people can't use something like "os.reboot()" or whatever).
Using an empty environment like this should work:local input = read() local func = loadstring("return "..input) if func then setfenv(func, {}) local ok, result = pcall(func) if ok then print(result) else printError("Error: ", result) end else printError("Invalid input") end
This way you could also make an environment with some math functions and constants.
setfenv(func, setmetatable({}, {__index=math}))
Yea I've been working on a compiler for a new implementation of Lua for a while now (so that I can extend the language however I like). I've read several chapters out of a number of books, and have read most of the infamous Dragon Book. Trust me, that's not enough for something like that. You've got to do lexical analysis to turn all the input characters into individual tokens, a full finite state machine to turn the input string into a parse tree, then you compact that down to an abstract syntax tree, and the rest should be easy calculation. But all that is rather complex.
What you've done is made sure the input string is legal in terms of what characters are include, but not in terms of actual syntax (for example, 1 ^* 3 shouldn't be legal)(also, you did this wrong. You should be putting the ^ after the square bracket in order to mean "not in this set". What you did means "the following set is at the beginning"). Then you've turned the input string into an array of all the characters. Then you say "Do the rest here…." Rather useless.
For a matter of fact, I know That 'do the rest here' is rather useless. But Im not going to write it out on my phone, so I decided to do get it started. Im really up for the challenge though when Im on an actual computer, where I can test and stuff.
I will definitely post a wroking piece of code right here, you just have to wait :)/> (I dont know how long its going to take to actually write it and when I can get to a computer)
For simple math expressions, it'll likely be much easier. Can't tell you quite how much easier. But chances are you can skip some of the proper compiler steps. I do however challenge you to write an actual Lua compiler that compiles down to either the Lua bytecode for LuaJ, or LASM (recommending LASM because it'd be a thousand times easier, and compiling to assembly is what real compilers do).
Hold on for a minute, a compiler?
I was actually more thinking about a function that calculates your string, nothing much more. Im actually very, very unfamilair with compiler theory and that stuff. So to clearify, Im going to make a function to calculate a string, nothing to due with compilers.
Why don't you just make a GUI calculator? It would be easier anyway.
Plus the "lua" program can already act as a calculator.
Well, the easiest way is what Lyqyd said, and you can use a custom environment that doesn't have any apis or global functions (so people can't use something like "os.reboot()" or whatever).
Using an empty environment like this should work:local input = read() local func = loadstring("return "..input) if func then setfenv(func, {}) local ok, result = pcall(func) if ok then print(result) else printError("Error: ", result) end else printError("Invalid input") end
This way you could also make an environment with some math functions and constants.
local calcString = function( s )
	assert( type(s) == "string", "Bad Argument: String expected, got " .. type( s ), 2 )
	s = s:gsub( "[^0-9%%%+%-%*/%^]", "" )
	assert( s:len() >= 3 and s:sub( -1 ):find( "[^%%%+%-%*/%^]" ), "Valid calculation expected", 2 )
	local combo = {
		[ "-+" ] = "-";   [ "+-" ] = "-";
		[ "--" ] = "+";   [ "/-" ] = "/ n";
		[ "*-" ] = "* n"; [ "%-" ] = "% n";
		[ "^-" ] = "% n";
	}
	
	local numbers = {}
	local operators = {}
	local mutate = function( operator, operatorIndex )
		local calc = nil
		if operator == "^" then
			calc = numbers[ operatorIndex ] ^ numbers[ operatorIndex + 1 ]
		elseif operator == "*" then
			calc = numbers[ operatorIndex ] * numbers[ operatorIndex + 1 ]
		elseif operator == "/" then
			calc = numbers[ operatorIndex ] / numbers[ operatorIndex + 1 ]
		elseif operator == "+" then
			calc = numbers[ operatorIndex ] + numbers[ operatorIndex + 1 ]
		elseif operator == "-" then
			calc = numbers[ operatorIndex ] - numbers[ operatorIndex + 1 ]
		end
		if calc then -- To avoid possible errors
			operators[ operatorIndex ] = "AaP"
			table.remove( numbers, operatorIndex )
			table.remove( numbers, operatorIndex + 1 )
			table.insert( numbers, operatorIndex, calc )
		end
	end
	local sequence = {
		[ 1 ] = "^" ; [ 2 ] = "*/";
		[ 3 ] = "+-";
	}
	
	for number in s:gmatch( "[0-9]+" ) do
		table.insert( numbers, tonumber(number) )
	end
	
	local first = true
	for operator in s:gmatch( "[%%%+%-%*/%^]+" ) do
		if operator:len() == 2 then
			if combo[ operator ] then
				if combo[ operator ]:find("n") then
					numbers[ #operators + 2 ] = -numbers[ #operators + 2 ]
				end
				table.insert( operators, combo[ operator ]:sub( 1, 1 ))
			else
				error( "Unexpected symbol in calculation.", 2 )
			end
		else
			table.insert( operators, operator )
			if first then
				if operator == "-" and s:sub( 1, 1 ) == "-" then
					numbers[ 1 ] = -numbers[ 1 ]
					table.remove( operators, #operators )
				elseif operator == "-" and s:sub( 1, 1 ) ~= "-" then
					error( "Unexpected symbol in calculation.", 2 )
				end
				first = false
			end
		end
	end
	
	for i = 1, 3 do
		for key, operator in ipairs( operators ) do
			if operator:find( "[" ..
				(function( sPattern )
					local mChars = {
						[ "^" ] = true; [ "*" ] = true; 
						[ "+" ] = true; [ "-" ] = true;
					}	
					local safePattern = ""
					for i = 1, sPattern:len() do
						if mChars[sPattern:sub( i, i )] then
							safePattern = safePattern .. "%" .. sPattern:sub( i, i )
						else
							safePattern = safePattern .. sPattern:sub( i, i )
						end
					end
					return safePattern
				end)( sequence[ i ] ).. "]" ) then
				
				if sequence[ i ]:len() == 2 then
					if operator == sequence[ i ]:sub( 1, 1 ) then
						mutate( sequence[ i ]:sub( 1, 1 ), key )
					elseif operator == sequence[ i ]:sub( 2, 2 ) then
						mutate( sequence[ i ]:sub( 2, 2 ), key )
					end
				else
					mutate( sequence[ i ], key )
				end
			end
		end
	end
	return numbers[ 1 ]
end
