造个轮子--用Python写个编程语言-逻辑运算

@[TOC]

前言

在上一篇文章里面,实现了基本的变量,并且详细地阐述了基本原理,所以的话,这里要实现的就是这个判断,由于架子基本上打好了,后面的操作无法就是确定这个AST的一个执行顺序,也就是我们希望解释器执行的一个情况。

那么这里要实现的效果是这样的: 在这里插入图片描述

这里的实现的话,就比较简单了,如果前面理解的话,只是多了些操作的东西而已。

关键词

那么老规矩,我们需要先来定义我们的关键词。

先定义我们的类型,和合法的字符:


TT_INT = "整数"
TT_FLOAT = "浮点数"
TT_PLUS = "加号"
TT_DIV = "除号"
TT_MINUS = "减号"
TT_LPAREN = "左括号"
TT_RPAREN = "右括号"
TT_POW	= '次幂'
TT_MUL = "乘"
TT_EOF = 'EOF'
TT_IDENTIFIER = '设'
TT_KEYWORD = '关键字'
TT_EQ = '赋值'
TT_EE = '等于'
TT_NE = '不等于'
TT_LT = '小于'
TT_GT = '大于'
TT_LTE = '小于等于'
TT_GTE = '大于等于'
KEYWORDS = [
    '设',
    '且',
    '或',
    '否'

]

在这里插入图片描述

解析token

之后的话,是解析我们的token,这里的话,完全是老规矩。 在这里插入图片描述

主要是这里,我们有>=,<=这种字符,我们要进行处理

那么这块的话,主要是这几个方法:

    def make_not_equals(self):
        pos_start = self.pos.copy()
        self.advance()

        if self.current_char == '=':
            self.advance()
            return Token(TT_NE, pos_start=pos_start, pos_end=self.pos), None

        self.advance()
        return None, ExpectedCharError(pos_start, self.pos, "'=' (after '!')")

    def make_equals(self):
        tok_type = TT_EQ
        pos_start = self.pos.copy()
        self.advance()

        if self.current_char == '=':
            self.advance()
            tok_type = TT_EE

        return Token(tok_type, pos_start=pos_start, pos_end=self.pos)

    def make_less_than(self):
        tok_type = TT_LT
        pos_start = self.pos.copy()
        self.advance()

        if self.current_char == '=':
            self.advance()
            tok_type = TT_LTE

        return Token(tok_type, pos_start=pos_start, pos_end=self.pos)

    def make_greater_than(self):
        tok_type = TT_GT
        pos_start = self.pos.copy()
        self.advance()

        if self.current_char == '=':
            self.advance()
            tok_type = TT_GTE

        return Token(tok_type, pos_start=pos_start, pos_end=self.pos)

通过这几个方法我们就可以实现这个效果。完成<=,>=这样的关键字的Token的生成

解析器

之后的话,就是我们的语法解析器了。

在这里的话,核心代码的修改主要在这块:

这块的话,前面重复过多次了,就不重复说明了。

  def arith_expr(self):
        return self.bin_op(self.term, (TT_PLUS, TT_MINUS))

    def comp_expr(self):
        res = ParseResult()

        if self.current_tok.matches(TT_KEYWORD, '否'):
            op_tok = self.current_tok
            res.register_advancement()
            self.advance()

            node = res.register(self.comp_expr())
            if res.error: return res
            return res.success(UnaryOpNode(op_tok, node))

        node = res.register(self.bin_op(self.arith_expr, (TT_EE, TT_NE, TT_LT, TT_GT, TT_LTE, TT_GTE)))

        if res.error:
            return res.failure(InvalidSyntaxError(
                self.current_tok.pos_start, self.current_tok.pos_end,
                "Expected int, float, identifier, '+', '-', '(' or 'NOT'"
            ))

        return res.success(node)

    def expr(self):
        res = ParseResult()

        if self.current_tok.matches(TT_KEYWORD, '设'):
            res.register_advancement()
            self.advance()

            if self.current_tok.type != TT_IDENTIFIER:
                return res.failure(InvalidSyntaxError(
                    self.current_tok.pos_start, self.current_tok.pos_end,
                    "Expected identifier"
                ))

            var_name = self.current_tok
            res.register_advancement()
            self.advance()

            if self.current_tok.type != TT_EQ:
                return res.failure(InvalidSyntaxError(
                    self.current_tok.pos_start, self.current_tok.pos_end,
                    "Expected '='"
                ))

            res.register_advancement()
            self.advance()
            expr = res.register(self.expr())
            if res.error: return res
            return res.success(VarAssignNode(var_name, expr))

        node = res.register(self.bin_op(self.comp_expr, ((TT_KEYWORD, '且'), (TT_KEYWORD, '或'))))

        if res.error:
            return res.failure(InvalidSyntaxError(
                self.current_tok.pos_start, self.current_tok.pos_end,
                "Expected 'VAR', int, float, identifier, '+', '-', '(' or 'NOT'"
            ))

        return res.success(node)

解释器

最后是我们的解释器。在这里我们需要为这种新加如的节点进行处理,所以核心是加入新的处理函数。

    def get_comparison_eq(self, other):
        if isinstance(other, Number):
            return Number(int(self.value == other.value)).set_context(self.context), None

    def get_comparison_ne(self, other):
        if isinstance(other, Number):
            return Number(int(self.value != other.value)).set_context(self.context), None

    def get_comparison_lt(self, other):
        if isinstance(other, Number):
            return Number(int(self.value < other.value)).set_context(self.context), None

    def get_comparison_gt(self, other):
        if isinstance(other, Number):
            return Number(int(self.value > other.value)).set_context(self.context), None

    def get_comparison_lte(self, other):
        if isinstance(other, Number):
            return Number(int(self.value <= other.value)).set_context(self.context), None

    def get_comparison_gte(self, other):
        if isinstance(other, Number):
            return Number(int(self.value >= other.value)).set_context(self.context), None

    def anded_by(self, other):
        if isinstance(other, Number):
            return Number(int(self.value and other.value)).set_context(self.context), None

    def ored_by(self, other):
        if isinstance(other, Number):
            return Number(int(self.value or other.value)).set_context(self.context), None

    def notted(self):
        return Number(1 if self.value == 0 else 0).set_context(self.context), None

    def copy(self):
        copy = Number(self.value)
        copy.set_pos(self.pos_start, self.pos_end)
        copy.set_context(self.context)
        return copy

那么在这里的话,我们就完成了基本这个逻辑运算了。因为核心的原理我们已经说清楚了,我们所有的代码基本上就是为指定的语法规则服务。比较核心的在这里,其实是AST的构建,而AST核心的是对语法规则的构建定义。这影响到你的代码到底如何执行递归,递归执行的顺序到底是怎么样的。

语法表示

所以在这块的话,我们现在来看到最新的语法表示:

expr		: KEYWORD:VAR IDENTIFIER EQ expr
			: comp-expr ((KEYWORD:AND|KEYWORD:OR) comp-expr)*

comp-expr	: NOT comp-expr
			: arith-expr ((EE|LT|GT|LTE|GTE) arith-expr)*

arith-expr	: term ((PLUS|MINUS) term)*

term		: factor ((MUL|DIV) factor)*

factor		: (PLUS|MINUS) factor
			: power

power		: atom (POW factor)*

atom 		: INT|FLOAT|IDENTIFIER
			: LPAREN expr RPAREN

全部评论

相关推荐

昨天 22:54
武汉大学 Java
点赞 评论 收藏
分享
已经入职数字马力4个月了,忍不住想和大家聊聊最真实的感受!🔥1️⃣&nbsp;岗位偏见?作为蚂蚁的子公司,很多人会担心“内包”身份会不会有岗位偏见。就我这几个月的体验来说,数字马力一直在快速扩招,面试流程也越来越规范(尤其是校招环节)。至于偏见问题,真的看部门和leader,很幸运我遇到的师兄和主管都特别nice,团队氛围很融洽。2️⃣&nbsp;待遇怎么样?试用期工资不打折!这点我真的吹爆💥!每天六点下班还有餐补,公积金按全额8%交(感动哭)……不过养老金也是实打实的8%,到手稍微心疼一下下😂3️⃣&nbsp;技术栈跟得上吗?技术栈多到学不完……而且我们有权限访问蚂蚁的知识库,自学能力强+愿意钻研的话,成长速度真的飞快!(当然,像我这种偶尔偷懒的也在慢慢进步中😝)4️⃣&nbsp;面试流程?一般是三面:两轮技术面(可能有线上笔试)+&nbsp;一轮HR面(含背调)。整体节奏比较顺畅,反馈也及时。5️⃣&nbsp;未来发展怎么看?老实说,数字马力不算头部大厂,不能指望它给简历镀金,但也绝不是那种会“减分”的外包。我更愿意把它看作一个扎实的中厂跳板,适合积累实战经验。6️⃣&nbsp;怎么投递?通过数字马力gzh,今天刚放出一批新HC!如果你正在看机会,不妨试试数字马力~之前面挂过也没关系,不妨再战一次,机会说不定就来了!🤝✅&nbsp;我的专属内推码:NTA6Nvs,可以直接帮大家推进流程。📮&nbsp;有任何关于公司、岗位、面试的问题,也欢迎留言,我会尽量回复~(小声说:大环境不易,希望大家都能找到心仪的工作,也欢迎来找我内推呀!)
数字马力公司福利 22人发布
点赞 评论 收藏
分享
hwwhwh:同双非,有大厂实习其实也没啥用,主要看运气,等就行了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务