This repository has been archived on 2026-01-16. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
greyhack-public/calc.src
2022-12-29 18:06:14 -08:00

297 lines
No EOL
7.1 KiB
Text

Token=function(type,value)
return {"type": type, "value": value}
end function
Lexer=function(text)
out={}
out.text=text
out.pos=0
out.currChar=out.text[out.pos]
out.error=function()
exit("Invalid character!")
end function
out.advance=function(self)
self.pos=self.pos+1
if self.pos > self.text.len-1 then
self.currChar=null
else
self.currChar=self.text[self.pos]
end if
end function
out.skip_ws=function(self)
while self.currChar and self.currChar == " "
self.advance
end while
end function
out.integer=function(self)
result=""
while self.currChar != null and (typeof(self.currChar.to_int) == "number" or self.currChar == ".")
result=result+self.currChar
self.advance
end while
return result.val
end function
out.gnt=function(self)
while self.currChar
if self.currChar == " " then
self.skip_ws
continue
end if
if typeof(self.currChar.to_int) == "number" then
return Token("INT",self.integer)
end if
if self.currChar == "+" then
self.advance
return Token("ADD","+")
end if
if self.currChar == "-" then
self.advance
return Token("SUB","-")
end if
if self.currChar == "*" then
self.advance
return Token("MUL","*")
end if
if self.currChar == "/" then
self.advance
return Token("DIV","/")
end if
if self.currChar == "^" then
self.advance
return Token("EXP","^")
end if
if self.currChar == "%" then
self.advance
return Token("MOD","%")
end if
if self.currChar == "(" then
self.advance
return Token("LPAREN","(")
end if
if self.currChar == ")" then
self.advance
return Token("RPAREN",")")
end if
self.error
end while
return Token("EOF",null)
end function
return out
end function
AST=function()
return {}
end function
BinOp=function(left,op,right)
out=AST
out.left=left
out.op=op
out.token=op
out.right=right
out.classID="BinOp"
return out
end function
Num=function(token)
out=AST
out.token=token
out.value=token.value
out.classID="Num"
return out
end function
UnaryOp=function(op,expr)
out=AST
out.op=op
out.token=op
out.expr=expr
out.classID="UnaryOp"
return out
end function
Parser=function(lexer)
out={}
out.lexer=lexer
out.ct=out.lexer.gnt
out.error=function()
exit("Invalid syntax!")
end function
out.eat=function(self,ttype)
if self.ct.type == ttype then self.ct=self.lexer.gnt else self.error
end function
out.factor=function(self)
token=self.ct
if token.type == "ADD" then
self.eat("ADD")
node=UnaryOp(token,self.factor)
return node
else if token.type == "SUB" then
self.eat("SUB")
node=UnaryOp(token,self.factor)
return node
else if token.type == "INT" then
self.eat("INT")
return Num(token)
else if token.type == "LPAREN" then
self.eat("LPAREN")
node=self.expr
self.eat("RPAREN")
return node
end if
end function
out.exp=function(self)
node=self.factor
while self.ct.type == "EXP"
token=self.ct
self.eat("EXP")
node=BinOp(node,token,self.factor)
end while
return node
end function
out.term=function(self)
node=self.exp
while ["MUL","DIV","MOD"].indexOf(self.ct.type) != null
token=self.ct
if token.type == "MUL" then
self.eat("MUL")
else if token.type == "DIV" then
self.eat("DIV")
else if token.type == "MOD" then
self.eat("MOD")
end if
node=BinOp(node,token,self.exp)
end while
return node
end function
out.expr=function(self)
node=self.term
while ["ADD","SUB"].indexOf(self.ct.type) != null
token=self.ct
if token.type == "ADD" then
self.eat("ADD")
else if token.type == "SUB" then
self.eat("SUB")
end if
node=BinOp(node,token,self.term)
end while
return node
end function
out.parse=function(self)
return self.expr
end function
return out
end function
NodeVisitor=function()
out={}
out.visit=function(self,node)
method="visit_"+typeof(node)
if not self.hasIndex(method) then self.generic_visit
result=null
if method == "visit_BinOp" then
result=self.visit_BinOp(node)
else if method == "visit_Num" then
result=self.visit_Num(node)
else if method == "visit_UnaryOp" then
result=self.visit_UnaryOp(node)
end if
return result
end function
out.generic_visit=function()
exit("No visit method")
end function
return out
end function
Interpreter=function(parser)
out=NodeVisitor
out.parser=parser
out.visit_BinOp=function(self,node)
if node.op.type == "ADD" then
return self.visit(node.left) + self.visit(node.right)
else if node.op.type == "SUB" then
return self.visit(node.left) - self.visit(node.right)
else if node.op.type == "MUL" then
return self.visit(node.left) * self.visit(node.right)
else if node.op.type == "DIV" then
return self.visit(node.left) / self.visit(node.right)
else if node.op.type == "MOD" then
return self.visit(node.left) % self.visit(node.right)
else if node.op.type == "EXP" then
return self.visit(node.left) ^ self.visit(node.right)
end if
end function
out.visit_Num=function(self,node)
return node.value
end function
out.visit_UnaryOp=function(self,node)
op=node.op.type
if op == "ADD" then
return self.visit(node.expr)
else if op == "SUB" then
return -self.visit(node.expr)
end if
end function
out.interp=function(self)
tree=self.parser.parse
return self.visit(tree)
end function
return out
end function
main=function()
print("Four Leaf Calculator")
print
while 1
text=user_input("calc> ")
if not text then continue
run(text)
end while
end function
run=function(script)
lexer=Lexer(script)
parser=Parser(lexer)
interp=Interpreter(parser)
result=interp.interp
print(result)
end function
main