解释器实例之算数计算(四)

模型:

230756_9AbL_2342410.png

参考这里https://ruslanspivak.com/lsbasi-part8/

# Token types
#
# EOF (end-of-file) token is used to indicate that
# there is no more input left for lexical analysis
INTEGER, PLUS,MINUS,MULT, DIV,LPAR,RPAR, EOF = 'INTEGER','PLUS','MINUS', 'MULT','DIV','LPAR','RPAR','EOF'


class Token(object):
    def __init__(self, type, value):
        # token type: INTEGER, PLUS, or EOF
        self.type = type
        # token value: 0, 1, 2. 3, 4, 5, 6, 7, 8, 9, '+', or None
        self.value = value

    def __str__(self):
        """String representation of the class instance.
        Examples:
            Token(INTEGER, 3)
            Token(PLUS '+')
        """
        return 'Token({type}, {value})'.format(
            type=self.type,
            value=repr(self.value)
        )

    def __repr__(self):
        return self.__str__()

class Lexer(object):
    def __init__(self,text):
        self.text=text
        self.current_pos=0
        self.current_char=self.text[self.current_pos]

    def error(self):
        raise Exception('Invalid character!')
    def advance(self):
        self.current_pos+=1
        if self.current_pos > len(self.text)-1 :
            self.current_char=None
        else:
            self.current_char=self.text[self.current_pos]

    def skip_whitespace(self):
        while self.current_char is not None and self.current_char.isspace():
            self.advance()

    def integer(self):
        result=''
        while self.current_char is not None and self.current_char.isdigit():
            result+=self.current_char
            self.advance()
        return int(result)

    def get_next_token(self):
        while self.current_char is not None:
            #print('get_next_token---->'+self.current_char)
            if self.current_char.isspace():
                self.skip_whitespace()
                continue
            if self.current_char.isdigit():
                return Token(INTEGER,self.integer())
            if self.current_char=='+':
                self.advance()
                return Token(PLUS,'+')
            if self.current_char=='-':
                self.advance()
                return Token(MINUS,'-')
            if self.current_char=='*':
                self.advance()
                return Token(MULT,'*')
            if self.current_char=='/':
                self.advance()
                return Token(DIV,'/')
            if self.current_char=='(':
                self.advance()
                return Token(LPAR,'(')
            if self.current_char==')':
                self.advance()
                return Token(RPAR,')')
            self.error()

        return Token(EOF,None)

class AST(object):
    pass

class BinOp(AST):
    def __init__(self,left,op,right):
        self.left=left
        self.token=self.op=op
        self.right=right

class Num(AST):
    def __init__(self,token):
        self.token=token
        self.value=token.value

class UnaryOp(AST):
    def __init__(self,op,expr):
        self.token=self.op=op
        self.expr=expr

class Parser(object):
    def __init__(self,lexer):
        self.lexer=lexer
        self.current_token=self.lexer.get_next_token()

    def error(self):
        raise Exception('Invalid syntax')

    def eat(self,token_type):
        #print('eat---->'+self.current_token.type)
        if self.current_token.type==token_type:
            self.current_token=self.lexer.get_next_token()
        else:
            self.error()

    def factor(self):
        """factor : (PLUS | MINUS) factor | INTEGER | LPAREN expr RPAREN"""
        token=self.current_token
        if token.type==INTEGER:
            self.eat(INTEGER)
            return Num(token)
        elif token.type==LPAR:
            self.eat(LPAR)
            result=self.expr()
            self.eat(RPAR)
            return result
        elif token.type == PLUS:
            self.eat(PLUS)
            node=UnaryOp(token,self.factor())
            return node
        elif token.type == MINUS:
            self.eat(MINUS)
            node=UnaryOp(token,self.factor())
            return node
        else:
            self.error()
        #self.eat(INTEGER)
        #return token.value
        #return result

    def term(self):
        r=self.factor()
        #print('term---->'+self.current_token.type)
        while self.current_token.type != EOF :
            if self.current_token.type==MULT:
                self.eat(MULT)
                #r=r*self.factor()
                r=BinOp(r,Token(MULT,'*'),self.factor())
            elif self.current_token.type==DIV:
                self.eat(DIV)
                #r=r/self.factor()
                r=BinOp(r,Token(DIV,'/'),self.factor())
            else:
                #?????
                break
                #print("term error....."+self.current_token.type)
        return r

    def expr(self):
        t=self.term()
        #print('expr---->'+str(t))
        #print('expr2---->'+self.current_token.type)
        while self.current_token.type != EOF :
            #print('expr3---->'+self.current_token.type)
            if self.current_token.type==PLUS:
                self.eat(PLUS)
                #t=t+self.term()
                t=BinOp(t,Token(PLUS,'+'),self.term())
            elif self.current_token.type==MINUS:
                self.eat(MINUS)
                #t=t-self.term()
                t=BinOp(t,Token(MINUS,'-'),self.term())
            else:
                break
        return t

    def parse(self):
        return self.expr()

class NodeVisitor(object):
    def visit(self,node):
        method_name='visit_'+type(node).__name__
        visitor=getattr(self,method_name,self.generic_visit)
        return visitor(node)

    def generic_visit(self,node):
        raise Exception('No visit_{} method'.format(type(node).__name__))

class Interpreter(NodeVisitor):
    def __init__(self,parser):
        self.parser=parser

    def visit_BinOp(self,node):
        if node.op.type == PLUS:
            return self.visit(node.left)+self.visit(node.right)
        elif node.op.type == MINUS:
            return self.visit(node.left)-self.visit(node.right)
        elif node.op.type == MULT:
            return self.visit(node.left)*self.visit(node.right)
        elif node.op.type == DIV:
            return self.visit(node.left)/self.visit(node.right)
        else:
            pass

    def visit_Num(self,node):
        #print(node.value)
        return node.value

    def visit_UnaryOp(self,node):
        op=node.op
        if op.type == PLUS:
            return +self.visit(node.expr)
        elif op.type == MINUS:
            return -self.visit(node.expr)
        else:
            pass

    def interprete(self):
        tree=self.parser.parse()
        return self.visit(tree)

def main():
    while True:
        try:
            try:
                text = raw_input('spi> ') #python 2
            except NameError:
                text = input('spi>') #python 3
        except EOFError:
            break
        if not text:
            continue

        lexer=Lexer(text)
        parser = Parser(lexer)
        interpreter=Interpreter(parser)
        result=interpreter.interprete()
        print(result)


if __name__ == '__main__':
    main()


转载于:https://my.oschina.net/shawnplaying/blog/665110

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值