tl;dr:@riciはすでにワンライナーの答えを出しています-パーサーを構築した私自身の経験からそれを少し拡張したいと思います。
以前は、入力から AST に 1 ステップで直接変換するパーサーを作成していました。保守性の悪夢になってしまったので、私はもうそれをしません。非常に多くの異なるタスク (文字列の認識、エラー報告、コンテキスト依存の制約、ツリーの構築) が一緒に粉砕されたため、パーサーは完全に混乱しました。テストとデバッグは非常に難しく、変更を加えるのは楽しくありませんでした。さらに、パーサーと文法の間の対応 (私の意見では、これは文法ベースの解析アプローチの非常に価値のある機能です) が失われました。
私の現在のアプローチは、入力文法に (できれば) 正確に対応するパーサーを作成し、同時にデフォルトの CST (Concrete Syntax Tree) を作成することです。はい、これは、CST に開き中括弧や閉じ中括弧などの「ジャンク」が含まれていることを意味しますが、パーサーがツリー構築で混乱する必要がまったくないことを意味します。
その後、後の状態で、CST は AST に変換されます。状況依存の制約 (オブジェクト リテラルの一意のキーなど) がある場合は、ここですべてをチェックしようとします (パーサーから除外します) 。このステップでは、「がらくた」(中括弧などの具体的な構文) が破棄されます。このステップは、具象構文シュガーを脱糖する場所でもあります。実際、私の構文シュガーの定義は、具象には現れるが抽象構文には現れないものです。
混乱を個々のステップに分離することで気付いた利点は、解析コードがより簡潔で短く、より宣言的であり、物事がよりモジュール化されていることです (つまり、CST を AST にマップする方法を変更せずに変更できます)。解析コードについても考える必要があります)。
要約:具象構文から抽象構文に変換するときに構文糖* を削除します。つまり、砂糖は AST にまったく表示されません。
*: シンタックス シュガーの定義は異なる場合があります。