900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 用Python开发一个自制的编程语言(虚拟机解释型)[2] 词法分析器(2)

用Python开发一个自制的编程语言(虚拟机解释型)[2] 词法分析器(2)

时间:2023-06-24 21:32:24

相关推荐

用Python开发一个自制的编程语言(虚拟机解释型)[2] 词法分析器(2)

在上一篇文章中,我们搭好了一个编程语言解释器基本的框架,完成了一部分的词法分析器,下面让我们继续努力。用Python开发一个自制的编程语言(虚拟机解释型)[1] 词法分析器(1)_嘉定世外的JinJiayang的博客-CSDN博客

目标分析

我们的解释器能解析字符串(双引号包围的字符),数字,标识符(由字母、数字和下划线组成,可以与关键字重名),符号(在上一集提到),操作符(在上一集提到)。

具体实现

step1 搭好大致框架

class WordParser:...def parse(self):token = ''line = 0result = []small_result = {"value": []}fg = False

这段代码的含义是什么呢?

在WordParser类内部声明了parse(分析)方法,里面又定义了五个变量:

token:当前分析的临时结果。line:当前分析是第几行。result:返回值。small_result:存储了每一行的信息,会被放在result里面。fg:标志当前是否处于字符串的内部。

然后让我们开始编写parse方法。

step2主循环

这个很简单:

for char in self._string:...if token != "":small_result["value"].append(token)if len(small_result["value"]) > 0:small_result["line"] = linesmall_result["string"] = self._string.split()[-1]result.append(small_result)return result

char就是当前需要分析的字符,在遍历结束后,有可能token和small_result不为空,因此我们需要将它们放进result中,最后方法结束,返回result。

step3行保存

我们的编程语言以换行符为结束标志,而不是分号,因此在每一行结束后都需要将small_result放入result。

if char == "\n":if token is not '':small_result["value"].append(token)token = ''line += 1if len(small_result["value"]) > 0:small_result["string"] = self._string.split("\n")[line - 1]small_result["line"] = lineresult.append(small_result)small_result = {"value": []}

step4 分析字符

step4.1 分析字符串

if char == '"':fg = not fgif not fg:small_result["value"].append(token)token = ''small_result["value"].append(char)elif fg:token += char

step4.2 分析空格(保存token)

elif self.is_space(char):if token is not '':small_result["value"].append(token)token = ''

step4.3 分析数字

elif self.is_digit(char) and (len(token) == 0 or token.isdigit()):token += charelif self.is_digit(char):for tk in token:if not (self.is_letter(tk) or self.is_digit(tk)):small_result["value"].append(token)token = ""breaktoken += char

step4.4 分析操作符

elif not (self.is_digit(char) or self.is_letter(char)):for tk in token:if self.is_letter(tk) or self.is_digit(tk):small_result["value"].append(token)token = ""breaktoken += char

step4.5 分析符号

elif char in self.symbols:if token != "":small_result["value"].append(token)token = ""small_result["value"].append(char)

注意,符号分析必须单独写,不可以和操作符(operator)混为一谈。

否则"()"将会解析成"()"合在一起,而不是我们希望的"("和")"。

step4.6 分析标识符

elif self.is_letter(char):if not self.is_var(token):small_result["value"].append(token)token = ''token += char

测试

下面我们给它来一段测试代码:

if __name__ == '__main__':code = """include sjstdfor(var i=1; i<=100; i=i+1) {sjio <- 1+2 <- ","sjio <- "world" <- _e}"""string_list = WordParser(code).parse()for i in string_list:print(i)

结果:

{'value': ['include', 'sjstd'], 'string': 'include sjstd', 'line': 2}{'value': ['for', '(', 'var', 'i', '=', '1', ';', 'i', '<=', '100', ';', 'i', '=', 'i', '+', '1', ')', '{'], 'string': 'for(var i=1; i<=100; i=i+1) {', 'line': 3}{'value': ['sjio', '<-', '1', '+', '2', '<-', '"', ',', '"'], 'string': ' sjio <- 1+2 <- ","', 'line': 4}{'value': ['sjio', '<-', '"', 'world', '"', '<-', '_e'], 'string': ' sjio <- "world" <- _e', 'line': 5}{'value': ['}'], 'string': '}', 'line': 6}

至此,我们的词法分析器构造完成。

最终完整代码

class WordParser:def __init__(self, s):self._string = sself.operators = ['+', '*', '-', '/', '%', "//",'=','>', '<', '>=', '==', '<=', '!=','<-', '->','.', ',','&', '|','++', '--','&&', '||', '!',"::", ":"]self.symbols = ['(', ')', '"', '{', '}', '[', ']', ',', ';']is_letter = staticmethod(lambda char: ('a' <= char <= 'z') or ('A' <= char <= 'Z') or (char == "_"))is_digit = staticmethod(lambda char: '9' >= char >= '0')is_space = staticmethod(lambda char: True if char == ' ' or char == '\t' else False)is_var = lambda self, char: __import__("functools").reduce(lambda x, y: x and y,[self.is_digit(i) or self.is_letter(i) for i in char],True)def parse(self):token = ''line = 0result = []small_result = {"value": []}fg = Falsefor char in self._string:if char == '"':fg = not fgif not fg:small_result["value"].append(token)token = ''small_result["value"].append(char)elif fg:token += charelif char == "\n":if token is not '':small_result["value"].append(token)token = ''line += 1if len(small_result["value"]) > 0:small_result["string"] = self._string.split("\n")[line - 1]small_result["line"] = lineresult.append(small_result)small_result = {"value": []}elif self.is_space(char):if token is not '':small_result["value"].append(token)token = ''elif char in self.symbols:if token != "":small_result["value"].append(token)token = ""small_result["value"].append(char)elif self.is_digit(char) and (len(token) == 0 or token.isdigit()):token += charelif self.is_digit(char):for tk in token:if not (self.is_letter(tk) or self.is_digit(tk)):small_result["value"].append(token)token = ""breaktoken += charelif self.is_letter(char):if not self.is_var(token):small_result["value"].append(token)token = ''token += charelif not (self.is_digit(char) or self.is_letter(char)):for tk in token:if self.is_letter(tk) or self.is_digit(tk):small_result["value"].append(token)token = ""breaktoken += charif token != "":small_result["value"].append(token)if len(small_result["value"]) > 0:small_result["line"] = linesmall_result["string"] = self._string.split()[-1]result.append(small_result)return result

END

好了,今天到此为止,下一篇我们将详细讲述如何根据符号流解析AST树,保证让你拥有一个属于自己的parser。

如果你也想尝试这个项目的话,创作不易,不妨点个赞,关注本专栏,thanks~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。