【问题标题】:While cycle implementation never ends in Ply issue虽然循环实施永远不会在 Ply 问题中结束
【发布时间】:2020-06-26 21:21:02
【问题描述】:

我试图在 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

【问题讨论】:

    标签: python while-loop compiler-construction yacc ply


    【解决方案1】:

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

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

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

    如果这一切看起来过于随意,我强烈建议您阅读 Abelson & Sussman 的计算机程序的结构和解释,这可以是 read for free on-line,这要归功于它的慷慨作者,在其首次出版近 40 年后,仍然是对底层计算机程序概念的最佳单卷介绍。如果你想写一个编译器(或解释器),从那里开始。

    【讨论】:

    • 谢谢你,我去看看书。我没有意识到在这种情况下,我正在尝试制作一个解释器而不是一个编译器,我在这个领域很新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2022-01-12
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多