所以我有一种语言,它是一个字节串,表示以下标题+数据组合的列表(例如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中通常使用的典型上下文自由语言。每个段的长度取决于其中包含的数字。但是,很容易将这些数据作为“细分”规则中的嵌入式操作:
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]]
实际上,这会生成一个字节列表,但它只是在第一个段头之后清除所有剩余数据。
除非您的语言还有更多内容,否则无上下文解析器实际上不是一个合适的工具。你可能会把方形钉子推入圆孔,但为什么要这么麻烦?
使用struct.unpack_from
可以很容易地拆分固定长度的头文件,一旦你有了有效载荷的长度,就可以用普通的Python切片来提取它。据推测,在尝试对bytestring进行任何操作之前,您将验证校验和。
如果有效负载包含由无上下文语法描述的语言的内容,则可以使用基于Ply的解析器来仅解析字符串。