加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

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

发布时间:2020-12-20 11:38:22 所属栏目:Python 来源:网络整理
导读:问题 我正在尝试使用Python Lex-Yacc(PLY)实现容错解析器,但我在输入字符串末尾使用错误恢复规则时遇到问题. 如何从意外的输入结束中恢复? 例 此示例语法生成A END A END A END A END形式的字符串… Statement : ExpressionsExpressions : Expression Expre
问题

我正在尝试使用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 END或A 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>>只在文件末尾匹配的令牌.在考虑完之后,我意识到通过在词法分析器周围使用代理,将该功能添加到PLY而不对原始模块进行任何更改是非常简单的.通过__getattr__特殊方法,可以轻松实现代理.

我只是补充一下

>将在文件末尾发送的新令牌EOF
>围绕词法分析器的令牌方法的代理,在文件末尾返回第一遍的特殊EOF令牌,然后是正常的无
> eof令牌结束语句规则

并且仍然反转规则表达式:表达式表达式而不是表达式:表达式表达式允许立即减少

代码变成:

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)

那样 :

>原始语法不变>错误恢复方法仍然很简单,并且不依赖于剩余的语法>它可以很容易地扩展到复杂的解析器

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读