167 lines
3.6 KiB
Lua
167 lines
3.6 KiB
Lua
--~ t = debug.getmetatable ("")
|
|
--~ t.__index = function(self,k)
|
|
--~ if type(k)=="number" then
|
|
--~ return string.sub(self,k,k)
|
|
--~ end
|
|
--~ end
|
|
Token = {}
|
|
Token.__index = Token
|
|
local INTEGER, PLUS, EOF, MINUS, MUL, DIV, LPAREN, RPAREN = "INT","+","EOF", "-", "*", "/", "(", ")"
|
|
function Token.__tostring(self)
|
|
return string.format("Token(%s, %s)",self.type,self.value)
|
|
end
|
|
function Token:new(tp,val)
|
|
local c = {}
|
|
setmetatable(c,self)
|
|
c.type = tp
|
|
c.value = val
|
|
print("Token:"..tp)
|
|
return c
|
|
end
|
|
|
|
Lexer = {}
|
|
Lexer.__index = Lexer
|
|
function Lexer:new(text)
|
|
local c = {}
|
|
setmetatable(c,self)
|
|
self.text = text
|
|
self.pos = 1
|
|
self.current_char = self.text:sub(1,1)
|
|
self.stop = false
|
|
return c
|
|
end
|
|
function Lexer:advance()
|
|
self.pos = self.pos + 1
|
|
if self.pos > #self.text then
|
|
self.current_char = false
|
|
else
|
|
self.current_char = self.text:sub(self.pos,self.pos)
|
|
end
|
|
end
|
|
function Lexer:error()
|
|
error("Invalid character")
|
|
end
|
|
function Lexer:skip_whitespace()
|
|
while self.current_char and self.current_char:match("%s") do
|
|
self:advance()
|
|
end
|
|
end
|
|
function Lexer:integer()
|
|
local result = {}
|
|
while self.current_char and self.current_char:match("%d") do
|
|
table.insert(result,self.current_char)
|
|
self:advance()
|
|
end
|
|
return tonumber(table.concat(result))
|
|
end
|
|
function Lexer:get_next_token()
|
|
while self.current_char do
|
|
::continue::
|
|
if self.current_char:match("%s") then
|
|
self:skip_whitespace()
|
|
goto continue
|
|
end
|
|
if self.current_char:match("%d") then
|
|
return Token:new(INTEGER,self:integer())
|
|
end
|
|
if self.current_char == "+" then
|
|
self:advance()
|
|
return Token:new(PLUS,"+")
|
|
end
|
|
if self.current_char == "-" then--55+77
|
|
self:advance()
|
|
return Token:new(MINUS,"-")
|
|
end
|
|
if self.current_char == "*" then
|
|
self:advance()
|
|
return Token:new(MUL,"*")
|
|
end
|
|
if self.current_char == "/" then
|
|
self:advance()
|
|
return Token:new(DIV,"/")
|
|
end
|
|
if self.current_char == "(" then
|
|
self:advance()
|
|
return Token:new(LPAREN,"(")
|
|
end
|
|
if self.current_char == ")" then
|
|
self:advance()
|
|
return Token:new(RPAREN,")")
|
|
end
|
|
self:error("Invalid Symbol!")
|
|
end
|
|
return Token:new(EOF, nil)
|
|
end
|
|
|
|
Interpreter = {}
|
|
Interpreter.__index = Interpreter
|
|
function Interpreter:new(lexer)
|
|
local c = {}
|
|
setmetatable(c,self)
|
|
c.lexer = lexer
|
|
c.current_token = c.lexer:get_next_token()
|
|
return c
|
|
end
|
|
function Interpreter:error()
|
|
error('Error Invalid Syntax')
|
|
end
|
|
function Interpreter:eat(token_type)
|
|
if self.current_token.type == token_type then
|
|
self.current_token = self.lexer:get_next_token()
|
|
else
|
|
self:error()
|
|
end
|
|
end
|
|
function Interpreter:factor()
|
|
local token = self.current_token
|
|
if token.type == INTEGER then
|
|
self:eat(INTEGER)
|
|
return token.value
|
|
elseif token.type == LPAREN then
|
|
self:eat(LPAREN)
|
|
local result = self:expr()
|
|
self:eat(RPAREN)
|
|
return result
|
|
end
|
|
end
|
|
function Interpreter:term()
|
|
local result = self:factor()
|
|
local token
|
|
while self.current_token.type == MUL or self.current_token.type == DIV do
|
|
token = self.current_token
|
|
if token.type == MUL then
|
|
self:eat(MUL)
|
|
result = result * self:factor()
|
|
elseif token.type == DIV then
|
|
self:eat(DIV)
|
|
result = result / self:factor()
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
function Interpreter:expr()
|
|
local result = self:term()
|
|
local token
|
|
while self.current_token.type == PLUS or self.current_token.type == MINUS do
|
|
token = self.current_token
|
|
if token.type == PLUS then
|
|
self:eat(PLUS)
|
|
result = result + self:term()
|
|
elseif token.type == MINUS then
|
|
self:eat(MINUS)
|
|
result = result - self:term()
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
while true do
|
|
io.write("calc> ")
|
|
local text = io.read()
|
|
if text then
|
|
l = Lexer:new(text)
|
|
i = Interpreter:new(l)
|
|
result = i:expr()
|
|
print(result)
|
|
end
|
|
end
|