Объяснение для реализации вложенной грамматики `#include" Header "в C / C ++ с помощью lex / flex? - PullRequest
0 голосов
/ 16 января 2020

Я изучаю Начальные состояния и вложенные входные файлы в lex / flex.

В книге flex and bison , я запутался в примере реализация C / C ++ #include "Header" грамматика:

Вот часть примера lex:

/* Companion source code for "flex & bison", published by O'Reilly
 * Media, ISBN 978-0-596-15597-1
 * Copyright (c) 2009, Taughannock Networks. All rights reserved.
 * See the README file for license conditions and contact info.
 * $Header: /home/johnl/flnb/code/RCS/fb2-3.l,v 2.3 2010/01/04 02:43:58 johnl Exp $
 */

/* fb2-3 skeleton for include files */

%option noyywrap warn nodefault
%x IFILE
  struct bufstack {
    struct bufstack *prev;  /* previous entry */
    YY_BUFFER_STATE bs;     /* saved buffer */
    int lineno;         /* saved line number */
    char *filename;     /* name of this file */
    FILE *f;            /* current file */
  } *curbs = 0;

  char *curfilename;        /* name of current input file */

  int newfile(char *fn);
  int popfile(void);

%%
^"#"[ \t]*include[ \t]*[\"<] { BEGIN IFILE; }

<IFILE>[^ \t\n\">]+          { 
                             { int c;
                   while((c = input()) && c != '\n') ;
                 }
                 yylineno++;
                 if(!newfile(yytext))
                                yyterminate(); /* no such file */
                 BEGIN INITIAL;
                           }

<IFILE>.|\n                { fprintf(stderr, "%4d bad include line\n", yylineno);
                     yyterminate();
               }
^.                         { fprintf(yyout, "%4d %s", yylineno, yytext); }
^\n                        { fprintf(yyout, "%4d %s", yylineno++, yytext); }
\n                         { ECHO; yylineno++; }
.                          { ECHO; }
<<EOF>>                    { if(!popfile()) { fprintf(yyout, "end of file, total lines: %4d %s", yylineno, yytext); yyterminate();}  }
%%

main(int argc, char **argv)
{
  if(argc < 2) {
    fprintf(stderr, "need filename\n");
    return 1;
  }
  if(newfile(argv[1]))
    yylex();
}

int
  newfile(char *fn)
{
  FILE *f = fopen(fn, "r");
  struct bufstack *bs = malloc(sizeof(struct bufstack));

  /* die if no file or no room */
  if(!f) { perror(fn); return 0; }
  if(!bs) { perror("malloc"); exit(1); }

  /* remember state */
  if(curbs)curbs->lineno = yylineno;
  bs->prev = curbs;

  /* set up current entry */
  bs->bs = yy_create_buffer(f, YY_BUF_SIZE);
  bs->f = f;
  bs->filename = fn;
  yy_switch_to_buffer(bs->bs);
  curbs = bs;
  yylineno = 1;
  curfilename = fn;
  return 1;
}

int
  popfile(void)
{
  struct bufstack *bs = curbs;
  struct bufstack *prevbs;

  if(!bs) return 0;

  /* get rid of current entry */
  fclose(bs->f);
  yy_delete_buffer(bs->bs);

  /* switch back to previous */
  prevbs = bs->prev;
  free(bs);

  if(!prevbs) return 0;

  yy_switch_to_buffer(prevbs->bs);
  curbs = prevbs;
  yylineno = curbs->lineno;
  curfilename = curbs->filename;
  return 1; 
}

Пожалуйста, помогите мне с этими вопросами:

  1. Почему <IFILE>[^ \t\n\">]+ соответствует концу " или > Header?
  2. Почему использование { int c; while((c = input()) && c != '\n') ; } съедает все символы до конца строки \n? Будет ли yytext точно соответствовать Header имени файла?
  3. Как реализовать грамматику, например java import java.util.Decoder;?

1 Ответ

3 голосов
/ 16 января 2020

Почему [^ \ t \ n \ ">] + соответствует концу" или> заголовка?

Ответ: Это не .

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

Давайте рассмотрим пример:

#include <foo/bar.h>
  • Правило ^"#"[ \t]*include[ \t]*[\"<] соответствует #include <.
  • Правило <IFILE>[^ \t\n\">]+ соответствует foo/bar.h

Когда вы запускаете код

int c;
while((c = input()) && c != '\n') ;

, он начинается с чтения конца >, а затем продолжает читать и отбрасывать все оставшиеся символы до конца строки.

Чтобы убедиться в этом, вы можете добавить некоторые выходные данные символа в l oop.

...