虽然循环实现永远不会在 Ply 问题中结束

While cycle implementation never ends in Ply issue

我试图在 python 3.8 中使用 ply 实现一种小型编程语言,问题是我实现的 while 循环 永远不会停止,并且 p[3] 中的条件似乎永远不会更新,这里是语句:

def p_statement_if(p):
    '''statement : IF LPAREN comparison RPAREN LBRAKET statement RBRAKET
                 | IF LPAREN comparison RPAREN LBRAKET statement RBRAKET ELSE LBRAKET statement RBRAKET'''
    if p[3]:
        p[0] = p[6]
    else:
        if p[10] is not None:
            p[0] = p[10]

def p_statement_while(p):
    'statement : WHILE LPAREN comparison RPAREN LBRAKET statement RBRAKET'
    while(p[3]):
        p[0] = p[6]

我的问题是如何让它始终更新 p[3] 中的条件?

我的整个代码是这样的:

tokens = (
    'NAME','NUMBER',
    'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
    'LPAREN','RPAREN','LBRAKET','RBRAKET',
    'EQUAL','NOTEQ','LARGE','SMALL','LRGEQ','SMLEQ',
    'ENDSTM',
    )

reserved = {
    'while' : 'WHILE',
    'if'    : 'IF',
    'else'  : 'ELSE',
    'print' : "PRINT",
}
tokens += tuple(reserved.values())
# Tokens

t_PLUS    = r'\+'
t_MINUS   = r'-'
t_TIMES   = r'\*'
t_DIVIDE  = r'/'
t_EQUALS  = r'='

t_LPAREN  = r'\('
t_RPAREN  = r'\)'
t_LBRAKET  = r'\{'
t_RBRAKET  = r'\}'

t_EQUAL   = r'\=\='
t_NOTEQ   = r'\!\='
t_LARGE   = r'\>'
t_SMALL   = r'\<'
t_LRGEQ   = r'\>\='
t_SMLEQ   = r'\<\='

t_ENDSTM  = r';'

def t_NUMBER(t):
    r'\d+'
    t.value = int(t.value)
    return t

def t_NAME(t):
    r'[a-zA-Z_][a-zA-Z0-9_]*'
    if t.value in reserved:
        t.type = reserved[t.value]
    return t

# Ignored characters
t_ignore = " \t"

def t_newline(t):
    r'\n+'
    t.lexer.lineno += t.value.count("\n")

def t_error(t):
    print(f"Illegal character {t.value[0]!r}")
    t.lexer.skip(1)

# Build the lexer
import ply.lex as lex
lex.lex()

# Precedence rules for the arithmetic operators
precedence = (
    ('left','PLUS','MINUS'),
    ('left','TIMES','DIVIDE'),
    ('right','UMINUS'),
    )

# dictionary of names (for storing variables)
names = { }

def p_statement_statement(p):
    'statement : statement statement'

def p_statement_assign(p):
    'statement : NAME EQUALS expression ENDSTM'
    names[p[1]] = p[3]

def p_statement_expr(p):
    'statement : expression ENDSTM'
    print(p[1])

def p_expression_binop(p):
    '''expression : expression PLUS expression
                  | expression MINUS expression
                  | expression TIMES expression
                  | expression DIVIDE expression'''
    if p[2] == '+'  : p[0] = p[1] + p[3]
    elif p[2] == '-': p[0] = p[1] - p[3]
    elif p[2] == '*': p[0] = p[1] * p[3]
    elif p[2] == '/': p[0] = p[1] / p[3]

def p_comparison_binop(p):
    '''comparison : expression EQUAL expression
                  | expression NOTEQ expression
                  | expression LARGE expression
                  | expression SMALL expression
                  | expression LRGEQ expression
                  | expression SMLEQ expression'''
    if p[2] == '==':
        p[0] = p[1] == p[3]
    elif p[2] == '!=':
        p[0] = p[1] != p[3]
    elif p[2] == '>':
        p[0] = p[1] > p[3]
    elif p[2] == '<':
        p[0] = p[1] < p[3]
    elif p[2] == '>=':
        p[0] = p[1] >= p[3]
    elif p[2] == '<=':
        p[0] = p[1] <= p[3]

def p_statement_if(p):
    '''statement : IF LPAREN comparison RPAREN LBRAKET statement RBRAKET
                 | IF LPAREN comparison RPAREN LBRAKET statement RBRAKET ELSE LBRAKET statement RBRAKET'''
    if p[3]:
        p[0] = p[6]
    else:
        if p[10] is not None:
            p[0] = p[10]

def p_statement_while(p):
    'statement : WHILE LPAREN comparison RPAREN LBRAKET statement RBRAKET'
    while(p[3]):
        p[0] = p[6]

def p_statement_print(p):
    'statement : PRINT LPAREN expression RPAREN ENDSTM'
    print(p[3])

def p_expression_uminus(p):
    'expression : MINUS expression %prec UMINUS'
    p[0] = -p[2]

def p_expression_group(p):
    'expression : LPAREN expression RPAREN'
    p[0] = p[2]

def p_expression_number(p):
    'expression : NUMBER'
    p[0] = p[1]

def p_expression_name(p):
    'expression : NAME'
    try:
        p[0] = names[p[1]]
    except LookupError:
        print(f"Undefined name {p[1]!r}")
        p[0] = 0

def p_error(p):
    try:
        print(f"Syntax error at {p.value!r}")
    except:
        print("Error")

import ply.yacc as yacc
yacc.yacc()

s = open('input.txt','r').read()
yacc.parse(s)

示例输入文件 input.txt 具有以下内容:

a = 7;
b = a * 2;
print(a + b);
if(a<b){
    print(a);
}
while(a<b){
    a = a + 1;
    print(a);
}

我得到了这个输出(永不停止):

21
7
8

Ply 不改变 Python 的规则。它解析一个输入(一次),生成您选择在解析操作函数中实现的任何结果。就是这样。

所以很明显,您不能将直接解释器编写为解析规则。执行发生在程序被解析之后,程序代码和执行之间没有一对一的关系:一些表达式(比如你的 while 条件)被计算了很多次;其他表达式(如 if-then-else 语句的失败分支)根本不会被评估。函数被调用,每次都有不同的参数;编译代码时,您无法预测这些参数的值。

编译程序的结果是一个“可执行文件”。该可执行文件可能是低级机器代码,也可能是程序的一些高级描述,解释程序在执行时做什么。

如果所有这些看起来都太手摇了,我强烈建议您通过 Abelson 和 Sussman 的计算机程序的结构和解释,这可以是read for free on-line 由于其作者的慷慨,在首次出版近 40 年后,它仍然是 概念 基础计算机程序的最佳单卷介绍。如果你想写一个编译器(或解释器),从这里开始。