Как заставить flex использовать в качестве входного файла текстовый файл (.txt / .c / etc.) - PullRequest
0 голосов
/ 27 декабря 2018

Я совершенно новичок в сгибании, и мой опыт программирования довольно мал.Мне нужно создать сканер с использованием flex, который в конечном итоге будет выводить поток токенов.На данный момент мне просто нужно получить абсолютные основы и запустить.Я хочу, чтобы скомпилированный выходной файл "a.exe" мог запускаться из текста в ОДНОМ файле, а не из пользовательского ввода.Вывод также должен быть в файл.Присвоение запрашивает, что программа может работать так же, как в окне cmd / PS:. \ A.exe inputfile.txt outputfile.txt Где входные и выходные файлы - это любые имена файлов, добавляемые в этом порядке.В настоящее время моя программа создает указанный мной выходной файл, но в него ничего не записывается.Когда я пытаюсь прочитать Руководство по Flex, я очень растерялся, потому что я все еще очень плохо знаком с компьютерными науками в целом.На данный момент, я просто хочу получить исполняемый файл, который будет придерживаться раздела правил и выводить правильно.При этом я обычно просто подсчитываю символы во входном файле и пытаюсь отобразить их в выходной файл.Я также пытаюсь помочь остальным в моем классе иметь место для начала (так как никто из нас официально не обучался этому делу), поэтому я не тороплюсь с попыткой создать этот файл в общем (с инструкциями по установке и использованию), чтобыЯ могу дать им место, чтобы начать собственное задание по изготовлению сканера.

Я установил Flex 2.5.4a из http://gnuwin32.sourceforge.net/packages.html. Я отредактировал свой путь для включения файла bin после установки.

Я создаю файл с помощью команды «flex tokenout.l», а затем «gcc lex.yy.c», и он генерирует файл a.exe.Кажется, что файл почти не работает после создания выходного файла.

код:

int num_lines = 0;
int num_chars = 0;
FILE *yyin;
FILE *yyout;

%%
\n  ++num_lines; ++num_chars;
.   ++num_chars;
%%

int yywrap(void) {
    return 0;
}
int main(int argc, char *argv[])
{
    yyin = fopen(argv[1],"r");
    yyout = fopen(argv[2],"w");
    yyparse();
    yylex();
    fprintf(yyout,"# of lines = %d, # of chars = %d\n", num_lines, num_chars);
    fclose(yyin);
    fclose(yyout);
    return 0;
}

В результате получается, что строка "# строк = фактическое количество строк, # of chars = фактическое количество символов "для файла, обозначенного как второй аргумент.

В настоящее время файл, обозначенный вторым аргументом, создан, но остается пустым.

Ответы [ 3 ]

0 голосов
/ 27 декабря 2018

Вызовы Lex (flex) (или, точнее, генерирует вызывающий код) yywrap по достижении конца входного потока (в yyin).Задача этой функции:

  1. Позаботиться о закрытии входного файла, если необходимо / уместно.
  2. Переключиться на следующий входной файл, если есть следующий файл.
  3. Возвращает ненулевое значение (1, предпочтительно), если flex должен завершиться, 0, если yyin теперь повторно открывается для следующего файла.

Или, как руководство выражает это:

Когда сканер получает указание конца файла от YY_INPUT, он затем проверяет функцию 'yywrap()'.Если 'yywrap()' возвращает false (ноль), то предполагается, что функция прошла вперед и настроила yyin для указания на другой входной файл, и сканирование продолжается.Если он возвращает true (не ноль), то сканер завершает работу, возвращая 0 своему вызывающему.Обратите внимание, что в любом случае условие запуска остается неизменным;он не возвращается к INITIAL.

Если вы не предоставите свою собственную версию 'yywrap()', то вы должны либо использовать '%option noyywrap' (в этом случае сканер ведет себя так, как если бы 'yywrap() 'вернул 1), или вы должны связать с' -lfl ', чтобы получить версию подпрограммы по умолчанию, которая всегда возвращает 1.

(Современный flex имеет <<EOF>> правила, которыеКак правило, это лучший способ иметь дело со стекированными входными файлами, так как переходы между файлами почти всегда должны устанавливать границу токена.)

0 голосов
/ 28 декабря 2018
yyin = fopen(argv[1],"r");
yyout = fopen(argv[2],"w");
yyparse();
yylex();

В текущем состоянии моя программа создает указанный мной выходной файл, но в него ничего не записывается.

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

Например, что если первый fopen (3) завершится неудачно?Что если yyparse завершится неудачей или не вернется?(Не будет.) Проверьте наличие ошибок, и программа сообщит вам, что происходит.

#include <err.h>
if( argc < 3 ) {
    errx(EXIT_FAILURE, "syntax: foo in out");
}
if( (yyin = fopen(argv[1],"r")) == NULL ) {
    err(EXIT_FAILURE, "could not read '%s'", argv[1]);
}
if (yyout = fopen(argv[2],"w")) == NULL ) {
    err(EXIT_FAILURE, "could not write '%s'", argv[2]);
}

printf("starting yyparse\n");
if( 0 != yyparse() ) {
    errx(EXIT_FAILURE, "parse error");
}
printf("starting yylex\n");
if( 0 != yylex() )  {
    errx(EXIT_FAILURE, "lex error");
}

Вышеуказанное гарантирует, что программа запускается с достаточным количеством аргументов, гарантирует, что оба файла открыты успешно, и проверяет наличие ошибок.ошибки разбора и лексирования.Это всего лишь пример.Как сказал Джон Боллинджер , вам не нужен yyparse, потому что вы не используете бизон, а yyout контролирует только файл, используемый оператором flex ECHO.Вы можете использовать свой собственный глобальный дескриптор FILE * и fprintf (3) в своих действиях flex.

Я думаю, вы обнаружите, что вы никогда не увидите «запускающий yylex» на экране, потому что yyparse никогда не возвращается, потому что - если он генерируется где-то - он не возвращается, потому что он вызывает yylex , который никогда ничего не возвращает ему.

Я бы удалил эти строки и включил бы отладку flex с помощью

  yy_flex_debug = 1;

перед вызовом yylex.Я думаю, вы найдете, что это имеет больше смысла тогда.

0 голосов
/ 27 декабря 2018

Вы, похоже, начинаете с адаптации примера программы из руководства по Flex .Это нормально, но, возможно, вашим первым шагом должно стать приведение примера программы в действие.После этого делайте один шаг за раз.Например, следующим шагом может быть использование первого аргумента в качестве имени входного файла (и никаких других изменений).

Что касается представленной вами частичной программы, я вижу две семантическиевыдает:

  1. Когда вы используете flex с bison (или yacc), генерируемый синтаксический анализатор (доступ через yyparse()) вызывает yylex(), и, как правило, это будет повторятьсяпока ввод не исчерпан.В этом случае бесполезно, чтобы основная программа вызывала лексер напрямую.

  2. yyout - это файл, в который flex будет направлять вывод операторов ECHO, и ничего более, не меньше.Это не особенно полезно для вас, и я бы проигнорировал это сейчас.

...