2015-01-17 6 views
0

вот мой код:Yacc остановка делать сдвиг && уменьшить один раз не может получить больше символа из yylex()

%{ 
#include<string.h> 
#include "y.tab.h" 
#define DEBUG 0 
void yyerror(char* s); 
void debug(char* string) { 
    if (DEBUG) { 
     printf(string); 
    } 
} 
%} 
selector "selector"[0-9]+ 
positive "+" 
negtive "-" 
contains "." 
before  "->" 
or   "||" 
and  "&&" 
delim  [ /n/t] 
ws   {delim}* 
%% 
{selector} { debug("Lex:SELECTOR\n"); yylval.string = yytext; return  SELECTOR; } 
{positive} { debug("Lex:POSITIVE\n"); return POSITIVE; } 
{negtive} { debug("Lex:NEGTIVE\n"); return NEGTIVE; } 
{contains} { debug("Lex:BELONGS\n"); return CONTAINS; } 
{before} { debug("Lex:BEFORE\n"); return BEFORE; } 
{or}  { debug("Lex:OR\n"); return OR; } 
{and}  { debug("Lex:AND\n"); return AND; } 
{ws}  ; 
.   { debug("Lex Parser Error"); exit(1); }  
%% 

.y: 
%{ 
#include <stdio.h> 
#define YYDEBUG 0 
int yyparse(void); 
void yyerror(char* s); 
%} 

%union { 
    char *string; 
} 

%token <string> SELECTOR 
%token POSITIVE 
%token NEGTIVE 
%left CONTAINS 
%left BEFORE 
%token OR 
%token AND 

%% 
logical_expr : assertion { printf("[reduce] L->A\n"); } 
    | logical_expr AND assertion { printf("[reduce] L->L && A\n");} 
    | logical_expr OR assertion { printf("[reduce] L->L || A\n"); }   
; 
assertion : POSITIVE prefix_relation { printf("[reduce] A->+P\n"); } 
    | NEGTIVE prefix_relation { printf("[reduce] A->-P\n"); } 
; 
prefix_relation : prefix_relation BEFORE contain_relation { printf("[reduce] P->P->C\n"); } 
    | contain_relation { printf("[reduce] P->C\n");;} 
; 
contain_relation : contain_relation CONTAINS SELECTOR { printf("[reduce] C->C.S[%s]\n", $3); } 
    | SELECTOR { printf("[reduce] C->S[%s]\n", $1); } 
; 
%% 
int main() 
{ 
    return yyparse(); 
} 
void yyerror(char* s) 
{ 
    fprintf(stderr,"%s",s); 
} 
int yywrap() 
{ 
    return 1; 
} 

моя входная строка: +selector1.selector2||-selector4->selector4

дерева синтаксического анализа этого входа, как ожидается, будет : the expected parse tree

моя программа генерируется Yacc дает выход, как показано ниже:

[reduce] C->S[selector1]  // stack: +C 
[reduce] C->C.S[selector2] // stack: +C 
[reduce] P->C    // stack: +P 
[reduce] A->+P    // stack: A 
[reduce] L->A    // stack: L 
[reduce] C->S[selector3]  // stack: L||-C 
[reduce] P->C    // stack: L||-P 
[reduce] C->S[selector4]  // stack: L||-P->C 

Кажется, что программа прекращает делать сдвиг & & уменьшить один раз не может получить больше символа из yylex(), но я ожидаю, что он уменьшит оставшиеся символы в стеке, таким образом, L||-P->C, так что я могу сгенерировать все дерево синтаксического анализа в мой код.

мой ожидается выход:

[reduce] C->S[selector1]  // stack: +C 
[reduce] C->C.S[selector2] // stack: +C 
[reduce] P->C    // stack: +P 
[reduce] A->+P    // stack: A 
[reduce] L->A    // stack: L 
[reduce] C->S[selector3]  // stack: L||-C 
[reduce] P->C    // stack: L||-P 
[reduce] C->S[selector4]  // stack: L||-P->C 
[reduce] P->P->C    // stack: L||-P 
[reduce] A->-P    // stack: L||A 
[reduce] L->L||A    // stack: L 
+1

Вы не показали весь файл lex. Фактически, вы вообще не показывали никакого правила; только определения. Несомненно, проблема связана с вашей обработкой EOF (и, скорее всего, вы решили каким-то образом ее обработать, а не позволить гибко обрабатывать ее автоматически) или некоторые проблемы с обработкой новой строки (например, вы делаете что-то, кроме игнорирования) но без дополнительной информации это невозможно сказать. – rici

+1

В вашем правиле 'delim' есть косые черты, где должны иметь обратную косую черту. – EJP

ответ

3

Есть целый ряд проблем с вашим сканером (прогибается) определения.

  1. Ваш умолчанию прогибается правило просто вызывает exit без сообщения об ошибке (если DEBUG не определен и не равен нулю), поэтому любая лексическая ошибка заставит программу молча остановиться. В этом случае было бы гораздо лучше позвонить yyerror и создать видимое сообщение об ошибке.

  2. Как EJP отмечает в комментарии, ваше delim определение использует /n и /t вместо \n и \t, поэтому он будет соответствовать ни новой строки, ни вкладку. Новая строка также не будет соответствовать вашему стандарту по умолчанию, поэтому она будет пропущена в правило Flex, созданное по умолчанию, которое просто печатает непревзойденный символ до stdout. (Лучше включать %option nodefault, что приведет к сгибать для получения сообщения об ошибке, если входные данные не соответствует ни один из ваших правил.)

  3. Ваше selector правило устанавливает yylval.string = yytext. Вы не можете этого сделать, потому что yytext указывает на внутреннее хранилище сканера, и строка, на которую указывает, будет изменена при следующем вызове yylex. Если вы хотите передать согласованный токен из сканера в синтаксический анализатор, вы должны сделать копию токена, а затем вам нужно обеспечить, чтобы вы хранилище, выделенное для него, когда вам больше не нужна строка, чтобы избежать утечка памяти.

  4. Вы должны знать, что анализаторы, сгенерированные bison или yacc, обычно должны читать токен-указатель перед выполнением сокращений. Следовательно, последняя серия сокращений, которую вы ожидаете, не будет выполняться до тех пор, пока сканер не вернет маркер END, который он будет делать только при чтении конца файла. Поэтому, если вы проверите свой парсер в интерактивном режиме, вы не увидите окончательные сокращения до тех пор, пока не сообщите конец файла, набрав ctrl D (в Unix).

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

+0

Я изменил 'ws' на' ws {delim} + ', но программа по-прежнему перестает сокращаться после выхода' [уменьшить] C-> S [selector4] ', и если я буду вводить' .selector5', output '[reduce] C-> CS [selector5]' – yeren1989

+0

Точка 1 неверна - lex/flex никогда не будет соответствовать пустой строке, так как это приведет к бесконечному циклу (как вы заметили). Правило «самое длинное совпадение» гарантирует, что что-то еще будет соответствовать ALWAYS вместо этого - либо правило одиночного токена, либо правило EOF по умолчанию, если вы не определяете что-то другое самостоятельно, которое соответствует. Таким образом, шаблоны '{ws} +' и '{ws} *' в точности эквивалентны. –

+0

Обратите внимание, что все еще есть способы получить бесконечный цикл - с помощью оператора '/' trailing context или 'yyless', но в этих случаях flex соответствует более длинному (непустому) токену, а затем нечетному символы, которые нужно перечитать. –