如何避免在不使用 python sly 中的 say 函数的情况下打印变量?

How to avoid printing a variable without using the say function in python sly?

所以我正在使用 python 包 sly,它有一个词法分析器和解析器 class。我正在制作自己的编程语言 NoobPy。所以目前,代码将打开 test.noob 并读取每一行并解析它。现在,如果我要定义一个变量,比方说 x,只需在一行中写入 x,它就会打印出来,而我不希望这样。我希望它只有在我创建的 say 函数中传递时才打印。 词法分析器class

class NoobpyLexer(Lexer):
    tokens = {NUMBER, STRING, FALSE, TRUE, NAME, WHILE, IF, ELSE, SAY,
              PLUS, MINUS, TIMES, DIVIDE, ASSIGN,
              EQ, LT, LE, GT, GE, NEQ}

    literals = {'(', ')', ':'}

    # String containing ignored characters
    ignore = ' \t'

    # Regular expression rules for tokens
    STRING = r'\".*?\"'
    PLUS = r'\+'
    MINUS = r'-'
    TIMES = r'\*'
    DIVIDE = r'/'
    EQ = r'=='
    NEQ = r'!='
    ASSIGN = r'='
    LE = r'<='
    GE = r'>='
    LT = r'<'
    GT = r'>'

    @_(r'\d+')
    def NUMBER(self, t):
        t.value = int(t.value)
        return t

    # @_(r'^((true$|false$)$)')
    # def BOOL(self, t):
    #     return t

    @_(r'true')
    def TRUE(self, t):
        return t

    @_(r'false')
    def FALSE(self, t):
        return t

    # Identifiers and keywords
    NAME = r'\b(?!((true$|false$)$)\b)\w+'  # [a-zA-Z_][a-zA-Z0-9_]*$
    NAME['if'] = IF
    NAME['else'] = ELSE
    NAME['while'] = WHILE
    NAME['say'] = SAY

    ignore_comment = r'\#.*'

    # Line number tracking
    @_(r'\n+')
    def ignore_newline(self, t):
        self.lineno += t.value.count('\n')

    def error(self, t):
        print("t: ", t)
        print('Line %d: Bad character %r' % (self.lineno, t.value[0]))
        self.index += 1

解析器class

class NoobpyParser(Parser):
    # Get the token list from the lexer (required)
    tokens = NoobpyLexer.tokens
    log = logging.getLogger()
    log.setLevel(logging.ERROR)
    # debugfile = 'parser.out'

    precedence = (
        ('left', PLUS, MINUS),
        ('left', TIMES, DIVIDE),
        ('right', UMINUS)
    )

    def __init__(self):
        self.variables = {}

    @_('')
    def statement(self, p):
        pass

    @_('SAY expr')
    def statement(self, p):
        return 'say', p.expr

    @_('NAME')
    def expr(self, p):
        return 'var', p.NAME

    @_('var_assign')
    def statement(self, p):
        return p.var_assign

    @_('NAME ASSIGN expr')
    def var_assign(self, p):
        return 'var_assign', p.NAME, p.expr

    @_('expr')
    def statement(self, p):
        return p.expr

    @_('expr PLUS expr')
    def expr(self, p):
        return 'add', p.expr0, p.expr1

    @_('expr MINUS expr')
    def expr(self, p):
        return 'sub', p.expr0, p.expr1

    @_('expr TIMES expr')
    def expr(self, p):
        return 'mul', p.expr0, p.expr1

    @_('expr DIVIDE expr')
    def expr(self, p):
        return 'div', p.expr0, p.expr1

    @_('MINUS expr %prec UMINUS')
    def expr(self, p):
        expression = list(p.expr)
        if isinstance(expression[1], tuple):
            res = 0
            for i in expression[1]:
                res += i
            expression[1] = res
        expression[1] = -expression[1]
        return expression

    @_('expr EQ expr')
    def expr(self, p):
        return 'eq', p.expr0, p.expr1

    @_('"(" expr ")"')
    def expr(self, p):
        return p.expr

    @_('NUMBER')
    def expr(self, p):
        return 'num', p.NUMBER

    @_('STRING')
    def expr(self, p):
        return 'str', p.STRING

    @_('TRUE')
    def expr(self, p):
        return p.TRUE

    @_('FALSE')
    def expr(self, p):
        return p.FALSE

执行class

class NoobpyExecute:
    def __init__(self, tree, variables):
        self.variables = variables
        result = self.walkTree(tree)
        if result is None:
            pass
        elif result is not None and type(result) in [int, float]:
            print(result)
        elif isinstance(result, str):
            print(result)
        elif isinstance(result, bool):
            if result is True:
                print("true")
            else:
                print("false")

    def walkTree(self, node):
        if isinstance(node, int):
            return node
        if isinstance(node, str):
            return node

        if node is None:
            return None

        if node[0] == 'say':
            return self.walkTree(node[1])
        if node[0] == 'num':
            return node[1]
        if node[0] == 'str':
            return node[1]
        if node[0] == 'eq':
            return self.walkTree(node[1]) == self.walkTree(node[2])

        if node[0] == 'add':
            return self.walkTree(node[1]) + self.walkTree(node[2])
        elif node[0] == 'sub':
            return self.walkTree(node[1]) - self.walkTree(node[2])
        elif node[0] == 'mul':
            return self.walkTree(node[1]) * self.walkTree(node[2])
        elif node[0] == 'div':
            return self.walkTree(node[1]) / self.walkTree(node[2])

        if node[0] == 'var_assign':
            self.variables[node[1]] = self.walkTree(node[2])

        if node[0] == 'var':
            try:
                return self.variables[node[1]]
            except LookupError:
                print("Undefined name '{}'".format(node[1]))
                return 0

这个:

if __name__ == '__main__':
    lexer = NoobpyLexer()
    parser = NoobpyParser()
    variables = {}

    args = argparse.ArgumentParser()
    args.add_argument(metavar='filename', dest="filename", type=str, help='name of the file you want to run')
    args = args.parse_args()

    with open(args.filename) as file:
        for line in file.readlines():
            tree = parser.parse(lexer.tokenize(line))
            NoobpyExecute(tree, variables)

示例test.noob

x = 2
x

^ 打印 2

在你的 NoobPy 构造函数中,你打印出评估语法树的结果(除非它是 None,如果你评估一个赋值就会发生):

        if result is None:
            pass
        elif result is not None and type(result) in [int, float]:
            print(result)
        elif isinstance(result, str):
            print(result)
        elif isinstance(result, bool):
            if result is True:
                print("true")
            else:
                print("false")

撇开所有可以简化的事实不谈,代码似乎清楚地表明了打印评估结果的意图。如果你现在不想打印求值结果,你就不应该打印求值结果。

当您在树中看到 say 函数时,您 return 计算其参数的结果:

        if node[0] == 'say':
            return self.walkTree(node[1]) 

如果您希望 say 函数具有打印其参数求值结果的效果,您应该打印其参数求值结果而不是 return其论点的评估结果(或 returning 结果,取决于您认为 say 的语义)。