Как получить синтаксический анализатор flex / bison для выдачи синтаксической ошибки для нераспознанных токенов - PullRequest
0 голосов
/ 29 сентября 2019

Я пытаюсь написать грамматический распознаватель, используя flex и bison, чтобы определить, находится ли входная строка в L (G), где язык представляет собой объединение:

L (G) = {a ^ib ^ jc ^ kd ^ le ^ m}, где i, j, k, l, m> 0 и i = m и k = l

и

L (G) = {e^ id ^ jc ^ kb ^ la ^ m} где i, j, k, l, m> 0 и i = 2m k = 3l и j = 2

Сейчас у меня все работает нормально, но толькопри использовании токенов на языках. Если я добавлю любой другой токен, он, кажется, будет проигнорирован, и тест пройден или не пройден на основе других разрешенных токенов. Это проблематично, поскольку допускает прохождение синтаксического анализа такими строками, как «abcdef», даже если «f» отсутствует в языке.

Ошибочный ввод, который я сейчас проверяю, - это «abcdef». Часть «abcde» является правильной и дает правильный вывод, но добавление «f» в конец вызывает как сообщение об ошибке синтаксиса от yyerror («ошибка синтаксиса»), так и оператор печати «поздравления; синтаксический анализ выполнен успешно» от main кprint.

Использование "fabcde" делает то же самое, что я описал выше. Это дает мне ошибку, но также дает мне вывод на печать. Я использую «if (yyparse () == 0))», чтобы напечатать утверждение об успехе в main, и я думаю, что это может быть причиной, хотя у меня были те же проблемы, когда я перемещал операторы print в. y файл и только что использованный yyparse () и return (1) в main.

Вот мой файл .in (за исключением минус):

%%

a return A;

b return B;

c return C;

d return D;

e return E;

. yyerror("syntax error\n\nSorry, Charlie, input string not in L(G)\n"); /* working but still prints success message too */

%%

Вот мой файл .y (минусвключает в себя):

%token A

%token B

%token C

%token D

%token E


%% /* Grammar Rules */

string: as bs cs ds es
{
if(($1 == $5) && ($3 == $4)) {
return(0);
}
else
{
return(-1);
}
}
;

string: es ds cs bs as
{
if(($1 == (2 * $5) && ($3 == (3 * $4)) && ($2 = 2)) {
return(0);
}
else
{
return(-1);
}
}
;


as: A as {$$ = $2 +1;}
;

as: A {$$ = 1;}
;

bs: B bs {$$ = $2 +1;}
;

bs: B {$$ = 1;}
;

cs: C cs {$$ = $2 +1;}
;

cs: C {$$ = 1;}
;

ds: D ds {$$ = $2 +1;}
;

ds: D {$$ = 1;}
;

es: E es {$$ = $2 +1;}
;

es: E {$$ = 1;}
;

%%

мой файл .c прост и просто возвращает «поздравления; синтаксический анализ успешен», если yyparse () == 0, и «входная строка не в L (G)» в противном случае.

Все прекрасно работает, когда входные строки включают только a, b, c, d и e. Мне просто нужно выяснить, как заставить синтаксический анализатор выдавать синтаксическую ошибку без оператора успеха, если в строке ввода есть какой-либо токен, кроме них.

Вот изображение, которое поможет показать мою проблему: Первые два разбора работают как задумано. Третий показывает мою проблему.

Ответы [ 2 ]

1 голос
/ 29 сентября 2019

Если правило (f) lex ничего не возвращает, то соответствующие ему токены будут игнорироваться. Это подходит для комментариев, но не для токенов, которые вы хотите иметь ошибки. Если вы измените свое универсальное гибкое правило на

.    return *yytext;

, то все нераспознанные символы на входе (кроме символа новой строки, который является единственным, что . не соответствует) будут возвращены и, вероятно, будутвызвать сообщение Syntax error от вашего синтаксического анализатора (и неудачный возврат из yyparse. Если ваша грамматика содержит буквенные символьные токены (например, '#' для совпадения с этим символом), то это, конечно, совпадет.

0 голосов
/ 29 сентября 2019

Синтаксический анализатор, сгенерированный бизоном / yacc, ожидает синтаксического анализа всего правильного ввода, вплоть до маркера конца ввода, включая его, и только затем возвращает указание успеха (возвращаемое значение 0).

Конечно, если ввод синтаксически некорректен, анализатор может вернуться рано с указанием ошибки (которое всегда равно значению 1 для синтаксических ошибок и 2, если ему не хватает памяти). В этом случае, прежде чем парсер вернется, он очистит свое внутреннее состояние и освободит всю выделенную память.

Важно, чтобы вы позволили парсеру сделать это. Возврат из семантического действия в синтаксическом анализаторе bison / yacc в лучшем случае неразумен (поскольку это почти наверняка утечка памяти) и может также привести к путанице именно потому, что это может привести к успешному возврату после выдачи сообщения об ошибке.

Рассмотрим, например, случай ввода abcdea, который является допустимой строкой, за которой следует неверный a. Вполне вероятно, что семантическое действие для string будет выполнено до , когда анализатор попытается обработать последний a из-за сжатия таблицы синтаксического анализатора (которое откладывает действия с ошибками для сохранения записей таблицы). Но ваше семантическое действие на самом деле возвращает 0, минуя отчеты об ошибках и очистку парсера. Если введен abcdef и ваш сканер вызывает yyerror для неверного токена (что тоже не очень хорошая идея), то последовательность действий будет такой:

  1. Сканер печатает ошибку
  2. Parser выполняет семантическое действие string, которое возвращает 0.

Опять же, правильная обработка ошибок и очистка были пропущены оператором return в семантическом действии.

Так что не делай этого. Если вы хотите сообщить об ошибке в семантическом действии, используйте YYABORT, который завершит синтаксический анализ с возвратом ошибки. Если ваша продукция на высшем уровне правильная, с другой стороны, ничего не делайте. Затем анализатор проверит, что следующий входной токен является маркером конца ввода, и вернет успех.

...