Регулярное выражение для подсчета ВСЕХ символов новой строки в C ++ - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь написать файл rules.l, чтобы сгенерировать flex, чтобы прочитать любой заданный ввод и распечатать все возможные данные (например, - string , int , + , - , , если , else , et c), вместе с длиной, токеном и линией, на которой он находится. Все работает должным образом, за исключением того, что он не учитывает символы новой строки в строковом литерале.

Я погуглил свое сердце и прочитал всевозможные вещи, и все они говорят, что простое использование выражения \n должно позволить мне считать каждую новую строку в тексте.

Я также используйте [ \t], чтобы съесть пробел.

Мой вывод должен сказать:

< line: 14, lexeme: |"last"|

, но вместо этого он говорит:

> line: 10, lexeme: |"last"|

Любой ввод / совет был бы очень признателен!

Вот немного моего .l файла для контекста:

%option noyywrap
%{
int line_number = 1;
%}
%%
if                          { return TOK_IF; }
else                        { return TOK_ELSE; }
.
.
.
[a-zA-Z]([a-zA-Z]|[0-9]|"_")*   { return TOK_IDENTIFIER; }
\"(\\.|[^"\\])*\"               { return TOK_STRINGLIT; }


[ \t]+  ;

[\n]                                {++line_number;}

1 Ответ

2 голосов
/ 10 апреля 2020

Я бы посоветовал вам добавить

%option yylineno

в ваш файл Flex, а затем использовать переменную yylineno вместо того, чтобы пытаться самостоятельно подсчитывать переводы строки. Flex получает правильное значение и обычно умудряется оптимизировать вычисления.

Тем не менее, \"([^"])*\" не является оптимальным способом чтения строковых литералов, потому что он заканчивается в первой кавычке. Это приведет к катастрофическим сбоям, если строковый литерал будет "\"Bother,\" he said. \"It's too short.\""

Вот лучший вариант:

\"(\\(.|\n)|[^\\"\n])*\"

(Это не будет соответствовать строковым литералам, которые содержат символы новой строки без экранирования; в C ++ это не законно. Но вам нужно будет добавить другое правило, чтобы оно соответствовало ошибочной строке и выдало соответствующее сообщение об ошибке.)


Я полагаю, возможно, что вы должны соответствовать искусственным требованиям курса разработан кем-то, кто не знает о функции yylineno. В этом случае простое решение добавления line_number = yylineno; в начале каждого правила, вероятно, будет считаться обманом.

Что вам нужно будет сделать, это то, что делает сам Flex (но он не делает ошибок, и мы, программисты, делаем): выясним, какие правила могут соответствовать тексту, включая одну или несколько строк новой строки, и вставьте код в эти конкретные c правила для подсчета совпадений новой строки. Как правило, речь идет о многострочных комментариях и самих строковых литералах (поскольку строковый литерал может включать в себя обратную строку sh продолжение строки.)

Один из способов выяснить, какие правила могут соответствовать символам новой строки, состоит в включите функцию yylineno, а затем изучите код, сгенерированный flex. Найдите YY_RULE_SETUP в этом файле; обработчик для каждого правила синтаксического анализатора (включая те, чье действие ничего не делает) начинается с этого вызова макроса. Если вы включили %option yylineno, flex определяет, какие правила могут соответствовать символу новой строки, и вставляет код перед YY_RULE_SETUP, чтобы исправить yylineno. Эти правила начинаются с комментария /* rule N can match eol */, где N - индекс правила. Вам нужно будет посчитать правила в исходном файле, чтобы они соответствовали N номеру строки. Или вы можете посмотреть директиву #line в сгенерированном коде.

...