栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

上文中实现了可以支持任意个整数相加减的计算器,本文将把它拓展到支持任意个整数加减乘除

大家都知道,当一个算式中同时含有加减 和 乘除时,乘除优先运算

如果实现优先级差异呢?解决办法是采用逐层分解的语法规则,如下所示

expr: term((PLUS|MINUS)term)*
term: factor((MUL|DIV)factor)*
factor: NUMBER

一旦定义好了语法规则,转换成代码其实很容易:

  • 冒号: 转换成函数调用
  • 竖线| 转换成 if … else …
  • 星号(...)* 转换成 while 循环
  • 如果语法中有递归,同样可以转化成函数递归(下一篇文章会讲)

下图是关于表达式 7 + 5 * 2 的处理逻辑,5 * 2 直接视为一个 term

整数计算器 Version 9
"""
expr: term((PLUS|MINUS)term)*
term: factor((MUL|DIV)factor)*
factor: NUMBER
"""
NUMBER, PLUS, MINUS, MUL, DIV, EOF = 'NUMBER', 'PLUS', 'MINUS', 'MUL', 'DIV', '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, '-')
        
        if self.current_char == '*':
            self.pos += 1
            return Token(MUL, '*')
        
        if self.current_char == '/':
            self.pos += 1
            return Token(DIV, '/')
        
        self.error()


class Interpreter:
    def __init__(self, lexer):
        self.lexer = lexer
        self.current_token = self.lexer.get_next_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}.')
        else:
            self.current_token = self.lexer.get_next_token()
            
    def factor(self,):
        f = self.current_token
        self.eat(NUMBER)
        return f
    
    def term(self,):
        """
        term: factor(MUL|DIV)factor)*
        """
        result = self.factor().value
        while(self.current_token.type not in [EOF, PLUS, MINUS]):
            op = self.current_token
            self.eat([MUL, DIV])
            f = self.factor()
            if op.type == MUL:
                result *= f.value
            else:
                result /= f.value
                
        return Token(NUMBER, result)
        
            
    def expr(self,):
        
        result = self.term().value

        while(self.current_token.type != EOF):
            op = self.current_token
            self.eat([PLUS, MINUS])
            t = self.term()
            if op.type == PLUS:
                result += t.value
            else:
                result -= t.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()


截止目前,一个支持任意个整数加减乘除的计算器就完成了

下回进一步实现带括号的表达式!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1019662.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号