浏览代码

added node

Olesya Ivanova 3 年之前
父节点
当前提交
ccede4d862
共有 7 个文件被更改,包括 131 次插入72 次删除
  1. 1 0
      interpreter/__init__.py
  2. 28 67
      interpreter/interpreter.py
  3. 5 1
      interpreter/lexer.py
  4. 24 0
      interpreter/node.py
  5. 66 0
      interpreter/parser.py
  6. 2 1
      interpreter/tokens.py
  7. 5 3
      main.py

+ 1 - 0
interpreter/__init__.py

@@ -1 +1,2 @@
 from .interpreter import Interpreter
+from .parser import Parser

+ 28 - 67
interpreter/interpreter.py

@@ -1,5 +1,5 @@
-from .tokens import TokenType, Token
-from .lexer import Lexer
+from .node import Node,Number,BinOp
+from .tokens import TokenType
 
 
 class InterpreterException(Exception):
@@ -7,69 +7,30 @@ class InterpreterException(Exception):
 
 
 class Interpreter():
-    def __init__(self):
-        self._current_token: Token = None
-        self._lexer = Lexer()
 
-    def _check_token_type(self, type_: TokenType):
-        print(type_)
-        if self._current_token.type_ == type_:
-            self._current_token = self._lexer.next()
-        else:
-            raise InterpreterException("invalid token order")
-
-    def _factor(self) -> float:
-        token = self._current_token
-        if token.type_ == TokenType.MINUS:
-            self._check_token_type(TokenType.MINUS)
-            val = self._factor()
-            return float(-val)
-        if token.type_ == TokenType.PLUS:
-            self._check_token_type(TokenType.PLUS)
-            val = self._factor()
-            return float(val)
-        if token.type_ == TokenType.INTEGER:
-            self._check_token_type(TokenType.INTEGER)
-            return float(token.value)
-        if token.type_ == TokenType.LPAREN:
-            self._check_token_type(TokenType.LPAREN)
-            result = self._expr()
-            self._check_token_type(TokenType.RPAREN)
-            return result
-        raise InterpreterException("invalid factor")
-
-    def _term(self) -> float:
-        result = self._factor()
-        ops = [TokenType.MUL, TokenType.DIV]
-        while self._current_token.type_ in ops:
-            token = self._current_token
-            if token.type_ == TokenType.MUL:
-                self._check_token_type(TokenType.MUL)
-                result *= self._factor()
-            elif token.type_ == TokenType.DIV:
-                self._check_token_type(TokenType.DIV)
-                result /= self._factor()
-        return result
-
-    def _expr(self) -> int:
-        ops = [TokenType.PLUS, TokenType.MINUS]
-        result = self._term()
-        while self._current_token.type_ in ops:
-            token = self._current_token
-            if token.type_ == TokenType.PLUS:
-                self._check_token_type(TokenType.PLUS)
-                result += self._term()
-            elif token.type_ == TokenType.MINUS:
-                self._check_token_type(TokenType.MINUS)
-                result -= self._term()
-            else:
-                raise InterpreterException("bad operator")
-        return result
-
-    def __call__(self, text: str) -> int:
-        return self.interpret(text)
-
-    def interpret(self, text: str) -> int:
-        self._lexer.init(text)
-        self._current_token = self._lexer.next()
-        return self._expr()
+    def interpret(self,tree:Node) -> float:
+        return self._visit(tree)
+
+    def _visit(self, node: Node) -> float:
+        if isinstance(node,Number):
+            return self._visit_number(node)
+        elif isinstance(node,BinOp):
+            return self._visit_binop(node)
+        raise InterpreterException("invalid node")
+
+    def _visit_number(self, node:Number) -> float:
+        return float(node.token.value)
+
+    def _visit_binop(self,node:BinOp) -> float:
+        op = node.op
+        if op.type_ == TokenType.PLUS:
+            return self._visit(node.left) + self._visit(node.right)
+        if op.type_ == TokenType.MINUS:
+            return self._visit(node.left) - self._visit(node.right)
+        if op.type_ == TokenType.MUL:
+            return self._visit(node.left) * self._visit(node.right)
+        if op.type_ == TokenType.DIV:
+            return self._visit(node.left) / self._visit(node.right)
+        if op.type_ == TokenType.POW:
+            return pow(self._visit(node.left), self._visit(node.right))
+        raise InterpreterException("invalid separator")

+ 5 - 1
interpreter/lexer.py

@@ -20,7 +20,7 @@ class Lexer():
                 self._skip()
                 continue
             if self._current_char.isdigit():
-                return Token(TokenType.INTEGER, self._integer())
+                return Token(TokenType.FLOAT, self._integer())
             if self._current_char == "+":
                 char = self._current_char
                 self._forward()
@@ -37,6 +37,10 @@ class Lexer():
                 char = self._current_char
                 self._forward()
                 return Token(TokenType.DIV, char)
+            if self._current_char == "^":
+                char = self._current_char
+                self._forward()
+                return Token(TokenType.POW, char)
             if self._current_char == "(":
                 char = self._current_char
                 self._forward()

+ 24 - 0
interpreter/node.py

@@ -0,0 +1,24 @@
+from .tokens import Token
+
+
+class Node:
+    pass
+
+
+class Number(Node):
+
+    def __init__(self, token: Token):
+        self.token = token
+
+    def __str__(self):
+        return f"Number({self.token})"
+
+
+class BinOp(Node):
+    def __init__(self,left:Node,op:Token,right:Node):
+        self.left = left
+        self.op = op
+        self.right = right
+
+    def __str__(self):
+        return f"BinOp{self.op.value}({self.left}, {self.right})"

+ 66 - 0
interpreter/parser.py

@@ -0,0 +1,66 @@
+from .tokens import TokenType, Token
+from .lexer import Lexer
+from .node import Node, BinOp, Number
+
+
+class ParserException(Exception):
+    pass
+
+
+class Parser():
+    def __init__(self):
+        self._current_token: Token = None
+        self._lexer = Lexer()
+
+    def __call__(self, text: str) -> Node:
+        return self.parse(text)
+
+    def _check_token_type(self, type_: TokenType):
+        if self._current_token.type_ == type_:
+            self._current_token = self._lexer.next()
+        else:
+            raise ParserException("invalid token order")
+
+    def _factor(self) -> Node:
+        token = self._current_token
+        if token.type_ == TokenType.FLOAT:
+            self._check_token_type(TokenType.FLOAT)
+            return Number(token)
+        if token.type_ == TokenType.LPAREN:
+            self._check_token_type(TokenType.LPAREN)
+            result = self._expr()
+            self._check_token_type(TokenType.RPAREN)
+            return result
+        raise ParserException("invalid factor")
+
+    def _term(self) -> Node:
+        result = self._factor()
+        ops = [TokenType.MUL, TokenType.DIV]
+
+        if self._current_token.type_ in ops:
+            token = self._current_token
+            if token.type_ == TokenType.MUL:
+                self._check_token_type(TokenType.MUL)
+            elif token.type_ == TokenType.DIV:
+                self._check_token_type(TokenType.DIV)
+            else:
+                self._check_token_type(TokenType.POW)
+            return BinOp(result,token,self._factor())
+        return result
+
+    def _expr(self) -> Node:
+        ops = [TokenType.PLUS, TokenType.MINUS]
+        result = self._term()
+        if self._current_token.type_ in ops:
+            token = self._current_token
+            if token.type_ == TokenType.PLUS:
+                self._check_token_type(TokenType.PLUS)
+            else:
+                self._check_token_type(TokenType.MINUS)
+            return BinOp(result,token,self._term())
+        return result
+
+    def parse(self, text: str) -> Node:
+        self._lexer.init(text)
+        self._current_token = self._lexer.next()
+        return self._expr()

+ 2 - 1
interpreter/tokens.py

@@ -3,11 +3,12 @@ from enum import Enum, auto
 
 class TokenType(Enum):
     INTEGER = auto()
-    # FLOAT = auto()
+    FLOAT = auto()
     PLUS = auto()
     MINUS = auto()
     MUL = auto()
     DIV = auto()
+    POW = auto()
     LPAREN = auto()
     RPAREN = auto()
     EOS = auto()  # конец строки

+ 5 - 3
main.py

@@ -1,5 +1,7 @@
-from interpreter import Interpreter
+from interpreter import Interpreter,Parser
+import interpreter
 
 if __name__ == "__main__":
-    interpreter = Interpreter()
-    print(interpreter.interpret("3 - 3"))
+    parser = Parser()
+    print(parser.parse("2 + 2"))
+