2016-10-19 6 views
0

インデントで定義されたPythonのブロックを再作成しようとすると、私はこの時点で右に遭遇しました。BisonパーサーでFlexの開始条件を処理する際に間違ったトークンがあります

レクサー/スキャナを別々に試してみると、私が作った開始条件を使って、期待通りの結果を返してくれます。しかし、それをBisonパーサーと組み合わせると、正しい状態が保持されず、予想外の状態からトークンを受け取ることになります。

私の予想される動作は、行の先頭にあるタブ/スペースの "INDENT"トークンを返すことになります。また、各シンボルの "OTHER"トークンを返す別のシンボル(タブ/スペースではありません)改行。

まず場合、期待される結果 "   試験   " は(二つの空間の前および "試験" 後)「インデントを返す入力

scanner.l

%{ 
    #include <iostream> 
%} 

%option noyywrap 

%x INDENT 
%% 

    BEGIN(INDENT); 

<INDENT>[ \t] { std::cout << "INDENT "; } 
<INDENT>.|\n { yyless(0); BEGIN(INITIAL); } 

\n { std::cout << std::endl; BEGIN(INDENT); } 
. { std::cout << "OTHER "; } 

%% 

int main(){ 
    yylex(); 
    return 0; 
} 

を返すレクサー他のすべての他の他の他の。

後者の場合、予期しない結果」   テスト を入力

scanner.l

%{ 
    #include <iostream> 

    #include "parser.h" 
%} 

%option noyywrap 

%x INDENT 
%% 

    BEGIN(INDENT); 

<INDENT>[ \t] { return T_INDENT; } 
<INDENT>.|\n { yyless(0); BEGIN(INITIAL); } 

\n { BEGIN(INDENT); return T_NEWLINE; } 
. { return T_OTHER; } 

%% 

parser.y

%{ 
    #include <iostream> 

    extern int yylex(); 

    void yyerror(const char *s); 
%} 

%define parse.error verbose 

%token T_INDENT T_OTHER T_NEWLINE 

%% 

program : program symbol 
     | %empty 
     ; 

symbol : T_INDENT { std::cout << "INDENT "; } 
     | T_NEWLINE { std::cout << std::endl; } 
     | T_OTHER { std::cout << "OTHER "; } 
     ; 

%% 

void yyerror(const char *s){ 
    std::cout << s; 
} 

int main(){ 
    yyparse(); 
    return 0; 
} 

を返すパーサ "(前と同じ)は、"インデントインデント他の他のインデントインデント "を返します。予想された結果は上記と同じですが。

Bisonパーサーは、開始条件を尊重していないかのように、間違ったトークンを受け取っているようです。先読みのためにパーサが開始条件を混乱させていることを読んだことがありますが、問題がこの中にあるかどうか、またどのように対処するかはわかりません。あなたはルールセクションのパターンのない

BEGIN(INDENT) 

を持っているので

+0

これは非常に奇妙な方法です。私は '^ [\ t] BEGIN INDENT;'を持ち、その状態では起動しません。 – EJP

答えて

0

、これはyylexの関数の先頭にそのままコピーされるので、yylexのが呼ばれるたびに実行されます。したがって、ビソンがyylexを呼び出して新しいトークンを取得するたびに、状態はINDENTにリセットされ、T_INDENTのトークンが取得されます。

「最初のケース」の例では、レクサーはEOFまで戻らないため、一度だけ呼び出すことができ、INDENTという状態を1回だけ設定します。

初めてこのコードを実行する場合は、yylexを初めて呼び出すときにのみ実行するように設定する必要があります。ような何か:

 { static bool not_first_time; 
      if (!not_first_time) { 
      BEGIN(INDENT); 
      not_first_time = true; } } 

代わりに、INITIALが期待される初期状態になるようなものを設定します。

+0

ありがとう、それはそれだった:)私は完全にこの細部を見落とした –

関連する問題