Как перезапустить сканирование в LEX

Я пытаюсь преобразовать синтаксис уценки в латекс и наоборот. Но я столкнулся с проблемой, которую не могу решить до сих пор. Допустим, у нас есть следующий текст:

* item
* item
* _Italic_ item
* Item with __nested _italic_ text__

Прямо сейчас моя программа lex сделает с текстом следующее:

\begin{itemize}
    \item{item}
    \item{item}
    \item{_Italic_ item}
    \item{Item with __nested _italic_ text__}
\end{itemize}

И если я снова запущу программу на этом выходе, я получу:

\begin{itemize}
    \item{item}
    \item{item}
    \item{\textit{Italic} item}
    \item{Item with nested \textit{italic} text}}
\end{itemize}

Это ожидаемый результат, но он должен сделать это за один прогон.

Я хочу знать, можно ли указать Flex для повторного запуска yylex() на выходе. Читая документацию, я нашел кое-что о Reentrant C Scanners и Multiple Input Buffers, но не знаю, решит ли это мою проблему.

Какое лучшее решение? Реентерабельные сканеры, несколько входных буферов или что-то попроще?

Я также думал о реализации функции yywrap, чтобы сообщить lex снова запустить сканер, но безуспешно:

int yywrap(){
    if (first_run == 1){
        first_run++;
        yyin = fopen ("/tmp/out1", "rt");
        yyout = fopen("salida", "wt");
        if (yyin == NULL) {
            printf ("El fichero no se puede abrir\n");
            exit (-1);
        }
        if (yyout == NULL) {
            printf ("El fichero no se puede abrir\n");
            exit (-1);
        }
        yyrestart(yyin);
        return 0;
    } else {
        return 1;
    }
}

Вот мой код:

                     /*----- Sección de Declaraciones --------------*/ 

    %option case-insensitive
    %option debug
    %option verbose

    %{
    #include<stdio.h>
    #include<string.h>

    int from_italic_text = 0; /* Para saber si venimos de una italic anidada en la bold*/
    int from_bold_text = 0;
    %}

    /* Primitives */ 
    word    .+

    scstrong    "__"|"**"
    scem    "_"|"*"
    list    ^"* "|"- "


    %x IN_MARKDOWN_LIST
    %x BOLD_TEXT_NESTED_ITALIC ITALIC_TEXT
    %x BOLD_TEXT ITALIC_TEXT_NESTED_BOLD

    %%
                     /*----- Sección de Reglas ----------------*/ 

    {list}  {BEGIN(IN_MARKDOWN_LIST);fprintf(yyout, "\\begin{itemize}\n");}

    <IN_MARKDOWN_LIST>{
        ^\n fprintf(yyout, "\\end{itemize}\n\n");BEGIN(INITIAL); /* si volvemos a detectar línea vacia, hemos acabado el itemize, o no era nada y salimos */
        ^"* "|"- "  /* Eliminar la sintáxis de itemize en markdown */
        [^"*"\-\n]+ fprintf(yyout, "\t\\item{%s}\n", yytext);   /* Éste es el texto que compone cada línea del itemize */
        \n  yylineno++;BEGIN(IN_MARKDOWN_LIST); /* Si detectamos salto de línea, aumentar el número de línea, y seguimos comprobando dentro de IN_MARKDOWN_LIST buscando más items*/
    }

    {scstrong}  {   BEGIN(BOLD_TEXT_NESTED_ITALIC); /* Comienzo de un strong __....*/} 
    <BOLD_TEXT_NESTED_ITALIC>{
        "__"    fprintf(yyout, "}");BEGIN(INITIAL); // Eat the end and exit
        "_" BEGIN(ITALIC_TEXT);     // Hay otro elemento anidado, un italic, pasamos a procesarlo
        [^_\n]* {   
            if (from_italic_text)
                fprintf(yyout, "%s", yytext); // Texto a continuación del italic
            else
                fprintf(yyout, "\\textbf{%s", yytext);
        }
        \n  BEGIN(INITIAL);
    }
    <ITALIC_TEXT>{
        [^_\n]* fprintf(yyout, "\\textit{%s", yytext);
        "_" fprintf(yyout, "}"); BEGIN(BOLD_TEXT_NESTED_ITALIC); from_italic_text = 1; /* Llegado al último _, cerramos }, volvemos al stado BOLD_TEXT y ponemos from_italic_text a 1 para saber que estuvimos aquí, y no cerra antes de tiempo el \textbf*/
    }

    {scem}  {   BEGIN(ITALIC_TEXT_NESTED_BOLD); /* Comienzo de un strong __....*/} 
    <ITALIC_TEXT_NESTED_BOLD>{
        "_" fprintf(yyout, "}"); BEGIN(INITIAL); // Eat the end and exit
        "__"    BEGIN(BOLD_TEXT);   // Hay otro elemento anidado, un italic, pasamos a procesarlo
        [^_\n]* { 
            if (from_bold_text) 
                fprintf(yyout, "%s", yytext); // Texto a continuación del italic
            else
                fprintf(yyout, "\\textit{%s", yytext);
        }
    \n  BEGIN(INITIAL);
    }
    <BOLD_TEXT>{
        [^_\n]* fprintf(yyout, "\\textbf{%s", yytext);
        "__"    fprintf(yyout, "}"); BEGIN(ITALIC_TEXT_NESTED_BOLD); from_bold_text = 1; /* Llegado al último _, cerramos }, volvemos al stado BOLD_TEXT y ponemos from_italic_text a 1 para saber que estuvimos aquí, y no cerra antes de tiempo el \textbf*/
    }

    .|\n            {ECHO;}

    %%   
                    /*----- Sección de Procedimientos --------*/ 

    int main (int argc, char *argv[]) {
        if (argc == 2) {
            yyin = fopen (argv[1], "rt");
            if (yyin == NULL) {
                printf ("El fichero %s no se puede abrir\n", argv[1]);
                exit (-1);
            }
        } else 
            yyin = stdin;

        yyout = fopen("/tmp/out1", "wt");

        if (yyout == NULL) {
            printf ("El fichero %s no se puede abrir\n", argv[1]);
            exit (-1);
        }

        yylex ();

        return 0;
    }

person ElBaulP    schedule 01.12.2014    source источник


Ответы (2)


Вместо того, чтобы выполнять несколько обходов, вы делаете это с помощью одного обхода и стеков:

%option stack 

и измените BEGIN state на

yy_push_state(STATE)      // ... push current-state; BEGIN STATE
yy_pop_state              // instead of BEGIN INITIAL we "return" to prev. state

Таким образом, легко иметь вложенные команды

{list}      { yy_push_state(IN_MARKDOWN_LIST);fprintf(yyout, "\\begin{itemize}\n");}

<IN_MARKDOWN_LIST>{
    ^\n     { yy_pop_state();         fprintf(yyout, "\\end{itemize}\n\n");  
    "__"    { yy_push_state(BOLD);    fprintf(yyout, "\\textbf{");
    "_"     { yy_push_state(ITALIC);  fprintf(yyout, "\\textit{");
    ...
}

<ITALIC>{
    "_"     { yy_pop_state();         fprintf(yyout, "}"); }
    ....
    .       {                         fprintf(yyout, "%s",yytext);}
}
person JJoao    schedule 12.12.2014

Наконец-то я нашел решение. Я не знаю, лучший ли он, но это сработало. Я реализовал yywrap следующим образом:

    int yywrap(){
        if (first_run == 1){
            first_run++;

            fclose(yyout);
            fclose(yyin);
            yyin = fopen ("/tmp/out", "rt");
            yyout = fopen("salida", "wt");

            if (yyin == NULL) {
                printf ("El fichero no se puede abrir\n");
                exit (-1);
            }
            if (yyout == NULL) {
                printf ("El fichero no se puede abrir\n");
                exit (-1);
            }
            return 0;
        } else {
            return 1;
        }
    }

    int main (int argc, char *argv[]) {
        yyin = fopen (argv[1], "rt");
        // ...
        yyout = fopen("/tmp/out", "wt");
        // .....
        yylex();
    }
person ElBaulP    schedule 03.12.2014