0

yacc には次の文法があります。

%{
    #include <stdio.h>
%}

%token texto SEP ERRO word

%start Ini

%%

Ini: Directivas SEP SEP Conceitos '$'
            { printf("Terminou bem...\n"); return 0; };

Directivas: Directiva
          | Directivas SEP Directiva
          ;

Conceitos: Conceito
         | Conceitos SEP SEP Conceito
         ;

Conceito: word SEP Atributos;

Atributos: Atributo
         | Atributos SEP Atributo
         ;

Directiva: texto;
Atributo: '-' texto;

%%

int main(){
    yyparse();
}

int yyerror(char *s){
    fprintf(stderr, "%s\n", s);
}

そしてフレックスでは:

%{
    #include "y.tab.h"
%}

%%

[a-zA-Z]+           return word;

[a-zA-Z ]+          return texto;

\-                  return '-';

\n                  return SEP;

[ \t]               ;

.                   return ERRO;

<<EOF>>             return '$';

次のような有効な解析を作成したい:

text line
text line
text line

word
-text line
-text line
-text line

word
-text line

ここで、最初の行は「Directivas」、次に 1 行の空白行であり、次に「Conceitos」が続きます。1 つの Conceitos は 1 つの単語であり、その後に「-」で始まるいくつかのテキスト行が続きます。これらの 'Conceitos は 1 つの空白行で区切られています

しかし、シフト/リデュースの競合が見つかります..私はこれが初めてで、理由がわかりません

私の英語でごめんなさい

ありがとうございました

4

1 に答える 1

2

yacc (または bison) の-vオプションを使用して、生成されたパーサーとファイル内の文法の競合の完全なリストを取得しy.outputます。文法でこれを行うと、(bison から) 次のような結果が得られます。

State 16 conflicts: 1 shift/reduce
        :
state 16

    6 Conceito: word SEP Atributos .
    8 Atributos: Atributos . SEP Atributo

    SEP  shift, and go to state 20

    SEP       [reduce using rule 6 (Conceito)]
    $default  reduce using rule 6 (Conceito)

これにより、競合がどこにあるかが正確にわかります。 を削減Attributosして先読みを調べた後SEP、パーサーは、 をシフトしてその後に別の解析を行うべきか、SEPまたはAtributoを削減する必要がConceitoあるかを判断できません。 (2 トークンSEPSEP先読みが必要)。

これを回避する 1 つの方法は、レクサーが複数SEPの s (空白行) を単一のトークンとして返すようにすることです。

\n      return SEP;
\n\n    return SEP_SEP;

代わりに、空白行または複数の空白行に空白を許可したい場合があります。

\n([ \t]*\n)+  return SEP_SEP;
于 2013-05-23T01:33:29.563 に答える