ホームページ バックエンド開発 PHPチュートリアル PHP 構文アナライザー: RE2C && BISON の概要_PHP チュートリアル

PHP 構文アナライザー: RE2C && BISON の概要_PHP チュートリアル

Jul 13, 2016 pm 05:54 PM
amp php アナライザ 要約する 私たち 文法 プロジェクト


この前に、PHP コードから拡張機能を自動的に生成するプロジェクトを試してみました

PHP にコンパイルされたものを phptoc と呼びます。

しかし、諸事情によりこのプロジェクトは中止となりました。

この記事を書いたのは、第一にこの分野の情報が少なすぎるため、第二に、PHP 構文解析を理解できるように、学んだことを要約するためです。

PHPソースコードの研究をより高いレベルに高めていきます^.^…

できるだけわかりやすく、わかりやすく書くように心がけています。

このプロジェクトのアイデアは、Facebook のオープンソース プロジェクト HipHop から生まれました。

実際のところ、私はこのプロジェクトの 50% ~ 60% のパフォーマンス向上については懐疑的です。根本的に言えば、PHP が APC キャッシュを使用するとパフォーマンスが低下するのではないかと考えています。

ヒップホップについては、まだテストしていないので、確かなことは言えません。

PHPtoc、私は C プログラマーを解放したいだけであり、PHPer が PHP コードを使用して PHP 拡張機能のパフォーマンスに近い拡張機能を作成できるように、それが達成されることを願っています。

プロセスは次のとおりです: PHP ファイルを読み取り、PHP コードを解析し、構文アナライザーを実行し、対応する ZendAPI を生成し、それを拡張機能にコンパイルします。

本題へ

ここで最も難しいのは構文アナライザーです。PHP にも独自の構文アナライザーがあることを誰もが知っているはずです。現在のバージョンでは re2c と Bison が使用されています。

ということで、当然私もこの組み合わせを使いました。

PHP の構文アナライザーを使用したい場合は、zend_ language_parser.y と zend_ language_scanner.l を変更して再コンパイルする必要があるため、現実的ではありません。これは難しいだけでなく、PHP 自体に影響を与える可能性もあります。

そこで、独自の構文解析ルールのセットを書き直すことにしました。この関数は、PHP の構文アナライザーを書き直すのと同じであり、もちろん、一部の珍しいものは破棄されます。

re2c && yacc/bison は、対応するファイルを参照して *.c ファイルにコンパイルし、最後に gcc でコンパイルすると

が生成されます

独自のプログラムに。したがって、これらは基本的に構文解析プログラムではなく、私たちのルールに基づいて独立した C テキストを生成するだけです

この c ファイルは、私たちが必要とする実際の構文解析プログラムです。私はこれを構文ジェネレーターと呼びたいと思います。以下に示すように:

注: 画像の a.c は、スキャナーによって生成された最終コードです。 。

re2c スキャナー、作成したスキャン ルール ファイルが scanner.l と呼ばれる場合、作成した PHP ファイルのコンテンツをスキャンし、

に従ってスキャンします。

私たちが作成したルールはさまざまなトークンを生成し、それらを解析に渡します。

私たちが書いた (f)lex 文法ルールは、たとえば、Parse.y と呼ばれます

yacc/bison を通じて parse.tab.h、parse.tab.c ファイルにコンパイルされます。Parse はさまざまなトークンに従ってさまざまな操作を実行します。

たとえば、PHP コードは「echo 1」です。

スキャンには次のルールがあります:

「エコー」{

T_ECHO を返します;

}

スキャナー関数 scan は「echo 1」文字列を取得し、このコード部分をループして、エコー文字列が見つかった場合は、トークンをキーワード T_ECHO,

として返します。

parse.y と Scanner.l はそれぞれ、scanner.c と parse.tab.c という 2 つの C ファイルを生成し、それらを gcc で一緒にコンパイルします。

以下で詳しくお話します

ご興味がございましたら、中国語版も翻訳しましたので、ぜひご覧ください。

まだ終わっていないので、また後日載せます。

re2c はいくつかのマクロ インターフェイスを提供していますが、私はそれを翻訳しただけなので、原文が必要な場合は、上記のアドレスにアクセスしてください。

インターフェースコード:
他のスキャナ プログラムとは異なり、re2c は完全なスキャナを生成しません。ユーザーはインターフェイス コードを提供する必要があります。ユーザーは、次のマクロまたはその他の対応する構成を定義する必要があります。
YYCONDTYPE
-c モードでは、-to パラメーターを使用してファイルを生成できます。列挙型を含む条件を使用します。各値はルール セットの条件として使用されます。
YYCタイプ
入力シンボルを維持するために使用されます。通常は char または unsigned char です。
YYCTXマーカー
*タイプ YYCTYPE の式の場合、生成されたコード トレースバック情報のコンテキストは YYCTXMARKER に保存されます。スキャナ ルールでコンテキスト内で 1 つ以上の正規表現を使用する必要がある場合、ユーザーはこのマクロを定義する必要があります。
YYカーソル
*YYCTYPE 型の式ポインターは現在入力されているシンボルを指し、生成されたコードは最初にシンボルとして照合され、YYCURSOR は現在のトークンの最初の文字を指すと想定されます。最後に、YYCURSOR は次のトークンの最初の文字を指します。
YYDEBUG(状態,現在)
これは、-d フラグが指定されている場合にのみ必要です。ユーザー定義関数を呼び出すときに、生成されたコードをデバッグするのは非常に簡単です。
この関数には、void YYDEBUG(int state,char current) というシグネチャが必要です。最初のパラメータは state を受け入れ、デフォルト値は -1 です。2 番目のパラメータは入力の現在位置を受け入れます。
YYFILL(n)
バッファーを埋める必要がある場合、生成されたコードは YYFILL(n) を呼び出し、少なくとも n 文字を提供します。 YYFILL(n) は、必要に応じて YYCURSOR、YYLIMIT、YYMARKER、および YYCTXMARKER を調整します。一般的なプログラミング言語では、n は最長のキーワードの長さに 1 を加えたものに等しいことに注意してください。ユーザーは /*!max:re2c*/ で YYMAXFILL を 1 回定義して、最大長を指定できます。 -1 を使用すると、YYMAXFILL は /*!re2c*/ の後に 1 回ブロックされます。
YYGETCONDITION()
-c モードを使用した場合、この定義はスキャナ コードの前に設定された条件を取得します。この値は、列挙型 YYCONDTYPE の型に初期化する必要があります。
YYGETSTATE()
-f モードが指定されている場合、ユーザーはこのマクロを定義する必要があります。その場合、スキャナーの開始時に保存された状態を取得するために、生成されたコードは YYGETSTATE() を呼び出します。この値が -1 の場合、YYGETSTATE() は符号付き整数を返す必要があります。初回実行。それ以外の場合、この値は以前の YYSETSTATE によって保存された状態と同じになります。それ以外の場合、スキャナは操作を再開した直後に YYFILL(n) を呼び出します。
イリミット
式 *YYCTYPE のタイプは、バッファーの終わりをマークします (YYLIMIT(-1) はバッファーの最後の文字です)。生成されたコードは、YYCORSUR と YYLIMIT を継続的に比較して、いつバッファーを埋めるかを決定します。
YYSETCONDITION(c)
このマクロは、-c モードが指定され、変換ルールが使用される場合にのみ、変換ルールの条件を設定するために使用されます。
YYSET州
ユーザーは、-f モードを指定する場合にのみこのマクロを定義する必要があります。その場合、生成されたコードは、YYFILL(n) の前に YYSETSTATE(s) を呼び出します。YYSETSTATE のパラメーターは、固有の ID と呼ばれる符号付き整数です。 ) 実例。
YYマーカー
*YYCTYPE タイプの式。生成されたコードはトレースバック情報を YYMARKER に保存します。一部の単純なスキャナは役に立たない場合があります。
スキャナーは、その名前が示すように、ファイルをスキャンしてキーコードを見つけます。

スキャナファイル構造:

/* #include ファイル*/
/*マクロ定義*/
//スキャン関数
int scan(char *p){
/*スキャナールールエリア*/
}
//scan 関数を実行し、トークンを yacc/bison に返します。
int yylex(){
int トークン;
char *p=YYCURSOR;//YYCURSOR は PHP テキスト コンテンツを指すポインターです
while(token=scan(p)){//ポインタ p は、上で定義したスキャナであるかどうかを判断するためにここに移動します...
トークンを返す;
}
}
int main(int argc,char**argv){
BEGIN(初期);///
YYCURSOR=argv[1];//YYCURSOR は PHP テキスト コンテンツを指すポインターです
yyparse();
}
BEGIN は定義されたマクロです

#define YYCTYPE char //入力記号の種類
#define STATE(名前) yyc##name
#define BEGIN(n) YYSETCONDITION(STATE(n))
#define LANG_SCNG(v) (sc_globals.v)
#SCNG LANG_SCNG を定義します
#define YYGETCONDITION() SCNG(yy_state)
#define YYSETCONDITION(s) SCNG(yy_state)=s
yyparse 関数は yacc で定義されています

その中に重要なマクロがあります: YYLEX

#define YYLEX yylex()

スキャナーのyylexを実行します

少しねじれている可能性がありますので、結び直してください:

scanner.l では、parse.y パーサー関数 yyparse を呼び出すことにより、この関数は scanner.l の yylex を呼び出して、キー コード トークン yylex を生成します

スキャナーから戻ってきました

トークンは parse.y に返され、parse は異なるトークンに基づいて異なるコードを実行します。

例:

スキャナー.l
#「scanner.h」を含める
#include "parse.tab.h"
int scan(char *p){
/*!re2c
" T_OPEN_TAG に戻る;
}
「エコー」{

T_ECHO を返す;

}
[0-9]+{
T_LNUMBER;
を返します }
*/
}
int yylex(){
int c;

// T_STRING を返します;

int トークン;
char *p=YYCURSOR;
while(token=scan(p)){
トークンを返す;
}
}

int main (int argc,char ** argv){

BEGIN(INITIAL);//初期化
YYCURSOR=argv[1];//ユーザーが入力した文字列をYYCURSORに入れる
yyparse();//yyparse() -》yylex()-》yyparse()
0 を返す;
}
こんな簡単なスキャナーが出来ました

パーサーについてはどうですか?

パーサーとして flex と bison を使用します。 。 。

flexのファイル構造について:

%{

/*
C コードセグメントは、lex コンパイル後に生成される C ソースファイルにそのままコピーされます
いくつかのグローバル変数、配列、関数ルーチンなどを定義できます...
*/
#含める
#「scanner.h」を含める
extern int yylex();//scanner.l で定義されています。 。
void yyerror(char *);
#YYPARSE_PARAM tsrm_ls を定義します
#YYLEX_PARAM tsrm_ls を定義します
%}
{トークンが定義される定義セクション}
//これがキーです。トークン プログラムはこれに基づいて切り替えを行います。
%トークンT_OPEN_TAG
%トークンT_ECHO
%トークン T_LNUMBER
%%
{ルールセクション}
開始:
T_OPEN_TAG{printf("startn") }
|開始ステートメント
;
ステートメント:
T_ECHO expr {printf("echo :%sn",$3)}
;
式:
T_LNUMBER {$$=$1;}
%%
{ユーザー コード スニペット}
void yyerror(char *msg){
printf("エラー:%sn",msg);
}
ルールセクションでは、start が始まりです。scan が PHP 開始タグを認識すると、T_OPEN_TAG を返し、括弧内のコードを実行して start を出力します。
scanner.l では、scan の呼び出しは while ループであるため、PHP コードの最後までチェックされます。

yyparse は、スキャンによって返されたタグに基づいて切り替えられ、その後、対応するコードに移動します。たとえば、yyparse.y は、現在のトークンが T_OPEN_TAG,

であることを検出します。

マクロ #line を介して parse.y に対応する 21 行目、T_OPEN_TAG の位置にマッピングされ、実行されます

では、TOKEN は yyparse に返された後、何をしたのでしょうか?

より直感的にするために、gdb トラッキングを使用します。

このとき、yycharは258です。258とは何ですか? PHP 構文アナライザー: RE2C && BISON の概要_PHP チュートリアル

258はbisonが自動生成する列挙型データです。 PHP 構文アナライザー: RE2C && BISON の概要_PHP チュートリアル

続ける

YYTRANSLATE マクロは yychar を受け入れ、対応する値を返します

#define YYTRANSLATE(YYX) ((unsigned int) (YYX)

/* YYTRANSLATE[YYLEX] -- YYLEX に対応する Bison シンボル番号。  */
static const yytype_uint8 yytranslate[] =
{
       0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 27, 2,
      22, 23, 2, 2, 28, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
       2, 26, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 24, 2, 25, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
       5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
      15、 16、 17、 18、 19、 20
};
yyparse拿到这个值,断続翻訳,

PHP 構文アナライザー: RE2C && BISON の概要_PHP チュートリアル

bison 会は多用して映る数グループを生成し、最終的な翻訳を yyn に保存します

この样bison就能找到トークン所对应的代码

スイッチ (yyn)
    {
        ケース 2:

/* yacc.c の 1455 行目 */
#30行目「parse.y」
    {printf("startn"); ;}
    休憩;
このように、不断循環、トークン条項の逐次実行を生成し、その後、所望の zend 関数等を解析し、对のop保護存在哈希表を生成します。これらはここでは取り上げません、

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/477941.html技術記事これに先立って、私は以前、あるトピックを検討していましたが、つまり、私たちの PHP コードを自動生成して PHP に展開し、phptoc を呼び出しました。
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Dec 24, 2024 pm 04:42 PM

PHP 8.4 では、いくつかの新機能、セキュリティの改善、パフォーマンスの改善が行われ、かなりの量の機能の非推奨と削除が行われています。 このガイドでは、Ubuntu、Debian、またはその派生版に PHP 8.4 をインストールする方法、または PHP 8.4 にアップグレードする方法について説明します。

今まで知らなかったことを後悔している 7 つの PHP 関数 今まで知らなかったことを後悔している 7 つの PHP 関数 Nov 13, 2024 am 09:42 AM

あなたが経験豊富な PHP 開発者であれば、すでにそこにいて、すでにそれを行っていると感じているかもしれません。あなたは、運用を達成するために、かなりの数のアプリケーションを開発し、数百万行のコードをデバッグし、大量のスクリプトを微調整してきました。

PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 Dec 20, 2024 am 11:31 AM

Visual Studio Code (VS Code とも呼ばれる) は、すべての主要なオペレーティング システムで利用できる無料のソース コード エディター (統合開発環境 (IDE)) です。 多くのプログラミング言語の拡張機能の大規模なコレクションを備えた VS Code は、

JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 Apr 05, 2025 am 12:04 AM

JWTは、JSONに基づくオープン標準であり、主にアイデンティティ認証と情報交換のために、当事者間で情報を安全に送信するために使用されます。 1。JWTは、ヘッダー、ペイロード、署名の3つの部分で構成されています。 2。JWTの実用的な原則には、JWTの生成、JWTの検証、ペイロードの解析という3つのステップが含まれます。 3. PHPでの認証にJWTを使用する場合、JWTを生成および検証でき、ユーザーの役割と許可情報を高度な使用に含めることができます。 4.一般的なエラーには、署名検証障害、トークンの有効期限、およびペイロードが大きくなります。デバッグスキルには、デバッグツールの使用とロギングが含まれます。 5.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

PHPでHTML/XMLを解析および処理するにはどうすればよいですか? PHPでHTML/XMLを解析および処理するにはどうすればよいですか? Feb 07, 2025 am 11:57 AM

このチュートリアルでは、PHPを使用してXMLドキュメントを効率的に処理する方法を示しています。 XML(拡張可能なマークアップ言語)は、人間の読みやすさとマシン解析の両方に合わせて設計された多用途のテキストベースのマークアップ言語です。一般的にデータストレージに使用されます

母音を文字列にカウントするPHPプログラム 母音を文字列にカウントするPHPプログラム Feb 07, 2025 pm 12:12 PM

文字列は、文字、数字、シンボルを含む一連の文字です。このチュートリアルでは、さまざまな方法を使用してPHPの特定の文字列内の母音の数を計算する方法を学びます。英語の母音は、a、e、i、o、u、そしてそれらは大文字または小文字である可能性があります。 母音とは何ですか? 母音は、特定の発音を表すアルファベットのある文字です。大文字と小文字など、英語には5つの母音があります。 a、e、i、o、u 例1 入力:string = "tutorialspoint" 出力:6 説明する 文字列「TutorialSpoint」の母音は、u、o、i、a、o、iです。合計で6元があります

PHPでの後期静的結合を説明します(静的::)。 PHPでの後期静的結合を説明します(静的::)。 Apr 03, 2025 am 12:04 AM

静的結合(静的::) PHPで後期静的結合(LSB)を実装し、クラスを定義するのではなく、静的コンテキストで呼び出しクラスを参照できるようにします。 1)解析プロセスは実行時に実行されます。2)継承関係のコールクラスを検索します。3)パフォーマンスオーバーヘッドをもたらす可能性があります。

PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? Apr 03, 2025 am 12:03 AM

PHPの魔法の方法は何ですか? PHPの魔法の方法には次のものが含まれます。1。\ _ \ _コンストラクト、オブジェクトの初期化に使用されます。 2。\ _ \ _リソースのクリーンアップに使用される破壊。 3。\ _ \ _呼び出し、存在しないメソッド呼び出しを処理します。 4。\ _ \ _ get、dynamic属性アクセスを実装します。 5。\ _ \ _セット、動的属性設定を実装します。これらの方法は、特定の状況で自動的に呼び出され、コードの柔軟性と効率を向上させます。

See all articles