我在 Python 中使用 PLY 创建词法分析器时遇到问题

I'm having a problem with creating a lexer using PLY in Python

提问人:FoxH Gaming 提问时间:7/6/2023 最后编辑:FoxH Gaming 更新时间:7/6/2023 访问量:100

问:

我最近试图创建一个 Lexer,但效果不佳。

问题是它抛出一条错误消息,显示“无法构建词法分析器”。以下是回溯:

ERROR: Rule 't_TIMES' defined for an unspecified token TIMES
ERROR: Rule 't_DIVIDE' defined for an unspecified token DIVIDE
Traceback (most recent call last):
  File "...\Lexer.py", line 24, in <module>
    lexer = lex.lex()
            ^^^^^^^^^
  File "...\lex.py", line 910, in lex
    raise SyntaxError("Can't build lexer")
SyntaxError: Can't build lexer

我知道这是因为我的功能。我也感觉到我制作的令牌可能有问题。请帮帮我,我知道这有点愚蠢,但我是新来的,所以请对我好一点。 顺便说一句,这是源代码t_error()

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

import sys

tokens = [
    "INT",
    "ID",
    "PLUS",
    "MINUS",
    "EOF",
]

t_INT = r"\d+"
t_ID = r"[a-zA-Z_][a-zA-Z0-9_]*"
t_PLUS = r"+"
t_MINUS = r"-"
t_TIMES = r"*"
t_DIVIDE = r"/"

def t_error(t):
    print("Illegal character '%s'" % t.lexer.lexeme, file=sys.stderr)

lexer = lex.lex()

def p_expression(p):
    """expression : INT
                 | ID
                 | expression PLUS expression
                 | expression MINUS expression
                 | expression TIMES expression
                 | expression DIVIDE expression"""
    if len(p) == 2:
        if isinstance(p[1], int):
            p[0] = p[1]
        elif isinstance(p[1], str):
            p[0] = p[1]
    else:
        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]

parser = yacc.yacc()

def test(text):
    try:
        result = parser.parse(text)
        if result:
            print(result)
        else:
            print("Empty expression")
    except yacc.YaccError:
        print("Error parsing input")

if __name__ == "__main__":
    test("123")
    test("hello")
    test("123 + 456")
    test("123 - 456")
    test("123 * 456")
    test("123 / 456")

也许我只是愚蠢,但正因为如此,所以我无法让它跑。

蟒蛇

评论

0赞 larsks 7/6/2023
这在什么方面不起作用?如果您收到特定的错误消息,请在您的问题中包含该错误消息(如果生成了错误消息,请提供完整的回溯)。
0赞 FoxH Gaming 7/6/2023
哦,我忘了提到问题是词法分析器无法构建

答:

1赞 larsks 7/6/2023 #1

这些错误...

ERROR: Rule 't_TIMES' defined for an unspecified token TIMES
ERROR: Rule 't_DIVIDE' defined for an unspecified token DIVIDE

...似乎很清楚。您尚未定义名为 或 在数组中命名的令牌。你需要:TIMESDIVIDEtokens

tokens = [
    "INT",
    "ID",
    "PLUS",
    "MINUS",
    "EOF",
    "TIMES",
    "DIVIDE",
]

修复这些错误后,您将获得:

ERROR: Invalid regular expression for rule 't_PLUS'. nothing to repeat at position 11
ERROR: Invalid regular expression for rule 't_TIMES'. nothing to repeat at position 12

这是因为字符 和 都是正则表达式通配符,所以如果你想要文字字符,你需要对它们进行转义:+*

t_PLUS = r"\+"
t_TIMES = r"\*"

修复这些错误后,最终将从方法中得到以下信息:t_error

AttributeError: 'Lexer' object has no attribute 'lexeme'. Did you mean: 'lexre'?

似乎没有属性,但您可以使用:lexemet.value

def t_error(t):
    print("Illegal character '%s'" % t.value, file=sys.stderr)

修复该错误后,您现在将获得:

123
hello
Illegal character ' + 456'
.
.
.
ply.lex.LexError: Scanning error. Illegal character ' '

你的表达式中有空格,但你没有在规则中考虑到这一点。快速解决方法是删除测试表达式中的空格:

if __name__ == "__main__":
    test("123")
    test("hello")
    test("123+456")
    test("123-456")
    test("123*456")
    test("123/456")

修复该错误后,您现在将获得:

123
hello
123456
.
.
.
TypeError: unsupported operand type(s) for -: 'str' and 'str'

这是因为您正在尝试在方法中添加字符串值。在应用算术运算符之前,您需要将它们转换为数字。最简单的解决方案是用这种方法替换你的定义:p_expressiont_INT

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

现在运行代码会产生:

123
hello
579
-333
56088
0.26973684210526316