7

CSS と JS 用に見つけたいくつかのライブラリに相当する PHP を作成する方法について考えています。

1つはLess CSSですdynamic stylesheet language。背後にLess CSSある基本的な考え方は、「通常の」CSS がサポートしていない などのエンティティを含むより動的な CSS ルールを作成しmixinsfunctions最終的にそれらの構文を通常の CSS にLess CSS コンパイルできるようにすることです。

(一種の) 同様のパターンで動作するもう 1 つの興味深い JS ライブラリは、CoffeeScript「より整然としたシンプルな」コードを記述して、通常の Javascriptにコンパイルできるものです。

PHP 用の単純な同様のインターフェースを作成するにはどうすればよいでしょうか? 概念実証として。私は物事を学ぼうとしているだけです。クラスを拡張する単純な使用例を見てみましょう。

class a
{
    function a_test()
    {
        echo "This is test in a ";
    }
}

class b extends a
{
    function b_test()
    {
        parent::a_test();
        echo "This is test in b";
    }
}

$b = new b();
$b->b_test();

ユーザーにクラスbを次のように書かせたいとします(例として):

class b[a] //would mean b extends a
{
    function b_test()
    {
        [a_test] //would mean parent::a_test()
        echo "This is test in b";
    }
}

そして、後でそのコードを通常のPHPに「解決」させます(通常は、別のコマンド/プロセスを実行することによって)。私の質問は、このようなものを作成するにはどうすればよいかということです。PHP で実行できますか? C/C++ のようなものを使用する必要がありますか? この問題に取り組むとしたら、どのようにアプローチすればよいでしょうか? オンラインのリソースはありますか? どんなポインタでも大歓迎です!

4

1 に答える 1

8

言語トランスコーダーは、思っているほど簡単ではありません。

preg_replaceあなたが与えた例は、クラス定義を探して に置き換える a で[a]非常に簡単に実装できますextends a

しかし、より複雑な機能には、より小さな論理的なコードのスイートであるトランスコーダーが必要です。

ほとんどのプログラマー専門用語では、トランスコーダーをコンパイラーと誤って呼んでいますが、コンパイラーとトランスコーダーの違いは、コンパイラーがソース コードを読み取って生のバイナリ マシン コードを出力するのに対し、トランスコーダーはソース コードを読み取って (別の) ソース コードを出力することです。

たとえば、PHP (または JavaScript) ランタイムは、コンパイラーでもトランスコーダーでもなく、インタープリターです。

専門用語については十分ですが、トランスコーダーについて話しましょう。

トランスコーダーを構築するには、最初にトークナイザーを構築する必要があります。トークナイザーはソース コードをトークンに分割します。つまり、「クラス」またはクラスの名前、「関数」または関数の名前などの単語全体が表示される場合、その単語をキャプチャし、それをトークンと見なします。開き丸かっこ、開き中かっこ、角かっこなどの別のトークンに遭遇すると、別のトークンと見なされます。

幸いなことに、PHP で使用できる認識済みのすべてのトークンは、PHP にバンドルされている関数であるtoken_get_allによって既に簡単にスキャンされています。PHP はシンボルの使用方法についていくつかのことを想定しているため、問題が発生する可能性がありますが、全体としてこの関数を使用することはできます。

トークナイザーは、見つけたすべてのトークンのフラット リストを作成し、それをパーサーに渡します。

パーサーはトランスコーダーの第 2 フェーズであり、トークンのリストを読み取り、「token[0] がクラスで、token[1] が name_value の場合、クラスがある」などを決定します。抽象構文ツリーを持つ必要があるトークンの完全なリスト。

抽象構文ツリーは、ソース コードに関する関連情報のみを記号的に保持する構造です。

$ast = array(
    'my_derived_class' => array(
        'implements' => array(
            'my_interface_1',
            'my_interface_2',
            'my_interface_3'),
        'extends' => 'my_base_class',
        'members' => array(
            'my_property_name' => 'my_default_value',
            'my_method_name' => array( /* ... */ )
        )
    )
);

抽象構文ツリーを取得したら、それを調べて宛先ソース コードを出力する必要があります。

本当にトリッキーな部分はパーサーです (解析している言語の複雑さに応じて) 類似のケースを互いに区別するために、バックトラッキング アルゴリズムまたはその他の形式のパターン マッチングが必要になる場合があります。

これについては、Terence Parr の本http://pragprog.com/book/tpdsl/language-implementation-patternsを読むことをお勧めします。この本では、トランスコーダーを作成するために必要な設計パターンが詳細に説明されています。

Terrence の本では、HTML や CSS などの一部の言語が PHP や JavaScript よりも (構造的に) はるかに単純である理由と、それが言語パーサーの複雑さにどのように関係しているかがわかります。

于 2012-10-03T21:37:57.960 に答える