В (f) lex, я бы просто использовал правило, начинающееся с ^
, чтобы заставить его совпадать только в начале строки, но jison не так интерпретирует значения, и в любом случае вы не делаетена самом деле не хочу ограничивать начальные комментарии точным началом строки, а скорее первым непробельным символом в строке.(Мне не ясно, как вы хотите обрабатывать токены, отличные от идентификаторов. Я проигнорировал эту проблему. См. Комментарий, начинающийся с трех вопросительных знаков.)
Один простой способ сделать это с "условиями запуска""(см. пример в документации Jison ), например: (но, пожалуйста, смотрите примечание ниже для лучшего решения) :
%lex
%s TRAILING
%%
\n this.begin('INITIAL')
\s /* skip whitespace */
<TRAILING>'--'.* return 'IDENTIFIER'; /* or whatever */
<INITIAL>'--'.* /* skip initial comments */
[a-zA-Z]+ this.begin('TRAILING'); return 'IDENTIFIER'
. /* ??? this.begin('TRAILING'); */ /* skip the others */
<<EOF>> return 'EOF'
Примечание: (Добавлено после того, как я запомнил это условие запуска Jison.) Приведенный выше код сильно зависит от интерфейса условий запуска (f) lex.И jison, и flex (но не lex) допускают стек начальных условий, что удобно, когда контексты гнездятся.Как показывает приведенный выше пример, контексты не всегда являются вложенными;иногда удобнее просто переключаться с одного на другой, как в автомате.Макрос lex BEGIN
(f) делает именно это;flex также предоставляет yy_push_state
и yy_pop_state
для использования стека условий запуска.(В flex вы должны указать %option stack
, чтобы это работало.)
Jison, по какой-то причине, только обеспечивает переходы, ориентированные на стек, а this.begin
- это просто псевдоним дляthis.pushStack
.Следовательно, в отличие от гибкого интерфейса, вы действительно должны балансировать каждый this.begin
с this.popStack
(и, возможно, изменить this.begin
на this.pushStack
, чтобы быть менее запутанным).Вышеприведенный код, как написано, выполняет много бесполезных нажатий стека условий запуска и никаких всплывающих окон, поэтому он будет излишне использовать много памяти, особенно при большом вводе.
Приведенный выше пример можно переписать, чтобы использовать стек болееэкономно, но это потребовало бы либо дублирования большинства правил шаблона (одна версия для условия INITIAL
, которая выдвигается, когда ИДЕНТИФИКАТОР найден, но не появляется на новых строках, и другая версия для TRAILING
, которая не выдвигает IDENTIFIER, но делаетпоп в правило новой строки).Это кажется мне немного уродливым, поэтому я предоставляю следующую альтернативную реализацию, которая использует настраиваемое поле в объекте лексера для хранения номера строки ранее обнаруженного IDENTIFIER и добавляет комментарии к выводу, только если они находятся в одной строке:
%lex
%%
\s+ /* skip whitespace */
'--'.* if (yylloc.first_line == this.last_id_line) return 'IDENTIFIER';
[a-zA-Z]+ this.last_id_line = yylloc.first_line; return 'IDENTIFIER'
. /* skip the others */
<<EOF>> return 'EOF'
Добавление пользовательских полей в объект lexer должно выполняться с осторожностью;нет документации, определяющей, какие имена зарезервированы (или какие префиксы имен могут быть использованы).