Пишем вновь входящий лексер с Flex - PullRequest
6 голосов
/ 14 апреля 2010

Я новичок, чтобы согнуть. Я пытаюсь написать простой лексер / сканер с Flex. Определение лексера идет ниже. Я застреваю с ошибками компиляции, как показано ниже (проблема yyg):

reentrant.l:

/* Definitions */

digit           [0-9]
letter          [a-zA-Z]
alphanum        [a-zA-Z0-9]
identifier      [a-zA-Z_][a-zA-Z0-9_]+
integer         [0-9]+
natural         [0-9]*[1-9][0-9]*
decimal         ([0-9]+\.|\.[0-9]+|[0-9]+\.[0-9]+)

%{
    #include <stdio.h>

    #define ECHO fwrite(yytext, yyleng, 1, yyout)

    int totalNums = 0;
%}

%option reentrant
%option prefix="simpleit_"

%%

^(.*)\r?\n     printf("%d\t%s", yylineno++, yytext);

%%
/* Routines */

int yywrap(yyscan_t yyscanner)
{
    return 1;
}

int main(int argc, char* argv[])
{
    yyscan_t yyscanner;

    if(argc < 2) {
        printf("Usage: %s fileName\n", argv[0]);
        return -1;
    }

    yyin = fopen(argv[1], "rb");

    yylex(yyscanner);

    return 0;
}

Ошибки компиляции:

vietlq@mylappie:~/Desktop/parsers/reentrant$ gcc lex.simpleit_.c 
reentrant.l: In function ‘main’:
reentrant.l:44: error: ‘yyg’ undeclared (first use in this function)
reentrant.l:44: error: (Each undeclared identifier is reported only once
reentrant.l:44: error: for each function it appears in.)

1 Ответ

11 голосов
/ 07 декабря 2010

Для реентерабельного лексера все сообщения должны включать состояние , которое содержится в сканере .

В любом месте вашей программы ( например, внутри main) вы можете получить доступ к переменным состояния через специальные функции, к которым вы передадите свой сканер. Например, , в оригинале reentrant.l вы можете сделать это:

yyscan_t scanner;
yylex_init(&scanner);
yyset_in(fopen(argv[1], "rb"), scanner);
yylex(scanner);
yylex_destroy(scanner);

Я переименовал scanner, чтобы избежать путаницы с yyscanner в действиях. В отличие от общего кода на C, все ваши действия происходят внутри гигантской функции yylex, которой ваш сканер передается под именем yyscanner. Таким образом, yyscanner доступно для всех ваших действий. Кроме того, yylex имеет локальную переменную с именем yyg, которая хранит все состояние, и большинство макросов обычно ссылаются на yyg.

Несмотря на то, что вы можете использовать макрос yyin внутри main, определив yyg, как вы это сделали в своем собственном ответе, это не рекомендуется. Для реентерабельного лексера макросы предназначены только для действий.

Чтобы увидеть, как это реализовано, вы всегда можете просмотреть сгенерированный код:


/* For convenience, these vars
   are macros in the reentrant scanner. */
#define yyin yyg->yyin_r
...

/* Holds the entire state of the reentrant scanner. */
struct yyguts_t
...

#define YY_DECL int yylex (yyscan_t yyscanner)

/** The main scanner function which does all the work.
 */
YY_DECL
{
    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
...
}

В flex документах есть много других параметров reentrant, которые включают в себя чистый пример компиляции. (Google " flex reentrant " и найдите ссылку flex.sourceforge.) В отличие от bison , flex имеет довольно простую модель для повторного входа. Я настоятельно рекомендую использовать реентрант flex с Lemon Parser , а не с yacc / bison .

...