在Python PLY中跳过令牌定义数量的标记

问题描述 投票:1回答:1

所以我有一种语言,它是一个字节串,表示以下标题+数据组合的列表(例如headerdataheaderdataheaderdata...):

Header

  • 18个字节无关紧要(分隔符,ID,时间戳,类型等)
  • 4个字节,指定数据和标题组合的长度。我们称之为datalen
  • 4个字节(校验和)

Data

  • datalen减去26个字节,实际上可以包含分隔符

Tokens

每字节值只需一个标记:

b00 = r'\x00'
...
bFF = r'\xFF'

Grammar

file      -> segments
segments  -> segment segment
           | segment
segment   -> delim id timestamp type group_id owner datalen checksum
delim     -> bFF bAA
id        -> int32
timestamp -> int32
type      -> int32
group_id  -> int16
owner     -> int32
datalen   -> int32
checksum  -> int32
int32     -> byte byte byte byte
int16     -> byte byte
byte      -> <oh my god one rule per value token>

The ploblem

我知道这不是PLY中通常使用的典型上下文自由语言。每个段的长度取决于其中包含的数字。但是,很容易将这些数据作为“细分”规则中的嵌入式操作:

def p_segment(t):
    ''' segment : delim id timestamp type group_id owner datalen checksum'''
    id = t[2]
    timestamp = t[3]
    type = t[4]
    group_id = t[5]
    owner = t[6]
    datalen = t[7]
    checksum = t[8]
    t[0] = (id,timestamp,type,group_id,owner,datalen,checksum)
    # Assume all rules for t[2:8] return the correct data type haha

现在我的想法只是累积额外的字节并将它们存储在lexer.token()的某处:

def p_segment(t):
    ''' segment : delim id timestamp type group_id owner datalen checksum'''
    id = t[2]
    timestamp = t[3]
    type = t[4]
    group_id = t[5]
    owner = t[6]
    datalen = t[7]
    checksum = t[8]

    data = []
    for i in range(datalen):
        data += t.lexer.token()

    t[0] = (id,timestamp,type,group_id,owner,datalen,checksum,data)

这在一定程度上起作用--data确实有数据,并且t.lexer.lexpos被更新,但是解析器在标头的最后一个字节之后立即丢失其大理石语法错误。这似乎意味着当词法分析器沿着字符串前进时,解析器不是。我该如何解决这个问题?我应该放弃PLY吗? (如果是的话,什么是合适的替代方案?)

此外,我已经尝试为数据添加规则,但只是添加'segment_data'规则并不真正起作用,因为没有分隔符或其他无上下文的长度忠实依赖:

def p_segment_data(t):
    ''' 
    segment_data : byte segment-data
                 | byte
    '''
    if len(t) > 2:
        t[0] = [t[1]] + t[2] # we want to return a list of bytes
    else:
        t[0] = [t[1]]

实际上,这会生成一个字节列表,但它只是在第一个段头之后清除所有剩余数据。

python parsing yacc lex ply
1个回答
0
投票

除非您的语言还有更多内容,否则无上下文解析器实际上不是一个合适的工具。你可能会把方形钉子推入圆孔,但为什么要这么麻烦?

使用struct.unpack_from可以很容易地拆分固定长度的头文件,一旦你有了有效载荷的长度,就可以用普通的Python切片来提取它。据推测,在尝试对bytestring进行任何操作之前,您将验证校验和。

如果有效负载包含由无上下文语法描述的语言的内容,则可以使用基于Ply的解析器来仅解析字符串。

© www.soinside.com 2019 - 2024. All rights reserved.