Advertisement
Guest User

EYYYYYY

a guest
Jan 21st, 2019
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.27 KB | None | 0 0
  1. # LEXER
  2.  
  3. NUMBER = 'NUMBER'
  4. ADD = 'ADD'
  5. SUB = 'SUB'
  6. MUL = 'MUL'
  7. DIV = 'DIV'
  8. LPAR = '('
  9. RPAR = ')'
  10. EOF = 'EOF'
  11.  
  12.  
  13. class Token(object):
  14.     def __init__(self, type, val):
  15.         self.type = type
  16.         self.val = val
  17.  
  18.     def __str__(self):
  19.         return 'Token({type}, {val})'.format(
  20.             type=self.type,
  21.             val=repr(self.val)
  22.         )
  23.  
  24.     def __repr__(self):
  25.         return self.__str__()
  26.  
  27. class Lexer(object):
  28.     def __init__(self, txt):
  29.         self.txt = txt
  30.         self.pos = 0
  31.         self.char_crnt = self.txt[self.pos]
  32.  
  33.     def movePointer(self):
  34.         self.pos += 1
  35.         if self.pos > len(self.txt) - 1:
  36.             self.char_crnt = None
  37.         else:
  38.             self.char_crnt = self.txt[self.pos]
  39.  
  40.     def skipSpace(self):
  41.         while self.char_crnt is not None and self.char_crnt.isspace():
  42.             self.movePointer()
  43.  
  44.     def getMultiNum(self):
  45.         result = ''
  46.         while self.char_crnt is not None and self.char_crnt.isdigit():
  47.             result += self.char_crnt
  48.             self.movePointer()
  49.         return int(result)
  50.  
  51.     def nextToken(self):
  52.         while self.char_crnt is not None:
  53.  
  54.             if self.char_crnt.isspace():
  55.                 self.skipSpace()
  56.                 continue
  57.  
  58.             if self.char_crnt.isdigit():
  59.                 return Token(NUMBER, self.getMultiNum())
  60.  
  61.             if self.char_crnt == '+':
  62.                 self.movePointer()
  63.                 return Token(ADD, '+')
  64.  
  65.             if self.char_crnt == '-':
  66.                 self.movePointer()
  67.                 return Token(SUB, '-')
  68.  
  69.             if self.char_crnt == '*':
  70.                 self.movePointer()
  71.                 return Token(MUL, '*')
  72.  
  73.             if self.char_crnt == '/':
  74.                 self.movePointer()
  75.                 return Token(DIV, '/')
  76.  
  77.             if self.char_crnt == '(':
  78.                 self.movePointer()
  79.                 return Token(LPAR, '(')
  80.  
  81.             if self.char_crnt == ')':
  82.                 self.movePointer()
  83.                 return Token(RPAR, ')')
  84.  
  85.             self.showError()
  86.  
  87.         return Token(EOF, None)
  88.  
  89.     def showError(self):
  90.         raise Exception('Character not valid.')
  91.  
  92. # PARSER
  93.  
  94. class AbsSynTree(object):
  95.     pass
  96.  
  97. class BinaryOperator(AbsSynTree):
  98.     def __init__(self, left, op, right):
  99.         self.left = left
  100.         self.token = self.op = op
  101.         self.right = right
  102.  
  103. class UnaryOperator(AbsSynTree):
  104.     def __init__(self, op, expr):
  105.         self.token = self.op = op
  106.         self.expr = expr
  107.  
  108. class Num(AbsSynTree):
  109.     def __init__(self, token):
  110.         self.token = token
  111.         self.val = token.val
  112.  
  113. class Parser(object):
  114.     def __init__(self, lexer):
  115.         self.lexer = lexer
  116.         self.crntToken = self.lexer.nextToken()
  117.  
  118.     def eat(self, token_type):
  119.         if self.crntToken.type == token_type:
  120.             self.crntToken = self.lexer.nextToken()
  121.         else:
  122.             self.showError()
  123.  
  124.     def factor(self):
  125.         token = self.crntToken
  126.         if token.type == ADD:
  127.             self.eat(ADD)
  128.             node = UnaryOperator(token, self.factor())
  129.             return node
  130.         elif token.type == SUB:
  131.             self.eat(SUB)
  132.             node = UnaryOperator(token, self.factor())
  133.             return node
  134.         elif token.type == NUMBER:
  135.             self.eat(NUMBER)
  136.             return Num(token)
  137.         elif token.type == LPAR:
  138.             self.eat(LPAR)
  139.             node = self.expr()
  140.             self.eat(RPAR)
  141.             return node
  142.  
  143.     def term(self):
  144.         node = self.factor()
  145.  
  146.         while self.crntToken.type in (MUL, DIV):
  147.             token = self.crntToken
  148.             if token.type == MUL:
  149.                 self.eat(MUL)
  150.             elif token.type == DIV:
  151.                 self.eat(DIV)
  152.  
  153.             node = BinaryOperator(left=node, op=token, right=self.factor())
  154.  
  155.         return node
  156.  
  157.     def expr(self):
  158.         node = self.term()
  159.  
  160.         while self.crntToken.type in (ADD, SUB):
  161.             token = self.crntToken
  162.             if token.type == ADD:
  163.                 self.eat(ADD)
  164.             elif token.type == SUB:
  165.                 self.eat(SUB)
  166.  
  167.             node = BinaryOperator(left=node, op=token, right=self.term())
  168.  
  169.         return node
  170.  
  171.     def parse(self):
  172.         node = self.expr()
  173.         if self.crntToken.type != EOF:
  174.             self.showError()
  175.         return node
  176.  
  177.     def showError(self):
  178.         raise Exception('Syntax is not valid.')
  179.  
  180.  
  181. # INTERPRETER
  182.  
  183. class NodeChecker(object):
  184.     def visit(self, node):
  185.         mthd_name = 'visit_' + type(node).__name__
  186.         visitor = getattr(self, mthd_name, self.visit_Generic)
  187.         return visitor(node)
  188.  
  189.     def visit_Generic(self, node):
  190.         raise Exception('visit_{} method not found.'.format(type(node).__name__))
  191.  
  192.  
  193. class Interpreter(NodeChecker):
  194.     def __init__(self, parser):
  195.         self.parser = parser
  196.  
  197.     def visit_BinaryOperator(self, node):
  198.         if node.op.type == ADD:
  199.             return self.visit(node.left) + self.visit(node.right)
  200.         elif node.op.type == SUB:
  201.             return self.visit(node.left) - self.visit(node.right)
  202.         elif node.op.type == MUL:
  203.             return self.visit(node.left) * self.visit(node.right)
  204.         elif node.op.type == DIV:
  205.             return self.visit(node.left) / self.visit(node.right)
  206.  
  207.     def visit_UnryOprtr(self, node):
  208.         op = node.op.type
  209.         if op == ADD:
  210.             return +self.visit(node.expr)
  211.         elif op == SUB:
  212.             return -self.visit(node.expr)
  213.  
  214.     def visit_Num(self, node):
  215.         return node.val
  216.  
  217.     def interpret(self):
  218.         tree = self.parser.parse()
  219.         if tree is None:
  220.             return ''
  221.         return self.visit(tree)
  222.  
  223. def main():
  224.     print('Welcome to Basic Arithmetic Expression (BAE) Interpreter.')
  225.     while True:
  226.         try:
  227.             try:
  228.                 txt = input('>> ')
  229.             except NameError:
  230.                 txt = input('>> ')
  231.         except EOFError:
  232.             break
  233.         if not txt:
  234.             continue
  235.  
  236.         lexer = Lexer(txt)
  237.         parser = Parser(lexer)
  238.         interpreter = Interpreter(parser)
  239.         result = interpreter.interpret()
  240.         print(result)
  241.  
  242.  
  243. if __name__ == '__main__':
  244.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement