表达式求值的递归实现,顺便复习编译原理

  本次试验的内容是四则运算——或者说表达式求值,我对此并不陌生,也曾用不同语言分别实现过,但都是利用“栈”实现的相关功能,对于这一问题的递归实现我还是第一次尝试。两种实现方式各有优劣,这里不再展开。

  程序总体结构图如下:

  词法分析的作用是将字符序列转换为单词(Token),本次实验中体现在读取整数功能,其余部分基本只有检测非法字符的作用。这部分没有难度不再详述。

  

  语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,生成抽象语法树。以表达式(4+3*2)为例,抽象语法树形式如下:

  

  这一部分的算法结构图如下:

  

  不难看出来这三种结构是循环定义的,这也是为什么我将之称为递归方法。

  最后,本实验实现的是词法分析和语法分析两个部分。也就是说我都讲完了,谢谢大家,请大家自己动手实现。

  

  讲完了原理就是代码实现了,我最近正好在学Python,就当练习了。完整代码如下:

  

INTEGER, PLUS, MINUS, MUL, DIV, LPAREN, RPAREN, EOF =(
    'INTEGER', 'PLUS', 'MINUS', 'MUL', 'DIV', 'LPAREN', 'RPAREN', 'EOF')

class Token:
    def __init__(self,type,value):
        self.type = type
        self.value = value
        
    def __str__(self):
        return 'Token(%s, %s)' % (self.type,self.value)
    
    __repr__ = __str__

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

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

    def step_forward(self):
        self.pos += 1
        while self.pos < len(self.text):
            if self.text[self.pos].isspace():
                self.pos += 1
                continue
            else:
                self.current_char = self.text[self.pos]
                return
        self.current_char = None

    def get_next_token(self):
        if self.current_char == None:
            return Token(EOF,None)
        
        if self.current_char.isdigit():
            value = ''
            while True:
                value += self.current_char
                self.step_forward()
                if (self.current_char == None) or (not self.current_char.isdigit()):
                    return Token(INTEGER,value)

        if self.current_char == '+':
            self.step_forward()
            return Token(PLUS,'+')
        
        if self.current_char == '-':
            self.step_forward()
            return Token(MINUS,'-')
        
        if self.current_char == '*':
            self.step_forward()
            return Token(MUL,'*')
        
        if self.current_char == '/':
            self.step_forward()
            return Token(DIV,'/')
        
        if self.current_char == '(':
            self.step_forward()
            return Token(LPAREN,'(')
        
        if self.current_char == ')':
            self.step_forward()
            return Token(RPAREN,')')

        self.error()

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

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

    def check_token(self, token_type):
        if self.current_token.type == token_type:
            self.current_token = self.lexer.get_next_token()
        else:
            self.error()
 
    def factor(self):
        token = self.current_token
        
        if token.type == INTEGER:
            self.check_token(INTEGER)
            return float(token.value)
        elif token.type == LPAREN:
            self.check_token(LPAREN)
            result = self.expr()
            self.check_token(RPAREN)
            return float(result)

        self.error()
 
    def term(self):
        result = self.factor()
        while self.current_token.type in (MUL,DIV):
            if self.current_token.type == MUL:
                self.check_token(MUL)
                result *= self.factor()
            elif self.current_token.type == DIV:
                self.check_token(DIV)
                result /= self.factor()
                
        return float(result)
 
    def expr(self):
        result = self.term()
        while self.current_token.type in (PLUS,MINUS):
            if self.current_token.type == PLUS:
                self.check_token(PLUS)
                result += self.term()
            elif self.current_token.type == MINUS:
                self.check_token(MINUS)
                result -= self.term()
        return float(result)     

if __name__ == '__main__':
    while True:
        try:
            text = input('>>>calc ')
            if text:
                interpreter = Interpreter(Lexer(text))
                result = interpreter.expr()
                if interpreter.current_token.type == EOF:
                    print(result)
                else:
                    raise Exception('Invalide syntax')
        except Exception as e:
            print(e)
            continue
 

 

  

  可以看到,基本上就是老师上课讲的内容,部分实现可能略有不同,逻辑功能基本是一样的。有几个部分做了改进,下面详细说:

 

 

 

  

  上图体现了课上所讲程序的几个漏洞,可以处理操作数和操作符之间的空格,但是数字中间的空格无法处理,也没有返回异常;由合法字符组成无意义序列无法处理,也没有返回异常。

 

  我对此做的改进在上面代码中都有体现,你自己翻回去看吧。这里带大家再回顾一遍。

  第一种情况:

 

    def step_forward(self):
        self.pos += 1
        while self.pos < len(self.text):
            if self.text[self.pos].isspace():
                self.pos += 1
                continue
            else:
                self.current_char = self.text[self.pos]
                return
        self.current_char = None

  

  第二种情况:

 

interpreter = Interpreter(Lexer(text))
result = interpreter.expr()
if interpreter.current_token.type == EOF:
    print(result)
else:
    raise Exception('Invalide syntax')

 

 

  改进后的代码运行效果:

 

  

  这下真的讲完了,可能有些地方讲的不够清楚,请你自己善用搜索引擎,谢谢。请大家见谅。

转载于:https://www.cnblogs.com/Tantalus/p/7747481.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值