所以我有一种语言,它是一个字节字符串,表示以下标头+数据组合(例如headerdataheaderdataheaderdata...
)的列表:
datalen
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]]
实际上,这会生成一个字节列表,但是它只是在第一段头之后对所有剩余数据进行了删节操作。
答案 0 :(得分:0)
除非您的语言有更多特色,否则上下文无关的解析器实际上不是合适的工具。您可能会迫使方钉进入圆孔,但是为什么要打扰呢?
使用struct.unpack_from
可以很容易地分解固定长度的标头,一旦拥有有效载荷的长度,就可以使用普通的Python切片将其提取。大概,在尝试对字节串执行任何操作之前,您将验证校验和。
如果有效负载包含上下文无关语法描述的语言中的内容,则可以使用基于Ply的解析器仅解析字符串。