PLY 解决简单句子解析器的歧义
PLY resolving ambiguity for simple sentence parser
我遇到一个问题,我需要将非常简单的句子解析为 BNF 解析。我能够轻松地标记标记并使用简单的句子。但是,在某些情况下,可以应用一个 reduce 规则,或者可能会发生移位,并且可能会发生另一个 reduce。例如:
贾里德追着汤姆和杰瑞吃饭。
我有一个规则可以将名词连词减为名词短语,还有一个规则可以将句子连词减为复合句。在 "Jerry" 似乎它自动假定句子的形式是名词动词名词短语,而不是句子连词句,并且在遇到 "ate" 时抛出错误,因为没有重写规则NP 副总裁 NP 副总裁。
我怎样才能改变这个,如果连词右边的词是一个句子,它将解析为 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")
你不能,至少不能使用 Ply 构建的确定性单标记先行解析器。
幸运的是(或不是)人脑不限于 Knuthian 从左到右的解析,尽管我们如何解析句子的细节并不完全清楚。更重要的是,大多数人类语言实际上是有歧义的,只有语义分析才能区分多种可能的解析。 (在口语中,还有一些其他的语言特征,例如语调、字间距和强调,这些也有助于指导解析。这些特征通常不会在书面语言中转录,但书面语言可以处理非线性;如有必要,眼睛可以重新阅读或向前扫描。)
对于人类语言解析,GLR 或类似算法将被证明更有用。尽管 Bison 可以生成 GLR 解析器,但据我所知,该功能尚未在 Ply 中实现。图表解析不是特别复杂;您可能无需太多工作就可以编写自己的代码。但是,除非您对解析算法感兴趣,否则没有太大意义,因为在 Python.
中已有用于人类语言处理的包
(因此不鼓励库推荐,但我相信自然语言工具包 NLTK 可能是使用最广泛的 Python 人类语言处理框架。)
我遇到一个问题,我需要将非常简单的句子解析为 BNF 解析。我能够轻松地标记标记并使用简单的句子。但是,在某些情况下,可以应用一个 reduce 规则,或者可能会发生移位,并且可能会发生另一个 reduce。例如:
贾里德追着汤姆和杰瑞吃饭。
我有一个规则可以将名词连词减为名词短语,还有一个规则可以将句子连词减为复合句。在 "Jerry" 似乎它自动假定句子的形式是名词动词名词短语,而不是句子连词句,并且在遇到 "ate" 时抛出错误,因为没有重写规则NP 副总裁 NP 副总裁。
我怎样才能改变这个,如果连词右边的词是一个句子,它将解析为 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")
你不能,至少不能使用 Ply 构建的确定性单标记先行解析器。
幸运的是(或不是)人脑不限于 Knuthian 从左到右的解析,尽管我们如何解析句子的细节并不完全清楚。更重要的是,大多数人类语言实际上是有歧义的,只有语义分析才能区分多种可能的解析。 (在口语中,还有一些其他的语言特征,例如语调、字间距和强调,这些也有助于指导解析。这些特征通常不会在书面语言中转录,但书面语言可以处理非线性;如有必要,眼睛可以重新阅读或向前扫描。)
对于人类语言解析,GLR 或类似算法将被证明更有用。尽管 Bison 可以生成 GLR 解析器,但据我所知,该功能尚未在 Ply 中实现。图表解析不是特别复杂;您可能无需太多工作就可以编写自己的代码。但是,除非您对解析算法感兴趣,否则没有太大意义,因为在 Python.
中已有用于人类语言处理的包(因此不鼓励库推荐,但我相信自然语言工具包 NLTK 可能是使用最广泛的 Python 人类语言处理框架。)