Обработка ошибок в Lex, а не в Yacc?
-
16-09-2019 - |
Вопрос
Предположим, у меня есть регулярное выражение lex, например
[aA][0-9]{2,2}[pP][sS][nN]? { return TOKEN; }
Если пользователь вводит
A75PsN
A75PS
Это будет соответствовать
Но если пользователь говорит что-то вроде
A75PKN
Я бы хотел, чтобы он допустил ошибку и сказал: «Символ K не распознан, ожидается S».
Сейчас я просто пишу это так:
let [a-zA-Z]
num [0-9]
{let}{num}{2,2}{let}{2,3}
А затем, по сути, перелексирую строку в Yacc, чтобы у меня были значимые условия ошибки.
Как я могу обойти это?
Единственное, о чем я могу думать, это использовать именованные группы?
Решение
Ух ты!Интересная схема.
Если вы собираетесь обнаружить это в лексическом анализаторе, вам понадобится универсальное правило, которое касается «любой иначе нераспознанной строки» и выдает сообщение об ошибке.
Определить, что именно буква «К» стала причиной проблемы, будет настоящим адом.
[^aA][0-9]{2,2}[pP][sS][nN]? { report_error(); return ERROR; }
[aA][0-9]{2,2}[^pP][sS][nN]? { report_error(); return ERROR; }
[aA][0-9]{2,2}[pP][^sS][nN]? { report_error(); return ERROR; }
[aA][0-9]{2,2}[pP][sS][^nN] { report_error(); return ERROR; }
Обратите внимание на расположение кареток и отсутствие вопросительного знака!Иметь дело с нецифрами, слишком большим количеством цифр или слишком малым количеством цифр - ух!
Как правило, вам лучше распознать все «идентификаторы», а затем проверить, какие из них в порядке:
[a-zA-Z][0-9]{2,2}[a-zA-Z]{2,5} { return validate_id_string(); }
Выберите свой яд, который вы допускаете в процедуру проверки;он решает, было ли введенное правильно или нет, и его возвращаемое значение определяет, что правило Lex возвращает в грамматику.Это также один из способов отличить ключевые слова от идентификаторов.
Обобщите и упростите регулярное выражение, чтобы оно соответствовало тому, что происходит на самом деле.