コード生成のためのインデント
-
03-07-2019 - |
質問
多くの場合、プログラマは他のコードを生成するコードを記述します。
(技術用語はメタプログラミングですが、単なるクロスコンパイラよりも一般的です; HTMLまたはすべてのXSLTファイルを生成するすべてのPHP Webページについて考えてください。)
私がやりがいのある分野の1つは、手書きのソースファイルとコンピューター生成オブジェクトファイルの両方がデバッグを容易にするために明確にインデントされていることを保証する技術を考案することです。多くの場合、2つの目標は競合しているようです。
PHP / HTMLの組み合わせでは、これが特に難しいと感じています。私はそれが理由だと思う:
- ソースファイルには、生成するPHPよりも多くのHTMLコードがある場合があります
- HTMLファイルは、たとえばSQLステートメントよりも長くなる傾向があり、インデントを改善する必要があります
- HTMLにはスペースに敏感な機能があります(タグ間など)
- 結果はSQLステートメントよりも一般に公開されているHTMLであるため、合理的な作業を行うためのプレッシャーが大きくなります。
これに対処するためにどのテクニックを使用しますか?
編集:私はきれいなHTMLコードを生成することを気にしないために少なくとも3つの引数があることを受け入れます:
- コード生成の複雑さが増します。
- ブラウザによるレンダリングと違いはありません。開発者はFirebugなどを使用して見やすく表示できます。
- 軽度のパフォーマンスヒット-空白文字のダウンロード時間の増加。
インデントを考慮せずにコードを生成することがあります(特にSQL)。
ただし、他の方法を推進するいくつかの引数があります:
- 実際には、生成されたコードを頻繁に読むすることに気づきます。それにアクセスするための余分なステップがあるのは不便です。
- HTMLには時折噛みつくスペースに敏感な問題があります。
たとえば、コードを検討してください:
<div class="foo">
<?php
$fooHeader();
$fooBody();
$fooFooter();
?>
</div>
次のコードよりも明確です:
<div class="foo"><?php
$fooHeader();
$fooBody();
$fooFooter();
?></div>
ただし、HTMLに空白が含まれているため、レンダリングも異なります。
解決
より一般的なケースでは、C ++データベースインターフェイスコードを生成するXSLTコードを記述しました。最初は正しくインデントされたコードをXSLTから出力しようとしましたが、これはすぐに受け入れられなくなりました。私の解決策は、XSLT出力の書式設定を完全に無視してから、を介して非常に長いコード行を実行することでした。 GNUインデント。これにより、デバッグに適した適切にフォーマットされたC ++ソースファイルが生成されました。
HTMLやPHPなどの複合ソースを処理する場合、問題がより厄介になることが想像できます。
他のヒント
ASTを生成し、それを順番に走査して、適切にフォーマットされたソースコードを出力します。
生成されたコードが生成されたコードを支配するときに使用する手法は、インデントパラメーターを渡すことです。
e.g.、Pythonで、より多くのPythonを生成します。
def generateWhileLoop(condition, block, indentPrefix = ""):
print indentPrefix + "while " + condition + ":"
generateBlock(block, indentPrefix + " ")
代わりに、私の気分に応じて:
def generateWhileLoop(condition, block, indentLevel = 0):
print " " * (indentLevel * spacesPerIndent) + "while " + condition + ":"
generateBlock(block, indentLevel + 1)
condition
は同じ行に収まる短いテキストであり、 block
は別のインデントされた行にあるという仮定に注意してください。サブコードをインデントする必要があるかどうかをこのコードで確認できない場合、このメソッドは失敗し始めます。
また、この手法は、比較的少量のPHPをHTMLに振りかける場合にはあまり有用ではありません。
[明確にするために編集:質問とこの回答を書きました。私が使用し、時には便利なテクニックを1つ使用して回答をシードしたかったのですが、このテクニックは一般的なPHPコーディングでは失敗するため、他のアイデアを探しています。]
生成中にインデントを無視するのが最適であることがわかりました。出力されたすべてのコードを後処理する汎用の「コードフォーマット」エンジンを作成しました。このようにして、インデント規則とコード構文規則をジェネレーターとは別に定義できます。この分離には明らかな利点があります。
私は奇数思考の答えに同意します。
問題を反転させて解決することが最善の場合もあります。大量のテキストを生成していることに気付いた場合は、インテリジェントな生成コードを少しだけ使用して、テキストをテンプレートとして作成する方が簡単かどうかを検討してください。または、問題を一連の小さなテンプレートに分割し、それらをアセンブルしてから、各テンプレート全体をインデントできる場合。
PHPでWebサイトを作成すると、HTMLと機能固有のPHPの混合に問題があり、概要が制限され、デバッグが難しくなります。この場合、混合を回避するための解決策は、テンプレート駆動型コンテンツを使用することです。たとえば、 Smarty を参照してください。より良い意図を除いて、コンテンツのテンプレート化は、たとえばパッチ適用の高速化など、他のことにも役立ちます。顧客がレイアウトの変更を必要とする場合、その特定のレイアウトの問題は、データを生成する機能的なPHPコード(およびその逆)に煩わされることなく、迅速に発見および修正できます。
特にHTML生成について-なぜ重要なのですか?
インデントパラメーターの周りを通過し、どれくらい深くネストされているかなどを把握しようとかなりの時間を費やしています。一般的な時間の浪費は別として(最終レンダリングには違いがないため)出力)、他のHTMLマークアップを追加し、divなどでページをラップするときに、これらすべてをどのように維持しますか?
とにかく、 Firebug (および IE開発者用ツールバー IEをテストするため)、両方ともネスト形式でHTMLを表示します、そしてページ要素をクリックするだけで直接マークアップを表示できます-未加工のソースHTML出力を見るよりもずっと効率的です。
私はPHP / HTMLの状況で、各コードフラグメントをそのソースコードで一貫してインデントしておくようにしています。これにより、コードが本当に重要な場所で読みやすくなり、通常には、読みやすいHTML出力が生成されるという副作用があります。他の人が言ったように、firebugは残りを処理します。