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

时间:2018-08-31 16:27:51

标签: python parsing yacc lex ply

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

标题

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

数据

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

代币

每个字节值只有一个令牌:

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

语法

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>

这个大问题

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

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]]

实际上,这会生成一个字节列表,但是它只是在第一段头之后对所有剩余数据进行了删节操作。

1 个答案:

答案 0 :(得分:0)

除非您的语言有更多特色,否则上下文无关的解析器实际上不是合适的工具。您可能会迫使方钉进入圆孔,但是为什么要打扰呢?

使用struct.unpack_from可以很容易地分解固定长度的标头,一旦拥有有效载荷的长度,就可以使用普通的Python切片将其提取。大概,在尝试对字节串执行任何操作之前,您将验证校验和。

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