You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PLY开发类Pascal解释器时,逗号处出现Syntax error的问题求助

使用PLY开发类Pascal解释器时,逗号处出现Syntax error的问题求助

我正在用PLY开发一个简单的类Pascal解释器,但解析时遇到了逗号处的语法错误。当尝试解析包含逗号的源文件时就会出现这个问题。下面是PLY代码以及导致错误的示例源代码。

Pascal.py

import ply.lex as lex
import ply.yacc as yacc

# Lexical Analysis
tokens = (
    'PROGRAM', 'VAR', 'BEGIN', 'END', 'INTEGER', 'REAL', 'ASSIGN',
    'SEMICOLON', 'COLON', 'COMMA', 'PLUS', 'DIVIDE', 'LPAREN', 'RPAREN',
    'WRITELN', 'STRING', 'ID', 'NUMBER', 'DOT'
)

# Reserved words
reserved = {
    'PROGRAM': 'PROGRAM',
    'VAR': 'VAR',
    'BEGIN': 'BEGIN',
    'END': 'END',
    'integer': 'INTEGER',
    'real': 'REAL',
    'WRITELN': 'WRITELN'
}

# Token definitions
t_ASSIGN = r':='
t_SEMICOLON = r';'
t_COLON = r':'
t_COMMA = r','
t_PLUS = r'\+'
t_DIVIDE = r'/'
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_DOT = r'\.'
t_ignore = ' \t'  # Ignore spaces and tabs

def t_STRING(t):
    r"'[^']*'"
    t.value = t.value[1:-1]  # Remove surrounding quotes
    return t

def t_ID(t):
    r'[a-zA-Z_][a-zA-Z_0-9]*'
    t.type = reserved.get(t.value, 'ID')  # Check if it's a reserved word
    return t

def t_NUMBER(t):
    r'\d+(\.\d+)?'
    t.value = float(t.value) if '.' in t.value else int(t.value)
    return t

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

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

lexer = lex.lex()

# Syntax Analysis
precedence = (
    ('left', 'PLUS', 'DIVIDE'),
)

def p_program(p):
    'program : PROGRAM ID SEMICOLON declarations BEGIN statements END DOT'
    interpret(p[5])  # Pass the parsed statements to the interpreter

def p_declarations(p):
    '''declarations : VAR var_declaration
                    | empty'''

def p_var_declaration(p):
    '''var_declaration : ID COLON type SEMICOLON var_declaration
                       | ID COLON type SEMICOLON'''

def p_type(p):
    '''type : INTEGER
            | REAL'''

def p_statements(p):
    '''statements : statements statement SEMICOLON
                  | statement SEMICOLON'''
    if len(p) == 4:
        p[0] = p[1] + [p[2]]
    else:
        p[0] = [p[1]]

def p_statement(p):
    '''statement : ID ASSIGN expression
                 | WRITELN LPAREN writeln_args RPAREN'''
    if p[1] == 'WRITELN':
        p[0] = ('WRITELN', p[3])
    else:
        p[0] = ('ASSIGN', p[1], p[3])

def p_writeln_args(p):
    '''writeln_args : writeln_args COMMA writeln_arg
                    | writeln_arg'''
    if len(p) == 4:
        p[0] = p[1] + [p[3]]
    else:
        p[0] = [p[1]]

def p_writeln_arg(p):
    '''writeln_arg : STRING
                   | expression'''
    p[0] = p[1]

def p_expression(p):
    '''expression : expression PLUS term
                  | expression DIVIDE term
                  | term'''
    if len(p) == 4:
        p[0] = (p[2], p[1], p[3])
    else:
        p[0] = p[1]

def p_term(p):
    '''term : ID
            | NUMBER'''
    p[0] = p[1]

def p_empty(p):
    'empty :'
    p[0] = []

def p_error(p):
    print(f"Syntax error at '{p.value}'" if p else "Syntax error at EOF")

parser = yacc.yacc()

# Interpreter
variables = {}

def evaluate(tree):
    if isinstance(tree, (int, float)):
        return tree
    if isinstance(tree, str):
        return variables.get(tree, 0)
    if tree[0] == '+':
        return evaluate(tree[1]) + evaluate(tree[2])
    if tree[0] == '/':
        return evaluate(tree[1]) / evaluate(tree[2])
    return 0

def interpret(statements):
    for stmt in statements:
        if stmt[0] == 'ASSIGN':
            variables[stmt[1]] = evaluate(stmt[2])
        elif stmt[0] == 'WRITELN':
            print(" ".join(str(evaluate(arg)) if not isinstance(arg, str) else arg for arg in stmt[1]))

# Run the Program
if __name__ == '__main__':
    import sys
    if len(sys.argv) < 2:
        print("Usage: python Pascal.py <file>")
        sys.exit(1)
    with open(sys.argv[1], 'r') as file:
        source = file.read()
    lexer.input(source)
    parser.parse(source)

Sample Source Code (SumAndAverage.pas)

PROGRAM SUMANDAVERAGE;
VAR num1,num2,num3: integer;
    sum:integer;
    avg:real;
BEGIN
    num1:=10;
    num2:=20;
    num3:=30;
    sum:=num1+num2+num3;
    avg:=sum/3;
    WRITELN('Num1 is ',num1);
    WRITELN('Num2 is ',num2);
    WRITELN('Num3 is ',num3);
    WRITELN('Sum 3 numbers is ',sum);
    WRITELN('Average is ',avg)
END.

输入和预期输出

输入命令:

python Pascal.py SumAndAverage.pas

预期输出:

Num1 is 10
Num2 is 20
Num3 is 30
Sum 3 numbers is 60
Average is 2.0000000000000000E+001

我检查过令牌定义和语法规则,但搞不懂为什么解析器在处理WRITELN语句中的逗号时会出问题。有人能帮我找出问题所在吗?


备注:内容来源于stack exchange,提问作者Juju

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 12:19:50