python 编写简单的程序解释器(三)

整数计算器 Version 4

上一篇文章中,实现了一个能够支持任意位数的整数加法的计算器,下面来把它拓展减法

具体修改之处:

  • get_next_token 函数增加减号的识别
  • expr 函数增加减法运算
NUMBER, PLUS, MINUS, EOF = 'NUMBER', 'PLUS', 'MINUS', 'EOF'

class Token:
    def __init__(self, token_type, value):
        self.type = token_type
        self.value = value
        
    def __repr__(self,):
        return f'Token({self.type}, {self.value})'

class Interpreter:
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current = None
        
    def error(self,):
        raise Exception('Parse Error!')
        
        
    def get_next_token(self, ):
        
        if self.pos >= len(self.text):
            return Token(EOF, None)
        
        self.current = self.text[self.pos]
        
        if self.current == ' ':
            while self.current == ' ':
                self.pos += 1
                if self.pos >= len(self.text):
                    return Token(EOF, None)
                self.current = self.text[self.pos]
        
        if self.current.isdigit():
            number = ''
            while self.current.isdigit():
                number += self.current
                self.pos += 1
                if self.pos >= len(self.text):
                    break
                self.current = self.text[self.pos]
            return Token(NUMBER, int(number))
        
        if self.current == '+':
            self.pos += 1
            return Token(PLUS, '+')
        
        if self.current == '-':
            self.pos += 1
            return Token(MINUS, '+')
        
        self.error()
        
    def expr(self,):
        
        a = self.get_next_token()
        op = self.get_next_token()
        b = self.get_next_token()

        if op.type == PLUS:
            result = a.value + b.value
        else:
            result = a.value - b.value
     
        
        return result

def main():
    while True:
        try:
            text = input('cal> ')
            interpreter = Interpreter(text)
            print(interpreter.expr())
        except Exception as e:
            print(e)
            break
            
main()

在这里插入图片描述
可以看到两个整数之间的加减法都已经可以支持了!

但是,超过两个数的时候还是不行,咱们后续再改进。

现在可以先把当前代码重构一下,因为注意到元素的识别和运算可以拆分成两个独立的功能,所以接下来,分离出一个类来执行词法分析的功能,称为 Lexer。

整数计算器 Version 5

NUMBER, PLUS, MINUS, EOF = 'NUMBER', 'PLUS', 'MINUS', 'EOF'

class Token:
    def __init__(self, token_type, value):
        self.type = token_type
        self.value = value
        
    def __repr__(self,):
        return f'Token({self.type}, {self.value})'
    
class Lexer:
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current_char = self.text[self.pos]
        
    def error(self,):
        raise Exception('Lexer Error!')
    
    def get_next_token(self, ):
        
        if self.pos >= len(self.text):
            return Token(EOF, None)
        
        self.current_char = self.text[self.pos]
        
        if self.current_char == ' ':
            while self.current_char == ' ':
                self.pos += 1
                if self.pos >= len(self.text):
                    return Token(EOF, None)
                self.current_char = self.text[self.pos]
        
        if self.current_char.isdigit():
            number = ''
            while self.current_char.isdigit():
                number += self.current_char
                self.pos += 1
                if self.pos >= len(self.text):
                    break
                self.current_char = self.text[self.pos]
            return Token(NUMBER, int(number))
        
        if self.current_char == '+':
            self.pos += 1
            return Token(PLUS, '+')
        
        if self.current_char == '-':
            self.pos += 1
            return Token(MINUS, '+')
        
        self.error()


class Interpreter:
    def __init__(self, lexer):
        self.lexer = lexer
        self.get_next_token = self.lexer.get_next_token

    def expr(self,):
        
        a = self.get_next_token()
        op = self.get_next_token()
        b = self.get_next_token()
        
        if op.type == PLUS:
            result = a.value + b.value
        else:
            result = a.value - b.value
     
        
        return result

def main():
    while True:
        try:
            text = input('cal> ')
            lexer = Lexer(text)
            interpreter = Interpreter(lexer)
            print(interpreter.expr())
        except Exception as e:
            print(e)
            break

main()

在这里插入图片描述
上述代码中,Lexer用于从输入的字符中识别出元素类型:多位整数、加号、减号,Interpreter则只做运算

从这版代码中,有个明显的缺陷是 Interpreter 没有进行错误处理,所以下面给它加上运算时的错误处理

整数计算器 Version 6

NUMBER, PLUS, MINUS, EOF = 'NUMBER', 'PLUS', 'MINUS', 'EOF'

class Token:
    def __init__(self, token_type, value):
        self.type = token_type
        self.value = value
        
    def __repr__(self,):
        return f'Token({self.type}, {self.value})'
    
class Lexer:
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current_char = self.text[self.pos]
        
    def error(self,):
        raise Exception('Lexer Error!')
    
    def get_next_token(self, ):
        
        if self.pos >= len(self.text):
            return Token(EOF, None)
        
        self.current_char = self.text[self.pos]
        
        if self.current_char == ' ':
            while self.current_char == ' ':
                self.pos += 1
                if self.pos >= len(self.text):
                    return Token(EOF, None)
                self.current_char = self.text[self.pos]
        
        if self.current_char.isdigit():
            number = ''
            while self.current_char.isdigit():
                number += self.current_char
                self.pos += 1
                if self.pos >= len(self.text):
                    break
                self.current_char = self.text[self.pos]
            return Token(NUMBER, int(number))
        
        if self.current_char == '+':
            self.pos += 1
            return Token(PLUS, '+')
        
        if self.current_char == '-':
            self.pos += 1
            return Token(MINUS, '-')
        
        self.error()


class Interpreter:
    def __init__(self, lexer):
        self.lexer = lexer
        self.current_token = None
        
    def get_next_token(self,):
        self.current_token = self.lexer.get_next_token()
        return self.current_token
        
    def error(self, msg = ''):
        raise Exception(f'Parse Error! {msg}')
        
    def eat(self, token_type):
        if type(token_type) == list and self.current_token.type not in token_type:
            self.error(f'current token not in list, expect {token_type}, got {self.current_token}.')
        elif type(token_type) == str and self.current_token.type != token_type:
            self.error(f'current token not match, expect {token_type}, got {self.current_token}.')
            
    def expr(self,):
        
        a = self.get_next_token()
        self.eat(NUMBER)
        op = self.get_next_token()
        self.eat([PLUS, MINUS])
        b = self.get_next_token()
        self.eat(NUMBER)
        
        if op.type == PLUS:
            result = a.value + b.value
        else:
            result = a.value - b.value
     
        
        return result

def main():
    while True:
        try:
            text = input('cal> ')
            lexer = Lexer(text)
            interpreter = Interpreter(lexer)
            print(interpreter.expr())
        except Exception as e:
            print(e)
            break

main()

在这里插入图片描述

新增了一个eat函数,用来校验当前的token是不是期望的类型,如果不是则报错!

接下来,咱们来把它拓展成支持任意多个整数相加减的计算器,且看下回分解!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值