PLY解决简单句子解析器的歧义

时间:2018-04-19 22:52:13

标签: python parsing ply

我遇到一个问题,我需要将非常简单的句子解析为BNF解析。我能够轻松地标记令牌并使用简单的句子。但是,有几种情况可以应用减少规则或者可以发生转换,并且可能发生另一种减少。例如:

Jared追着Tom和Jerry吃了。

我有一个规则可以将名词连词名词缩减为名词短语,另一个规则可以将句子连词句子缩减为复合句子。杰瑞"杰里"似乎它自动假定句子是名词动词名词短语的形式,而不是句子连词句子,并且当它遇到" ate"时会抛出错误。因为NP VP NP VP没有重写规则。

如何改变这一点,以便如果连词右边的单词是一个句子,它会将其解析为S CONJ S,但如果不是,则将其解析为NP VP NP?

编辑:澄清一下,这是我目前的代码:

import ply.yacc as yacc
from lexer import tokens

precedence = (('left', 'Vi'),('left', 'N'))

def p_S(p):
    """S : NP VP"""
    p[0] = '[S ' + p[1] + ' ' + p[2] + ' ]'

def p_VP(p):
    """VP : VP Conj VP"""
    p[0] = '[VP ' + p[1] + ' ' + p[2] + ' ' + p[3] + ' ]'

def p_Vi(p):
    """VP : Vi"""
    p[0] = '[VP [VI ' + p[1] + ' ] ]'

def p_Vt(p):
    """VP : Vt NP"""
    p[0] = '[VP [Vt ' + p[1] + ' ] ' + p[2] + ' ]'

def p_Vd(p):
    """VP : Vd NP NP"""
    p[0] = '[VP [VT ' + p[1] + ' ] ' + p[2] + ' ' + p[3] + ' ]'

def p_NP(p):
    """NP : NP Conj NP
    | N"""
    if len(p) == 4:
        p[0] = '[NP ' + p[1] + ' [Conj ' + p[2] + ' ] ' + p[3] + ' ]'
    else:
        p[0] = '[N ' + p[1] + ' ]'

def p_error(p):
    print("Syntax Error in input!\n")

parser = yacc.yacc()
while True:

    try:
        s = input('calc > ')
        if not s: continue
        result = parser.parse(s)
        if result is not None: print(result + '\n')
    except EOFError:
        print("Please try again")

1 个答案:

答案 0 :(得分:1)

你不能,至少没有确定性的单令牌先行解析器,这是Ply构建的。

幸运的是(或不是)人脑不仅限于Knuthian从左到右的解析,尽管我们解析句子的细节并不完全清楚。而且,大多数人类语言实际上是模棱两可的,只有语义分析才能区分多个可能的解析。 (在口语中,还有许多其他语言功能,如语调,词间距和强调,这也有助于指导解析。这些功能通常不会用书面语言转录,但书面语言可以处理非线性的;如有必要,眼睛可以重读或扫描。)

对于人类语言解析,GLR或类似算法将证明更有用。虽然Bison可以生产GLR解析器,但据我所知,该功能尚未在Ply中实现。图表解析并不是特别复杂;你可以在没有太多工作的情况下编写自己的代码。但是,除非您对解析算法感兴趣,否则没有太大意义,因为Python中存在用于人类语言处理的现有包。

(SO不赞成库建议,但我相信NLTK,自然语言工具包,可能是人类语言处理中使用最广泛的Python框架。)