構文解析過程は2つの部から構成されています。
gram.yとscan.lで定義されているパーサは、Unixのツールyaccとlexを使って構築されます。
変換プロセスは、パーサから返されたデータ構造の変更や追加を行います。
パーサは、(平文のASCIIテキストとして渡される)問い合わせ文字列が正しい構文になっているかチェックしなければいけません。 もし構文が正しい場合は構文解析ツリーが作られて返されます。 正しくない場合はエラーが返されます。 パーサと字句解析はUnixでよく知られたツールのlexとyaccを使用して実装されています。
字句解析はファイルscan.lで定義され、識別子やSQLキーワードなどの確認を担当します。 検出された全てのキーワードや識別子に対しトークンが生成されパーサに渡されます。
パーサはファイルgram.yの中で定義され、文法ルールとルールが実行された時に実行されるアクションの組から構成されています。 アクションのコード(実際はC言語コードです)は構文解析ツリーを作るのに使われます。
ファイルscan.lはプログラムlexを使ってCのソースファイルscan.cに変換されます。 そしてgram.yはyaccを使ってgram.cに書き換えられます。 これらの書き換えが終わると、パーサを作るために通常のCコンパイラが使えるようになります。 生成されたCのファイルには絶対に変更を加えないでください。 と言うのは次にlexもしくはyacc が呼ばれた時に上書きされる可能性があるからです。
注意: ここで言及した書き換えやコンパイルは通常PostgreSQLのソースと一緒に配布されるmakefileを使って自動的に行われます。
yaccまたはgram.yで定義される文法ルールの詳細は本稿では説明しきれません。 lexやyaccについては本や資料がたくさん出ています。 gram.yの文法の勉強を始める前にyaccの知識が必須となります。 その知識なしではそこで何が起こっているのかを理解することは難しいでしょう。
構文解析過程ではSQLの構文構造に関する固定ルールのみを使って構文解析ツリーを作成します。 システムカタログの参照を行わないので、要求されている操作の詳細な語義は理解しません。 構文解析が終わった後に入力としてパーサから戻されたツリーを書き換えプロセスが引き受け、どのテーブル、関数、そして演算子が問い合わせによって参照されているのかの判断に必要な語義翻訳を行います。 この情報を表すために作成されるデータ構造を問い合わせツリーと呼びます。
語義解釈と入力の構文解釈を切り分ける理由はシステムカタログの参照はトランザクション内でのみ行われ、問い合わせ文字列を受け取ってすぐにトランザクションを開始することは好ましくないと考えられるからです。 入力に対する構文解析過程ではトランザクション管理コマンド(BEGIN、ROLLBACKなど)を特定するだけで十分であるとともに、それ以上の分析を行わなくても正しい処理が実行されます。 実際の問い合わせ(例えばSELECTもしくはUPDATE)に関わっていると言うことがわかっていて既にあるトランザクション内にいなければ新規トランザクションを開始することは問題ありません。これ以降に限り書き換えプロセスを起動することができます。
変換過程で作成された問い合わせツリーはほとんどの箇所での素の構文解析ツリーに構造的には似ています。 とは言っても細部では多くの相違が存在します。 例えば、構文解析ツリーのFuncCallノードは構文的には関数呼び出しのように見えます。 参照された名前が通常の関数になるか集約関数となるかによってFuncExprもしくはAggrefに書き換えられることがあります。 さらに、列の実際のデータ型と表現結果に関する情報が問い合わせツリーに書き加えられます。