2017-01-08 8 views
1

私はLexとBisonパーサジェネレータを使用しています。 私は、セマンティクスを定義する構文と.yppファイルを定義する.lexファイルを持っています。yylinenoにはどのような行が印刷されますか?

Statement : Type ID ASSIGN Exp {check_types_match($1.type, $4.type)} SC 
  • タイプがint型またはブールことができます:私の.yppに私はこのラインを持っています。
  • IDは識別子です。
  • ASSIGNは=シンボルです。
  • Expは多くのものがありますが、Exp:trueはブール型として式のタイプを保存します。
  • SCは、半導体「;」です。
  • check_types_matchは型の不一致をチェックし、エラーがあればその行(yylineno)を出力します。

は、この単純な入力ファイルに:

int x = true 
; 

私はエラーが2行目にあり、1行目にどのように私はそれが代わりに1行目でエラーを印刷することができないことをもらいますか?

答えて

1

あなたがそうcheck_types_matchが呼ばれた瞬間に、yylinenoは、あなたがエラーを生成したい場合2.

行目にポイントする必要があり、2行目にあるセミコロンを、到達するまで、文はそのように認識されていませんメッセージに異なる行番号がある場合は、印刷する行を決定する必要があります。エラーはトークンintとトークンtrueの間にあるため、少なくとも2つの可能性があります。この場合、それらの両方は、1行目にありますが、どのようなプログラムテキストがあった場合:

int x = 
    true; 

これらのトークンのいずれかがエラーの原因としてフラグ付けされるべきであると合理的なようなので問題は把握に減少しトークンがどの行に現れたかを調べる。そのトークンは、減少が起こるまでの古代の歴史なので、これを行う唯一の方法は、依然としてパーサースタックに残っているすべてのトークンである、まだ必要なすべてのトークンの場所を覚えておくことです。

幸いにも、bisonには簡単な方法があります。必要に応じて、パーザスタックと並行して位置スタックを維持し、次に@1を参照するだけでトークン1のロケーションオブジェクトにアクセスできます。さらに簡単に、あなたのバイソンファイルのどこかにあるロケーションオブジェクトへの参照を使うだけで、バイソンにこの情報を維持するように説得するのに十分です。だから、あなたがあなたの行動を変えることができる:(。あなたはExpにエラーを帰することがより適切と思われる場合、または@4

Statement : Type ID ASSIGN Exp {check_types_match($1.type, $4.type, @1)} SC 

もちろん

を、それは非常に単純なことはありません。 bisonには、すべての着信トークンの場所を知るために、また、新しく作成された非終端記号の場所を作成する方法を理解する必要があります(上記の例ではExpなど)。)

ロケーションオブジェクトは、(非終端記号の場合のように)トークンのシーケンスの場所を参照することがあります。これは、複数の行にまたがって表示されることがあります。終点。さらに、正確なエラーメッセージを生成するために、行番号と列オフセットの両方を使用することが一般的です。このため、デフォルトの場所のオブジェクトは、次のタイプがあります。

typedef struct YYLTYPE { 
    int first_line; 
    int first_column; 
    int last_line; 
    int last_column; 
} YYLTYPE; 

、デフォルトでは、あなたが

Nがある
@$.first_line = @1.first_line; 
@$.first_column = @1.first_column; 
@$.last_line = @N.last_line; 
@$.last_column = @N.last_column; 

のようなものを書いていたかのように、非端末の位置オブジェクトが計算され、右側の最後の文法記号のインデックス。 (bisonは "文法記号の数"の表記法を持たず、$N構造の変数も許可していないので、実際には書き込むことはできません)。

あなたが望むものをかなりよく、バイソンの側からは問題はありません。しかし、あなたはまた、最初にflexから情報を取得する必要があります。

グローバル変数に依存しflexbison間の単純なインタフェースを使用する場合は、現在のトークンに対応する位置のオブジェクトの名前(yylvalに類似)yyllocあります。 flexyylinenoを自動的に作成できますが、自動的にはyyllocに格納されませんし、列番号を追跡するためのメカニズムも組み込まれていません。返されたトークンが2行以上に渡っている場合も処理できます文字列定数など)。

インフラストラクチャをすべて正しく設定することは、回線番号情報のみを要求するため、この質問の対象外です。あなただけの行番号を追跡する必要があり、複数行のトークンを持っていない、すべてのフレックスルールに以下を追加するのに十分である場合:あなたは、あなたが複数行のトークンを持っている場合は

yylloc.first_line = yylloc.last_line = yylineno; 

すべてのトークンのアクション、何も(コメントと空白文字)を行わないものも含めに追加しなければならないであろう

yylloc.first_line = yylloc.last_line; 
yylloc.last_line = yylineno; 

:代わりに以下を使用することができます。幸運なことに、flexには、すべてのアクションの冒頭に追加されるマクロがあります。したがって、フレックスファイル全体を複雑にする必要はありません。あなたはまた、yylloc.last_line1に初期化されていることを確認する必要があります(あなたが列番号を追跡してしまう場合は、あまりにも、あなたはそれを修正する必要があります)

#define YY_USER_ACTION do {    \ 
    yylloc.first_line = yylloc.last_line; \ 
    yylloc.last_line = yylineno;   \ 
} while(0) 

;:それはのような何かを追加するのに十分ですそれ以外の場合、最初のトークンは0行目から開始します。詳細については

、取扱説明書をお読みください:

あなたが再入/純粋スキャナとパーサを使用している場合は、マニュアルを参照してくださいする必要があります場所オブジェクトがグローバルなしでどのように渡されるかについて。 %bison-locations宣言は、必ずしもあなたが望むものではないことに注意してください(リエントラント/純粋なスキャナとパーサを使用していない場合は、あなたが望むものではありません)。

+0

詳細な返信をありがとうございます!それは私を助けました:)乾杯! – Loay

関連する問題