PLY 不匹配正确的终端

PLY not matching the correct terminal

我在 PLY 中创建了一个简单的解析器,它有两个规则:

对应代码:

from ply import lex, yacc

tokens = ['Name', 'Number']

def t_Number(t):
    r'[0-9]'
    return t

def t_Name(t):
    r'[a-zA-Z0-9]'
    return t

literals = [':', '=']

def t_error(t):
    print("lex error: " + str(t.value[0]))
    t.lexer.skip(1)

lex.lex()

def p_name(p):
    '''
    expression : ':' Name
    '''
    print("name: " + str(list(p)))

def p_number(p):
    '''
    expression : '=' Number
    '''
    print("number: " + str(list(p)))

def p_error(p):
    print("yacc error: " + str(p.value))

yacc.yacc()
yacc.parse("=3")
yacc.parse(":a")
yacc.parse(":3")

我的期望是,如果它看到 := 它会进入相应的规则并尝试匹配相应的终端。然而在第三个例子中,它匹配了一个应该是名字的数字然后失败了。 Afaik 语法应该是上下文无关的(需要解析),是这样吗?另外,当一个标记是另一个标记的超集时,我将如何处理?

Ply 在查询语法之前进行标记化,因此上下文不会影响标记化。(更准确地说,解析器接收由词法分析器生成的标记流。这两个过程在实践中交错,但它们保持独立。)

您可以将上下文构建到词法分析器中,但这会很快变得丑陋。 (尽管如此,这是一种常见的策略。)

最好的办法是编写词法规则以尽可能生成最细粒度的结果,然后编写语法以接受所有备选方案:

def p_name(p):
    '''
    expression : ':' Name
    expression : ':' Number
    '''
    print("name: " + str(list(p)))

def p_number(p):
    '''
    expression : '=' Number
    '''
    print("number: " + str(list(p)))

假设您更改了词法规则以将最具体的模式放在首位。