gpt4 book ai didi

yacc - Python Lex-Yacc (PLY) 输入结束时的错误恢复

转载 作者:行者123 更新时间:2023-12-01 18:30:15 30 4
gpt4 key购买 nike

问题

我正在尝试使用 Python Lex-Yacc (PLY) 实现容错解析器,但在输入字符串末尾使用错误恢复规则时遇到问题。

如何从意外的输入结束中恢复?

示例

此示例语法生成以下形式的字符串 A END A END A END A END ...

Statement   : Expressions

Expressions : Expression Expressions
|

Expression : A END

如果省略了 END token ,我想执行错误恢复,因此解析器将识别诸如 A A A ENDA A A 之类的字符串。

我的方法

我添加了一个错误恢复规则,它允许我接受像 A A A END 这样的输入

Expression : A END
| A error

这允许我接受以下输入:A A A END

但是如果省略最后一个 END 标记 (A A A),我仍然会收到语法错误并且无法恢复。

<小时/>

示例 PLY 代码

from __future__ import print_function

# Tokens
tokens = ('A', 'END')

t_A = r'A'
t_END = r'END'
t_ignore = " "

def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)

# Build the lexer
import ply.lex as lex
lex.lex()

# Rules
def p_statement_expr(p):
'''statement : expressions'''
print("parsed:", p[1])

def p_expressions(p):
'''expressions : expression expressions'''
p[0] = [p[1]] + p[2]

def p_expressions_empty(p):
'''expressions : '''
p[0] = list()

def p_expression_pharse(p):
'''expression : A END
| A error'''
p[0] = 'A'

def p_error(p):
if p:
print("Syntax error at '%s'" % p.value)
else:
print("Syntax error at EOI")

import ply.yacc as yacc
yacc.yacc()

while 1:
try:
s = raw_input('query > ') # use input() on Python 3
except EOFError:
break
yacc.parse(s)

最佳答案

我将其添加为新答案(并且确实知道对于赏金来说为时已晚:-( ),因为这是一种非常不同的方法。如果我们使用 flex ,它会容易得多,因为它具有<<EOF>> 标记仅在文件末尾匹配的概念。经过思考,我意识到通过使用围绕词法分析器的代理。由于 __getattr__ 特殊方法,Python 允许轻松实现代理。

我只是添加

  • 新 token EOF将在文件末尾发送
  • 围绕 token 的代理词法分析器的方法,在文件末尾返回特殊的 EOF第一次传递 token ,然后是正常的 None
  • 结束的 eof token statement规则

并且仍然颠倒规则expressions : expressions expression而不是expressions : expression expressions允许立即减少

代码变为:

from __future__ import print_function

# Tokens
tokens = ('A', 'END', 'EOF')

t_A = r'A'
t_END = r'END'
t_ignore = " "

def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)

# Build the lexer
import ply.lex as lex

orig_lexer = lex.lex()

class ProxyLexer(object):
def __init__(self, lexer, eoftoken):
self.end = False
self.lexer = lexer
self.eof = eoftoken
def token(self):
tok = self.lexer.token()
if tok is None:
if self.end :
self.end = False
else:
self.end = True
tok = lex.LexToken()
tok.type = self.eof
tok.value = None
tok.lexpos = self.lexer.lexpos
tok.lineno = self.lexer.lineno
# print ('custom', tok)
return tok
def __getattr__(self, name):
return getattr(self.lexer, name)

lexer = ProxyLexer(orig_lexer, 'EOF')

# Rules
def p_statement_expr(p):
'''statement : expressions EOF'''
print("parsed:", p[1])

def p_expressions(p):
'''expressions : expressions expression'''
p[0] = p[1] + [p[2]]

def p_expressions_empty(p):
'''expressions : '''
p[0] = list()

def p_expression_pharse(p):
'''expression : A END
| A error'''
p[0] = 'A'

def p_error(p):
if p:
print("Syntax error at '%s'" % p.value)
else:
print("Syntax error at EOI")

import ply.yacc as yacc
parser = yacc.yacc()

while 1:
try:
s = raw_input('query > ') # use input() on Python 3
except EOFError:
break
parser.parse(s, lexer = lexer)

这样:

  • 原始语法不变
  • 错误恢复方法仍然非常简单,并且不依赖于语法的其余部分
  • 它可以轻松扩展到复杂的解析器

关于yacc - Python Lex-Yacc (PLY) 输入结束时的错误恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26338060/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com