Working on compiler
This commit is contained in:
parent
f4e1fe1522
commit
8a3a0ade1f
166
compiler.lua
Normal file
166
compiler.lua
Normal file
@ -0,0 +1,166 @@
|
||||
--~ 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
|
||||
Loading…
x
Reference in New Issue
Block a user