Hlang--用Python写个编程语言-函数与基本数据结构实现

这篇具有很好参考价值的文章主要介绍了Hlang--用Python写个编程语言-函数与基本数据结构实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

okey,经过一段时间的努力,接下来要实现的是函数。当然还有对应的基本数据结构,那么之后的话,我们的工作就开始进一步转换了。

那么在这块我们要实现的有:

  1. 函数的定义
  2. String类型的实现
  3. 列表类型的实现

实话实话,这个的实现是相当简陋的。不过作为一个小模型,应该是够用了,后面可以尝试打磨一下这个细节,比如这个变量的管理,函数的管理等等。

那么这块先看到我们的实现效果:
Hlang--用Python写个编程语言-函数与基本数据结构实现,基于Python的中文编程语言-Hlang(毕设第一部分),python,数据结构,开发语言

okey,我们开始吧。

语法表述

okey,现在的话,想要实现这个的话,我们需要先来看到我们的这个语法表述,前面我们一直在强调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		: call (POW factor)*

call		: atom (LPAREN (expr (COMMA expr)*)? RPAREN)?

atom 		: INT|FLOAT|STRING|IDENTIFIER
			: LPAREN expr RPAREN
			: if-expr
			: for-expr
			: while-expr
			: func-def

if-expr		: KEYWORD:IF expr KEYWORD:THEN expr
			                (KEYWORD:ELIF expr KEYWORD:THEN expr)*
			                (KEYWORD:ELSE expr)?

for-expr	: KEYWORD:FOR IDENTIFIER EQ expr KEYWORD:TO expr
							(KEYWORD:STEP expr)? KEYWORD:THEN expr

while-expr	: KEYWORD:WHILE expr KEYWORD:THEN expr

func-def	: KEYWORD:FUN IDENTIFIER?
							LPAREN (IDENTIFIER (COMMA IDENTIFIER)*)? RPAREN
							ARROW expr

前面的都是老朋友,我们主要看到这个call,和func-def.
这两个家伙就是我们这个函数部分的操作。
这个和我们的变量实现一样,其实分两个部分,一个是函数本身的定义
例如Python的函数定义:

def add(a,b):

然后的话,是我们对函数的调用

add(a,b)

这里的话,其实是一样的。

所以的话,定义了这两个东西。

之后的话,我们来看到完整的描述:

  1. expr:表示一个表达式。它可以是一个变量赋值表达式(以关键字 ‘VAR’ 开头),或者是一个比较表达式 comp-expr,多个比较表达式之间可以使用逻辑运算符 ‘AND’ 和 ‘OR’ 进行连接。

  2. comp-expr:表示一个比较表达式。它可以是一个逻辑非表达式(以关键字 ‘NOT’ 开头),或者是一个算术表达式 arith-expr,多个算术表达式之间可以使用比较运算符进行比较。

  3. arith-expr:表示一个算术表达式。它由一个项 term 开始,后面可以跟随多个加减运算符和项。

  4. term:表示一个项。它由一个因子 factor 开始,后面可以跟随多个乘除运算符和因子。

  5. factor:表示一个因子。它可以是正负号与另一个因子相乘的结果,或者是一个幂运算表达式 power

  6. power:表示一个幂运算表达式。它由一个函数调用 call 开始,后面可以跟随多个幂运算操作。

  7. call:表示一个函数调用。它由一个原子表达式 atom 开始,后面可以跟随一对括号和多个参数表达式。

  8. atom:表示一个原子表达式。它可以是整数、浮点数、字符串或标识符,也可以是一个被括号包裹的表达式,或者是一个 if 表达式、for 循环表达式、while 循环表达式或函数定义表达式。

  9. if-expr:表示一个 if 表达式。它以关键字 ‘IF’ 开头,后面跟随条件表达式、关键字 ‘THEN’ 和对应的表达式。之后可以有零个或多个关键字 ‘ELIF’、条件表达式和关键字 ‘THEN’ 和对应的表达式。最后可以有一个可选的关键字
    ‘ELSE’ 和对应的表达式。

  10. for-expr:表示一个 for 循环表达式。它以关键字 ‘FOR’ 开头,后面跟随循环变量、赋值运算符、起始值、关键字 ‘TO’、结束值,然后可以是可选的关键字 ‘STEP’ 和步长值,最后是关键字 ‘THEN’ 和对应的表达式。

  11. while-expr:表示一个 while 循环表达式。它以关键字 ‘WHILE’ 开头,后面跟随条件表达式,然后是关键字 ‘THEN’ 和对应的表达式。

  12. func-def:表示一个函数定义表达式。它以关键字 ‘FUN’ 开头,后面可以是可选的标识符作为函数名称,然后是一对括号和多个参数标识符。最后是箭头符号和对应的表达式。

这样的话,就定义好了这个家伙。

解析器修改

okey,现在的话,开始来正式进入代码的编写部分。首先的话,毫无疑问的是,我们要做的是分为两个大部分,首先是对token词法解析的修改,然后是我们语法解析器的修改。当然这块的话我们就一起说了。

词法解析

首先,我们还是老规矩,去定义:


TT_INT = "整数"
TT_FLOAT = "浮点数"
TT_STRING = '字符串'
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 = '大于等于'
TT_LSQUARE = '[括号'
TT_RSQUARE = ']括号'
TT_COMMA = ',号'
TT_ARROW = '-> 符号'

KEYWORDS = [
  'var',
  'and',
  'or',
  'not',
  'if',
  'elif',
  'else',
  'for',
  'to',
  'step',
  'while',
  'fun',
  'then'
]

可以看到,这个就是我们目前定义的关键字,还有对应的Token类型。

在解析器这里的话,我们要重新新增修改的代码不多,因为关键字匹配我们先前就是写好的,现在要做的只是匹配这个[]括号,主要是为了,处理这个列表变量。

当然还有这个:
Hlang--用Python写个编程语言-函数与基本数据结构实现,基于Python的中文编程语言-Hlang(毕设第一部分),python,数据结构,开发语言
这个家伙的话,可以去获取到我们的这个字符串,出现“ 这个符号的时候,我们就需要进行特殊处理了。

  def make_string(self):
        string = ''
        pos_start = self.pos.copy()
        escape_character = False
        self.advance()

        escape_characters = {
            'n': '\n',
            't': '\t'
        }

        while self.current_char != None and (self.current_char != '"' or escape_character):
            if escape_character:
                string += escape_characters.get(self.current_char, self.current_char)
            else:
                if self.current_char == '\\':
                    escape_character = True
                else:
                    string += self.current_char
            self.advance()
            escape_character = False

        self.advance()
        return Token(TT_STRING, string, pos_start, self.pos)

函数节点

那么同样的,我们要加入这个函数节点。
这里的话,我们有两个:

FuncDefNode 类表示函数定义的节点。它具有以下属性:

var_name_tok:函数名称的记号(Token)。
arg_name_toks:参数名称的记号列表。
body_node:函数体的节点。
pos_start:节点在源代码中的起始位置。如果存在函数名记号,
则起始位置为该记号的起始位置;如果不存在函数名记号但存在参数名记号,
则起始位置为第一个参数名记号的起始位置;否则起始位置为函数体节点的起始位置。
pos_end:节点在源代码中的结束位置,等于函数体节点的结束位置。

CallNode 类表示函数调用的节点。它具有以下属性:

node_to_call:被调用的函数节点。
arg_nodes:参数节点列表。
pos_start:节点在源代码中的起始位置,等于被调用函数节点的起始位置。
pos_end:节点在源代码中的结束位置。如果存在参数节点,
则结束位置为最后一个参数节点的结束位置;否则结束位置为被调用函数节点的结束位置。
class FuncDefNode:
  def __init__(self, var_name_tok, arg_name_toks, body_node):
    self.var_name_tok = var_name_tok
    self.arg_name_toks = arg_name_toks
    self.body_node = body_node

    if self.var_name_tok:
      self.pos_start = self.var_name_tok.pos_start
    elif len(self.arg_name_toks) > 0:
      self.pos_start = self.arg_name_toks[0].pos_start
    else:
      self.pos_start = self.body_node.pos_start

    self.pos_end = self.body_node.pos_end

class CallNode:
  def __init__(self, node_to_call, arg_nodes):
    self.node_to_call = node_to_call
    self.arg_nodes = arg_nodes

    self.pos_start = self.node_to_call.pos_start

    if len(self.arg_nodes) > 0:
      self.pos_end = self.arg_nodes[len(self.arg_nodes) - 1].pos_end
    else:
      self.pos_end = self.node_to_call.pos_en

函数节点解析

定义号函数节点之后的话,我们要做就是构建函数节点了,那么对于这个节点的处理,其实和我们的这个for循环,while 还有这个if的其实是类似的。
Hlang--用Python写个编程语言-函数与基本数据结构实现,基于Python的中文编程语言-Hlang(毕设第一部分),python,数据结构,开发语言

我们直接上代码吧,然后在注释里面说明:

    def func_def(self):
        res = ParseResult()
        # 当前节处理是函数节点,检查有没有fun关键字
        if not self.current_tok.matches(TT_KEYWORD, 'fun'):
            return res.failure(InvalidSyntaxError(
                self.current_tok.pos_start, self.current_tok.pos_end,
                f"Expected 'fun'"
            ))
	
        res.register_advancement()
        self.advance()
		
		# 处理函数的形式变量,也就是参数
		# 问:为什么可以检查到下一个节点
		# 答,算过了(狗头) 好吧是adanven这个函数,它会滑动,
		# 这里面的话register其实是递归调用了,所以,前面结束之后,拿到的一定
		# 就是符合语法规范的下一个token
        if self.current_tok.type == TT_IDENTIFIER:
            var_name_tok = self.current_tok
            res.register_advancement()
            self.advance()
            #检查左括号
            if self.current_tok.type != TT_LPAREN:
                return res.failure(InvalidSyntaxError(
                    self.current_tok.pos_start, self.current_tok.pos_end,
                    f"Expected '('"
                ))
        #没有参数
        else:
            var_name_tok = None
            if self.current_tok.type != TT_LPAREN:
                return res.failure(InvalidSyntaxError(
                    self.current_tok.pos_start, self.current_tok.pos_end,
                    f"Expected identifier or '('"
                ))

        res.register_advancement()
        self.advance()
        arg_name_toks = []
		# 处理参数
        if self.current_tok.type == TT_IDENTIFIER:
            arg_name_toks.append(self.current_tok)
            res.register_advancement()
            self.advance()
			#下一个参数逗号隔开
            while self.current_tok.type == TT_COMMA:
                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,
                        f"Expected identifier"
                    ))

                arg_name_toks.append(self.current_tok)
                res.register_advancement()
                self.advance()

            if self.current_tok.type != TT_RPAREN:
                return res.failure(InvalidSyntaxError(
                    self.current_tok.pos_start, self.current_tok.pos_end,
                    f"Expected ',' or ')'"
                ))
        # 没有参数了
        else:
            if self.current_tok.type != TT_RPAREN:
                return res.failure(InvalidSyntaxError(
                    self.current_tok.pos_start, self.current_tok.pos_end,
                    f"Expected identifier or ')'"
                ))

        res.register_advancement()
        self.advance()
	
        if self.current_tok.type != TT_ARROW:
            return res.failure(InvalidSyntaxError(
                self.current_tok.pos_start, self.current_tok.pos_end,
                f"Expected '->'"
            ))

        res.register_advancement()
        self.advance()
        node_to_return = res.register(self.expr())
        if res.error: return res
		# 完成参数节点定义,得到函数名,参数名(变量名)
        return res.success(FuncDefNode(
            var_name_tok,
            arg_name_toks,
            node_to_return
        ))

同样的,我们来看到call的实现。

    def call(self):
        res = ParseResult()
        atom = res.register(self.atom())
        if res.error: return res
		"""
		函数是可以有括号把里面的东西括起来的,就像这样:
		fun show()-> ( var b=3 )
		"""
        if self.current_tok.type == TT_LPAREN:
            res.register_advancement()
            self.advance()
            arg_nodes = []

            if self.current_tok.type == TT_RPAREN:
                res.register_advancement()
                self.advance()
            else:
                arg_nodes.append(res.register(self.expr()))
                if res.error:
                    return res.failure(InvalidSyntaxError(
                        self.current_tok.pos_start, self.current_tok.pos_end,
                        "Expected ')', 'var', 'if', 'for', 'while', 'fun', int, float, identifier, '+', '-', '(', '[' or 'not'"
                    ))

                while self.current_tok.type == TT_COMMA:
                    res.register_advancement()
                    self.advance()

                    arg_nodes.append(res.register(self.expr()))
                    if res.error: return res

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

                res.register_advancement()
                self.advance()
             # 当前面的都执行完毕之后的话,我们的这个Call节点就ok了。
            return res.success(CallNode(atom, arg_nodes))
        return res.success(atom)

他们着两个的关系其实就是这样的:
Hlang--用Python写个编程语言-函数与基本数据结构实现,基于Python的中文编程语言-Hlang(毕设第一部分),python,数据结构,开发语言

List的解析实现

ok, 这里别忘了,我们还实现了我们的数据结构,String和List,所以这里的话,我们还要对这个两个家伙处理。不过这块的话,对于String的话其实没有什么特殊的,只需要解释的时候进行处理,但是对于List的话,因为这个家伙是有语法规则的,因此还需要单独处理。

 def list_expr(self):
        res = ParseResult()
        element_nodes = []
        pos_start = self.current_tok.pos_start.copy()

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

        res.register_advancement()
        self.advance()

        if self.current_tok.type == TT_RSQUARE:
            res.register_advancement()
            self.advance()
        else:
            element_nodes.append(res.register(self.expr()))
            if res.error:
                return res.failure(InvalidSyntaxError(
                    self.current_tok.pos_start, self.current_tok.pos_end,
                    "Expected ']', 'var', 'if', 'for', 'while', 'fun', int, float, identifier, '+', '-', '(', '[' or 'not'"
                ))

            while self.current_tok.type == TT_COMMA:
                res.register_advancement()
                self.advance()

                element_nodes.append(res.register(self.expr()))
                if res.error: return res

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

            res.register_advancement()
            self.advance()

        return res.success(ListNode(
            element_nodes,
            pos_start,
            self.current_tok.pos_end.copy()
        ))

这里的话,我特意把注释删掉了,按照我们前面的套路,我想应该是可以把这个看明白的。

解释器

之后是我们的解释器。

节点

同样的在我们的解释器里面也有节点,这个节点,前面忘记说了,先前的话我只要Number这个节点,主要是因为当时我们只有这个对数学的基本运算,没有啥高级的操作,因此一个就够了,这个玩意就是用来存储运算结果的。

同样的,现在的话,操作复杂了,因此我们要做的事情就多了,所以的话,在这里我们有这些玩意:


class Value:
    def __init__(self):
        self.set_pos()
        self.set_context()

    def set_pos(self, pos_start=None, pos_end=None):
        self.pos_start = pos_start
        self.pos_end = pos_end
        return self

    def set_context(self, context=None):
        self.context = context
        return self

    def added_to(self, other):
        return None, self.illegal_operation(other)

    def subbed_by(self, other):
        return None, self.illegal_operation(other)

    def multed_by(self, other):
        return None, self.illegal_operation(other)

    def dived_by(self, other):
        return None, self.illegal_operation(other)

    def powed_by(self, other):
        return None, self.illegal_operation(other)

    def get_comparison_eq(self, other):
        return None, self.illegal_operation(other)

    def get_comparison_ne(self, other):
        return None, self.illegal_operation(other)

    def get_comparison_lt(self, other):
        return None, self.illegal_operation(other)

    def get_comparison_gt(self, other):
        return None, self.illegal_operation(other)

    def get_comparison_lte(self, other):
        return None, self.illegal_operation(other)

    def get_comparison_gte(self, other):
        return None, self.illegal_operation(other)

    def anded_by(self, other):
        return None, self.illegal_operation(other)

    def ored_by(self, other):
        return None, self.illegal_operation(other)

    def notted(self,other):
        return None, self.illegal_operation(other)

    def execute(self, args):
        return RTResult().failure(self.illegal_operation())

    def copy(self):
        raise Exception('No copy method defined')

    def is_true(self):
        return False

    def illegal_operation(self, other=None):
        if not other: other = self
        return RTError(
            self.pos_start, other.pos_end,
            'Illegal operation',
            self.context
        )


class Number(Value):
    def __init__(self, value):
        super().__init__()
        self.value = value

    def added_to(self, other):
        if isinstance(other, Number):
            return Number(self.value + other.value).set_context(self.context), None
        else:
            return None, Value.illegal_operation(self, other)

    def subbed_by(self, other):
        if isinstance(other, Number):
            return Number(self.value - other.value).set_context(self.context), None
        else:
            return None, Value.illegal_operation(self, other)

    def multed_by(self, other):
        if isinstance(other, Number):
            return Number(self.value * other.value).set_context(self.context), None
        else:
            return None, Value.illegal_operation(self, other)

    def dived_by(self, other):
        if isinstance(other, Number):
            if other.value == 0:
                return None, RTError(
                    other.pos_start, other.pos_end,
                    'Division by zero',
                    self.context
                )

            return Number(self.value / other.value).set_context(self.context), None
        else:
            return None, Value.illegal_operation(self, other)

    def powed_by(self, other):
        if isinstance(other, Number):
            return Number(self.value ** other.value).set_context(self.context), None
        else:
            return None, Value.illegal_operation(self, other)

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

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

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

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

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

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

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

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

    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

    def is_true(self):
        return self.value != 0

    def __repr__(self):
        return str(self.value)


class String(Value):
    def __init__(self, value):
        super().__init__()
        self.value = value

    def added_to(self, other):
        if isinstance(other, String):
            return String(self.value + other.value).set_context(self.context), None
        else:
            return None, Value.illegal_operation(self, other)

    def multed_by(self, other):
        if isinstance(other, Number):
            return String(self.value * other.value).set_context(self.context), None
        else:
            return None, Value.illegal_operation(self, other)

    def is_true(self):
        return len(self.value) > 0

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

    def __repr__(self):
        return f'"{self.value}"'


class List(Value):
    def __init__(self, elements):
        super().__init__()
        self.elements = elements

    def added_to(self, other):
        new_list = self.copy()
        new_list.elements.append(other)
        return new_list, None

    def subbed_by(self, other):
        if isinstance(other, Number):
            new_list = self.copy()
            try:
                new_list.elements.pop(other.value)
                return new_list, None
            except:
                return None, RTError(
                    other.pos_start, other.pos_end,
                    'Element at this index could not be removed from list because index is out of bounds',
                    self.context
                )
        else:
            return None, Value.illegal_operation(self, other)

    def multed_by(self, other):
        if isinstance(other, List):
            new_list = self.copy()
            new_list.elements.extend(other.elements)
            return new_list, None
        else:
            return None, Value.illegal_operation(self, other)

    def dived_by(self, other):
        if isinstance(other, Number):
            try:
                return self.elements[other.value], None
            except:
                return None, RTError(
                    other.pos_start, other.pos_end,
                    'Element at this index could not be retrieved from list because index is out of bounds',
                    self.context
                )
        else:
            return None, Value.illegal_operation(self, other)

    def copy(self):
        copy = List(self.elements[:])
        copy.set_pos(self.pos_start, self.pos_end)
        copy.set_context(self.context)
        return copy

    def __repr__(self):
        return f'[{", ".join([str(x) for x in self.elements])}]'


class Function(Value):
    def __init__(self, name, body_node, arg_names):
        super().__init__()
        self.name = name or "<anonymous>"
        self.body_node = body_node
        self.arg_names = arg_names

    def execute(self, args):
        res = RTResult()
        interpreter = Interpreter()
        new_context = Context(self.name, self.context, self.pos_start)
        new_context.symbol_table = SymbolTable(new_context.parent.symbol_table)

        if len(args) > len(self.arg_names):
            return res.failure(RTError(
                self.pos_start, self.pos_end,
                f"{len(args) - len(self.arg_names)} too many args passed into '{self.name}'",
                self.context
            ))

        if len(args) < len(self.arg_names):
            return res.failure(RTError(
                self.pos_start, self.pos_end,
                f"{len(self.arg_names) - len(args)} too few args passed into '{self.name}'",
                self.context
            ))

        for i in range(len(args)):
            arg_name = self.arg_names[i]
            arg_value = args[i]
            arg_value.set_context(new_context)
            new_context.symbol_table.set(arg_name, arg_value)

        value = res.register(interpreter.visit(self.body_node, new_context))
        if res.error: return res
        return res.success(value)

    def copy(self):
        copy = Function(self.name, self.body_node, self.arg_names)
        copy.set_context(self.context)
        copy.set_pos(self.pos_start, self.pos_end)
        return copy

    def __repr__(self):
        return f"<function {self.name}>"

函数名非常直接。同时的话,在看到函数节点,还有这个执行的操作。

函数操作

我们先来看到我们的函数处理:
在我们的解释器部分有这个代码:
Hlang--用Python写个编程语言-函数与基本数据结构实现,基于Python的中文编程语言-Hlang(毕设第一部分),python,数据结构,开发语言
我们把这个函数相关的信息,进行组装,然后得到这个函数对象,然后通过函数对象进行操作。得到结果,或者运行函数里面的代码。
所以在这里的话,我们要重点看到这里,函数的执行代码:

可以看到,我们在这里的操作,是,我们得到了函数主体的入口节点,画图题可能是这样的:
Hlang--用Python写个编程语言-函数与基本数据结构实现,基于Python的中文编程语言-Hlang(毕设第一部分),python,数据结构,开发语言

我们的execute函数会拿到这个body,当然还有参数,然后我们让解释器,从这个body头节点开始执行

然后就是我们的局部参数,可以看到我们的代码在这里面:

        for i in range(len(args)):
            arg_name = self.arg_names[i]
            arg_value = args[i]
            arg_value.set_context(new_context)
            new_context.symbol_table.set(arg_name, arg_value)

我们把这个变量的值什么的都放在了函数内部的局部context里面,所以这个就是局部参数的由来,我们在这里面实现了变量的隔离。

okey,接下来我们看到这个完整代码:

    def execute(self, args):
        res = RTResult()
        interpreter = Interpreter()
        new_context = Context(self.name, self.context, self.pos_start)
        new_context.symbol_table = SymbolTable(new_context.parent.symbol_table)

        if len(args) > len(self.arg_names):
            return res.failure(RTError(
                self.pos_start, self.pos_end,
                f"{len(args) - len(self.arg_names)} too many args passed into '{self.name}'",
                self.context
            ))

        if len(args) < len(self.arg_names):
            return res.failure(RTError(
                self.pos_start, self.pos_end,
                f"{len(self.arg_names) - len(args)} too few args passed into '{self.name}'",
                self.context
            ))

        for i in range(len(args)):
            arg_name = self.arg_names[i]
            arg_value = args[i]
            arg_value.set_context(new_context)
            new_context.symbol_table.set(arg_name, arg_value)

        value = res.register(interpreter.visit(self.body_node, new_context))
        if res.error: return res
        return res.success(value)

String和List处理

接下来的话,就是String和List的处理,这里面的话没啥,直接看到代码就好了。

  def visit_StringNode(self, node, context):
        return RTResult().success(
            String(node.tok.value).set_context(context).set_pos(node.pos_start, node.pos_end)
        )

    def visit_ListNode(self, node, context):
        res = RTResult()
        elements = []

        for element_node in node.element_nodes:
            elements.append(res.register(self.visit(element_node, context)))
            if res.error: return res

        return res.success(
            List(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
        )

总结

接下来的话,我们的实现就要到尾声了,当然接下来我们要处理的是这个,怎么和中文联系起来。先前我们一直做到的是中文,但是在后面,发现用中文实在是太啰嗦了,但是这个玩意的目标用户又是小学生,淦。文章来源地址https://www.toymoban.com/news/detail-658812.html

到了这里,关于Hlang--用Python写个编程语言-函数与基本数据结构实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 函数探秘:深入理解C语言函数,实现高效模块化编程

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 在数学中我们就知道了函数这个概念,而C语言同样引入了函数这个概念,那C语言的函数到底是什么样的呢? 在C语言中, 函数也叫子程序,它是一段可以

    2024年03月09日
    浏览(26)
  • 掌握Go语言:Go语言递归函数,解密编程之谜,探索算法的奥秘!(27)

    递归函数是指在函数内部调用自身的函数。在Go语言中,递归函数使用起来非常方便,但需要注意递归的终止条件,以避免无限循环。 Go语言递归函数的使用方法 在Go语言中,编写递归函数的基本步骤如下: 上述三点内容详细解释如下: 定义一个函数,函数内部调用自身 :

    2024年04月15日
    浏览(11)
  • 什么是栈,为什么函数式编程语言都离不开栈?

    ​ 栈是一种具有特殊访问方式的存储空间,它的特殊性在于, 最后进入这个空间的数据,最先出去 ,可以画图来描述一下这种操作方式。 假设有一个盒子和三本书,依次将三本书他们放入盒子中。 入栈模拟图 ​ 现在有一个问题,如果一次只能取一本,我们如何将书从盒子

    2024年02月06日
    浏览(21)
  • Socket编程详解:从基本概念到实例应用(TCP|UDP C语言实例详解)

    简介: Socket编程是网络编程中至关重要的一部分,它提供了一种在不同主机之间进行数据通信的方式。本篇博客将详细介绍Socket编程的基本概念、原理和实例应用,帮助读者深入理解和掌握这一重要技术。 正文: 一、Socket编程概述 Socket是一种通信机制,通过它可以在不同主

    2024年02月14日
    浏览(11)
  • 【跟小嘉学 Rust 编程】十三、函数式语言特性:迭代器和闭包

    【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学 Rust 编程】六、枚举

    2024年02月11日
    浏览(20)
  • Python编程语言简介

    Python 是荷兰人 Guido van Rossum (吉多·范罗苏姆,中国程序员称其为“龟叔”)在 1990 年初开发的一种解释型编程语言。 Python 的诞生是极具戏曲性的,据 Guido 自述记载,Python 语言是在圣诞节期间为了打发无聊的时间而开发的,之所以会选择 Python 作为该编程语言的名字,是因

    2024年02月07日
    浏览(24)
  • 编程语言与Python介绍

    计算机存储数据格式 原理: 计算机的工作需要基于电,而电信号只有高低电频两种状态。将高低电频命名为0和1(也就意味着计算机只识别0和1的二进制数)所以计算机才能识别诸多信息,原因是使用了二进制数进行排列组合 存储单位: 二进制数使用比特位(bit)表示:一

    2024年02月04日
    浏览(17)
  • [从零开始学习FPGA编程-32]:进阶篇 - 基本时序电路-D触发器(Verilog语言)

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:  目录 第1章 什么是时序电路 1.1 时序电路 1.2 什么是触发器

    2023年04月08日
    浏览(14)
  • 最喜爱的编程语言——Python

            编程语言(programming language)可以简单的理解为一种计算机和人都能识别的语言。一种能够让程序员准确地定义计算机所需数据的计算机语言,并精确地定义在不同情况下所应当采取的行动。        编程语言处在不断的发展和变化中,从最初的机器语言发展到如今

    2024年02月09日
    浏览(17)
  • 一文了解Python编程语言及安装

    目录 🍒初识Python 🍒什么是编程语言 🍒安装python(windows) 🍒安装python(Linux)     🦐博客主页:大虾好吃吗的博客     🦐专栏地址:Python从入门到精通专栏 人生苦短,我用python          Python是一种高级编程语言,由荷兰人Guido van Rossum于1989年创造。 Python是一种高

    2024年02月11日
    浏览(18)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包