Одной из самых больших проблем при проектировании комбинации лексический анализатор/парсер является чрезмерное усердие при проектировании анализатора. (f)lex не предназначен для логики синтаксического анализатора, которая иногда может мешать разработке мини-парсеров (с помощью yy_push_state()
, yy_pop_state()
и yy_top_state()
.
Моя цель - проанализировать документ формы:
CODE1 this is the text that might appear for a 'CODE' entry
SUBCODE1 the CODE group will have several subcodes, which
may extend onto subsequent lines.
SUBCODE2 however, not all SUBCODEs span multiple lines
SUBCODE3 still, however, there are some SUBCODES that span
not only one or two lines, but any number of lines.
this makes it a challenge to use something like \r\n
as a record delimiter.
CODE2 Moreover, it's not guaranteed that a SUBCODE is the
only way to exit another SUBCODE's scope. There may
be CODE blocks that accomplish this.
В конце концов, я решил, что этот раздел проекта лучше предоставить лексическому анализатору, так как я не хочу создавать шаблон, который соответствует каждой строке (и идентифицирует записи-продолжения). Частично причина в том, что я хочу, чтобы лексический анализатор знал содержимое каждой строки без включения собственной логики токенизации. То есть, если я совпаду с ^SUBCODE[ ][ ].{71}\r\n
(все записи заблокированы в 80-символьных записях), я не смогу использовать силу гибкости для токенизации структурированных данных, находящихся в .{71}
.
Учитывая эти ограничения, я думаю о следующем:
- Entering a
CODE1
state from the<INITIAL>
start condition results in calls to:yy_push_state(CODE_STATE)
yy_push_state(CODE_CODE1_STATE)
- (сделать что-нибудь с содержимым идентификатора состояния
CODE1
, если такое содержимое существует) yy_push_state(SUBCODE_STATE)
(чтобы указать анализатору ожидатьSUBCODE
состояний, принадлежащих CODE_CODE1_STATE. Здесь анализатор начинает маскироваться под синтаксический анализатор.
- Условие запуска
<SUBCODE1_STATE>
вложено следующим образом:<CODE_STATE>{ <CODE_CODE1_STATE> { <SUBCODE_STATE>{ <SUBCODE1_STATE> { (perform actions based on the matching patterns) } } }
. Он также устанавливает для глобальной переменнойprevious_state
значениеyy_top_state()
, то естьSUBCODE1_STATE
. - В рамках
<SUBCODE1_STATE>
\r\n
вызоветyy_pop_state()
. Если присутствует запись продолжения (которая является шаблоном в самой высокой области, с которой сопоставляется весь текст), вызываетсяyy_push_state(continuation_record_states[previous_state])
, возвращая нас к области в 2.continuation_record_states[]
сопоставляет каждое состояние с его состоянием записи продолжения, которое используется синтаксическим анализатором.
Как видите, это довольно сложно, что приводит меня к выводу, что я сильно усложняю задачу.
Вопросы
- Приемлемо ли предлагаемое мной решение для государств, в которых отсутствует чрезвычайно четкий токен, означающий конец его сферы действия?
- Учитывая, что я хочу токенизировать ввод с помощью flex, есть ли способ сделать это без условий запуска?
Самая большая проблема, с которой я сталкиваюсь, заключается в том, что каждая запись (начинающаяся с префикса (SUB)CODE
) уникальна, а информация, появляющаяся после префикса (SUB)CODE
, — нет. Поэтому кажется почти обязательным иметь несколько состояний, подобных этому, и абстрактные состояния CODE_STATE
и SUBCODE_STATE
будут действовать как группы для каждого из конкретных состояний SUBCODE[0-9]+_STATE
и CODE[0-9]+_STATE
.