1

私は言語のフロントエンドを書いています ( by ocamllexand ocamlyacc)。

したがって、フロントエンドはAbstract Syntax Tree (AST)プログラムからビルドできます。次に、AST を受け取ってプログラムを出力する pretty printer をよく作成します。後で AST をコンパイルまたは分析するだけの場合、ほとんどの場合、印刷されたプログラムが、空白に関して元のプログラムとまったく同じである必要はありません。ただし、今回は、空白に関して元のプログラムとまったく同じプログラムを印刷するきれいなプリンターを作成したいと思います。

したがって、私の質問は、AST の種類をあまり変更しないようにしながら、空白を処理するためのベスト プラクティスは何かということです。AST の各型に (空白の) 数を追加したくありません。

たとえば、これは私が現在 で空白を処理する (つまり、スキップする) 方法ですlexer.mll

rule token = parse
  ...
  | [' ' '\t']       { token lexbuf }     (* skip blanks *)
  | eof              { EOF }

これとフロントエンドの他の部分を変更して、後で印刷するために空白を正しく考慮に入れる方法を知っている人はいますか?

4

2 に答える 2

1

各トークンのソース ファイルの場所情報を保持することは非常に一般的です。この情報により、たとえば、より正確なエラーが可能になります。

これを行う最も一般的な方法は、各トークンの開始行番号と終了行番号、および列位置を保持することです。これは合計 4 つの数値です。トークンの値と開始位置からトークンの終了位置を簡単に計算できれば、2 つの数値に減らすことができますが、コードがさらに複雑になります。

Bison には、位置オブジェクトを記憶する簿記作業を簡素化する機能がいくつかあります。ocamlyacc にも同様の機能が含まれている可能性がありますが、ドキュメントには何もありませんでした。いずれにせよ、各入力トークンに関連付けられたロケーション オブジェクトを維持するのは簡単です。

その情報を使用すると、トークンを分離するものが空白である限り、隣接する 2 つのトークン間の空白を簡単に再作成できます。コメントは別の問題です。

各トークンが語彙化されているときに、先行する空白 (およびコメント) を各トークンに追加するよりも簡単かどうかは、判断の呼び出しです。

于 2016-06-01T22:52:58.103 に答える
0

処理しているトークンに応じて、異なる数のスペースを出力する match ステートメントを使用できます。トークンが id,num,define statement, assign(=) の場合、通常は前に 1 つのスペースを出力します。

トークンが算術式の場合、前に 1 つのスペース、後に 1 つのスペースを出力します。

if または while ステートメントを扱っている場合は、本文を 4 つのスペースでインデントします。

次のような pretty_print 関数を作成するのが最善の策だと思います。

let rec pretty_print pos ast =
   match ast with
    |Some_token -> String.make pos ' '; (* adds 'pos' number of spaces; pos will start off as zero. *)
                   print_string "Some_token";
    |Other_token...

つまり、再帰関数で各トークンを個別に照合し、適切な数のスペースを出力することで、空白を処理します。

于 2016-06-03T08:02:58.683 に答える