Пропуск определенного токена числа токенов в Python PLY

1

Таким образом, у меня есть язык, на котором bytestring представляет список следующих headerdataheaderdataheaderdata... заголовка + данных (например, headerdataheaderdataheaderdata...):

заголовок

  • 18 байтов, которые не имеют значения (разделитель, идентификатор, временная метка, тип и т.д.)
  • 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. Длина каждого сегмента зависит от числа, содержащегося в нем. Однако легко получить эти данные как встроенное действие в правиле "сегмента":

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)

Это работает на extent-- 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]]

Это на практике генерирует список байтов, но он просто обходит ВСЕ оставшиеся данные после заголовка первого сегмента.

Теги:
lex
parsing
yacc
ply

1 ответ

0

Если на вашем языке нет чего-то большего, то контекстно-свободный парсер действительно не является подходящим инструментом. Вероятно, вы могли бы заставить квадратный колышек в круглое отверстие, но зачем беспокоиться?

Заголовки с фиксированной длиной можно легко struct.unpack_from, используя struct.unpack_from, и как только у вас будет длина полезной нагрузки, вы можете извлечь ее с помощью обычного кусочка Python. Предположительно, вы проверили бы контрольную сумму, прежде чем пытаться что-либо сделать с помощью байта.

Если полезная нагрузка содержит контент на языке, описанном без контекстной грамматики, вы можете использовать парсер, основанный на Ply, для синтаксического анализа только строки.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню