本次试验的内容是四则运算——或者说表达式求值,我对此并不陌生,也曾用不一样语言分别实现过,但都是利用“栈”实现的相关功能,对于这一问题的递归实现我仍是第一次尝试。两种实现方式各有优劣,这里再也不展开。git
程序整体结构图以下:算法
词法分析的做用是将字符序列转换为单词(Token),本次实验中体如今读取整数功能,其他部分基本只有检测非法字符的做用。这部分没有难度再也不详述。ide
语法分析的任务是在词法分析的基础上将单词序列组合成各种语法短语,生成抽象语法树。以表达式(4+3*2)为例,抽象语法树形式以下:搜索引擎
这一部分的算法结构图以下:spa
不难看出来这三种结构是循环定义的,这也是为何我将之称为递归方法。code
最后,本实验实现的是词法分析和语法分析两个部分。也就是说我都讲完了,谢谢你们,请你们本身动手实现。blog
讲完了原理就是代码实现了,我最近正好在学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
能够看到,基本上就是老师上课讲的内容,部分实现可能略有不一样,逻辑功能基本是同样的。有几个部分作了改进,下面详细说:索引
上图体现了课上所讲程序的几个漏洞,能够处理操做数和操做符之间的空格,可是数字中间的空格没法处理,也没有返回异常;由合法字符组成无心义序列没法处理,也没有返回异常。token
我对此作的改进在上面代码中都有体现,你本身翻回去看吧。这里带你们再回顾一遍。
第一种状况:
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')
改进后的代码运行效果:
这下真的讲完了,可能有些地方讲的不够清楚,请你本身善用搜索引擎,谢谢。请你们见谅。