240 lines
No EOL
5.6 KiB
Python
240 lines
No EOL
5.6 KiB
Python
class Analyzer:
|
|
def __init__(self, itr):
|
|
self.itr = itr
|
|
|
|
def next(self,amount=1):
|
|
if len(self.itr) == 0: return None
|
|
if amount == 1: return self.itr[0]
|
|
return self.itr[:amount]
|
|
|
|
def take(self,amount=1):
|
|
m, self.itr = self.next(amount), self.itr[amount:]
|
|
return m
|
|
|
|
def __len__(self):
|
|
return len(self.itr)
|
|
|
|
class StringAnalyzer(Analyzer):
|
|
def nextOrd(self):
|
|
m = self.next()
|
|
if m is None: return None
|
|
return ord(m)
|
|
|
|
def between(self,cmin,cmax):
|
|
c = self.nextOrd()
|
|
if c is None: return False
|
|
return c >= ord(cmin) and c <= ord(cmax)
|
|
|
|
def is_a(self,c):
|
|
return self.next() == c
|
|
|
|
class TokenListAnalyzer(Analyzer):
|
|
def takeUntilType(self,end):
|
|
return self.takeUntil(lambda t: t[0] == end)
|
|
|
|
def takeUntil(self,condition, dropEnd=True):
|
|
t = []
|
|
while self.next() is not None and not condition(self.next()):
|
|
t.append( self.take() )
|
|
if dropEnd and self.next() is not None:
|
|
self.take()
|
|
return t
|
|
|
|
|
|
class Lexer:
|
|
keywords = ["setze","auf","durch","schreibe"]
|
|
operators = ["plus","minus","mal","geteilt"]
|
|
IDENT = 0
|
|
KEYWORD = 1
|
|
INT = 2
|
|
FLOAT = 3
|
|
OP = 4
|
|
BRACE_OPEN = 5
|
|
BRACE_CLOSE = 6
|
|
NEWLINE = 7
|
|
|
|
def lex(self, source):
|
|
tokens = []
|
|
sa = StringAnalyzer(source)
|
|
braces = 0
|
|
stack = 0
|
|
while len(sa) != 0:
|
|
if sa.between('a', 'z') or sa.between('A', 'Z'): #identifier or keyword
|
|
ident = ""
|
|
while sa.between('a', 'z') or sa.between('A', 'Z') or sa.between('0', '9') or sa.is_a('_'):
|
|
ident += sa.take()
|
|
if ident.lower() in self.keywords:
|
|
tokens.append( (self.KEYWORD,ident.lower()) )
|
|
elif ident.lower() in self.operators:
|
|
tokens.append( (self.OP,ident.lower()) )
|
|
elif ident.lower() == "wenn":
|
|
tokens.append( ( self.KEYWORD, "wenn", stack ) )
|
|
stack += 1
|
|
elif ident.lower() == "ende":
|
|
stack -= 1
|
|
tokens.append( ( self.KEYWORD, "ende", stack ) )
|
|
else:
|
|
tokens.append( (self.IDENT,ident) )
|
|
elif sa.between('0', '9'): #number
|
|
num = ""
|
|
t = (self.INT, int)
|
|
while sa.between('0', '9'):
|
|
num += sa.take()
|
|
if sa.is_a(','):
|
|
t = (self.FLOAT, float)
|
|
sa.take()
|
|
num += "."
|
|
while sa.between('0', '9'):
|
|
num += sa.take()
|
|
|
|
tokens.append( (t[0],t[1](num)) )
|
|
elif sa.is_a('('):
|
|
tokens.append( (self.BRACE_OPEN,braces) )
|
|
braces+=1
|
|
elif sa.is_a(')'):
|
|
braces-=1
|
|
tokens.append( (self.BRACE_CLOSE,braces) )
|
|
elif sa.is_a('\n'):
|
|
tokens.append( (self.NEWLINE,) )
|
|
sa.take()
|
|
elif sa.is_a(' ') or sa.is_a('\t') or sa.is_a('\r'):
|
|
sa.take()
|
|
else:
|
|
raise ParserException("WTF is %s" % sa.take() )
|
|
|
|
return tokens
|
|
|
|
class ParserException(Exception):
|
|
pass
|
|
|
|
class Parser:
|
|
def parse(self,tokens):
|
|
block = BlockTerm()
|
|
ta = TokenListAnalyzer(tokens)
|
|
while len(ta) > 0:
|
|
if ta.next()[0] == Lexer.KEYWORD:
|
|
if ta.next()[1] == "setze":
|
|
ta.take()
|
|
if ta.next()[0] != Lexer.IDENT:
|
|
raise ParseException("missing identifier after setze")
|
|
ident = ta.take()[1]
|
|
if ta.next()[0] != Lexer.KEYWORD or ta.next()[1] != "auf":
|
|
raise ParserException("missing auf after identifier")
|
|
ta.take()
|
|
term = self.__parseTerm(ta.takeUntil(lambda t: t[0] == Lexer.NEWLINE))
|
|
block.append(AssignmentTerm(ident,term))
|
|
elif ta.next()[1] == "schreibe":
|
|
ta.take()
|
|
term = self.__parseTerm(ta.takeUntilType(Lexer.NEWLINE))
|
|
block.append(PrintTerm(term))
|
|
elif ta.next()[1] == "wenn":
|
|
stack = ta.next()[2]
|
|
ta.take()
|
|
condition = ta.takeUntil(lambda t: t[0] == Lexer.NEWLINE)
|
|
b = ta.takeUntil(lambda t: t[0] == Lexer.KEYWORD and t[1] == "ende" and t[2] == stack)
|
|
block.append( ConditionalTerm(self.__parseTerm(condition), self.parse(b) ) )
|
|
else:
|
|
raise Exception("what? %s" % str(ta.next()))
|
|
elif ta.next()[0] == Lexer.NEWLINE:
|
|
ta.take()
|
|
else:
|
|
raise Exception("huh? %s" % str(ta.next()))
|
|
return block
|
|
|
|
def __parseTerm(self,tokens):
|
|
t = tokens[0]
|
|
if t[0] == Lexer.INT or t[0] == Lexer.FLOAT:
|
|
return ValueTerm(t[1])
|
|
elif t[0] == Lexer.IDENT:
|
|
return IdentifierTerm(t[1])
|
|
else:
|
|
return ValueTerm(0)
|
|
|
|
class Context():
|
|
pass
|
|
|
|
class SubContext(Context):
|
|
pass
|
|
|
|
class Term(object):
|
|
def run(self,context):
|
|
raise Exception("get_value must be overwritten")
|
|
|
|
class Operator2(Term):
|
|
token = None
|
|
priority = 0
|
|
def __init__(self, left, right):
|
|
self.left = left
|
|
self.right = right
|
|
|
|
def run(self,context):
|
|
return self.calc( self.left.run(context), self.right.run(context) )
|
|
|
|
def calc(self, r, l):
|
|
raise Exception("calc not implemented")
|
|
|
|
class IdentifierTerm:
|
|
def __init__(self, ident):
|
|
self.ident = ident
|
|
|
|
def run(self,context):
|
|
return context[self.ident]
|
|
|
|
class ValueTerm:
|
|
def __init__(self, value):
|
|
self.value = value
|
|
|
|
def run(self,context):
|
|
return self.value
|
|
|
|
class AssignmentTerm(Term):
|
|
def __init__(self,ident,term):
|
|
self.ident = ident
|
|
self.term = term
|
|
|
|
def run(self,context):
|
|
context[self.ident] = self.term.run(context)
|
|
return None
|
|
|
|
class PrintTerm(Term):
|
|
def __init__(self,term):
|
|
self.term = term
|
|
|
|
def run(self,context):
|
|
print self.term.run(context)
|
|
return None
|
|
|
|
class ConditionalTerm(Term):
|
|
def __init__(self,condition,block):
|
|
self.condition = condition
|
|
self.block = block
|
|
|
|
def run(self,context):
|
|
m = self.condition.run(context)
|
|
if m != 0:
|
|
self.block.run(context)
|
|
|
|
|
|
class BlockTerm(Term):
|
|
def __init__(self):
|
|
self.terms = []
|
|
|
|
def append(self,item):
|
|
self.terms.append(item)
|
|
|
|
def run(self,context):
|
|
result = None
|
|
for term in self.terms:
|
|
result = term.run(context)
|
|
return result
|
|
|
|
def main():
|
|
context = {}
|
|
while True:
|
|
code = raw_input(">>> ")
|
|
tokens = Lexer().lex(code)
|
|
term = Parser().parse(tokens)
|
|
term.run(context)
|
|
|
|
if __name__ == '__main__':
|
|
main() |