2015-01-29 4 views
1

Я пытаюсь разобрать два файла с помощью win flex и bison, но я столкнулся с проблемой, когда lex не находится в состоянии, которое я ожидаю. В ЛЕКС файле:Неверное состояние lex при разборе нескольких файлов

include[ \t]+\" { BEGIN(include_state); } 
<include_state>([^\\\"\n]|\\.)+ { 
    yyin = fopen(yytext, "r"); 
    if (!yyin) { 
     printf("Error opening include file: %s\n", yytext); 
     return 1; 
    } 
    yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner), 
     yyscanner); 
    BEGIN(INITIAL); 
} 
<include_state>\"[ \t]*";" { BEGIN(INITIAL); } 
<<EOF>> { 
    yypop_buffer_state(yyscanner); 
    if (!YY_CURRENT_BUFFER) 
     yyterminate(); 
} 

Первый файл разбираемый включает в себя второй файл следующим образом:

include "hello.txt"; 

Что происходит при разборе, что второй файл («hello.txt») анализируется OK без проблем, но есть проблема при возврате в первый файл. Чтение цитаты и полуплоскости в конце строки читается, но lex находится в состоянии INITIAL. Поэтому lex не соответствует правилу, которое я ожидаю от него. Я знаю это точно, потому что, если я добавлю следующее правило (это соответствует):

<INITIAL>\"[ \t]*";" { printf("Right matching, wrong state.\n"); return 1; } 

Почему не вернуться к include_state и как я могу это исправить?

+0

Я ответил на этот вопрос в своем предыдущем вопросе: Условие пуска * не * часть состояния буфера, поэтому вам нужно управлять им отдельно. В этом случае самым простым решением было бы прочитать закрытие '' 'перед тем, как сделать include. – rici

ответ

2

Похоже, что он отправляется в НАЧАЛЬНУЮ, потому что это то, что вы говорите, чтобы сделать это после звонка yypush_buffer_state(). Как это будет соответствовать второму <include_state>, если вы это сделаете? Что произойдет, если вы удалите это изменение состояния?

+1

Я думаю, что ваш диагноз проблемы верен. Что произойдет, если удалить BEGIN (INITIAL);', то это содержимое содержимого содержимого включено в 'include_state', что дает проблемы, потому что тело файла, вероятно, должно быть прочитано в исходном состоянии. Я не уверен, что правило EOF может сбросить состояние до' include_state' (когда EOF для одного из включенных файлов) –

+1

@JonathanLeffler Это звучит разумно. Может быть, это альтернатива не использовать состояния, но, столкнувшись с объявлением #include, оттолкните текущий yyin в сторону, включите содержимое содержимого include и EOF поп назад yyin и продолжайте. Или посмотрите, как современные препроцессоры C справляются с проблемой :-) – Jens

+1

@Jens: Это не сработает, потому что текущий буфер не синхронизирован, у него уже есть будущие данные. nging 'yyin' не вступит в силу до тех пор, пока не будет достигнут конец буфера. При принудительном изменении данные будут отбрасываться. Вот почему '(f) lex' предоставляет буферы и буферные стеки; вы должны использовать их. Кроме того, нет абсолютно никакой проблемы с установкой условия запуска, когда вы хотите, даже в правиле EOF, потому что это * global *, а не часть состояния буфера. (В чистом лексере это часть состояния сканера, но для каждого сканера есть только один.) – rici

1

Состояние пуска глобально. Он не является частью состояния буфера. Нажатие и выскакивание состояния буфера не измените его. Вы должны управлять им самим.

Вы можете восстановить начальное состояние до include_state после того, как вы сделаете yypop_buffer_state. Вы даже можете сохранить свой собственный стек лексерских состояний вдоль стека буферов. Но самое простое решение, как представляется, чтение пунктуации в #include заявления перед выполнением #include, так что вы всегда в INITIAL состояния при изменении буфера:

<include_state>[^\n"]+\" { 
    yytext[yyleng - 1] = 0; // Get rid of the close quote. 
    yyin = fopen(yytext, "r"); 
    if (!yyin) { 
     printf("Error opening include file: %s\n", yytext); 
     return 1; 
    } 
    yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner), 
         yyscanner); 
    BEGIN(INITIAL); 
} 
<include_state>.|\n { /* Handle syntax error in #include */ }