2013-04-15 1 views
5

Я беру курс по построению компилятора, и мое текущее задание - написать лексер для языка, который мы реализуем. Я не могу понять, как удовлетворить требование, чтобы лексер должен распознавать сцепленные маркеры. То есть, токены не разделяются пробелами. Например: строка 39if должна быть признана цифрой 39 и ключевым словом if. Одновременно лексер должен также exit(1), когда он встречает недействительный ввод.Как сделать лекс/flex распознать маркеры, не разделенные пробелами?

упрощенная версия кода у меня есть:

%{ 
#include <stdio.h> 
%} 

%option main warn debug 

%% 

if  | 
then | 
else printf("keyword: %s\n", yytext); 

[[:digit:]]+ printf("number: %s\n", yytext); 

[[:alpha:]][[:alnum:]]*  printf("identifier: %s\n", yytext); 

[[:space:]]+ // skip whitespace 
[[:^space:]]+ { printf("ERROR: %s\n", yytext); exit(1); } 

%% 

Когда я запускаю этот (или мою полную версию), и передать его на вход 39if, правило об ошибке сопоставляется и выход ERROR: 39if, когда Я хотел бы, чтобы это было:

number: 39 
keyword: if 

(т.е. такой же, как если бы я вошел 39 if как вход.)

Going by the manual, у меня есть догадка, что причина в том, что правило ошибки соответствует более длинному возможному вводу, чем правила числа и ключевых слов, и Flex предпочтет его. Тем не менее, я понятия не имею, как разрешить эту ситуацию. Представляется невозможным написать явное regexp, которое отклонит все входные данные без ошибок, и я не знаю, как еще написать правило «catch-all» для обработки ошибок lexer.

UPDATE: Я полагаю, я мог бы просто сделать всеохватывающее правило быть . { exit(1); }, но я хотел бы получить более хороший отладочный вывод, чем «я запутался в строке 1».

+0

a) Вы используете упрощенную версию? б) Что делает это неправильно? –

+0

@IraBaxter Извините, кажется, я забыл быть явным о своем тестовом случае, проиграв в спекуляциях в последнем абзаце. Ответы: ** a) ** да; и ** b) ** сообщает об ошибке лексера вместо двух токенов. (Я также добавил их в вопрос.) – millimoose

+1

Ах.Хорошо, да, ваше правило «^ space» будет употреблять любую последовательность не-пробелов и, следовательно, потреблять «39if». Секрет: избегайте правил, чьи регулярные выражения перекрываются, если только более длинное правило не вступит в первую очередь. В вашем случае я бы использовал (я не lex-pert) что-то заменить:^space: это было «не цифра, не буква, а не пробел». ... –

ответ

4

Вы совершенно правы, что вы должны просто соответствовать одному «любому» символу в качестве резерва. «Стандартный» способ получения информации о том, где находится строка, в которой используется синтаксический анализ, заключается в использовании опции --bison-bridge, но это может быть немного больно, особенно если вы не используете bison. Есть куча других способов - смотрите в руководстве для способов определить свои собственные функции ввода/вывода, например, - но все вокруг Простейшим ИМХО использовать начальное условие:

%x LEXING_ERROR 
%% 
// all your rules; the following *must* be at the end 
.     { BEGIN(LEXING_ERROR); yyless(1); } 
<LEXING_ERROR>.+ { fprintf(stderr, 
          "Invalid character '%c' found at line %d," 
          " just before '%s'\n", 
          *yytext, yylineno, yytext+1); 
        exit(1); 
        } 

Примечание. Убедитесь, что вы игнорировали пробелы в своих правилах. Образец .+ соответствует любому номеру, но хотя бы одному символу, отличному от новой строки, или, другими словами, до конца текущей строки (это заставит flex читать так далеко, что не должно быть проблемой). yyless(n) выполняет резервное копирование указателя чтения на n символов, поэтому после совпадения правила . оно будет повторять запрос, который будет генерировать (надеюсь) полу-разумное сообщение об ошибке. (Это не будет разумно, если ваш вход многобайтовый или имеет странные управляющие символы, поэтому вы можете написать более тщательный код. До вас. Также может быть неразумно, если ошибка находится в конце строки, поэтому вы также можете написать более тщательного регулярное выражение, которое получает больше контекста, и, возможно, даже ограничивает количество символов прямого чтения. Много вариантов здесь.)

Посмотрите start conditions в гибком руководстве для получения дополнительной информации о %x и BEGIN

+0

Я прочитал в стартовых условиях, но не смог собрать кусочки, спасибо! – millimoose

+0

Гораздо проще просто вернуть yytext [0] в парсер в. и разрешить восстановление ошибки парсера. Не требуется никаких состояний начала. Это также устраняет все правила для отдельных специальных символов. – EJP

+0

@EJP: ОП конкретно указывает, что одним из требований является то, что лексер должен «выходить (1)», когда он встречает недопустимый ввод. Нет никаких признаков того, что существует синтаксический анализатор, с восстановлением или без него. – rici

 Смежные вопросы

  • Нет связанных вопросов^_^